diff options
-rw-r--r-- | src/client/views/nodes/AudioBox.scss | 15 | ||||
-rw-r--r-- | src/client/views/nodes/AudioBox.tsx | 118 | ||||
-rw-r--r-- | src/server/index.ts | 1 |
3 files changed, 110 insertions, 24 deletions
diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss index 306062ced..c0743933e 100644 --- a/src/client/views/nodes/AudioBox.scss +++ b/src/client/views/nodes/AudioBox.scss @@ -150,6 +150,21 @@ z-index: 1000; overflow: hidden; + .audiobox-container { + position: absolute; + width: 10px; + top: 2.5%; + height: 0px; + background: lightblue; + border-radius: 5px; + // box-shadow: black 2px 2px 1px; + opacity: 0.3; + z-index: 500; + border-style: solid; + border-color: darkblue; + border-width: 1px; + } + .audiobox-current { width: 1px; height: 100%; diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index eba1046b2..4805b8643 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -7,7 +7,7 @@ import { AudioField, nullAudio } from "../../../fields/URLField"; import { ViewBoxAnnotatableComponent } from "../DocComponent"; import { makeInterface, createSchema } from "../../../fields/Schema"; import { documentSchema } from "../../../fields/documentSchemas"; -import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse, returnZero, formatTime } from "../../../Utils"; +import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse, returnZero, formatTime, setupMoveUpEvents } from "../../../Utils"; import { runInAction, observable, reaction, IReactionDisposer, computed, action, trace, toJS } from "mobx"; import { DateField } from "../../../fields/DateField"; import { SelectionManager } from "../../util/SelectionManager"; @@ -60,20 +60,22 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD _start: number = 0; _hold: boolean = false; _left: boolean = false; - _markers: Array<any> = []; _first: boolean = false; _dragging = false; _count: Array<any> = []; _timeline: Opt<HTMLDivElement>; _duration = 0; - + _containerX: number = 0; + _invertedX: boolean = false; private _isPointerDown = false; private _currMarker: any; + @observable _visible: boolean = false; + @observable _currX: number = 0; @observable _position: number = 0; @observable _buckets: Array<number> = new Array<number>(); - @observable private _height: number = NumCast(this.layoutDoc._height); + @observable _waveHeight: number | undefined = this.layoutDoc._height; @observable private _paused: boolean = false; @observable private static _scrubTime = 0; @computed get audioState(): undefined | "recording" | "paused" | "playing" { return this.dataDoc.audioState as (undefined | "recording" | "paused" | "playing"); } @@ -354,6 +356,68 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD return (this._pauseEnd - this._pauseStart); } + // starting the drag event for marker resizing + @action + onPointerDownTimeline = (e: React.PointerEvent): void => { + e.stopPropagation(); + e.preventDefault(); + this._isPointerDown = true; + this._timeline?.setPointerCapture(e.pointerId); + + this.start(this._ele!.currentTime); + + const rect = (e.target as any).getBoundingClientRect(); + this._containerX = this._currX = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration); + + document.removeEventListener("pointermove", this.onPointerMoveTimeline); + document.addEventListener("pointermove", this.onPointerMoveTimeline); + document.removeEventListener("pointerup", this.onPointerUpTimeline); + document.addEventListener("pointerup", this.onPointerUpTimeline); + } + + // ending the drag event for marker resizing + @action + onPointerUpTimeline = (e: PointerEvent): void => { + e.stopPropagation(); + e.preventDefault(); + this._isPointerDown = false; + + const rect = (e.target as any).getBoundingClientRect(); + const time = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration); + + // if drag is greater than 15px (didn't use setupMoveEvent) + (this._visible && Math.abs(this._currX - this._containerX) * rect.width / NumCast(this.dataDoc.duration) > 15) ? this.end(time) : this._start = 0; + this._visible = false; + + this._containerX = 0; + this._timeline?.releasePointerCapture(e.pointerId); + + document.removeEventListener("pointermove", this.onPointerMoveTimeline); + document.removeEventListener("pointerup", this.onPointerUpTimeline); + } + + // resizes the marker while dragging + @action + onPointerMoveTimeline = (e: PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); + + if (!this._isPointerDown) { + return; + } + this._visible = true; + const rect = (e.target as any).getBoundingClientRect(); + + this._currX = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration); + + (this._currX - this._containerX < 0) ? this._invertedX = true : this._invertedX = false; + } + + // returns the selection container + @computed get container() { + return <div className="audiobox-container" style={{ left: !this._invertedX ? `${NumCast(this._containerX) / NumCast(this.dataDoc.duration, 1) * 100}%` : `${this._currX / NumCast(this.dataDoc.duration, 1) * 100}%`, width: `${Math.abs(this._containerX - this._currX) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: "100%", top: "0%" }}></div> + } + // creates a new label @action newMarker(marker: Doc) { @@ -375,7 +439,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD @action end(marker: number) { this._hold = false; - const newMarker = Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false, useLinkSmallAnchor: true, hideLinkButton: true, audioStart: this._start, audioEnd: marker, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document }); + const newMarker = this._invertedX ? + Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false, useLinkSmallAnchor: true, hideLinkButton: true, audioStart: marker, audioEnd: this._start, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document }) + : + Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, isLabel: false, useLinkSmallAnchor: true, hideLinkButton: true, audioStart: this._start, audioEnd: marker, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document }); newMarker.data = ""; if (this.dataDoc[this.annotationKey]) { this.dataDoc[this.annotationKey].push(newMarker); @@ -497,9 +564,9 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD @computed get waveform() { return <Waveform color={"darkblue"} - height={this._height} + height={this._waveHeight} barWidth={0.1} - // pos={this.layoutDoc.currentTimecode} + // pos={this.layoutDoc.currentTimecode} need to correctly resize parent to make this work (not very necessary for function) pos={this.dataDoc.duration} duration={this.dataDoc.duration} peaks={this._buckets.length === 100 ? this._buckets : undefined} @@ -559,12 +626,12 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD @action update = (width: number, height: number) => { if (height) { - this._height = 0.8 * NumCast(this.layoutDoc._height); - const canvas2 = document.getElementsByTagName("canvas")[0]; + const height = 0.8 * NumCast(this.layoutDoc._height); + let canvas2 = document.getElementsByTagName("canvas")[0]; if (canvas2) { - const oldWidth = canvas2.width; - const oldHeight = canvas2.height; - canvas2.style.height = `${this._height}`; + let oldWidth = canvas2.width; + let oldHeight = canvas2.height; + canvas2.style.height = `${height}`; canvas2.style.width = `${width}`; const ratio1 = oldWidth / window.innerWidth; @@ -579,7 +646,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD if (canvas1) { const oldWidth = canvas1.width; const oldHeight = canvas1.height; - canvas1.style.height = `${this._height}`; + canvas1.style.height = `${height}`; canvas1.style.width = `${width}`; const ratio1 = oldWidth / window.innerWidth; @@ -592,7 +659,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD const parent = canvas1.parentElement; if (parent) { parent.style.width = `${width}`; - parent.style.height = `${this._height}`; + parent.style.height = `${height}`; } } } @@ -641,23 +708,26 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD if (e.button === 0 && !e.ctrlKey) { const rect = (e.target as any).getBoundingClientRect(); + if (e.target as HTMLElement !== document.getElementById("current")) { const wasPaused = this.audioState === "paused"; this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration); wasPaused && this.pause(); } + + this.onPointerDownTimeline(e); } - if (e.button === 0 && e.altKey) { + if (e.button === 0 && e.shiftKey) { this.newMarker(Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`formatToTime(self.audioStart)`) as any, useLinkSmallAnchor: true, hideLinkButton: true, isLabel: true, audioStart: this._ele!.currentTime, _showSidebar: false, _autoHeight: true, annotationOn: this.props.Document })); } - if (e.button === 0 && e.shiftKey) { - const rect = (e.target as any).getBoundingClientRect(); - this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration); - this._hold ? this.end(this._ele!.currentTime) : this.start(this._ele!.currentTime); - } + // if (e.button === 0 && e.shiftKey) { + // const rect = (e.target as any).getBoundingClientRect(); + // this._ele!.currentTime = this.layoutDoc.currentTimecode = (e.clientX - rect.x) / rect.width * NumCast(this.dataDoc.duration); + // this._hold ? this.end(this._ele!.currentTime) : this.start(this._ele!.currentTime); + // } }}> - <div className="waveform" id="waveform" style={{ height: `${100}%`, width: "100%", bottom: "0px" }}> + <div className="waveform" id="waveform" style={{ height: `${100}%`, width: "100%", bottom: "0px", pointerEvents: "none" }}> {this.waveform} </div> {DocListCast(this.dataDoc[this.annotationKey]).map((m, i) => { @@ -669,8 +739,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD title={`${formatTime(Math.round(NumCast(m.audioStart)))}` + " - " + `${formatTime(Math.round(NumCast(m.audioEnd)))}`} style={{ left: `${NumCast(m.audioStart) / NumCast(this.dataDoc.duration, 1) * 100}%`, - width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 1) * 100}%`, - top: `${this.isOverlap(m) * 1 / (this.dataDoc.markerAmount + 1) * 100}%` + top: `${this.isOverlap(m) * 1 / (this.dataDoc.markerAmount + 1) * 100}%`, + width: `${(NumCast(m.audioEnd) - NumCast(m.audioStart)) / NumCast(this.dataDoc.duration, 1) * 100}%`, height: `${1 / (this.dataDoc.markerAmount + 1) * 100}%` }} onClick={e => { this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation(); }} > <div className="left-resizer" onPointerDown={e => this.onPointerDown(e, m, true)}></div> @@ -747,6 +817,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { const wasPaused = this.audioState === "paused"; this.playFrom(linkTime); e.stopPropagation(); e.preventDefault(); } }} /> </div>; })} + {this._visible ? this.container : null} + <div className="audiobox-current" id="current" onClick={e => { e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc.currentTimecode) / NumCast(this.dataDoc.duration, 1) * 100}%`, pointerEvents: "none" }} /> {this.audio} </div> diff --git a/src/server/index.ts b/src/server/index.ts index 97a90825d..c4e6be8a2 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -103,7 +103,6 @@ function routeSetter({ isRelease, addSupervisedRoute, logRegistrationOutcome }: const serve: PublicHandler = ({ req, res }) => { const detector = new mobileDetect(req.headers['user-agent'] || ""); const filename = detector.mobile() !== null ? 'mobile/image.html' : 'index.html'; - console.log(detector.is("iPhone")); res.sendFile(path.join(__dirname, '../../deploy/' + filename)); }; |