diff options
-rw-r--r-- | src/client/documents/Documents.ts | 4 | ||||
-rw-r--r-- | src/client/views/InkingCanvas.tsx | 11 | ||||
-rw-r--r-- | src/client/views/InkingControl.tsx | 1 | ||||
-rw-r--r-- | src/client/views/InkingStroke.tsx | 18 | ||||
-rw-r--r-- | src/client/views/nodes/AudioBox.tsx | 21 | ||||
-rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 2 | ||||
-rw-r--r-- | src/new_fields/InkField.ts | 4 | ||||
-rw-r--r-- | src/server/authentication/models/current_user_utils.ts | 1 |
8 files changed, 38 insertions, 24 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 316efe44c..5ae4ca82a 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -334,9 +334,7 @@ export namespace Docs { let dataDoc = MakeDataDelegate(proto, protoProps, data); let viewDoc = Doc.MakeDelegate(dataDoc, delegId); - AudioBox.ActiveRecordings.map(d => { - DocUtils.MakeLink({ doc: viewDoc }, { doc: d }, "audio link", "link to audio: " + d.title); - }); + AudioBox.ActiveRecordings.map(d => DocUtils.MakeLink({ doc: viewDoc }, { doc: d }, "audio link", "link to audio: " + d.title)); return Doc.assign(viewDoc, delegateProps); } diff --git a/src/client/views/InkingCanvas.tsx b/src/client/views/InkingCanvas.tsx index 920ebaedd..0037b95d0 100644 --- a/src/client/views/InkingCanvas.tsx +++ b/src/client/views/InkingCanvas.tsx @@ -78,7 +78,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> { this.previousState = new Map(this.inkData); - if (InkingControl.Instance.selectedTool !== InkTool.Eraser) { + if (InkingControl.Instance.selectedTool !== InkTool.Eraser && InkingControl.Instance.selectedTool !== InkTool.Scrubber) { // start the new line, saves a uuid to represent the field of the stroke this._currentStrokeId = Utils.GenerateGuid(); const data = this.inkData; @@ -87,7 +87,8 @@ export class InkingCanvas extends React.Component<InkCanvasProps> { color: InkingControl.Instance.selectedColor, width: InkingControl.Instance.selectedWidth, tool: InkingControl.Instance.selectedTool, - displayTimecode: NumCast(this.props.Document.currentTimecode, -1) + displayTimecode: NumCast(this.props.Document.currentTimecode, -1), + creationTime: new Date().getTime() }); this.inkData = data; } @@ -120,7 +121,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> { onPointerMove = (e: PointerEvent): void => { e.stopPropagation(); e.preventDefault(); - if (InkingControl.Instance.selectedTool !== InkTool.Eraser) { + if (InkingControl.Instance.selectedTool !== InkTool.Eraser && InkingControl.Instance.selectedTool !== InkTool.Scrubber) { let data = this.inkData; // add points to new line as it is being drawn let strokeData = data.get(this._currentStrokeId); if (strokeData) { @@ -161,6 +162,7 @@ export class InkingCanvas extends React.Component<InkCanvasProps> { color={strokeData.color} width={strokeData.width} tool={strokeData.tool} + creationTime={strokeData.creationTime} deleteCallback={this.removeLine} />); } return paths; @@ -181,7 +183,8 @@ export class InkingCanvas extends React.Component<InkCanvasProps> { render() { let svgCanvasStyle = InkingControl.Instance.selectedTool !== InkTool.None && !this.props.Document.isBackground ? "canSelect" : "noSelect"; - let cursor = svgCanvasStyle === "canSelect" ? (InkingControl.Instance.selectedTool === InkTool.Eraser ? "pointer" : "default") : undefined; + let cursor = svgCanvasStyle === "canSelect" ? (InkingControl.Instance.selectedTool === InkTool.Eraser || + InkingControl.Instance.selectedTool === InkTool.Scrubber ? "pointer" : "default") : undefined; return ( <div className="inkingCanvas"> <div className={`inkingCanvas-${svgCanvasStyle}`} onPointerDown={this.onPointerDown} style={{ cursor: cursor }} /> diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 105adc03d..75faa9641 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -126,6 +126,7 @@ export class InkingControl { Scripting.addGlobal(function activatePen(pen: any, width: any, color: any) { InkingControl.Instance.switchTool(pen ? InkTool.Pen : InkTool.None); InkingControl.Instance.switchWidth(width); InkingControl.Instance.updateSelectedColor(color); }); Scripting.addGlobal(function activateBrush(pen: any, width: any, color: any) { InkingControl.Instance.switchTool(pen ? InkTool.Highlighter : InkTool.None); InkingControl.Instance.switchWidth(width); InkingControl.Instance.updateSelectedColor(color); }); Scripting.addGlobal(function activateEraser(pen: any) { return InkingControl.Instance.switchTool(pen ? InkTool.Eraser : InkTool.None); }); +Scripting.addGlobal(function activateScrubber(pen: any) { return InkingControl.Instance.switchTool(pen ? InkTool.Scrubber : InkTool.None); }); Scripting.addGlobal(function deactivateInk() { return InkingControl.Instance.switchTool(InkTool.None); }); Scripting.addGlobal(function setInkWidth(width: any) { return InkingControl.Instance.switchWidth(width); }); Scripting.addGlobal(function setInkColor(color: any) { return InkingControl.Instance.updateSelectedColor(color); });
\ No newline at end of file diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index b8d428d31..7bbf71482 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -1,9 +1,10 @@ import { observer } from "mobx-react"; -import { observable, trace } from "mobx"; +import { observable, trace, runInAction } from "mobx"; import { InkingControl } from "./InkingControl"; import React = require("react"); import { InkTool } from "../../new_fields/InkField"; import "./InkingStroke.scss"; +import { AudioBox } from "./nodes/AudioBox"; interface StrokeProps { @@ -15,6 +16,7 @@ interface StrokeProps { color: string; width: string; tool: InkTool; + creationTime: number; deleteCallback: (index: string) => void; } @@ -31,6 +33,11 @@ export class InkingStroke extends React.Component<StrokeProps> { e.stopPropagation(); e.preventDefault(); } + if (InkingControl.Instance.selectedTool === InkTool.Scrubber && e.buttons === 1) { + runInAction(() => AudioBox.ScrubTime = this.props.creationTime); + e.stopPropagation(); + e.preventDefault(); + } } parseData = (line: Array<{ x: number, y: number }>): string => { @@ -55,10 +62,9 @@ export class InkingStroke extends React.Component<StrokeProps> { let pathlength = this.props.count; // bcz: this is needed to force reactions to the line's data changes let marker = this.props.tool === InkTool.Highlighter ? "-marker" : ""; - let pointerEvents: any = InkingControl.Instance.selectedTool === InkTool.Eraser ? "all" : "none"; - return ( - <path className={`inkingStroke${marker}`} d={pathData} style={{ ...pathStyle, pointerEvents: pointerEvents }} strokeLinejoin="round" strokeLinecap="round" - onPointerOver={this.deleteStroke} onPointerDown={this.deleteStroke} /> - ); + let pointerEvents: any = InkingControl.Instance.selectedTool === InkTool.Eraser || + InkingControl.Instance.selectedTool === InkTool.Scrubber ? "all" : "none"; + return (<path className={`inkingStroke${marker}`} d={pathData} style={{ ...pathStyle, pointerEvents: pointerEvents }} + strokeLinejoin="round" strokeLinecap="round" onPointerOver={this.deleteStroke} onPointerDown={this.deleteStroke} />); } }
\ No newline at end of file diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 55b472726..62ec683da 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -38,11 +38,13 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume _linkPlayDisposer: IReactionDisposer | undefined; _reactionDisposer: IReactionDisposer | undefined; + _scrubbingDisposer: IReactionDisposer | undefined; _ele: HTMLAudioElement | null = null; _recorder: any; _lastUpdate = 0; @observable private _audioState = 0; + @observable public static ScrubTime = 0; public static ActiveRecordings: Doc[] = []; componentDidMount() { @@ -53,7 +55,9 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume const la1 = l.anchor1 as Doc; const la2 = l.anchor2 as Doc; if (l[Id] === scrollLinkId && la1 && la2) { - setTimeout(() => this.playFrom(Doc.AreProtosEqual(la1, this.dataDoc) ? la2 : la1), 250); + let doc = Doc.AreProtosEqual(la1, this.dataDoc) ? la2 : la1; + let seek = DateCast(la1.creationTime); + setTimeout(() => this.playFrom(seek.date.getTime()), 250); } }); scrollLinkId && (this.layoutDoc.scrollLinkID = undefined); @@ -61,8 +65,9 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume this._reactionDisposer = reaction(() => SelectionManager.SelectedDocuments(), selected => { let sel = selected.length ? selected[0].props.Document : undefined; - this.Document.playOnSelect && sel && !Doc.AreProtosEqual(sel, this.props.Document) && this.playFrom(sel); + this.Document.playOnSelect && sel && !Doc.AreProtosEqual(sel, this.props.Document) && this.playFrom(DateCast(sel.creationTime).date.getTime()); }); + this._scrubbingDisposer = reaction(() => AudioBox.ScrubTime, time => this.Document.playOnSelect && this.playFrom(time)); } updateHighlights = () => { @@ -86,14 +91,13 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume } } - playFrom = (sel: Doc) => { + playFrom = (seek: number) => { const extensionDoc = this.extensionDoc; let start = extensionDoc && DateCast(extensionDoc.recordingStart); - let seek = sel && DateCast(sel.creationDate); - if (this._ele && start && seek) { - if (sel) { - let delta = (seek.date.getTime() - start.date.getTime()) / 1000; - if (start && seek && delta > 0 && delta < this._ele.duration) { + if (this._ele && start) { + if (seek) { + let delta = (seek - start.date.getTime()) / 1000; + if (start && delta > 0 && delta < this._ele.duration) { this._ele.currentTime = delta; this._ele.play(); this._lastUpdate = delta; @@ -110,6 +114,7 @@ export class AudioBox extends DocExtendableComponent<FieldViewProps, AudioDocume componentWillUnmount() { this._reactionDisposer && this._reactionDisposer(); this._linkPlayDisposer && this._linkPlayDisposer(); + this._scrubbingDisposer && this._scrubbingDisposer(); } recordAudioAnnotation = () => { diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 48a699e58..53baea4ae 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -301,7 +301,6 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum this._isResetClick = 0; document.addEventListener("pointermove", this.onResetMove, true); document.addEventListener("pointerup", this.onResetUp, true); - InkingControl.Instance.switchTool(InkTool.Eraser); } onResetMove = (e: PointerEvent) => { @@ -314,7 +313,6 @@ export class VideoBox extends DocAnnotatableComponent<FieldViewProps, VideoDocum onResetUp = (e: PointerEvent) => { document.removeEventListener("pointermove", this.onResetMove, true); document.removeEventListener("pointerup", this.onResetUp, true); - InkingControl.Instance.switchTool(InkTool.None); this._isResetClick < 10 && (this.Document.currentTimecode = 0); } diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts index e381d0218..d94834e91 100644 --- a/src/new_fields/InkField.ts +++ b/src/new_fields/InkField.ts @@ -8,7 +8,8 @@ export enum InkTool { None, Pen, Highlighter, - Eraser + Eraser, + Scrubber } export interface StrokeData { @@ -17,6 +18,7 @@ export interface StrokeData { width: string; tool: InkTool; displayTimecode: number; + creationTime: number; } export type InkData = Map<string, StrokeData>; diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 477b36ea4..95ebe3cb6 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -58,6 +58,7 @@ export class CurrentUserUtils { { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", unchecked: `!sameDocs(this.activePen.pen, this)`, activePen: doc }, { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", unchecked: `!sameDocs(this.activePen.pen, this)`, activePen: doc }, { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', unchecked: `!sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc }, + { title: "use scrubber", icon: "eraser", click: 'activateScrubber(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', unchecked: `!sameDocs(this.activePen.pen, this)`, backgroundColor: "green", activePen: doc }, { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', unchecked: `!sameDocs(this.activePen.pen, this) && this.activePen.pen !== undefined`, backgroundColor: "white", activePen: doc }, ]; return docProtoData.map(data => Docs.Create.FontIconDocument({ |