aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/VideoBox.tsx
diff options
context:
space:
mode:
authorbrynnchernosky <56202540+brynnchernosky@users.noreply.github.com>2022-10-28 10:10:04 -0400
committerbrynnchernosky <56202540+brynnchernosky@users.noreply.github.com>2022-10-28 10:10:04 -0400
commitceb338752aacc383c97a0e3a9b608365a1cf39b6 (patch)
treed2f355b726a9b21950f332c0f65931d7d6eef515 /src/client/views/nodes/VideoBox.tsx
parent5d6a0458b9d4f35e0c568a4d76d4fcab4e22f698 (diff)
parent2fc88a931cb2fc3408297b000208990633445585 (diff)
merge
Diffstat (limited to 'src/client/views/nodes/VideoBox.tsx')
-rw-r--r--src/client/views/nodes/VideoBox.tsx104
1 files changed, 89 insertions, 15 deletions
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 5a3594ffc..fb47bfc07 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -30,6 +30,7 @@ import { StyleProp } from '../StyleProvider';
import { FieldView, FieldViewProps } from './FieldView';
import { RecordingBox } from './RecordingBox';
import './VideoBox.scss';
+import { ObjectField } from '../../../fields/ObjectField';
const path = require('path');
/**
@@ -397,13 +398,14 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
// sets video info on load
videoLoad = action(() => {
const aspect = this.player!.videoWidth / (this.player!.videoHeight || 1);
- if (aspect) {
+ if (aspect && !this.isCropped) {
Doc.SetNativeWidth(this.dataDoc, this.player!.videoWidth);
Doc.SetNativeHeight(this.dataDoc, this.player!.videoHeight);
this.layoutDoc._height = NumCast(this.layoutDoc._width) / aspect;
}
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']);
});
@@ -570,7 +572,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
key="video"
autoPlay={this._screenCapture}
ref={this.setVideoRef}
- style={this._fullScreen ? this.fullScreenSize() : {}}
+ style={this._fullScreen ? this.fullScreenSize() : this.isCropped ? { width: 'max-content', height: 'max-content', transform: `scale(${1 / NumCast(this.rootDoc._viewScale)})`, transformOrigin: 'top left' } : {}}
onCanPlay={this.videoLoad}
controls={VideoBox._nativeControls}
onPlay={() => this.Play()}
@@ -914,27 +916,47 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
// renders video controls
componentUI = (boundsLeft: number, boundsTop: number) => {
- const bounds = this.props.docViewPath().lastElement().getBounds();
- const left = bounds?.left || 0;
- const right = bounds?.right || 0;
- const top = bounds?.top || 0;
- const height = (bounds?.bottom || 0) - top;
- const width = Math.max(right - left, 100);
- const uiHeight = Math.max(25, Math.min(50, height / 10));
- const uiMargin = Math.min(10, height / 20);
- const vidHeight = (height * this.heightPercent) / 100;
- const yPos = top + vidHeight - uiHeight - uiMargin;
- const xPos = uiHeight / vidHeight > 0.4 ? right + 10 : left + 10;
+ const xf = this.props.ScreenToLocalTransform().inverse();
+ const height = this.props.PanelHeight();
+ const vidHeight = (height * this.heightPercent) / 100 / this.scaling();
+ const vidWidth = this.props.PanelWidth() / this.scaling();
+ const uiHeight = 25;
+ const uiMargin = 10;
+ const yBot = xf.transformPoint(0, vidHeight)[1];
+ // prettier-ignore
+ const yMid = (xf.transformPoint(0, 0)[1] +
+ xf.transformPoint(0, height / this.scaling())[1]) / 2;
+ const xPos = xf.transformPoint(vidWidth / 2, 0)[0];
+ const xRight = xf.transformPoint(vidWidth, 0)[0];
const opacity = this._scrubbing ? 0.3 : this._controlsVisible ? 1 : 0;
- return this._fullScreen || right - left < 50 ? null : (
+ return this._fullScreen || this.isCropped || (xRight - xPos) * 2 < 50 ? null : (
<div className="videoBox-ui-wrapper" style={{ clip: `rect(${boundsTop}px, 10000px, 10000px, ${boundsLeft}px)` }}>
- <div className="videoBox-ui" style={{ left: xPos, top: yPos, height: uiHeight, width: width - 20, transition: this._clicking ? 'top 0.5s' : '', opacity: opacity }}>
+ <div
+ className="videoBox-ui"
+ style={{
+ transformOrigin: 'top left',
+ transform: `rotate(${NumCast(this.rootDoc.rotation)}deg) translate(${-(xRight - xPos) + 10}px, ${yBot - yMid - uiHeight - uiMargin}px)`,
+ left: xPos,
+ top: yMid,
+ height: uiHeight,
+ width: (xRight - xPos) * 2 - 20,
+ transition: this._clicking ? 'top 0.5s' : '',
+ opacity,
+ }}>
{this.UIButtons}
</div>
</div>
);
};
+ scrollFocus = (doc: Doc, smooth: boolean) => {
+ 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,12 +990,63 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
</div>
);
}
+ @computed get isCropped() {
+ return this.dataDoc.videoCrop; // bcz: hack to identify a cropped video
+ }
// renders annotation layer
@computed get annotationLayer() {
return <div className="videoBox-annotationLayer" style={{ transition: this.transition, height: `${this.heightPercent}%` }} ref={this._annotationLayer} />;
}
+ crop = (region: Doc | undefined, addCrop?: boolean) => {
+ if (!region) return;
+ const cropping = Doc.MakeCopy(region, true);
+ Doc.GetProto(region).backgroundColor = 'transparent';
+ Doc.GetProto(region).lockedPosition = true;
+ Doc.GetProto(region).title = 'region:' + this.rootDoc.title;
+ Doc.GetProto(region).isPushpin = true;
+ region._timecodeToHide = NumCast(region._timecodeToShow) + 0.0001;
+ this.addDocument(region);
+ const anchx = NumCast(cropping.x);
+ const anchy = NumCast(cropping.y);
+ const anchw = NumCast(cropping._width);
+ const anchh = NumCast(cropping._height);
+ 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);
+ cropping._width = anchw * (this.props.NativeDimScaling?.() || 1);
+ cropping._height = anchh * (this.props.NativeDimScaling?.() || 1);
+ cropping.timecodeToHide = undefined;
+ cropping.timecodeToShow = undefined;
+ cropping.isLinkButton = undefined;
+ const croppingProto = Doc.GetProto(cropping);
+ croppingProto.annotationOn = undefined;
+ croppingProto.isPrototype = 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.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;
+ if (addCrop) {
+ DocUtils.MakeLink({ doc: region }, { doc: cropping }, 'cropped image', '');
+ }
+ this.props.bringToFront(cropping);
+ return cropping;
+ };
+
savedAnnotations = () => this._savedAnnotations;
render() {
const borderRad = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BorderRounding);
@@ -1036,6 +1109,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
savedAnnotations={this.savedAnnotations}
annotationLayer={this._annotationLayer.current}
mainCont={this._mainCont.current}
+ anchorMenuCrop={this.crop}
/>
)}
{this.renderTimeline}