aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/collectionFreeForm
diff options
context:
space:
mode:
authorandrewdkim <adkim414@gmail.com>2019-07-26 17:37:12 -0400
committerandrewdkim <adkim414@gmail.com>2019-07-26 17:37:12 -0400
commit2dfd6378cf3f472132143bc231090777e49eeec7 (patch)
tree34e631e0551391e5786ae136ba1d596dbc876c76 /src/client/views/collections/collectionFreeForm
parent7cb850105aeefd1234f76aaab5badd45a8660dc4 (diff)
parente189378e5ce01eedd1373172fbd8d8dabf2ad197 (diff)
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into animationtimeline
Diffstat (limited to 'src/client/views/collections/collectionFreeForm')
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss5
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx150
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx2
3 files changed, 112 insertions, 45 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index 00407d39a..cca199afa 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -19,6 +19,11 @@
transform-origin: left top;
}
+.collectionFreeform-customText {
+ position: absolute;
+ text-align: center;
+}
+
.collectionfreeformview-container {
.collectionfreeformview>.jsx-parser {
position: inherit;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 4a085bb70..bf938f433 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -32,7 +32,14 @@ import { ScriptField } from "../../../../new_fields/ScriptField";
import { OverlayView, OverlayElementOptions } from "../../OverlayView";
import { ScriptBox } from "../../ScriptBox";
import { CompileScript } from "../../../util/Scripting";
+import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
+import { library } from "@fortawesome/fontawesome-svg-core";
+import { faEye } from "@fortawesome/free-regular-svg-icons";
+import { faTable, faPaintBrush, faAsterisk, faExpandArrowsAlt, faCompressArrowsAlt } from "@fortawesome/free-solid-svg-icons";
+import { undo } from "prosemirror-history";
+import { number } from "prop-types";
+library.add(faEye, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt);
export const panZoomSchema = createSchema({
panX: "number",
@@ -52,25 +59,31 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
private _lastY: number = 0;
private get _pwidth() { return this.props.PanelWidth(); }
private get _pheight() { return this.props.PanelHeight(); }
+ private inkKey = "ink";
+
+ get parentScaling() {
+ return (this.props as any).ContentScaling && this.Document.nativeWidth && this.fitToBox && !this.isAnnotationOverlay ? (this.props as any).ContentScaling() : 1;
+ }
@computed get contentBounds() {
- let bounds = this.props.fitToBox && !NumCast(this.nativeWidth) ? Doc.ComputeContentBounds(DocListCast(this.props.Document.data)) : undefined;
+ let bounds = this.fitToBox && !this.nativeWidth && !this.isAnnotationOverlay ? Doc.ComputeContentBounds(DocListCast(this.props.Document.data)) : undefined;
return {
panX: bounds ? (bounds.x + bounds.r) / 2 : this.Document.panX || 0,
panY: bounds ? (bounds.y + bounds.b) / 2 : this.Document.panY || 0,
- scale: bounds ? Math.min(this.props.PanelHeight() / (bounds.b - bounds.y), this.props.PanelWidth() / (bounds.r - bounds.x)) : this.Document.scale || 1
+ scale: (bounds ? Math.min(this.props.PanelHeight() / (bounds.b - bounds.y), this.props.PanelWidth() / (bounds.r - bounds.x)) : this.Document.scale || 1) / this.parentScaling
};
}
- @computed get nativeWidth() { return this.Document.nativeWidth || 0; }
- @computed get nativeHeight() { return this.Document.nativeHeight || 0; }
+ @computed get fitToBox() { return this.props.fitToBox || this.props.Document.fitToBox; }
+ @computed get nativeWidth() { return this.fitToBox ? 0 : this.Document.nativeWidth || 0; }
+ @computed get nativeHeight() { return this.fitToBox ? 0 : this.Document.nativeHeight || 0; }
public get isAnnotationOverlay() { return this.props.fieldExt ? true : false; } // fieldExt will be "" or "annotation". should maybe generalize this, or make it more specific (ie, 'annotation' instead of 'fieldExt')
private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; }
private panX = () => this.contentBounds.panX;
private panY = () => this.contentBounds.panY;
private zoomScaling = () => this.contentBounds.scale;
- private centeringShiftX = () => !this.nativeWidth ? this._pwidth / 2 : 0; // shift so pan position is at center of window for non-overlay collections
- private centeringShiftY = () => !this.nativeHeight ? this._pheight / 2 : 0;// shift so pan position is at center of window for non-overlay collections
+ private centeringShiftX = () => !this.nativeWidth && !this.isAnnotationOverlay ? this._pwidth / 2 / this.parentScaling : 0; // shift so pan position is at center of window for non-overlay collections
+ private centeringShiftY = () => !this.nativeHeight && !this.isAnnotationOverlay ? this._pheight / 2 / this.parentScaling : 0;// shift so pan position is at center of window for non-overlay collections
private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform());
private getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth);
private getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY());
@@ -104,11 +117,11 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
@undoBatch
@action
drop = (e: Event, de: DragManager.DropEvent) => {
+ let xf = this.getTransform();
if (super.drop(e, de)) {
if (de.data instanceof DragManager.DocumentDragData) {
if (de.data.droppedDocuments.length) {
- let dragDoc = de.data.droppedDocuments[0];
- let [xp, yp] = this.getTransform().transformPoint(de.x, de.y);
+ let [xp, yp] = xf.transformPoint(de.x, de.y);
let x = xp - de.data.xOffset;
let y = yp - de.data.yOffset;
let dropX = NumCast(de.data.droppedDocuments[0].x);
@@ -196,10 +209,10 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
this._pheight / this.zoomScaling());
let panelwidth = panelDim[0];
let panelheight = panelDim[1];
- if (ranges[0][0] - dx > (this.panX() + panelwidth / 2)) x = ranges[0][1] + panelwidth / 2;
- if (ranges[0][1] - dx < (this.panX() - panelwidth / 2)) x = ranges[0][0] - panelwidth / 2;
- if (ranges[1][0] - dy > (this.panY() + panelheight / 2)) y = ranges[1][1] + panelheight / 2;
- if (ranges[1][1] - dy < (this.panY() - panelheight / 2)) y = ranges[1][0] - panelheight / 2;
+ // if (ranges[0][0] - dx > (this.panX() + panelwidth / 2)) x = ranges[0][1] + panelwidth / 2;
+ // if (ranges[0][1] - dx < (this.panX() - panelwidth / 2)) x = ranges[0][0] - panelwidth / 2;
+ // if (ranges[1][0] - dy > (this.panY() + panelheight / 2)) y = ranges[1][1] + panelheight / 2;
+ // if (ranges[1][1] - dy < (this.panY() - panelheight / 2)) y = ranges[1][0] - panelheight / 2;
}
this.setPan(x - dx, y - dy);
this._lastX = e.pageX;
@@ -359,7 +372,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
getChildDocumentViewProps(childDocLayout: Doc): DocumentViewProps {
let self = this;
let resolvedDataDoc = !this.props.Document.isTemplate && this.props.DataDoc !== this.props.Document ? this.props.DataDoc : undefined;
- let layoutDoc = Doc.expandTemplateLayout(childDocLayout, resolvedDataDoc);
+ let layoutDoc = childDocLayout;
+ if (resolvedDataDoc && Doc.WillExpandTemplateLayout(childDocLayout, resolvedDataDoc)) {
+ Doc.UpdateDocumentExtensionForField(resolvedDataDoc, this.props.fieldKey);
+ let fieldExtensionDoc = Doc.resolvedFieldDataDoc(resolvedDataDoc, StrCast(childDocLayout.templateField, StrCast(childDocLayout.title)), "dummy");
+ layoutDoc = Doc.expandTemplateLayout(childDocLayout, fieldExtensionDoc !== resolvedDataDoc ? fieldExtensionDoc : undefined);
+ } else layoutDoc = Doc.expandTemplateLayout(childDocLayout, resolvedDataDoc);
return {
DataDoc: resolvedDataDoc !== layoutDoc && resolvedDataDoc ? resolvedDataDoc : undefined,
Document: layoutDoc,
@@ -414,6 +432,25 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
return result.result === undefined ? {} : result.result;
}
+ private viewDefToJSX(viewDef: any): JSX.Element | undefined {
+ if (viewDef.type === "text") {
+ const text = Cast(viewDef.text, "string");
+ const x = Cast(viewDef.x, "number");
+ const y = Cast(viewDef.y, "number");
+ const width = Cast(viewDef.width, "number");
+ const height = Cast(viewDef.height, "number");
+ const fontSize = Cast(viewDef.fontSize, "number");
+ if ([text, x, y].some(val => val === undefined)) {
+ return undefined;
+ }
+
+ return <div className="collectionFreeform-customText" style={{
+ transform: `translate(${x}px, ${y}px)`,
+ width, height, fontSize
+ }}>{text}</div>;
+ }
+ }
+
@computed.struct
get views() {
let curPage = FieldValue(this.Document.curPage, -1);
@@ -421,10 +458,20 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
const script = this.Document.arrangeScript;
let state: any = undefined;
const docs = this.childDocs;
+ let elements: JSX.Element[] = [];
if (initScript) {
const initResult = initScript.script.run({ docs, collection: this.Document });
if (initResult.success) {
- state = initResult.result;
+ const result = initResult.result;
+ const { state: scriptState, views } = result;
+ state = scriptState;
+ if (Array.isArray(views)) {
+ elements = views.reduce<JSX.Element[]>((prev, ele) => {
+ const jsx = this.viewDefToJSX(ele);
+ jsx && prev.push(jsx);
+ return prev;
+ }, elements);
+ }
}
}
let docviews = docs.reduce((prev, doc) => {
@@ -439,7 +486,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
}
return prev;
- }, [] as JSX.Element[]);
+ }, elements);
setTimeout(() => this._selectOnLoaded = "", 600);// bcz: surely there must be a better way ....
@@ -453,7 +500,13 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
onContextMenu = () => {
ContextMenu.Instance.addItem({
+ description: `${this.fitToBox ? "Unset" : "Set"} Fit To Container`,
+ event: undoBatch(async () => this.props.Document.fitToBox = !this.fitToBox),
+ icon: !this.fitToBox ? "expand-arrows-alt" : "compress-arrows-alt"
+ });
+ ContextMenu.Instance.addItem({
description: "Arrange contents in grid",
+ icon: "table",
event: async () => {
const docs = await DocListCastAsync(this.Document[this.props.fieldKey]);
UndoManager.RunInBatch(() => {
@@ -479,42 +532,51 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
}
});
ContextMenu.Instance.addItem({
- description: "Add freeform arrangement",
- event: () => {
- let addOverlay = (key: "arrangeScript" | "arrangeInit", options: OverlayElementOptions, params?: Record<string, string>, requiredType?: string) => {
- let overlayDisposer: () => void = emptyFunction;
- const script = this.Document[key];
- let originalText: string | undefined = undefined;
- if (script) originalText = script.script.originalScript;
- // tslint:disable-next-line: no-unnecessary-callback-wrapper
- let scriptingBox = <ScriptBox initialText={originalText} onCancel={() => overlayDisposer()} onSave={(text, onError) => {
- const script = CompileScript(text, {
- params,
- requiredType,
- typecheck: false
- });
- if (!script.compiled) {
- onError(script.errors.map(error => error.messageText).join("\n"));
- return;
- }
- const docs = DocListCast(this.Document[this.props.fieldKey]);
- docs.map(d => d.transition = "transform 1s");
- this.Document[key] = new ScriptField(script);
- overlayDisposer();
- setTimeout(() => docs.map(d => d.transition = undefined), 1200);
- }} />;
- overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, options);
- };
- addOverlay("arrangeInit", { x: 400, y: 100, width: 400, height: 300, title: "Layout Initialization" }, { collection: "Doc", docs: "Doc[]" }, undefined);
- addOverlay("arrangeScript", { x: 400, y: 500, width: 400, height: 300, title: "Layout Script" }, { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}");
- }
+ description: "Analyze Strokes", event: async () => {
+ let data = Cast(this.fieldExtensionDoc[this.inkKey], InkField);
+ if (!data) {
+ return;
+ }
+ let relevantKeys = ["inkAnalysis", "handwriting"];
+ CognitiveServices.Inking.Manager.analyzer(this.fieldExtensionDoc, relevantKeys, data.inkData);
+ }, icon: "paint-brush"
});
}
+
private childViews = () => [
<CollectionFreeFormBackgroundView key="backgroundView" {...this.props} {...this.getDocumentViewProps(this.props.Document)} />,
...this.views
]
+
+ public static AddCustomLayout(doc: Doc, dataKey: string): () => void {
+ return () => {
+ let addOverlay = (key: "arrangeScript" | "arrangeInit", options: OverlayElementOptions, params?: Record<string, string>, requiredType?: string) => {
+ let overlayDisposer: () => void = emptyFunction;
+ const script = Cast(doc[key], ScriptField);
+ let originalText: string | undefined = undefined;
+ if (script) originalText = script.script.originalScript;
+ // tslint:disable-next-line: no-unnecessary-callback-wrapper
+ let scriptingBox = <ScriptBox initialText={originalText} onCancel={() => overlayDisposer()} onSave={(text, onError) => {
+ const script = CompileScript(text, {
+ params,
+ requiredType,
+ typecheck: false
+ });
+ if (!script.compiled) {
+ onError(script.errors.map(error => error.messageText).join("\n"));
+ return;
+ }
+ doc[key] = new ScriptField(script);
+ overlayDisposer();
+ }} />;
+ overlayDisposer = OverlayView.Instance.addWindow(scriptingBox, options);
+ };
+ addOverlay("arrangeInit", { x: 400, y: 100, width: 400, height: 300, title: "Layout Initialization" }, { collection: "Doc", docs: "Doc[]" }, undefined);
+ addOverlay("arrangeScript", { x: 400, y: 500, width: 400, height: 300, title: "Layout Script" }, { doc: "Doc", index: "number", collection: "Doc", state: "any", docs: "Doc[]" }, "{x: number, y: number, width?: number, height?: number}");
+ };
+ }
+
render() {
const easing = () => this.props.Document.panTransformType === "Ease";
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index b765517a2..d96e93aeb 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -365,7 +365,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps>
marqueeSelect() {
let selRect = this.Bounds;
let selection: Doc[] = [];
- this.props.activeDocuments().map(doc => {
+ this.props.activeDocuments().filter(doc => !doc.isBackground).map(doc => {
var z = NumCast(doc.zoomBasis, 1);
var x = NumCast(doc.x);
var y = NumCast(doc.y);