diff options
author | Michael Foiani <sotech117@michaels-mbp-5.devices.brown.edu> | 2022-06-13 14:57:34 -0400 |
---|---|---|
committer | Michael Foiani <sotech117@michaels-mbp-5.devices.brown.edu> | 2022-06-13 14:57:34 -0400 |
commit | c7e4bf8c4e19669666cce610020969cf0d865e49 (patch) | |
tree | 5bce1f51bc61df39337ee5e4c1e3b830d2e034e9 | |
parent | f8bfda0b0139db5f8bf1de602ce211a091d5d9ef (diff) |
Revert "debug w bob"
This reverts commit 1dfb694ffa8f34a834387eb073ffb9bd3a678039.
return to stable version without printing the logs.
-rw-r--r-- | src/client/util/RecordingApi.ts | 385 | ||||
-rw-r--r-- | src/client/views/nodes/RecordingBox/RecordingBox.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/RecordingBox/RecordingView.tsx | 29 |
3 files changed, 186 insertions, 230 deletions
diff --git a/src/client/util/RecordingApi.ts b/src/client/util/RecordingApi.ts index 4c8f55ce5..d56093cee 100644 --- a/src/client/util/RecordingApi.ts +++ b/src/client/util/RecordingApi.ts @@ -5,10 +5,10 @@ import { Doc } from "../../fields/Doc"; import { VideoBox } from "../views/nodes/VideoBox"; type Movement = { - time: number, - panX: number, - panY: number, - scale: number, + time: number, + panX: number, + panY: number, + scale: number, } export type Presentation = { @@ -20,10 +20,9 @@ export type Presentation = { export class RecordingApi { private static get NULL_PRESENTATION(): Presentation { - return { movements: null, meta: {}, totalTime: -1,} + return { movements: null, meta: {}, totalTime: -1, } } -<<<<<<< HEAD // instance variables private currentPresentation: Presentation; private tracking: boolean; @@ -49,78 +48,54 @@ export class RecordingApi { // for now, set playFFView this.playFFView = null; this.timers = null; + + // put a pointerdown event on the doucment to see what the target } -======= - // instance variables - private currentPresentation: Presentation; - private tracking: boolean; - private absoluteStart: number; - - - // create static instance and getter for global use - @observable static _instance: RecordingApi; - public static get Instance(): RecordingApi { return RecordingApi._instance } - public constructor() { - // init the global instance - RecordingApi._instance = this; - - // init the instance variables - this.currentPresentation = RecordingApi.NULL_PRESENTATION - this.tracking = false; - this.absoluteStart = -1; - - // used for tracking movements in the view frame - this.disposeFunc = null; - this.recordingFFView = null; - - // for now, set playFFView - this.playFFView = null; - this.timers = null; - - // put a pointerdown event on the doucment to see what the target - } ->>>>>>> parent of d91ff1f93 (fix bugs with selecting tracking. very stable now.) - // little helper :) - private get isInitPresenation(): boolean { - return this.currentPresentation.movements === null - } + // little helper :) + private get nullPresentation(): boolean { + return this.currentPresentation.movements === null + } - public start = (meta?: Object) => { - // update the presentation mode - Doc.UserDoc().presentationMode = 'recording'; - - // (1a) get start date for presenation - const startDate = new Date(); - // (1b) set start timestamp to absolute timestamp - this.absoluteStart = startDate.getTime(); - - // (2) assign meta content if it exists - this.currentPresentation.meta = meta || {} - // (3) assign start date to currentPresenation - this.currentPresentation.movements = [] - // (4) set tracking true to allow trackMovements - this.tracking = true - } + public start = (meta?: Object) => { + // update the presentation mode + Doc.UserDoc().presentationMode = 'recording'; + + // (1a) get start date for presenation + const startDate = new Date(); + // (1b) set start timestamp to absolute timestamp + this.absoluteStart = startDate.getTime(); + + // (2) assign meta content if it exists + this.currentPresentation.meta = meta || {} + // (3) assign start date to currentPresenation + this.currentPresentation.movements = [] + // (4) set tracking true to allow trackMovements + this.tracking = true + } - /* stops the video and returns the presentatation; if no presentation, returns undefined */ - public * yieldPresentation(clearData: boolean = true): Generator<Presentation | null> { + /* stops the video and returns the presentatation; if no presentation, returns undefined */ + public yieldPresentation(clearData: boolean = true): Presentation | null { // if no presentation or done tracking, return null - if (!this.isInitPresenation || !this.tracking) return null; + if (this.nullPresentation || !this.tracking) return null; // set the previus recording view to the play view this.playFFView = this.recordingFFView; // ensure we add the endTime now that they are done recording - yield { ...this.currentPresentation, totalTime: new Date().getTime() - this.absoluteStart }; + const cpy = { ...this.currentPresentation, totalTime: new Date().getTime() - this.absoluteStart }; // reset the current presentation clearData && this.clear(); + + return cpy; } - public stop = (): void => { + public finish = (): void => { // make is tracking false this.tracking = false + // reset the RecordingApi instance + this.clear(); } public clear = (): void => { @@ -137,155 +112,138 @@ export class RecordingApi { // clear absoluteStart this.absoluteStart = -1 } - - // call on dispose function to stop tracking movements - public removeRecordingFFView = (): void => { - this.disposeFunc?.(); - this.disposeFunc = null; - } - // public pause = (): Error | undefined => { - // if (this.isInitPresenation) { - // console.error('[recordingApi.ts] pause() failed: no presentation started. try calling init() first') - // return new Error('[recordingApi.ts] pause(): no presentation') - // } - // // don't allow track movments - // this.tracking = false - - // // set adjust absoluteStart to add the time difference - // const timestamp = new Date().getTime() - // this.absoluteStart = timestamp - this.absoluteStart - // } - - // public resume = () => { - // this.tracking = true - // // set absoluteStart to the difference in time - // this.absoluteStart = new Date().getTime() - this.absoluteStart - // } - - private trackMovements = (panX: number, panY: number, scale: number = 0): Error | undefined => { - // ensure we are recording - if (!this.tracking) { - return new Error('[recordingApi.ts] trackMovements()') - } - // check to see if the presetation is init - if (this.isInitPresenation) { - return new Error('[recordingApi.ts] trackMovements(): no presentation') - } - - // TO FIX: bob - // console.debug('track movment') - - // get the time - const time = new Date().getTime() - this.absoluteStart - // make new movement object - const movement: Movement = { time, panX, panY, scale } - - // add that movement to the current presentation data's movement array - this.currentPresentation.movements && this.currentPresentation.movements.push(movement) - } + // call on dispose function to stop tracking movements + public removeRecordingFFView = (): void => { + this.disposeFunc?.(); + this.disposeFunc = null; + } - // instance variable for the FFView - private disposeFunc: IReactionDisposer | null; - private recordingFFView: CollectionFreeFormView | null; - - // set the FFView that will be used in a reaction to track the movements - public setRecordingFFView = (view: CollectionFreeFormView): void => { - // set the view to the current view - if (view === this.recordingFFView || view == null) return; - - // this.recordingFFView = view; - // set the reaction to track the movements - this.disposeFunc = reaction( - () => ({ x: NumCast(view.Document.panX, -1), y: NumCast(view.Document.panY, -1), scale: NumCast(view.Document.viewScale, -1) }), - (res) => (res.x !== -1 && res.y !== -1 && this.tracking) && this.trackMovements(res.x, res.y, res.scale) - ) - - // for now, set the most recent recordingFFView to the playFFView - this.recordingFFView = view; + private trackMovements = (panX: number, panY: number, scale: number = 0) => { + // ensure we are recording + if (!this.tracking) { + console.error('[recordingApi.ts] trackMovements(): tracking is false') + return; + } + // check to see if the presetation is init + if (this.nullPresentation) { + console.error('[recordingApi.ts] trackMovements(): no presentation') + return; } - // TODO: extract this into different class with pause and resume recording - // TODO: store the FFview with the movements - private playFFView: CollectionFreeFormView | null; - private timers: NodeJS.Timeout[] | null; + // TO FIX: bob + // console.debug('track movment') + + // get the time + const time = new Date().getTime() - this.absoluteStart + // make new movement object + const movement: Movement = { time, panX, panY, scale } + + // add that movement to the current presentation data's movement array + this.currentPresentation.movements && this.currentPresentation.movements.push(movement) + } + + // instance variable for the FFView + private disposeFunc: IReactionDisposer | null; + private recordingFFView: CollectionFreeFormView | null; + + // set the FFView that will be used in a reaction to track the movements + public setRecordingFFView = (view: CollectionFreeFormView): void => { + // set the view to the current view + if (view === this.recordingFFView || view == null) return; + + // this.recordingFFView = view; + // set the reaction to track the movements + this.disposeFunc = reaction( + () => ({ x: NumCast(view.Document.panX, -1), y: NumCast(view.Document.panY, -1), scale: NumCast(view.Document.viewScale, -1) }), + (res) => (res.x !== -1 && res.y !== -1 && this.tracking) && this.trackMovements(res.x, res.y, res.scale) + ) + + // for now, set the most recent recordingFFView to the playFFView + this.recordingFFView = view; + } + + // TODO: extract this into different class with pause and resume recording + // TODO: store the FFview with the movements + private playFFView: CollectionFreeFormView | null; + private timers: NodeJS.Timeout[] | null; - public setPlayFFView = (view: CollectionFreeFormView): void => { - this.playFFView = view + public setPlayFFView = (view: CollectionFreeFormView): void => { + this.playFFView = view + } + + // pausing movements will dispose all timers that are planned to replay the movements + // play movemvents will recreate them when the user resumes the presentation + public pauseMovements = (): undefined | Error => { + if (this.playFFView === null) { + return new Error('[recordingApi.ts] pauseMovements() failed: no view') } - // pausing movements will dispose all timers that are planned to replay the movements - // play movemvents will recreate them when the user resumes the presentation - public pauseMovements = (): undefined | Error => { - if (this.playFFView === null) { - return new Error('[recordingApi.ts] pauseMovements() failed: no view') - } - - if (!this._isPlaying) { - //return new Error('[recordingApi.ts] pauseMovements() failed: not playing') - return - } - this._isPlaying = false - // TODO: set userdoc presentMode to browsing - this.timers?.map(timer => clearTimeout(timer)) - - // this.videoBox = null; + if (!this._isPlaying) { + //return new Error('[recordingApi.ts] pauseMovements() failed: not playing') + return } - - private videoBox: VideoBox | null = null; + this._isPlaying = false + // TODO: set userdoc presentMode to browsing + this.timers?.map(timer => clearTimeout(timer)) + + // this.videoBox = null; + } + + private videoBox: VideoBox | null = null; + + // by calling pause on the VideoBox, the pauseMovements will be called + public pauseVideoAndMovements = (): boolean => { + this.videoBox?.Pause() + + this.pauseMovements() + return this.videoBox == null + } - // by calling pause on the VideoBox, the pauseMovements will be called - public pauseVideoAndMovements = (): boolean => { - this.videoBox?.Pause() + public _isPlaying = false; - this.pauseMovements() - return this.videoBox == null + public playMovements = (presentation: Presentation, timeViewed: number = 0, videoBox?: VideoBox): undefined | Error => { + if (presentation.movements === null || this.playFFView === null) { + return new Error('[recordingApi.ts] followMovements() failed: no presentation data or no view') } + if (this._isPlaying) return; - public _isPlaying = false; - - public playMovements = (presentation: Presentation, timeViewed: number = 0, videoBox?: VideoBox): undefined | Error => { - if (presentation.movements === null || this.playFFView === null) { - return new Error('[recordingApi.ts] followMovements() failed: no presentation data or no view') - } - if(this._isPlaying) return; - - this._isPlaying = true; - Doc.UserDoc().presentationMode = 'watching'; - - // TODO: consider this bug at the end of the clip on seek - this.videoBox = videoBox || null; - - // only get the movements that are remaining in the video time left - const filteredMovements = presentation.movements.filter(movement => movement.time > timeViewed * 1000) - - // helper to replay a movement - const document = this.playFFView - let preScale = -1; - const zoomAndPan = (movement: Movement) => { - const { panX, panY, scale } = movement; - (scale !== -1 && preScale !== scale) && document.zoomSmoothlyAboutPt([panX, panY], scale, 0); - document.Document._panX = panX; - document.Document._panY = panY; - - preScale = scale; - } - - // set the first frame to be at the start of the pres - zoomAndPan(filteredMovements[0]); - - // make timers that will execute each movement at the correct replay time - this.timers = filteredMovements.map(movement => { - const timeDiff = movement.time - timeViewed*1000 - return setTimeout(() => { - // replay the movement - zoomAndPan(movement) - // if last movement, presentation is done -> set the instance var - if (movement === filteredMovements[filteredMovements.length - 1]) RecordingApi.Instance._isPlaying = false; - }, timeDiff) - }) + this._isPlaying = true; + Doc.UserDoc().presentationMode = 'watching'; + + // TODO: consider this bug at the end of the clip on seek + this.videoBox = videoBox || null; + + // only get the movements that are remaining in the video time left + const filteredMovements = presentation.movements.filter(movement => movement.time > timeViewed * 1000) + + // helper to replay a movement + const document = this.playFFView + let preScale = -1; + const zoomAndPan = (movement: Movement) => { + const { panX, panY, scale } = movement; + (scale !== -1 && preScale !== scale) && document.zoomSmoothlyAboutPt([panX, panY], scale, 0); + document.Document._panX = panX; + document.Document._panY = panY; + + preScale = scale; } - + + // set the first frame to be at the start of the pres + zoomAndPan(filteredMovements[0]); + + // make timers that will execute each movement at the correct replay time + this.timers = filteredMovements.map(movement => { + const timeDiff = movement.time - timeViewed * 1000 + return setTimeout(() => { + // replay the movement + zoomAndPan(movement) + // if last movement, presentation is done -> set the instance var + if (movement === filteredMovements[filteredMovements.length - 1]) RecordingApi.Instance._isPlaying = false; + }, timeDiff) + }) + } + // method that concatenates an array of presentatations into one public concatPresentations = (presentations: Presentation[]): Presentation => { // these three will lead to the combined presentation @@ -295,6 +253,7 @@ export class RecordingApi { presentations.forEach((presentation) => { const { movements, totalTime, meta } = presentation; + // update movements if they had one if (movements) { // add the summed time to the movements @@ -302,8 +261,10 @@ export class RecordingApi { // concat the movements already in the combined presentation with these new ones combinedMovements.push(...addedTimeMovements); } + // update the totalTime sumTime += totalTime; + // concatenate the metas combinedMetas.push(...meta); }); @@ -312,19 +273,19 @@ export class RecordingApi { return { movements: combinedMovements, totalTime: sumTime, meta: combinedMetas }; } - // Unfinished code for tracing multiple free form views - // export let pres: Map<CollectionFreeFormView, IReactionDisposer> = new Map() - - // export function AddRecordingFFView(ffView: CollectionFreeFormView): void { - // pres.set(ffView, - // reaction(() => ({ x: ffView.panX, y: ffView.panY }), - // (pt) => RecordingApi.trackMovements(ffView, pt.x, pt.y))) - // ) - // } - - // export function RemoveRecordingFFView(ffView: CollectionFreeFormView): void { - // const disposer = pres.get(ffView); - // disposer?.(); - // pres.delete(ffView) - // } + // Unfinished code for tracing multiple free form views + // export let pres: Map<CollectionFreeFormView, IReactionDisposer> = new Map() + + // export function AddRecordingFFView(ffView: CollectionFreeFormView): void { + // pres.set(ffView, + // reaction(() => ({ x: ffView.panX, y: ffView.panY }), + // (pt) => RecordingApi.trackMovements(ffView, pt.x, pt.y))) + // ) + // } + + // export function RemoveRecordingFFView(ffView: CollectionFreeFormView): void { + // const disposer = pres.get(ffView); + // disposer?.(); + // pres.delete(ffView) + // } } diff --git a/src/client/views/nodes/RecordingBox/RecordingBox.tsx b/src/client/views/nodes/RecordingBox/RecordingBox.tsx index 6fe67b6db..a28677525 100644 --- a/src/client/views/nodes/RecordingBox/RecordingBox.tsx +++ b/src/client/views/nodes/RecordingBox/RecordingBox.tsx @@ -46,7 +46,7 @@ export class RecordingBox extends ViewBoxBaseComponent() { this.dataDoc.layout = VideoBox.LayoutString(this.fieldKey); this.dataDoc[this.props.fieldKey] = new VideoField(this.result.accessPaths.client); this.dataDoc[this.fieldKey + "-recorded"] = true; - // stringify the presenation and store it + // stringify the presentation and store it presentation?.movements && (this.dataDoc[this.fieldKey + "-presentation"] = JSON.stringify(presentation)); } diff --git a/src/client/views/nodes/RecordingBox/RecordingView.tsx b/src/client/views/nodes/RecordingBox/RecordingView.tsx index ba9479f41..15883632a 100644 --- a/src/client/views/nodes/RecordingBox/RecordingView.tsx +++ b/src/client/views/nodes/RecordingBox/RecordingView.tsx @@ -60,7 +60,7 @@ export function RecordingView(props: IRecordingViewProps) { } } - useEffect(() => console.log('progress', progress), [progress]) + // useEffect(() => console.debug('progress', progress), [progress]) useEffect(() => { if (finished) { @@ -93,8 +93,7 @@ export function RecordingView(props: IRecordingViewProps) { useEffect(() => { let interval: any = null; if (recording) { - interval = setTimeout(() => { - console.log('update interval') + interval = setInterval(() => { setRecordingTimer(unit => unit + 1); }, 10); } else if (!recording && recordingTimer !== 0) { @@ -141,7 +140,6 @@ export function RecordingView(props: IRecordingViewProps) { } videoRecorder.current.onstop = () => { - // RecordingApi.Instance.stop(); // if we have a last portion if (videoChunks.length > 1) { // append the current portion to the video pieces @@ -150,9 +148,10 @@ export function RecordingView(props: IRecordingViewProps) { endTime: recordingTimerRef.current, startTime: videos?.lastElement()?.endTime || 0 }; + // depending on if a presenation exists, add it to the video - const { done: presError, value: presentation } = RecordingApi.Instance.yieldPresentation().next(); - setVideos(videos => [...videos, (!presError && trackScreen) ? { ...nextVideo, presentation } : nextVideo]); + const presentation = RecordingApi.Instance.yieldPresentation(); + setVideos(videos => [...videos, (presentation != null && trackScreen) ? { ...nextVideo, presentation } : nextVideo]); } // reset the temporary chunks @@ -175,8 +174,8 @@ export function RecordingView(props: IRecordingViewProps) { const stream = videoElementRef.current!.srcObject; stream instanceof MediaStream && stream.getTracks().forEach(track => track.stop()); - // clear the recoringApi - RecordingApi.Instance.clear(); + // finish/clear the recoringApi + RecordingApi.Instance.finish(); // this will call upon progessbar to update videos to be in the correct order setFinished(true); @@ -189,12 +188,10 @@ export function RecordingView(props: IRecordingViewProps) { } const start = (e: React.PointerEvent) => { - // the code to start or resume does not get triggered if we start dragging the button setupMoveUpEvents({}, e, returnTrue, returnFalse, e => { - if (!videoRecorder.current || videoRecorder.current.state === "inactive") { - record(); - // trackScreen && - } + // start recording if not already recording + if (!videoRecorder.current || videoRecorder.current.state === "inactive") record(); + return true; // cancels propagation to documentView to avoid selecting it. }, false, false); } @@ -204,9 +201,7 @@ export function RecordingView(props: IRecordingViewProps) { setDoUndo(prev => !prev); } - const handleOnTimeUpdate = () => { - playing && setVideoProgressHelper(videoElementRef.current!.currentTime); - }; + const handleOnTimeUpdate = () => { playing && setVideoProgressHelper(videoElementRef.current!.currentTime); }; const millisecondToMinuteSecond = (milliseconds: number) => { const toTwoDigit = (digit: number) => { @@ -223,7 +218,7 @@ export function RecordingView(props: IRecordingViewProps) { <video id={`video-${props.id}`} autoPlay muted - onTimeUpdate={handleOnTimeUpdate} + onTimeUpdate={() => handleOnTimeUpdate()} ref={videoElementRef} /> <div className="recording-sign"> |