From 6cec290f98103827727905874c5a9c5ced0bcca8 Mon Sep 17 00:00:00 2001 From: mehekj Date: Thu, 14 Oct 2021 16:21:03 -0400 Subject: pre-redesign changes (zoom but no scroll) --- src/client/views/AudioWaveform.tsx | 26 +-- .../collections/CollectionStackedTimeline.scss | 167 ++++++++++--------- .../collections/CollectionStackedTimeline.tsx | 46 +++--- src/client/views/nodes/AudioBox.scss | 178 +++++++++++++-------- src/client/views/nodes/AudioBox.tsx | 14 ++ 5 files changed, 256 insertions(+), 175 deletions(-) (limited to 'src') diff --git a/src/client/views/AudioWaveform.tsx b/src/client/views/AudioWaveform.tsx index 270b3869c..7b9b1aa81 100644 --- a/src/client/views/AudioWaveform.tsx +++ b/src/client/views/AudioWaveform.tsx @@ -18,6 +18,7 @@ export interface AudioWaveformProps { layoutDoc: Doc; clipStart: number; clipEnd: number; + zoomFactor: number; PanelHeight: () => number; } @@ -28,28 +29,30 @@ export class AudioWaveform extends React.Component { @computed get waveHeight() { return Math.max(50, this.props.PanelHeight()); } @computed get clipStart() { return this.props.clipStart; } @computed get clipEnd() { return this.props.clipEnd; } - @computed get audioBuckets() { return Cast(this.props.layoutDoc[this.audioBucketField(this.clipStart, this.clipEnd)], listSpec("number"), []); } + @computed get zoomFactor() { return this.props.zoomFactor; } + @computed get audioBuckets() { return Cast(this.props.layoutDoc[this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor)], listSpec("number"), []); } - audioBucketField = (start: number, end: number) => "audioBuckets/" + start.toFixed(2).replace(".", "_") + "/" + end.toFixed(2).replace(".", "_"); + audioBucketField = (start: number, end: number, zoomFactor: number) => "audioBuckets/" + "/" + start.toFixed(2).replace(".", "_") + "/" + end.toFixed(2).replace(".", "_") + "/" + (zoomFactor * 10); componentWillUnmount() { this._disposer?.(); } componentDidMount() { - this._disposer = reaction(() => ({ clipStart: this.clipStart, clipEnd: this.clipEnd, fieldKey: this.audioBucketField(this.clipStart, this.clipEnd) }), - ({ clipStart, clipEnd, fieldKey }) => { + console.log("new waveform"); + this._disposer = reaction(() => ({ clipStart: this.clipStart, clipEnd: this.clipEnd, fieldKey: this.audioBucketField(this.clipStart, this.clipEnd, this.zoomFactor), zoomFactor: this.props.zoomFactor }), + ({ clipStart, clipEnd, fieldKey, zoomFactor }) => { if (!this.props.layoutDoc[fieldKey]) { // setting these values here serves as a "lock" to prevent multiple attempts to create the waveform at nerly the same time. - const waveform = Cast(this.props.layoutDoc[this.audioBucketField(0, this.props.rawDuration)], listSpec("number")); + const waveform = Cast(this.props.layoutDoc[this.audioBucketField(0, this.props.rawDuration, 1)], listSpec("number")); this.props.layoutDoc[fieldKey] = waveform && new List(waveform.slice(clipStart / this.props.rawDuration * waveform.length, clipEnd / this.props.rawDuration * waveform.length)); - setTimeout(() => this.createWaveformBuckets(fieldKey, clipStart, clipEnd)); + setTimeout(() => this.createWaveformBuckets(fieldKey, clipStart, clipEnd, zoomFactor)); } }, { fireImmediately: true }); } // decodes the audio file into peaks for generating the waveform - createWaveformBuckets = async (fieldKey: string, clipStart: number, clipEnd: number) => { + createWaveformBuckets = async (fieldKey: string, clipStart: number, clipEnd: number, zoomFactor: number) => { axios({ url: this.props.mediaPath, responseType: "arraybuffer" }).then( (response) => { const context = new window.AudioContext(); @@ -60,12 +63,15 @@ export class AudioWaveform extends React.Component { const startInd = clipStart / this.props.rawDuration; const endInd = clipEnd / this.props.rawDuration; const decodedAudioData = rawDecodedAudioData.slice(Math.floor(startInd * rawDecodedAudioData.length), Math.floor(endInd * rawDecodedAudioData.length)); + const numBuckets = Math.floor(AudioWaveform.NUMBER_OF_BUCKETS * zoomFactor); + + console.log(numBuckets); const bucketDataSize = Math.floor( - decodedAudioData.length / AudioWaveform.NUMBER_OF_BUCKETS + decodedAudioData.length / numBuckets ); const brange = Array.from(Array(bucketDataSize)); - const bucketList = numberRange(AudioWaveform.NUMBER_OF_BUCKETS).map( + const bucketList = numberRange(numBuckets).map( (i: number) => brange.reduce( (p, x, j) => @@ -87,7 +93,7 @@ export class AudioWaveform extends React.Component { NumCast(anchor._timecodeToShow, NumCast(anchor[this.props.startTag])); @@ -216,7 +220,9 @@ export class CollectionStackedTimeline extends CollectionSubView< @action onPointerDownTimeline = (e: React.PointerEvent): void => { const rect = this._timeline?.getBoundingClientRect(); + const scrollLeft = this._timeline?.scrollLeft; const clientX = e.clientX; + const diff = rect ? clientX - rect?.x : null; const shiftKey = e.shiftKey; if (rect && this.props.isContentActive()) { const wasPlaying = this.props.playing(); @@ -529,7 +535,7 @@ export class CollectionStackedTimeline extends CollectionSubView< } @computed get renderAudioWaveform() { return !this.props.mediaPath ? null : ( -
+
); @@ -556,7 +563,7 @@ export class CollectionStackedTimeline extends CollectionSubView< } render() { - const timelineContentWidth = this.props.PanelWidth(); + const timelineContentWidth = this.props.PanelWidth() * this.zoomFactor; const overlaps: { anchorStartTime: number; anchorEndTime: number; @@ -573,8 +580,9 @@ export class CollectionStackedTimeline extends CollectionSubView< ref={(timeline: HTMLDivElement | null) => (this._timeline = timeline)} onClick={(e) => this.isContentActive() && StopEvent(e)} onPointerDown={(e) => this.isContentActive() && this.onPointerDownTimeline(e)} - style={{ width: `${this._zoomFactor * 100}%` }} + onPointerEnter={(e) => { console.log("scroll"); e.preventDefault(); e.stopPropagation(); }} > + {drawAnchors.map((d) => { const start = this.anchorStart(d.anchor); const end = this.anchorEnd( @@ -868,19 +876,19 @@ class StackedTimelineAnchor extends React.Component {inner.view} {!inner.anchor.view || !SelectionManager.IsSelected(inner.anchor.view) ? null : ( - <> -
this.onAnchorDown(e, this.props.mark, true)} - /> -
this.onAnchorDown(e, this.props.mark, false)} - /> - - )} + <> +
this.onAnchorDown(e, this.props.mark, true)} + /> +
this.onAnchorDown(e, this.props.mark, false)} + /> + + )} ); } diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss index b33c7f506..a2fdd38e5 100644 --- a/src/client/views/nodes/AudioBox.scss +++ b/src/client/views/nodes/AudioBox.scss @@ -1,51 +1,50 @@ @import "../global/globalCssVariables.scss"; - .audiobox-container, .audiobox-container-interactive { - width: 100%; - height: 100%; - position: inherit; - display: flex; - position: relative; - cursor: default; - - .audiobox-buttons { - display: flex; width: 100%; - align-items: center; + height: 100%; + position: inherit; + display: flex; + position: relative; + cursor: default; - .audiobox-dictation { - position: relative; - width: 30px; - height: 100%; - align-items: center; - display: inherit; - background: $medium-gray; - left: 0px; - color: $dark-gray; - &:hover { - color: $black; - cursor: pointer; - } + .audiobox-buttons { + display: flex; + width: 100%; + align-items: center; + + .audiobox-dictation { + position: relative; + width: 30px; + height: 100%; + align-items: center; + display: inherit; + background: $medium-gray; + left: 0px; + color: $dark-gray; + &:hover { + color: $black; + cursor: pointer; + } + } } - } - .audiobox-control, - .audiobox-control-interactive { - top: 0; - max-height: 32px; - width: 100%; - display: inline-block; - pointer-events: none; - } + .audiobox-control, + .audiobox-control-interactive { + top: 0; + max-height: 32px; + width: 100%; + display: inline-block; + pointer-events: none; + } - .audiobox-control-interactive { - pointer-events: all; - } + .audiobox-control-interactive { + pointer-events: all; + } - .audiobox-record-interactive, - .audiobox-record { + .audiobox-record-interactive, + .audiobox-record { pointer-events: all; cursor: pointer; width: 100%; @@ -59,45 +58,46 @@ color: white; font-weight: bold; background-color: $dark-gray; - } + } - .audiobox-record { + .audiobox-record { pointer-events: none; - } + } - .recording { - margin-top: auto; - margin-bottom: auto; - width: 100%; - height: 100%; - position: relative; - padding-right: 5px; - display: flex; - background-color: $medium-blue; + .recording { + margin-top: auto; + margin-bottom: auto; + width: 100%; + height: 100%; + position: relative; + padding-right: 5px; + display: flex; + background-color: $medium-blue; - .time { - position: relative; - width: 100%; - font-size: $large-header; - text-align: center; - } + .time { + position: relative; + width: 100%; + font-size: $large-header; + text-align: center; + } - .recording-buttons { - position: relative; - margin-top: auto; - margin-bottom: auto; - color: $dark-gray; - &:hover { - color: $black; - } - } + .recording-buttons { + position: relative; + margin-top: auto; + margin-bottom: auto; + color: $dark-gray; + &:hover { + color: $black; + } + } - .time, .recording-buttons { - display: flex; - align-items: center; - padding: 5px; + .time, + .recording-buttons { + display: flex; + align-items: center; + padding: 5px; + } } - } .audiobox-buttons { display: flex; width: 100%; @@ -267,6 +267,44 @@ right: 2px; } + .toolbar-slider { + position: absolute; + top: 75px; + left: 70px; + } + + input[type="range"] { + width: calc(100% - 100px); + height: 16px; + -webkit-appearance: none; + background: none; + } + + input[type="range"]:focus { + outline: none; + } + + input[type="range"]::-webkit-slider-runnable-track { + width: 100%; + height: 5px; + cursor: pointer; + box-shadow: 0; + background: #dfdfdf; + border-radius: 3px; + } + + input[type="range"]::-webkit-slider-thumb { + box-shadow: 0; + border: 0; + height: 7px; + width: 7px; + border-radius: 10px; + background: #4476f7; + cursor: pointer; + -webkit-appearance: none; + margin: -1px; + } + .audiobox-zoom { bottom: 0; left: 30px; diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 2eb34d27a..f2001adcd 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -45,6 +45,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent { + this.timeline?.setZoom(zoom); + } + setupTimelineDrop = (r: HTMLDivElement | null) => { if (r && this.timeline) { this._dropDisposer?.(); @@ -437,6 +442,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent
+
+
{this.timeline && formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode) - NumCast(this.timeline.clipStart)))}
+ + {/* { e.stopPropagation(); }} + onChange={(e: React.ChangeEvent) => { this.zoom(e.target.value); }} + /> */} +
{this.timeline && formatTime(Math.round(NumCast(this.timeline?.clipDuration)))}
-- cgit v1.2.3-70-g09d2