aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx')
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx204
1 files changed, 162 insertions, 42 deletions
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 910aa744d..42a42ddf1 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -11,9 +11,13 @@ import { Document } from "../../../fields/documentSchemas";
import { TraceMobx } from "../../../fields/util";
import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
import { List } from "../../../fields/List";
-import { numberRange } from "../../../Utils";
+import { numberRange, smoothScroll } from "../../../Utils";
import { ComputedField } from "../../../fields/ScriptField";
import { listSpec } from "../../../fields/Schema";
+import { DocumentType } from "../../documents/DocumentTypes";
+import { Zoom, Fade, Flip, Rotate, Bounce, Roll, LightSpeed } from 'react-reveal';
+import { PresBox } from "./PresBox";
+import { InkingStroke } from "../InkingStroke";
export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined;
@@ -21,7 +25,7 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
zIndex?: number;
highlight?: boolean;
jitterRotation: number;
- transition?: string;
+ dataTransition?: string;
fitToBox?: boolean;
replica: string;
}
@@ -36,7 +40,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
return min + rnd * (max - min);
}
get displayName() { return "CollectionFreeFormDocumentView(" + this.rootDoc.title + ")"; } // this makes mobx trace() statements more descriptive
- get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${this.random(-1, 1) * this.props.jitterRotation}deg)`; }
+ get maskCentering() { return this.props.Document.isInkMask ? InkingStroke.MaskDim / 2 : 0; }
+ get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X - this.maskCentering}px, ${this.Y - this.maskCentering}px) rotate(${this.random(-1, 1) * this.props.jitterRotation}deg)`; }
get X() { return this.dataProvider ? this.dataProvider.x : (this.Document.x || 0); }
get Y() { return this.dataProvider ? this.dataProvider.y : (this.Document.y || 0); }
get Opacity() { return this.dataProvider ? this.dataProvider.opacity : Cast(this.layoutDoc.opacity, "number", null); }
@@ -58,10 +63,10 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
const someView = Cast(this.props.Document.someView, Doc);
const minimap = Cast(this.props.Document.minimap, Doc);
if (someView instanceof Doc && minimap instanceof Doc) {
- const x = (NumCast(someView._panX) - NumCast(someView._width) / 2 / NumCast(someView.scale) - (NumCast(minimap.fitX) - NumCast(minimap.fitW) / 2)) / NumCast(minimap.fitW) * NumCast(minimap._width) - NumCast(minimap._width) / 2;
- const y = (NumCast(someView._panY) - NumCast(someView._height) / 2 / NumCast(someView.scale) - (NumCast(minimap.fitY) - NumCast(minimap.fitH) / 2)) / NumCast(minimap.fitH) * NumCast(minimap._height) - NumCast(minimap._height) / 2;
- const w = NumCast(someView._width) / NumCast(someView.scale) / NumCast(minimap.fitW) * NumCast(minimap.width);
- const h = NumCast(someView._height) / NumCast(someView.scale) / NumCast(minimap.fitH) * NumCast(minimap.height);
+ const x = (NumCast(someView._panX) - NumCast(someView._width) / 2 / NumCast(someView._viewScale) - (NumCast(minimap.fitX) - NumCast(minimap.fitW) / 2)) / NumCast(minimap.fitW) * NumCast(minimap._width) - NumCast(minimap._width) / 2;
+ const y = (NumCast(someView._panY) - NumCast(someView._height) / 2 / NumCast(someView._viewScale) - (NumCast(minimap.fitY) - NumCast(minimap.fitH) / 2)) / NumCast(minimap.fitH) * NumCast(minimap._height) - NumCast(minimap._height) / 2;
+ const w = NumCast(someView._width) / NumCast(someView._viewScale) / NumCast(minimap.fitW) * NumCast(minimap.width);
+ const h = NumCast(someView._height) / NumCast(someView._viewScale) / NumCast(minimap.fitH) * NumCast(minimap.height);
return { x: x, y: y, width: w, height: h };
}
}
@@ -71,55 +76,141 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
public static getValues(doc: Doc, time: number) {
const timecode = Math.round(time);
return ({
- x: Cast(doc["x-indexed"], listSpec("number"), []).reduce((p, x, i) => (i <= timecode && x !== undefined) || p === undefined ? x : p, undefined as any as number),
- y: Cast(doc["y-indexed"], listSpec("number"), []).reduce((p, y, i) => (i <= timecode && y !== undefined) || p === undefined ? y : p, undefined as any as number),
- opacity: Cast(doc["opacity-indexed"], listSpec("number"), []).reduce((p, o, i) => i <= timecode || p === undefined ? o : p, undefined as any as number),
+ h: Cast(doc["h-indexed"], listSpec("number"), [NumCast(doc._height)]).reduce((p, h, i) => (i <= timecode && h !== undefined) || p === undefined ? h : p, undefined as any as number),
+ w: Cast(doc["w-indexed"], listSpec("number"), [NumCast(doc._width)]).reduce((p, w, i) => (i <= timecode && w !== undefined) || p === undefined ? w : p, undefined as any as number),
+ x: Cast(doc["x-indexed"], listSpec("number"), [NumCast(doc.x)]).reduce((p, x, i) => (i <= timecode && x !== undefined) || p === undefined ? x : p, undefined as any as number),
+ y: Cast(doc["y-indexed"], listSpec("number"), [NumCast(doc.y)]).reduce((p, y, i) => (i <= timecode && y !== undefined) || p === undefined ? y : p, undefined as any as number),
+ scroll: Cast(doc["scroll-indexed"], listSpec("number"), [NumCast(doc._scrollTop, 0)]).reduce((p, s, i) => (i <= timecode && s !== undefined) || p === undefined ? s : p, undefined as any as number),
+ opacity: Cast(doc["opacity-indexed"], listSpec("number"), [NumCast(doc.opacity, 1)]).reduce((p, o, i) => i <= timecode || p === undefined ? o : p, undefined as any as number),
});
}
- public static setValues(time: number, d: Doc, x?: number, y?: number, opacity?: number) {
+ public static setValues(time: number, d: Doc, x?: number, y?: number, h?: number, w?: number, scroll?: number, opacity?: number) {
const timecode = Math.round(time);
- Cast(d["x-indexed"], listSpec("number"), [])[Math.max(0, timecode - 1)] = x as any as number;
- Cast(d["y-indexed"], listSpec("number"), [])[Math.max(0, timecode - 1)] = y as any as number;
- Cast(d["x-indexed"], listSpec("number"), [])[timecode] = x as any as number;
- Cast(d["y-indexed"], listSpec("number"), [])[timecode] = y as any as number;
- Cast(d["opacity-indexed"], listSpec("number"), null)[timecode] = opacity as any as number;
+ const hindexed = Cast(d["h-indexed"], listSpec("number"), []).slice();
+ const windexed = Cast(d["w-indexed"], listSpec("number"), []).slice();
+ const xindexed = Cast(d["x-indexed"], listSpec("number"), []).slice();
+ const yindexed = Cast(d["y-indexed"], listSpec("number"), []).slice();
+ const oindexed = Cast(d["opacity-indexed"], listSpec("number"), []).slice();
+ const scrollIndexed = Cast(d["scroll-indexed"], listSpec("number"), []).slice();
+ xindexed[timecode] = x as any as number;
+ yindexed[timecode] = y as any as number;
+ hindexed[timecode] = h as any as number;
+ windexed[timecode] = w as any as number;
+ oindexed[timecode] = opacity as any as number;
+ scrollIndexed[timecode] = scroll as any as number;
+ d["x-indexed"] = new List<number>(xindexed);
+ d["y-indexed"] = new List<number>(yindexed);
+ d["h-indexed"] = new List<number>(hindexed);
+ d["w-indexed"] = new List<number>(windexed);
+ d["opacity-indexed"] = new List<number>(oindexed);
+ d["scroll-indexed"] = new List<number>(scrollIndexed);
+ if (d.appearFrame) {
+ if (d.appearFrame === timecode + 1) {
+ d["text-color"] = "red";
+ } else if (d.appearFrame < timecode + 1) {
+ d["text-color"] = "grey";
+ } else { d["text-color"] = "black"; }
+ } else if (d.appearFrame === 0) {
+ d["text-color"] = "black";
+ }
+ }
+
+ public static updateScrollframe(doc: Doc, time: number) {
+ const timecode = Math.round(time);
+ const scrollIndexed = Cast(doc['scroll-indexed'], listSpec("number"), null);
+ scrollIndexed?.length <= timecode + 1 && scrollIndexed.push(undefined as any as number);
+ setTimeout(() => doc.dataTransition = "inherit", 1010);
+ }
+
+ public static setupScroll(doc: Doc, timecode: number, scrollProgressivize: boolean = false) {
+ const scrollList = new List<number>();
+ scrollList[timecode] = NumCast(doc._scrollTop);
+ doc["scroll-indexed"] = scrollList;
+ doc.activeFrame = ComputedField.MakeFunction("self.currentFrame");
+ doc._scrollTop = ComputedField.MakeInterpolated("scroll", "activeFrame");
}
+
+
public static updateKeyframe(docs: Doc[], time: number) {
const timecode = Math.round(time);
docs.forEach(doc => {
const xindexed = Cast(doc['x-indexed'], listSpec("number"), null);
const yindexed = Cast(doc['y-indexed'], listSpec("number"), null);
+ const hindexed = Cast(doc['h-indexed'], listSpec("number"), null);
+ const windexed = Cast(doc['w-indexed'], listSpec("number"), null);
const opacityindexed = Cast(doc['opacity-indexed'], listSpec("number"), null);
+ hindexed?.length <= timecode + 1 && hindexed.push(undefined as any as number);
+ windexed?.length <= timecode + 1 && windexed.push(undefined as any as number);
xindexed?.length <= timecode + 1 && xindexed.push(undefined as any as number);
yindexed?.length <= timecode + 1 && yindexed.push(undefined as any as number);
opacityindexed?.length <= timecode + 1 && opacityindexed.push(undefined as any as number);
- doc.transition = "all 1s";
+ if (doc.appearFrame) {
+ if (doc.appearFrame === timecode + 1) {
+ doc["text-color"] = "red";
+ } else if (doc.appearFrame < timecode + 1) {
+ doc["text-color"] = "grey";
+ } else { doc["text-color"] = "black"; }
+ } else if (doc.appearFrame === 0) {
+ doc["text-color"] = "black";
+ }
+ doc.dataTransition = "all 1s";
});
- setTimeout(() => docs.forEach(doc => doc.transition = "inherit"), 1010);
+ setTimeout(() => docs.forEach(doc => doc.dataTransition = "inherit"), 1010);
}
public static gotoKeyframe(docs: Doc[]) {
- docs.forEach(doc => doc.transition = "all 1s");
- setTimeout(() => docs.forEach(doc => doc.transition = "inherit"), 1010);
+ docs.forEach(doc => doc.dataTransition = "all 1s");
+ setTimeout(() => docs.forEach(doc => doc.dataTransition = "inherit"), 1010);
+ }
+
+ public static setupZoom(doc: Doc, zoomProgressivize: boolean = false) {
+ const width = new List<number>();
+ const height = new List<number>();
+ const top = new List<number>();
+ const left = new List<number>();
+ width.push(NumCast(doc.width));
+ height.push(NumCast(doc.height));
+ top.push(NumCast(doc.height) / -2);
+ left.push(NumCast(doc.width) / -2);
+ doc["viewfinder-width-indexed"] = width;
+ doc["viewfinder-height-indexed"] = height;
+ doc["viewfinder-top-indexed"] = top;
+ doc["viewfinder-left-indexed"] = left;
}
public static setupKeyframes(docs: Doc[], timecode: number, progressivize: boolean = false) {
docs.forEach((doc, i) => {
+ if (doc.appearFrame === undefined) doc.appearFrame = i;
const curTimecode = progressivize ? i : timecode;
const xlist = new List<number>(numberRange(timecode + 1).map(i => undefined) as any as number[]);
const ylist = new List<number>(numberRange(timecode + 1).map(i => undefined) as any as number[]);
- const olist = new List<number>(numberRange(timecode + 1).map(t => progressivize && t < i ? 0 : 1));
- xlist[Math.max(curTimecode - 1, 0)] = xlist[curTimecode] = NumCast(doc.x);
- ylist[Math.max(curTimecode - 1, 0)] = ylist[curTimecode] = NumCast(doc.y);
+ const wlist = new List<number>(numberRange(timecode + 1).map(i => undefined) as any as number[]);
+ const hlist = new List<number>(numberRange(timecode + 1).map(i => undefined) as any as number[]);
+ const olist = new List<number>(numberRange(timecode + 1).map(t => progressivize && t < (doc.appearFrame ? doc.appearFrame : i) ? 0 : 1));
+ const oarray = olist;
+ oarray.fill(0, 0, NumCast(doc.appearFrame) - 1);
+ oarray.fill(1, NumCast(doc.appearFrame), timecode);
+ // oarray.fill(0, 0, NumCast(doc.appearFrame) - 1);
+ // oarray.fill(1, NumCast(doc.appearFrame), timecode);\
+ wlist[curTimecode] = NumCast(doc._width);
+ hlist[curTimecode] = NumCast(doc._height);
+ xlist[curTimecode] = NumCast(doc.x);
+ ylist[curTimecode] = NumCast(doc.y);
+ doc.xArray = xlist;
+ doc.yArray = ylist;
doc["x-indexed"] = xlist;
doc["y-indexed"] = ylist;
- doc["opacity-indexed"] = olist;
- doc.activeFrame = ComputedField.MakeFunction("self.context ? (self.context.currentFrame||0) : 0");
+ doc["w-indexed"] = wlist;
+ doc["h-indexed"] = hlist;
+ doc["opacity-indexed"] = oarray;
+ doc.activeFrame = ComputedField.MakeFunction("self.context?.currentFrame||0");
+ doc._height = ComputedField.MakeInterpolated("h", "activeFrame");
+ doc._width = ComputedField.MakeInterpolated("w", "activeFrame");
doc.x = ComputedField.MakeInterpolated("x", "activeFrame");
doc.y = ComputedField.MakeInterpolated("y", "activeFrame");
doc.opacity = ComputedField.MakeInterpolated("opacity", "activeFrame");
- doc.transition = "inherit";
+ doc.dataTransition = "inherit";
});
}
@@ -128,6 +219,44 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
this.props.Document.y = NumCast(this.props.Document.y) + y;
}
+ @computed get freeformNodeDiv() {
+ const node = <DocumentView {...this.props}
+ nudge={this.nudge}
+ dragDivName={"collectionFreeFormDocumentView-container"}
+ ContentScaling={this.contentScaling}
+ ScreenToLocalTransform={this.getTransform}
+ backgroundColor={this.props.backgroundColor}
+ opacity={this.opacity}
+ NativeHeight={this.NativeHeight}
+ NativeWidth={this.NativeWidth}
+ PanelWidth={this.panelWidth}
+ PanelHeight={this.panelHeight} />;
+ if (PresBox.Instance && this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc) {
+ const effectProps = {
+ left: this.layoutDoc.presEffectDirection === 'left',
+ right: this.layoutDoc.presEffectDirection === 'right',
+ top: this.layoutDoc.presEffectDirection === 'top',
+ bottom: this.layoutDoc.presEffectDirection === 'bottom',
+ opposite: true,
+ delay: this.layoutDoc.presTransition,
+ // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc,
+ };
+ switch (this.layoutDoc.presEffect) {
+ case "Zoom": return (<Zoom {...effectProps}>{node}</Zoom>); break;
+ case "Fade": return (<Fade {...effectProps}>{node}</Fade>); break;
+ case "Flip": return (<Flip {...effectProps}>{node}</Flip>); break;
+ case "Rotate": return (<Rotate {...effectProps}>{node}</Rotate>); break;
+ case "Bounce": return (<Bounce {...effectProps}>{node}</Bounce>); break;
+ case "Roll": return (<Roll {...effectProps}>{node}</Roll>); break;
+ case "LightSpeed": return (<LightSpeed {...effectProps}>{node}</LightSpeed>); break;
+ case "None": return node; break;
+ default: return node; break;
+ }
+ } else {
+ return node;
+ }
+ }
+
contentScaling = () => this.nativeWidth > 0 && !this.props.fitToBox && !this.freezeDimensions ? this.width / this.nativeWidth : 1;
panelWidth = () => (this.sizeProvider?.width || this.props.PanelWidth?.());
panelHeight = () => (this.sizeProvider?.height || this.props.PanelHeight?.());
@@ -144,20 +273,21 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
boxShadow:
this.Opacity === 0 ? undefined : // if it's not visible, then no shadow
this.layoutDoc.z ? `#9c9396 ${StrCast(this.layoutDoc.boxShadow, "10px 10px 0.9vw")}` : // if it's a floating doc, give it a big shadow
- this.props.backgroundHalo?.() ? (`${this.props.backgroundColor?.(this.props.Document)} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(this.layoutDoc.isBackground ? 100 : 50) / this.props.ContentScaling()}px`)}`) : // if it's just in a cluster, make the shadown roughly match the cluster border extent
+ this.props.backgroundHalo?.() && this.props.Document.type !== DocumentType.INK ? (`${this.props.backgroundColor?.(this.props.Document)} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(this.layoutDoc.isBackground ? 100 : 50) / this.props.ContentScaling()}px`)}`) : // if it's just in a cluster, make the shadown roughly match the cluster border extent
this.layoutDoc.isBackground ? undefined : // if it's a background & has a cluster color, make the shadow spread really big
StrCast(this.layoutDoc.boxShadow, ""),
borderRadius: StrCast(Doc.Layout(this.layoutDoc).borderRounding),
outline: this.Highlight ? "orange solid 2px" : "",
transform: this.transform,
- transition: this.props.transition ? this.props.transition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.transition),
- width: this.width,
- height: this.height,
+ transition: this.props.dataTransition ? this.props.dataTransition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.dataTransition),
+ width: this.props.Document.isInkMask ? InkingStroke.MaskDim : this.width,
+ height: this.props.Document.isInkMask ? InkingStroke.MaskDim : this.height,
zIndex: this.ZInd,
mixBlendMode: StrCast(this.layoutDoc.mixBlendMode) as any,
display: this.ZInd === -99 ? "none" : undefined,
- pointerEvents: this.props.Document.isBackground || this.Opacity === 0 ? "none" : this.props.pointerEvents ? "all" : undefined
+ pointerEvents: this.props.Document.isBackground || this.Opacity === 0 || this.props.Document.type === DocumentType.INK || this.props.Document.isInkMask ? "none" : this.props.pointerEvents ? "all" : undefined
}} >
+
{Doc.UserDoc().renderStyle !== "comic" ? (null) :
<div style={{ width: "100%", height: "100%", position: "absolute" }}>
<svg style={{ transform: `scale(1,${this.props.PanelHeight() / this.props.PanelWidth()})`, transformOrigin: "top left", overflow: "visible" }} viewBox="0 0 12 14">
@@ -167,17 +297,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
</div>}
{!this.props.fitToBox ?
- <DocumentView {...this.props}
- nudge={this.nudge}
- dragDivName={"collectionFreeFormDocumentView-container"}
- ContentScaling={this.contentScaling}
- ScreenToLocalTransform={this.getTransform}
- backgroundColor={this.props.backgroundColor}
- opacity={this.opacity}
- NativeHeight={this.NativeHeight}
- NativeWidth={this.NativeWidth}
- PanelWidth={this.panelWidth}
- PanelHeight={this.panelHeight} />
+ <>{this.freeformNodeDiv}</>
: <ContentFittingDocumentView {...this.props}
ContainingCollectionDoc={this.props.ContainingCollectionDoc}
DataDoc={this.props.DataDoc}