aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2021-01-22 21:14:37 -0500
committerbobzel <zzzman@gmail.com>2021-01-22 21:14:37 -0500
commitd0025200b23f57ec25d3452d425de8725a032c6a (patch)
tree843ef1f021239af4b7f82c9eee553a9978fe0f46 /src
parentb9326dfc3e15683190a7d520daca6791ef049dea (diff)
fixed selection bounds for video box annotations, especially when in full screen view.
Diffstat (limited to 'src')
-rw-r--r--src/client/views/collections/TabDocView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx6
-rw-r--r--src/client/views/nodes/AudioBox.tsx18
-rw-r--r--src/client/views/nodes/DocumentView.tsx6
-rw-r--r--src/client/views/nodes/VideoBox.scss20
-rw-r--r--src/client/views/nodes/VideoBox.tsx113
6 files changed, 88 insertions, 77 deletions
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 5ca069fb9..e5f05c407 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -358,7 +358,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
}
active = () => this._isActive;
ScreenToLocalTransform = () => {
- const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont?.children?.[0]?.firstChild as HTMLElement);
+ const { translateX, translateY } = Utils.GetScreenTransform(this._mainCont?.children?.[0] as HTMLElement);
return CollectionDockingView.Instance?.props.ScreenToLocalTransform().translate(-translateX, -translateY);
}
PanelWidth = () => this._panelWidth;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index bc86ecd19..013472a04 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -137,11 +137,11 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
@computed get cachedCenteringShiftX(): number {
const scaling = this.fitToContent || !this.contentScaling ? 1 : this.contentScaling;
- return !this.props.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling / scaling : 0; // shift so pan position is at center of window for non-overlay collections
+ return this.props.isAnnotationOverlay ? 0 : this.props.PanelWidth() / 2 / this.parentScaling / scaling; // shift so pan position is at center of window for non-overlay collections
}
@computed get cachedCenteringShiftY(): number {
const scaling = this.fitToContent || !this.contentScaling ? 1 : this.contentScaling;
- return !this.props.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling / scaling : 0;// shift so pan position is at center of window for non-overlay collections
+ return this.props.isAnnotationOverlay ? 0 : this.props.PanelHeight() / 2 / this.parentScaling / scaling;// shift so pan position is at center of window for non-overlay collections
}
@computed get cachedGetLocalTransform(): Transform {
return Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY());
@@ -200,7 +200,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const dispTime = NumCast(doc.displayTimecode, -1);
const endTime = NumCast(doc.undisplayTimecode, dispTime + 1.5);
const curTime = NumCast(this.Document._currentTimecode, -1);
- return dispTime === -1 || (curTime > dispTime && curTime < endTime);
+ return dispTime === -1 || ((curTime - dispTime) >= -0.1 && curTime <= endTime);
}
public getActiveDocuments = () => {
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 4ddb0502b..6ebd16bf3 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -91,10 +91,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
AudioBox.Instance = this;
// onClick play scripts
- AudioBox.RangeScript = AudioBox.RangeScript || ScriptField.MakeScript(`scriptContext.clickMarker(self, this.audioStart, this.audioEnd)`, { self: Doc.name, scriptContext: "any" })!;
- AudioBox.LabelScript = AudioBox.LabelScript || ScriptField.MakeScript(`scriptContext.clickMarker(self, this.audioStart)`, { self: Doc.name, scriptContext: "any" })!;
- AudioBox.RangePlayScript = AudioBox.RangePlayScript || ScriptField.MakeScript(`scriptContext.playOnClick(self, this.audioStart, this.audioEnd)`, { self: Doc.name, scriptContext: "any" })!;
- AudioBox.LabelPlayScript = AudioBox.LabelPlayScript || ScriptField.MakeScript(`scriptContext.playOnClick(self, this.audioStart)`, { self: Doc.name, scriptContext: "any" })!;
+ AudioBox.RangeScript = AudioBox.RangeScript || ScriptField.MakeFunction(`scriptContext.clickMarker(self, this.audioStart, this.audioEnd)`, { self: Doc.name, scriptContext: "any" })!;
+ AudioBox.LabelScript = AudioBox.LabelScript || ScriptField.MakeFunction(`scriptContext.clickMarker(self, this.audioStart)`, { self: Doc.name, scriptContext: "any" })!;
+ AudioBox.RangePlayScript = AudioBox.RangePlayScript || ScriptField.MakeFunction(`scriptContext.playOnClick(self, this.audioStart, this.audioEnd)`, { self: Doc.name, scriptContext: "any" })!;
+ AudioBox.LabelPlayScript = AudioBox.LabelPlayScript || ScriptField.MakeFunction(`scriptContext.playOnClick(self, this.audioStart)`, { self: Doc.name, scriptContext: "any" })!;
}
getLinkData(l: Doc) {
@@ -189,18 +189,16 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
// play back the audio from time
@action
playOnClick = (anchorDoc: Doc, seekTimeInSeconds: number, endTime: number = this.audioDuration) => {
- DocumentManager.Instance.getDocumentView(anchorDoc)?.select(false);
this.playFrom(seekTimeInSeconds, endTime);
+ return true;
}
// play back the audio from time
@action
clickMarker = (anchorDoc: Doc, seekTimeInSeconds: number, endTime: number = this.audioDuration) => {
- if (this.layoutDoc.playOnClick) this.playOnClick(anchorDoc, seekTimeInSeconds, endTime);
- else {
- DocumentManager.Instance.getDocumentView(anchorDoc)?.select(false);
- this._ele && (this._ele.currentTime = this.layoutDoc._currentTimecode = seekTimeInSeconds);
- }
+ if (this.layoutDoc.playOnClick) return this.playOnClick(anchorDoc, seekTimeInSeconds, endTime);
+ this._ele && (this._ele.currentTime = this.layoutDoc._currentTimecode = seekTimeInSeconds);
+ return true;
}
// play back the audio from time
@action
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 6217f473f..e3da48749 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -410,7 +410,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
if (!Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-undo"] as Doc) &&
!Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-redo"] as Doc) &&
!this.onClickHandler.script.originalScript.includes("selectMainMenu")) {
- UndoManager.RunInBatch(func, "on click");
+ UndoManager.RunInBatch(() => func().result === true ? this.props.select(false) : "", "on click");
} else func();
};
if (this.onDoubleClickHandler) {
@@ -935,7 +935,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
PanelWidth = () => this.panelWidth;
PanelHeight = () => this.panelHeight;
ContentScale = () => this.nativeScaling;
- screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(-this.centeringX, -this.centeringY).scale(1 / this.nativeScaling);
+ screenToLocalTransform = () => {
+ return this.props.ScreenToLocalTransform().translate(-this.centeringX, -this.centeringY).scale(1 / this.nativeScaling);
+ }
componentDidMount() {
!BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.AddView(this);
diff --git a/src/client/views/nodes/VideoBox.scss b/src/client/views/nodes/VideoBox.scss
index 8bba5d1ff..19f605278 100644
--- a/src/client/views/nodes/VideoBox.scss
+++ b/src/client/views/nodes/VideoBox.scss
@@ -183,14 +183,18 @@
pointer-events:all;
}
-// .timeline-button {
-// position: absolute;
-// bottom: 35px;
-// right: 235px;
-// color: lightgrey;
-// width: 20px;
-
-// }
+.timeline-button {
+ position: absolute;
+ display: flex;
+ align-items: center;
+ z-index: 1010;
+ bottom: 35px;
+ right: 235px;
+ color: white;
+ background: dimgrey;
+ width: 20px;
+ height: 20px;
+}
.videoBox-play {
width: 25px;
height: 20px;
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 608d7daa3..c5e61eedd 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -49,7 +49,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
static LabelScript: ScriptField;
static RangePlayScript: ScriptField;
static LabelPlayScript: ScriptField;
- static heightPercent = 20; // height of timeline in percent of height of videoBox.
+ static heightPercent = 60; // height of timeline in percent of height of videoBox.
private _disposers: { [name: string]: IReactionDisposer } = {};
private _youtubePlayer: YT.Player | undefined = undefined;
private _videoRef: HTMLVideoElement | null = null;
@@ -58,8 +58,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
private _isResetClick = 0;
private _mainCont: React.RefObject<HTMLDivElement> = React.createRef();
private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
- @observable _marqueeing: number[] | undefined;
- @observable _savedAnnotations: Dictionary<number, HTMLDivElement[]> = new Dictionary<number, HTMLDivElement[]>();
_play: any = null;
_timeline: Opt<HTMLDivElement>;
_audioRef = React.createRef<HTMLDivElement>();
@@ -68,7 +66,11 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
_count: Array<any> = [];
_duration = 0;
_start: boolean = true;
- private _currMarker: any;
+ _currMarker: any;
+ @observable _marqueeing: number[] | undefined;
+ @observable _savedAnnotations: Dictionary<number, HTMLDivElement[]> = new Dictionary<number, HTMLDivElement[]>();
+ @observable _screenCapture = false;
+ @observable static _showControls: boolean;
@observable static SelectingRegion: VideoBox | undefined = undefined;
@observable _visible: boolean = false;
@observable _markerEnd: number = 0;
@@ -76,7 +78,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
@observable _playTimer?: NodeJS.Timeout = undefined;
@observable _fullScreen = false;
@observable _playing = false;
- @observable static _showControls: boolean;
+ @computed get heightPercent() { return this.layoutDoc._showTimeline ? NumCast(this.layoutDoc._videoTimelineHeightPercent, VideoBox.heightPercent) : 100; }
@computed get videoDuration() { return NumCast(this.dataDoc[this.fieldKey + "-duration"]); }
@computed get markerDocs() { return DocListCast(this.dataDoc[this.annotationKey + "-timeline"]).concat(DocListCast(this.dataDoc[this.annotationKey])); }
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(VideoBox, fieldKey); }
@@ -90,10 +92,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
VideoBox.Instance = this;
// onClick play scripts
- VideoBox.RangeScript = VideoBox.RangeScript || ScriptField.MakeScript(`scriptContext.clickMarker(self, this.displayTimecode, this.undisplayTimecode)`, { self: Doc.name, scriptContext: "any" })!;
- VideoBox.LabelScript = VideoBox.LabelScript || ScriptField.MakeScript(`scriptContext.clickMarker(self, this.displayTimecode)`, { self: Doc.name, scriptContext: "any" })!;
- VideoBox.RangePlayScript = VideoBox.RangePlayScript || ScriptField.MakeScript(`scriptContext.playOnClick(self, this.displayTimecode, this.undisplayTimecode)`, { self: Doc.name, scriptContext: "any" })!;
- VideoBox.LabelPlayScript = VideoBox.LabelPlayScript || ScriptField.MakeScript(`scriptContext.playOnClick(self, this.displayTimecode)`, { self: Doc.name, scriptContext: "any" })!;
+ VideoBox.RangeScript = VideoBox.RangeScript || ScriptField.MakeFunction(`scriptContext.clickMarker(self, this.displayTimecode, this.undisplayTimecode)`, { self: Doc.name, scriptContext: "any" })!;
+ VideoBox.LabelScript = VideoBox.LabelScript || ScriptField.MakeFunction(`scriptContext.clickMarker(self, this.displayTimecode)`, { self: Doc.name, scriptContext: "any" })!;
+ VideoBox.RangePlayScript = VideoBox.RangePlayScript || ScriptField.MakeFunction(`scriptContext.playOnClick(self, this.displayTimecode, this.undisplayTimecode)`, { self: Doc.name, scriptContext: "any" })!;
+ VideoBox.LabelPlayScript = VideoBox.LabelPlayScript || ScriptField.MakeFunction(`scriptContext.playOnClick(self, this.displayTimecode)`, { self: Doc.name, scriptContext: "any" })!;
}
videoLoad = () => {
@@ -311,7 +313,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
console.log("VideoBox :" + e);
}
}
- @observable _screenCapture = false;
+
specificContextMenu = (e: React.MouseEvent): void => {
const field = Cast(this.dataDoc[this.props.fieldKey], VideoField);
if (field) {
@@ -337,10 +339,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
const field = Cast(this.dataDoc[this.fieldKey], VideoField);
const interactive = Doc.GetSelectedTool() !== InkTool.None || !this.props.isSelected() ? "" : "-interactive";
const style = "videoBox-content" + (this._fullScreen ? "-fullScreen" : "") + interactive;
- const h = this.layoutDoc._showTimeline ? `${100 - VideoBox.heightPercent}%` : "100%";
return !field ? <div>Loading</div> :
<div className="container" style={{ pointerEvents: this._isChildActive || this.active() ? "all" : "none" }}>
- <div className={`${style}`} style={{ width: "100%", height: h, left: "0px" }}>
+ <div className={`${style}`} style={{ width: "100%", height: "100%", left: "0px" }}>
<video key="video" autoPlay={this._screenCapture} ref={this.setVideoRef}
style={{ height: "100%", width: "auto", display: "flex", margin: "auto" }}
onCanPlay={this.videoLoad}
@@ -412,13 +413,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
<FontAwesomeIcon icon="camera" size="lg" />
</div>,
<div className="timeline-button" key="timeline-button" onPointerDown={this.toggleTimeline} style={{
- position: "absolute",
- bottom: 0,
- right: 0,
- zIndex: 1001,
- color: "white",
- background: "dimgrey",
- width: "20px"
+ transform: `scale(${this.scaling()})`,
+ right: this.scaling() * 10 - 10,
+ bottom: this.scaling() * 10 - 10
}}>
<FontAwesomeIcon icon={this.layoutDoc._showTimeline ? "eye-slash" : "eye"} style={{ width: "100%" }} />
</div>,
@@ -520,9 +517,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
toggleTimeline = (e: React.PointerEvent) => this.layoutDoc._showTimeline = !this.layoutDoc._showTimeline
// ref for timeline
- timelineRef = (timeline: HTMLDivElement) => {
- this._timeline = timeline;
- }
+ timelineRef = (timeline: HTMLDivElement) => { this._timeline = timeline; }
// starting the drag event creating a range marker
@action
@@ -579,18 +574,16 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
// play back the video from time
@action
playOnClick = (anchorDoc: Doc, seekTimeInSeconds: number, endTime: number = this.videoDuration) => {
- DocumentManager.Instance.getDocumentView(anchorDoc)?.select(false);
this.playFrom(seekTimeInSeconds, endTime);
+ return true; // select
}
// play back the video from time
@action
clickMarker = (anchorDoc: Doc, seekTimeInSeconds: number, endTime: number = this.videoDuration) => {
- if (this.layoutDoc.playOnClick) this.playOnClick(anchorDoc, seekTimeInSeconds, endTime);
- else {
- DocumentManager.Instance.getDocumentView(anchorDoc)?.select(false);
- this.player && (this.player.currentTime = this.layoutDoc._currentTimecode = seekTimeInSeconds);
- }
+ if (this.layoutDoc.playOnClick) return this.playOnClick(anchorDoc, seekTimeInSeconds, endTime);
+ this.player && (this.player.currentTime = this.layoutDoc._currentTimecode = seekTimeInSeconds);
+ return true; // select
}
// starting the drag event for marker resizing
@@ -644,12 +637,13 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
DataDoc={undefined}
PanelWidth={() => width}
PanelHeight={() => height}
+ renderDepth={this.props.renderDepth + 1}
rootSelected={returnFalse}
LayoutTemplate={undefined}
LayoutTemplateString={LabelBox.LayoutString("data")}
ContainingCollectionDoc={this.props.Document}
removeDocument={(doc: Doc | Doc[]) => this.removeDocument(doc, annotationKey)}
- ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1).translate(-x - 4, -y - 3)}
+ ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().scale(this.scaling()).translate(-x, -y)}
parentActive={(out) => this.props.isSelected(out) || this._isChildActive}
whenActiveChanged={action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive))}
onClick={script}
@@ -675,13 +669,17 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
// returns the timeline
@computed get renderTimeline() {
const timelineContentWidth = this.props.PanelWidth();
- const timelineContentHeight = this.props.PanelHeight() * VideoBox.heightPercent / 100;
+ const timelineContentHeight = this.props.PanelHeight() * (100 - this.heightPercent) / 100;
const overlaps: { videoStart: number, videoEnd: number, level: number }[] = [];
const drawMarkers: { level: number, marker: Doc }[] = this.markerDocs.map((m, i) => ({ level: this.getLevel(m, overlaps), marker: m }));
const maxLevel = overlaps.reduce((m, o) => Math.max(m, o.level), 0) + 2;
return !this.layoutDoc._showTimeline ? (null) :
- <div className="audiobox-timeline" ref={this.timelineRef} style={{ height: `${VideoBox.heightPercent}%` }}
- onClick={e => { if (this._isChildActive || this.props.isSelected()) { e.stopPropagation(); e.preventDefault(); } }}
+ <div className="audiobox-timeline" ref={this.timelineRef} style={{ height: `${100 - this.heightPercent}%` }}
+ onClick={e => {
+ if (this._isChildActive || this.props.isSelected()) {
+ e.stopPropagation(); e.preventDefault();
+ }
+ }}
onPointerDown={e => {
if (this._isChildActive || this.props.isSelected()) {
e.button === 0 && !e.ctrlKey && this.onPointerDownTimeline(e);
@@ -758,7 +756,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
rangePlayScript = () => VideoBox.RangePlayScript;
labelPlayScript = () => VideoBox.LabelPlayScript;
- screenToLocalTransform = () => this.props.ScreenToLocalTransform();
contentFunc = () => [this.youtubeVideoId ? this.youtubeContent : this.content];
@computed get annotationLayer() {
@@ -774,33 +771,43 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
this.props.select(true);
});
+ scaling = () => this.props.scaling?.() || 1;
+ panelWidth = () => this.props.PanelWidth() * this.heightPercent / 100;
+ panelHeight = () => this.props.PanelHeight() * this.heightPercent / 100;
+ screenToLocalTransform = () => {
+ const offset = (this.props.PanelWidth() - this.panelWidth()) / 2 / this.scaling();
+ return this.props.ScreenToLocalTransform().translate(-offset, 0).scale(100 / this.heightPercent);
+ }
+
render() {
const borderRad = this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.BorderRounding);
- const borderRadius = borderRad?.includes("px") ? `${Number(borderRad.split("px")[0]) / (this.props.scaling?.() || 1)}px` : borderRad;
+ const borderRadius = borderRad?.includes("px") ? `${Number(borderRad.split("px")[0]) / this.scaling()}px` : borderRad;
return (<div className="videoBox" onContextMenu={this.specificContextMenu} ref={this._mainCont}
style={{
pointerEvents: this.props.layerProvider?.(this.layoutDoc) === false ? "none" : undefined,
borderRadius
}} >
- <div className="videoBox-viewer" onPointerDown={this.marqueeDown}>
- <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
- forceScaling={true}
- fieldKey={this.annotationKey}
- isAnnotationOverlay={true}
- select={emptyFunction}
- active={this.annotationsActive}
- scaling={returnOne}
- PanelWidth={() => this.props.PanelWidth() * (this.layoutDoc._showTimeline ? .8 : 1)}
- PanelHeight={() => this.props.PanelHeight() * (this.layoutDoc._showTimeline ? .8 : 1)}
- ScreenToLocalTransform={() => this.screenToLocalTransform().scale(this.layoutDoc._showTimeline ? 1 / .8 : 1)}
- whenActiveChanged={this.whenActiveChanged}
- removeDocument={this.removeDocument}
- moveDocument={this.moveDocument}
- addDocument={this.addDocumentWithTimestamp}
- CollectionView={undefined}
- renderDepth={this.props.renderDepth + 1}>
- {this.contentFunc}
- </CollectionFreeFormView>
+ <div className="videoBox-viewer" onPointerDown={this.marqueeDown} >
+ <div style={{ position: "absolute", width: this.panelWidth(), height: this.panelHeight(), top: 0, left: `${(100 - this.heightPercent) / 2}%` }}>
+ <CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight", "setContentView"]).omit}
+ fieldKey={this.annotationKey}
+ isAnnotationOverlay={true}
+ forceScaling={true}
+ select={emptyFunction}
+ active={this.annotationsActive}
+ scaling={returnOne}
+ PanelWidth={this.panelWidth}
+ PanelHeight={this.panelHeight}
+ ScreenToLocalTransform={this.screenToLocalTransform}
+ whenActiveChanged={this.whenActiveChanged}
+ removeDocument={this.removeDocument}
+ moveDocument={this.moveDocument}
+ addDocument={this.addDocumentWithTimestamp}
+ CollectionView={undefined}
+ renderDepth={this.props.renderDepth + 1}>
+ {this.contentFunc}
+ </CollectionFreeFormView>
+ </div>
{this.uIButtons}
{this.annotationLayer}
{this.renderTimeline}