diff options
| author | bobzel <zzzman@gmail.com> | 2023-05-22 11:25:32 -0400 |
|---|---|---|
| committer | bobzel <zzzman@gmail.com> | 2023-05-22 11:25:32 -0400 |
| commit | bed3309e1fda6597b2a8fea10ad82cd3a0402051 (patch) | |
| tree | fe599bbdc5fca2c221e1e0f7a60995b7cd39f870 /src/client/views/nodes/VideoBox.tsx | |
| parent | 887a4f7e0fc25fde87b20a5de2e7b0aee561cc78 (diff) | |
| parent | 3d26d5b2654841a9b92f3d66b28d1dc8e36cca6a (diff) | |
merged physics with master
Diffstat (limited to 'src/client/views/nodes/VideoBox.tsx')
| -rw-r--r-- | src/client/views/nodes/VideoBox.tsx | 233 |
1 files changed, 113 insertions, 120 deletions
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 1dfa55c64..9cf929679 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -3,17 +3,18 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, untracked } from 'mobx'; import { observer } from 'mobx-react'; import { basename } from 'path'; -import * as rp from 'request-promise'; -import { Doc, DocListCast, HeightSym, WidthSym } from '../../../fields/Doc'; +import { Doc, HeightSym, StrListCast, WidthSym } from '../../../fields/Doc'; import { InkTool } from '../../../fields/InkField'; import { List } from '../../../fields/List'; +import { ObjectField } from '../../../fields/ObjectField'; import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { AudioField, ImageField, VideoField } from '../../../fields/URLField'; -import { emptyFunction, formatTime, OmitKeys, returnEmptyString, returnFalse, returnOne, setupMoveUpEvents, Utils } from '../../../Utils'; +import { emptyFunction, formatTime, returnEmptyString, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from '../../documents/DocumentTypes'; import { Networking } from '../../Network'; import { DocumentManager } from '../../util/DocumentManager'; +import { LinkManager } from '../../util/LinkManager'; import { ReplayMovements } from '../../util/ReplayMovements'; import { SelectionManager } from '../../util/SelectionManager'; import { SnappingManager } from '../../util/SnappingManager'; @@ -27,11 +28,13 @@ import { DocumentDecorations } from '../DocumentDecorations'; import { MarqueeAnnotator } from '../MarqueeAnnotator'; import { AnchorMenu } from '../pdf/AnchorMenu'; import { StyleProp } from '../StyleProvider'; +import { OpenWhere } from './DocumentView'; import { FieldView, FieldViewProps } from './FieldView'; import { RecordingBox } from './RecordingBox'; +import { PinProps, PresBox } from './trails'; import './VideoBox.scss'; -import { ObjectField } from '../../../fields/ObjectField'; -import { DocFocusOptions, OpenWhere } from './DocumentView'; +import { ScriptField } from '../../../fields/ScriptField'; +import { FollowLinkScript } from '../../util/LinkFollower'; const path = require('path'); /** @@ -51,30 +54,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp public static LayoutString(fieldKey: string) { return FieldView.LayoutString(VideoBox, fieldKey); } - /** - * Uploads an image buffer to the server and stores with specified filename. by default the image - * is stored at multiple resolutions each retrieved by using the filename appended with _o, _s, _m, _l (indicating original, small, medium, or large) - * @param imageUri the bytes of the image - * @param returnedFilename the base filename to store the image on the server - * @param nosuffix optionally suppress creating multiple resolution images - */ - public static async convertDataUri(imageUri: string, returnedFilename: string, nosuffix = false, replaceRootFilename?: string) { - try { - const posting = Utils.prepend('/uploadURI'); - const returnedUri = await rp.post(posting, { - body: { - uri: imageUri, - name: returnedFilename, - nosuffix, - replaceRootFilename, - }, - json: true, - }); - return returnedUri; - } catch (e) { - console.log('VideoBox :' + e); - } - } static _youtubeIframeCounter: number = 0; static heightPercent = 80; // height of video relative to videoBox when timeline is open @@ -109,12 +88,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp @observable _scrubbing: boolean = false; @computed get links() { - return DocListCast(this.dataDoc.links); + return LinkManager.Links(this.dataDoc); } @computed get heightPercent() { - return NumCast(this.layoutDoc._timelineHeightPercent, 100); + return NumCast(this.layoutDoc._layout_timelineHeightPercent, 100); } // current percent of video relative to VideoBox height - // @computed get rawDuration() { return NumCast(this.dataDoc[this.fieldKey + "-duration"]); } + // @computed get rawDuration() { return NumCast(this.dataDoc[this.fieldKey + "_duration"]); } @observable rawDuration: number = 0; @computed get youtubeVideoId() { @@ -242,10 +221,20 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp } } + _keepCurrentlyPlaying = false; // flag to prevent document when paused from being removed from global 'currentlyPlaying' list + IsPlaying = () => this._playing; + TogglePause = () => { + if (!this._playing) this.Play(); + else { + this._keepCurrentlyPlaying = true; + this.pause(); + setTimeout(() => (this._keepCurrentlyPlaying = false)); + } + }; + // pauses video - @action public Pause = (update: boolean = true) => { + @action public pause = (update: boolean = true) => { this._playing = false; - this.removeCurrentlyPlaying(); try { update && this.player?.pause(); update && this._audioPlayer?.pause(); @@ -263,6 +252,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp } this._playRegionTimer = undefined; }; + @action Pause = (update: boolean = true) => { + this.pause(update); + !this._keepCurrentlyPlaying && this.removeCurrentlyPlaying(); + }; // toggles video full screen @action public FullScreen = () => { @@ -332,19 +325,19 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp y: NumCast(this.layoutDoc.y, 1), _width: 150, _height: 50, - title: (this.layoutDoc._currentTimecode || 0).toString(), - _isLinkButton: true, + title: (this.layoutDoc._layout_currentTimecode || 0).toString(), + onClick: FollowLinkScript(), }); this.props.addDocument?.(b); - DocUtils.MakeLink({ doc: b }, { doc: this.rootDoc }, 'video snapshot'); + DocUtils.MakeLink(b, this.rootDoc, { link_relationship: 'video snapshot' }); Networking.PostToServer('/youtubeScreenshot', { id: this.youtubeVideoId, - timecode: this.layoutDoc._currentTimecode, + timecode: this.layoutDoc._layout_currentTimecode, }).then(response => { const resolved = response?.accessPaths?.agnostic?.client; if (resolved) { this.props.removeDocument?.(b); - this.createRealSummaryLink(resolved); + this.createSnapshotLink(resolved); } }); } else { @@ -352,51 +345,51 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp const dataUrl = canvas.toDataURL('image/png'); // can also use 'image/png' // if you want to preview the captured image, const retitled = StrCast(this.rootDoc.title).replace(/[ -\.:]/g, ''); - const encodedFilename = encodeURIComponent('snapshot' + retitled + '_' + (this.layoutDoc._currentTimecode || 0).toString().replace(/\./, '_')); + const encodedFilename = encodeURIComponent('snapshot' + retitled + '_' + (this.layoutDoc._layout_currentTimecode || 0).toString().replace(/\./, '_')); const filename = basename(encodedFilename); - VideoBox.convertDataUri(dataUrl, filename).then((returnedFilename: string) => returnedFilename && (cb ?? this.createRealSummaryLink)(returnedFilename, downX, downY)); + Utils.convertDataUri(dataUrl, filename).then((returnedFilename: string) => returnedFilename && (cb ?? this.createSnapshotLink)(returnedFilename, downX, downY)); } }; updateIcon = () => { const makeIcon = (returnedfilename: string) => { this.dataDoc.icon = new ImageField(returnedfilename); - this.dataDoc['icon-nativeWidth'] = this.layoutDoc[WidthSym](); - this.dataDoc['icon-nativeHeight'] = this.layoutDoc[HeightSym](); + this.dataDoc.icon_nativeWidth = this.layoutDoc[WidthSym](); + this.dataDoc.icon_nativeHeight = this.layoutDoc[HeightSym](); }; this.Snapshot(undefined, undefined, makeIcon); }; // creates link for snapshot - createRealSummaryLink = (imagePath: string, downX?: number, downY?: number) => { + createSnapshotLink = (imagePath: string, downX?: number, downY?: number) => { const url = !imagePath.startsWith('/') ? Utils.CorsProxy(imagePath) : imagePath; const width = NumCast(this.layoutDoc._width) || 1; const height = NumCast(this.layoutDoc._height); - const imageSummary = Docs.Create.ImageDocument(url, { + const imageSnapshot = Docs.Create.ImageDocument(url, { _nativeWidth: Doc.NativeWidth(this.layoutDoc), _nativeHeight: Doc.NativeHeight(this.layoutDoc), x: NumCast(this.layoutDoc.x) + width, y: NumCast(this.layoutDoc.y), - _isLinkButton: true, + onClick: FollowLinkScript(), _width: 150, _height: (height / width) * 150, - title: '--snapshot' + NumCast(this.layoutDoc._currentTimecode) + ' image-', + title: '--snapshot' + NumCast(this.layoutDoc._layout_currentTimecode) + ' image-', }); - Doc.SetNativeWidth(Doc.GetProto(imageSummary), Doc.NativeWidth(this.layoutDoc)); - Doc.SetNativeHeight(Doc.GetProto(imageSummary), Doc.NativeHeight(this.layoutDoc)); - this.props.addDocument?.(imageSummary); - const link = DocUtils.MakeLink({ doc: imageSummary }, { doc: this.getAnchor(true) }, 'video snapshot'); - link && (Doc.GetProto(link.anchor2 as Doc).timecodeToHide = NumCast((link.anchor2 as Doc).timecodeToShow) + 3); - setTimeout(() => downX !== undefined && downY !== undefined && DocumentManager.Instance.getFirstDocumentView(imageSummary)?.startDragging(downX, downY, 'move', true)); + Doc.SetNativeWidth(Doc.GetProto(imageSnapshot), Doc.NativeWidth(this.layoutDoc)); + Doc.SetNativeHeight(Doc.GetProto(imageSnapshot), Doc.NativeHeight(this.layoutDoc)); + this.props.addDocument?.(imageSnapshot); + const link = DocUtils.MakeLink(imageSnapshot, this.getAnchor(true), { link_relationship: 'video snapshot' }); + link && (Doc.GetProto(link.link_anchor_2 as Doc).timecodeToHide = NumCast((link.link_anchor_2 as Doc).timecodeToShow) + 3); + setTimeout(() => downX !== undefined && downY !== undefined && DocumentManager.Instance.getFirstDocumentView(imageSnapshot)?.startDragging(downX, downY, 'move', true)); }; - getAnchor = (addAsAnnotation: boolean) => { - const timecode = Cast(this.layoutDoc._currentTimecode, 'number', null); + getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { + const timecode = Cast(this.layoutDoc._layout_currentTimecode, 'number', null); const marquee = AnchorMenu.Instance.GetAnchor?.(undefined, addAsAnnotation); - return ( - CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, '_timecodeToShow' /* videoStart */, '_timecodeToHide' /* videoEnd */, timecode ? timecode : undefined, undefined, marquee, addAsAnnotation) || - this.rootDoc - ); + if (!addAsAnnotation && marquee) marquee.backgroundColor = 'transparent'; + const anchor = CollectionStackedTimeline.createAnchor(this.rootDoc, this.dataDoc, this.annotationKey, timecode ? timecode : undefined, undefined, marquee, addAsAnnotation) || this.rootDoc; + PresBox.pinDocView(anchor, { pinDocLayout: pinProps?.pinDocLayout, pinData: { ...(pinProps?.pinData ?? {}), temporal: true } }, this.rootDoc); + return anchor; }; // sets video info on load @@ -409,25 +402,29 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp } if (Number.isFinite(this.player!.duration)) { this.rawDuration = this.player!.duration; - this.dataDoc[this.fieldKey + '-duration'] = this.rawDuration; - } else this.rawDuration = NumCast(this.dataDoc[this.fieldKey + '-duration']); + this.dataDoc[this.fieldKey + '_duration'] = this.rawDuration; + } else this.rawDuration = NumCast(this.dataDoc[this.fieldKey + '_duration']); }); // updates video time @action updateTimecode = () => { - this.player && (this.layoutDoc._currentTimecode = this.player.currentTime); + this.player && (this.layoutDoc._layout_currentTimecode = this.player.currentTime); try { - this._youtubePlayer && (this.layoutDoc._currentTimecode = this._youtubePlayer.getCurrentTime?.()); + this._youtubePlayer && (this.layoutDoc._layout_currentTimecode = this._youtubePlayer.getCurrentTime?.()); } catch (e) { console.log('Video Timecode Exception:', e); } }; + // getView = async (doc: Doc) => { + // return new Promise<Opt<DocumentView>>(res => DocumentManager.Instance.AddViewRenderedCb(doc, dv => res(dv))); + // }; + // extracts video thumbnails and saves them as field of doc getVideoThumbnails = () => { - if (this.dataDoc.thumbnails !== undefined) return; - this.dataDoc.thumbnails = new List<string>(); + if (this.dataDoc[this.fieldKey + '_thumbnails'] !== undefined) return; + this.dataDoc[this.fieldKey + '_thumbnails'] = new List<string>(); const thumbnailPromises: Promise<any>[] = []; const video = document.createElement('video'); @@ -440,12 +437,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp canvas.getContext('2d')?.drawImage(video, 0, 0, video.videoWidth, video.videoHeight, 0, 0, 100, 100); const retitled = StrCast(this.rootDoc.title).replace(/[ -\.:]/g, ''); const encodedFilename = encodeURIComponent('thumbnail' + retitled + '_' + video.currentTime.toString().replace(/\./, '_')); - thumbnailPromises?.push(VideoBox.convertDataUri(canvas.toDataURL(), basename(encodedFilename), true)); + thumbnailPromises?.push(Utils.convertDataUri(canvas.toDataURL(), basename(encodedFilename), true)); const newTime = video.currentTime + video.duration / (VideoBox.numThumbnails - 1); if (newTime < video.duration) { video.currentTime = newTime; } else { - Promise.all(thumbnailPromises).then(thumbnails => (this.dataDoc.thumbnails = new List<string>(thumbnails))); + Promise.all(thumbnailPromises).then(thumbnails => (this.dataDoc[this.fieldKey + '_thumbnails'] = new List<string>(thumbnails))); } }; @@ -463,12 +460,12 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp // vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen); this._disposers.reactionDisposer?.(); this._disposers.reactionDisposer = reaction( - () => NumCast(this.layoutDoc._currentTimecode), + () => NumCast(this.layoutDoc._layout_currentTimecode), time => !this._playing && (vref.currentTime = time), { fireImmediately: true } ); - (!this.dataDoc.thumbnails || this.dataDoc.thumbnails.length != VideoBox.numThumbnails) && this.getVideoThumbnails(); + (!this.dataDoc[this.fieldKey + '_thumbnails'] || this.dataDoc[this.fieldKey + '_thumbnails'].length != VideoBox.numThumbnails) && this.getVideoThumbnails(); } }; @@ -534,7 +531,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp this.dataDoc.layout = RecordingBox.LayoutString(this.fieldKey); // delete assoicated video data this.dataDoc[this.props.fieldKey] = ''; - this.dataDoc[this.fieldKey + '-duration'] = ''; + this.dataDoc[this.fieldKey + '_duration'] = ''; // delete assoicated presentation data this.dataDoc[this.fieldKey + '-presentation'] = ''; }, @@ -576,7 +573,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp key="video" autoPlay={this._screenCapture} ref={this.setVideoRef} - style={this._fullScreen ? this.fullScreenSize() : this.isCropped ? { width: 'max-content', height: 'max-content', transform: `scale(${1 / NumCast(this.rootDoc._viewScale)})`, transformOrigin: 'top left' } : {}} + style={this._fullScreen ? this.fullScreenSize() : this.isCropped ? { width: 'max-content', height: 'max-content', transform: `scale(${1 / NumCast(this.rootDoc._freeform_scale)})`, transformOrigin: 'top left' } : {}} onCanPlay={this.videoLoad} controls={VideoBox._nativeControls} onPlay={() => this.Play()} @@ -623,8 +620,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp this._disposers.reactionDisposer?.(); this._disposers.youtubeReactionDisposer?.(); this._disposers.reactionDisposer = reaction( - () => this.layoutDoc._currentTimecode, - () => !this._playing && this.Seek(NumCast(this.layoutDoc._currentTimecode)) + () => this.layoutDoc._layout_currentTimecode, + () => !this._playing && this.Seek(NumCast(this.layoutDoc._layout_currentTimecode)) ); this._disposers.youtubeReactionDisposer = reaction( () => Doc.ActiveTool === InkTool.None && this.props.isSelected(true) && !SnappingManager.GetIsDragging() && !DocumentDecorations.Instance.Interacting, @@ -680,15 +677,15 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp this._clicking = false; if (this.props.isContentActive()) { // const local = this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).transformPoint(e.clientX, e.clientY); - // this.layoutDoc._timelineHeightPercent = Math.max(0, Math.min(100, local[1] / this.props.PanelHeight() * 100)); + // this.layoutDoc._layout_timelineHeightPercent = Math.max(0, Math.min(100, local[1] / this.props.PanelHeight() * 100)); - this.layoutDoc._timelineHeightPercent = 80; + this.layoutDoc._layout_timelineHeightPercent = 80; } return false; }), emptyFunction, () => { - this.layoutDoc._timelineHeightPercent = this.heightPercent !== 100 ? 100 : VideoBox.heightPercent; + this.layoutDoc._layout_timelineHeightPercent = this.heightPercent !== 100 ? 100 : VideoBox.heightPercent; setTimeout( action(() => (this._clicking = false)), 500 @@ -699,23 +696,24 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp ); }; - // removes video from currently playing display + // removes from currently playing display @action removeCurrentlyPlaying = () => { - if (CollectionStackedTimeline.CurrentlyPlaying) { - const index = CollectionStackedTimeline.CurrentlyPlaying.indexOf(this.layoutDoc); + const docView = this.props.DocumentView?.(); + if (CollectionStackedTimeline.CurrentlyPlaying && docView) { + const index = CollectionStackedTimeline.CurrentlyPlaying.indexOf(docView); index !== -1 && CollectionStackedTimeline.CurrentlyPlaying.splice(index, 1); } }; - - // adds video to currently playing display + // adds doc to currently playing display @action addCurrentlyPlaying = () => { + const docView = this.props.DocumentView?.(); if (!CollectionStackedTimeline.CurrentlyPlaying) { CollectionStackedTimeline.CurrentlyPlaying = []; } - if (CollectionStackedTimeline.CurrentlyPlaying.indexOf(this.layoutDoc) === -1) { - CollectionStackedTimeline.CurrentlyPlaying.push(this.layoutDoc); + if (docView && CollectionStackedTimeline.CurrentlyPlaying.indexOf(docView) === -1) { + CollectionStackedTimeline.CurrentlyPlaying.push(docView); } }; @@ -723,7 +721,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp this._youtubeIframeId = VideoBox._youtubeIframeCounter++; this._youtubeContentCreated = this._forceCreateYouTubeIFrame ? true : true; const classname = 'videoBox-content-YouTube' + (this._fullScreen ? '-fullScreen' : ''); - const start = untracked(() => Math.round(NumCast(this.layoutDoc._currentTimecode))); + const start = untracked(() => Math.round(NumCast(this.layoutDoc._layout_currentTimecode))); return ( <iframe key={this._youtubeIframeId} @@ -742,7 +740,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp @action.bound addDocWithTimecode(doc: Doc | Doc[]): boolean { const docs = doc instanceof Doc ? [doc] : doc; - const curTime = NumCast(this.layoutDoc._currentTimecode); + const curTime = NumCast(this.layoutDoc._layout_currentTimecode); docs.forEach(doc => (doc._timecodeToHide = (doc._timecodeToShow = curTime) + 1)); return this.addDocument(doc); } @@ -861,7 +859,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp // starts marquee selection marqueeDown = (e: React.PointerEvent) => { - if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._viewScale, 1) === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) { + if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) === 1 && this.props.isContentActive(true) && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) { setupMoveUpEvents( this, e, @@ -872,7 +870,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp }), returnFalse, () => MarqueeAnnotator.clearAnnotations(this._savedAnnotations), - false + false, false ); } }; @@ -892,18 +890,16 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp .scale(this.scaling()) .translate(0, (-this.heightPercent / 100) * this.props.PanelHeight()); - setPlayheadTime = (time: number) => (this.player!.currentTime = this.layoutDoc._currentTimecode = time); + setPlayheadTime = (time: number) => (this.player!.currentTime = this.layoutDoc._layout_currentTimecode = time); timelineHeight = () => (this.props.PanelHeight() * (100 - this.heightPercent)) / 100; playing = () => this._playing; - contentFunc = () => [this.youtubeVideoId ? this.youtubeContent : this.content]; - scaling = () => this.props.NativeDimScaling?.() || 1; panelWidth = () => (this.props.PanelWidth() * this.heightPercent) / 100; - panelHeight = () => (this.layoutDoc._fitWidth ? this.panelWidth() / (Doc.NativeAspect(this.rootDoc) || 1) : (this.props.PanelHeight() * this.heightPercent) / 100); + panelHeight = () => (this.layoutDoc._layout_fitWidth ? this.panelWidth() / (Doc.NativeAspect(this.rootDoc) || 1) : (this.props.PanelHeight() * this.heightPercent) / 100); screenToLocalTransform = () => { const offset = (this.props.PanelWidth() - this.panelWidth()) / 2 / this.scaling(); @@ -953,14 +949,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp ); }; - scrollFocus = (doc: Doc, options: DocFocusOptions) => { - if (doc !== this.rootDoc) { - const showTime = Cast(doc._timecodeToShow, 'number', null); - showTime !== undefined && setTimeout(() => this.Seek(showTime), 100); - return 0.1; - } - }; - // renders CollectionStackedTimeline @computed get renderTimeline() { return ( @@ -968,14 +956,15 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp <CollectionStackedTimeline ref={action((r: any) => (this._stackedTimeline = r))} {...this.props} + dataFieldKey={this.fieldKey} fieldKey={this.annotationKey} dictationKey={this.fieldKey + '-dictation'} mediaPath={this.audiopath} + thumbnails={() => StrListCast(this.dataDoc[this.fieldKey + '_thumbnails'])} renderDepth={this.props.renderDepth + 1} startTag={'_timecodeToShow' /* videoStart */} endTag={'_timecodeToHide' /* videoEnd */} bringToFront={emptyFunction} - CollectionView={undefined} playFrom={this.playFrom} setTime={this.setPlayheadTime} playing={this.playing} @@ -1016,7 +1005,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp const anchy = NumCast(cropping.y); const anchw = NumCast(cropping._width); const anchh = NumCast(cropping._height); - const viewScale = NumCast(this.rootDoc[this.fieldKey + '-nativeWidth']) / anchw; + const viewScale = NumCast(this.rootDoc[this.fieldKey + '_nativeWidth']) / anchw; cropping.title = 'crop: ' + this.rootDoc.title; cropping.x = NumCast(this.rootDoc.x) + NumCast(this.rootDoc._width); cropping.y = NumCast(this.rootDoc.y); @@ -1024,28 +1013,28 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp cropping._height = anchh * (this.props.NativeDimScaling?.() || 1); cropping.timecodeToHide = undefined; cropping.timecodeToShow = undefined; - cropping.isLinkButton = undefined; + cropping.onClick = undefined; const croppingProto = Doc.GetProto(cropping); croppingProto.annotationOn = undefined; - croppingProto.isPrototype = true; + croppingProto.isDataDoc = true; croppingProto.proto = Cast(this.rootDoc.proto, Doc, null)?.proto; // set proto of cropping's data doc to be IMAGE_PROTO croppingProto.type = DocumentType.VID; croppingProto.layout = VideoBox.LayoutString('data'); croppingProto.data = ObjectField.MakeCopy(this.rootDoc[this.fieldKey] as ObjectField); - croppingProto['data-nativeWidth'] = anchw; - croppingProto['data-nativeHeight'] = anchh; + croppingProto['data_nativeWidth'] = anchw; + croppingProto['data_nativeHeight'] = anchh; croppingProto.videoCrop = true; - croppingProto.currentTimecode = this.layoutDoc._currentTimecode; - croppingProto.viewScale = viewScale; - croppingProto.viewScaleMin = viewScale; - croppingProto.panX = anchx / viewScale; - croppingProto.panY = anchy / viewScale; - croppingProto.panXMin = anchx / viewScale; - croppingProto.panXMax = anchw / viewScale; - croppingProto.panYMin = anchy / viewScale; - croppingProto.panYMax = anchh / viewScale; + croppingProto.layout_currentTimecode = this.layoutDoc._layout_currentTimecode; + croppingProto.freeform_scale = viewScale; + croppingProto.freeform_scale_min = viewScale; + croppingProto.freeform_ = anchx / viewScale; + croppingProto.freeform_panY = anchy / viewScale; + croppingProto.freeform_panX_min = anchx / viewScale; + croppingProto.freeform_panX_max = anchw / viewScale; + croppingProto.freeform_panY_min = anchy / viewScale; + croppingProto.freeform_panY_max = anchh / viewScale; if (addCrop) { - DocUtils.MakeLink({ doc: region }, { doc: cropping }, 'cropped image', ''); + DocUtils.MakeLink(region, cropping, { link_relationship: 'cropped image' }); } this.props.bringToFront(cropping); return cropping; @@ -1063,7 +1052,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp style={{ pointerEvents: this.layoutDoc._lockedPosition ? 'none' : undefined, borderRadius, - overflow: this.props.docViewPath?.().slice(-1)[0].fitWidth ? 'auto' : undefined, + overflow: this.props.docViewPath?.().slice(-1)[0].layout_fitWidth ? 'auto' : undefined, }} onWheel={e => { e.stopPropagation(); @@ -1080,23 +1069,27 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp left: (this.props.PanelWidth() - this.panelWidth()) / 2, }}> <CollectionFreeFormView - {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit} + {...this.props} + setContentView={emptyFunction} + NativeWidth={returnZero} + NativeHeight={returnZero} renderDepth={this.props.renderDepth + 1} fieldKey={this.annotationKey} - CollectionView={undefined} isAnnotationOverlay={true} annotationLayerHostsContent={true} PanelWidth={this.panelWidth} PanelHeight={this.panelHeight} + isAnyChildContentActive={returnFalse} ScreenToLocalTransform={this.screenToLocalTransform} docFilters={this.timelineDocFilter} select={emptyFunction} + focus={emptyFunction} NativeDimScaling={returnOne} whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} removeDocument={this.removeDocument} moveDocument={this.moveDocument} addDocument={this.addDocWithTimecode}> - {this.contentFunc} + {this.youtubeVideoId ? this.youtubeContent : this.content} </CollectionFreeFormView> </div> {this.annotationLayer} @@ -1126,7 +1119,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp @computed get UIButtons() { const bounds = this.props.docViewPath().lastElement().getBounds(); const width = (bounds?.right || 0) - (bounds?.left || 0); - const curTime = NumCast(this.layoutDoc._currentTimecode) - (this.timeline?.clipStart || 0); + const curTime = NumCast(this.layoutDoc._layout_currentTimecode) - (this.timeline?.clipStart || 0); return ( <> <div className="videobox-button" title={this._playing ? 'play' : 'pause'} onPointerDown={this.onPlayDown}> |
