aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/util/Transform.ts94
-rw-r--r--src/client/views/Main.tsx5
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx11
-rw-r--r--src/client/views/collections/CollectionFreeFormView.tsx24
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx6
-rw-r--r--src/client/views/collections/CollectionViewBase.tsx11
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx7
-rw-r--r--src/client/views/nodes/DocumentView.tsx8
8 files changed, 156 insertions, 10 deletions
diff --git a/src/client/util/Transform.ts b/src/client/util/Transform.ts
new file mode 100644
index 000000000..7861ed308
--- /dev/null
+++ b/src/client/util/Transform.ts
@@ -0,0 +1,94 @@
+export class Transform {
+ private _translateX: number = 0;
+ private _translateY: number = 0;
+ private _scale: number = 1;
+
+ static get Identity(): Transform {
+ return new Transform(0, 0, 1);
+ }
+
+ constructor(x: number, y: number, scale: number) {
+ this._translateX = x;
+ this._translateY = y;
+ this._scale = scale;
+ }
+
+ translate = (x: number, y: number): Transform => {
+ this._translateX += x;
+ this._translateY += y;
+ return this;
+ }
+
+ translated = (x: number, y: number): Transform => {
+ return this.copy().translate(x, y);
+ }
+
+ preTranslate = (x: number, y: number): Transform => {
+ this._translateX += x * this._scale;
+ this._translateY += y * this._scale;
+ return this;
+ }
+
+ preTranslated = (x: number, y: number): Transform => {
+ return this.copy().preTranslate(x, y);
+ }
+
+ scale = (scale: number): Transform => {
+ this._scale *= scale;
+ return this;
+ }
+
+ scaled = (scale: number): Transform => {
+ return this.copy().scale(scale);
+ }
+
+ preScale = (scale: number): Transform => {
+ this._scale *= scale;
+ this._translateX *= scale;
+ this._translateY *= scale;
+ return this;
+ }
+
+ preScaled = (scale: number): Transform => {
+ return this.copy().preScale(scale);
+ }
+
+ transform = (transform: Transform): Transform => {
+ this._translateX += transform._translateX * this._scale;
+ this._translateY += transform._translateY * this._scale;
+ this._scale *= transform._scale;
+ return this;
+ }
+
+ transformed = (transform: Transform): Transform => {
+ return this.copy().transform(transform);
+ }
+
+ preTransform = (transform: Transform): Transform => {
+ this._translateX = transform._translateX + this._translateX * transform._scale;
+ this._translateY = transform._translateY + this._translateY * transform._scale;
+ this._scale *= transform._scale;
+ return this;
+ }
+
+ preTransformed = (transform: Transform): Transform => {
+ return this.copy().preTransform(transform);
+ }
+
+ transformPoint = (x: number, y: number): [number, number] => {
+ x *= this._scale;
+ x += this._translateX;
+ y *= this._scale;
+ y += this._translateY;
+ return [x, y];
+ }
+
+ inverse = () => {
+ return new Transform(-this._translateX / this._scale, -this._translateY / this._scale, 1 / this._scale)
+ }
+
+ copy = () => {
+ return new Transform(this._translateX, this._translateY, this._scale);
+ }
+
+} \ No newline at end of file
diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx
index 9a359e868..ac6f1de00 100644
--- a/src/client/views/Main.tsx
+++ b/src/client/views/Main.tsx
@@ -13,6 +13,7 @@ import "./Main.scss";
import { ContextMenu } from './ContextMenu';
import { DocumentView } from './nodes/DocumentView';
import { ImageField } from '../../fields/ImageField';
+import { Transform } from '../util/Transform';
configure({
@@ -84,7 +85,9 @@ document.addEventListener("pointerdown", action(function (e: PointerEvent) {
ReactDOM.render((
<div style={{ position: "absolute", width: "100%", height: "100%" }}>
- <DocumentView Document={mainContainer} ContainingCollectionView={undefined} DocumentView={undefined} />
+ <DocumentView Document={mainContainer}
+ AddDocument={undefined} RemoveDocument={undefined} GetTransform={() => Transform.Identity}
+ ContainingCollectionView={undefined} DocumentView={undefined} />
<DocumentDecorations />
<ContextMenu />
</div>),
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 9aee9c10f..32d00d41a 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -14,6 +14,7 @@ import * as GoldenLayout from "golden-layout";
import * as ReactDOM from 'react-dom';
import { DragManager } from "../../util/DragManager";
import { CollectionViewBase, CollectionViewProps, COLLECTION_BORDER_WIDTH } from "./CollectionViewBase";
+import { Transform } from "../../util/Transform";
@observer
export class CollectionDockingView extends CollectionViewBase {
@@ -95,7 +96,10 @@ export class CollectionDockingView extends CollectionViewBase {
const value: Document[] = Document.GetData(fieldKey, ListField, []);
for (var i: number = 0; i < value.length; i++) {
if (value[i].Id === component) {
- return (<DocumentView key={value[i].Id} ContainingCollectionView={this} Document={value[i]} DocumentView={undefined} />);
+ return (<DocumentView key={value[i].Id} Document={value[i]}
+ AddDocument={this.addDocument} RemoveDocument={this.removeDocument}
+ GetTransform={() => Transform.Identity}
+ ContainingCollectionView={this} DocumentView={undefined} />);
}
}
if (component === "text") {
@@ -236,7 +240,10 @@ export class CollectionDockingView extends CollectionViewBase {
container.getElement().html("<div id='" + containingDiv + "'></div>");
setTimeout(function () {
ReactDOM.render((
- <DocumentView key={state.doc.Id} Document={state.doc} ContainingCollectionView={me} DocumentView={undefined} />
+ <DocumentView key={state.doc.Id} Document={state.doc}
+ AddDocument={me.addDocument} RemoveDocument={me.removeDocument}
+ GetTransform={() => Transform.Identity}
+ ContainingCollectionView={me} DocumentView={undefined} />
),
document.getElementById(containingDiv)
);
diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx
index 9cf29d000..50f4f1892 100644
--- a/src/client/views/collections/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/CollectionFreeFormView.tsx
@@ -13,6 +13,7 @@ import { ListField } from "../../../fields/ListField";
import { NumberField } from "../../../fields/NumberField";
import { Documents } from "../../documents/Documents";
import { FieldWaiting } from "../../../fields/Field";
+import { Transform } from "../../util/Transform";
@observer
export class CollectionFreeFormView extends CollectionViewBase {
@@ -172,6 +173,23 @@ export class CollectionFreeFormView extends CollectionViewBase {
}
}
+ @computed
+ get translate(): [number, number] {
+ const x = this.props.DocumentForCollection.GetNumber(KeyStore.PanX, 0);
+ const y = this.props.DocumentForCollection.GetNumber(KeyStore.PanY, 0);
+ return [x, y];
+ }
+
+ @computed
+ get scale(): number {
+ return this.props.DocumentForCollection.GetNumber(KeyStore.Scale, 1);
+ }
+
+ getTransform = (): Transform => {
+ const [x, y] = this.translate;
+ return this.props.GetTransform().scaled(this.scale).translate(x, y);
+ }
+
render() {
const { CollectionFieldKey: fieldKey, DocumentForCollection: Document } = this.props;
const value: Document[] = Document.GetList<Document>(fieldKey, []);
@@ -194,7 +212,11 @@ export class CollectionFreeFormView extends CollectionViewBase {
<div className="node-container" ref={this._nodeContainerRef}>
{value.map(doc => {
- return (<CollectionFreeFormDocumentView key={doc.Id} ContainingCollectionView={this} Document={doc} DocumentView={undefined} />);
+ return (<CollectionFreeFormDocumentView key={doc.Id} Document={doc}
+ AddDocument={this.addDocument}
+ RemoveDocument={this.removeDocument}
+ GetTransform={this.getTransform}
+ ContainingCollectionView={this} DocumentView={undefined} />);
})}
</div>
</div>
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index 2d5bd6c99..b897fd481 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -14,6 +14,7 @@ import { CompileScript, ToField } from "../../util/Scripting";
import { KeyStore as KS, Key } from "../../../fields/Key";
import { Document } from "../../../fields/Document";
import { Field } from "../../../fields/Field";
+import { Transform } from "../../util/Transform";
@observer
export class CollectionSchemaView extends CollectionViewBase {
@@ -104,7 +105,10 @@ export class CollectionSchemaView extends CollectionViewBase {
let content;
if (this.selectedIndex != -1) {
content = (
- <DocumentView Document={children[this.selectedIndex]} DocumentView={undefined} ContainingCollectionView={this} />
+ <DocumentView Document={children[this.selectedIndex]}
+ AddDocument={this.addDocument} RemoveDocument={this.removeDocument}
+ GetTransform={() => Transform.Identity}//TODO This should probably be an actual transform
+ DocumentView={undefined} ContainingCollectionView={this} />
)
} else {
content = <div />
diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx
index 09e8ec729..ff54d88d7 100644
--- a/src/client/views/collections/CollectionViewBase.tsx
+++ b/src/client/views/collections/CollectionViewBase.tsx
@@ -10,12 +10,14 @@ import React = require("react");
import { DocumentView } from "../nodes/DocumentView";
import { CollectionDockingView } from "./CollectionDockingView";
import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView";
+import { Transform } from "../../util/Transform";
export interface CollectionViewProps {
CollectionFieldKey: Key;
DocumentForCollection: Document;
ContainingDocumentView: Opt<DocumentView>;
+ GetTransform: () => Transform;
}
export const COLLECTION_BORDER_WIDTH = 2;
@@ -43,15 +45,18 @@ export class CollectionViewBase extends React.Component<CollectionViewProps> {
}
@action
- removeDocument = (doc: Document): void => {
+ removeDocument = (doc: Document): boolean => {
//TODO This won't create the field if it doesn't already exist
const value = this.props.DocumentForCollection.GetData(this.props.CollectionFieldKey, ListField, new Array<Document>())
- if (value.indexOf(doc) !== -1) {
- value.splice(value.indexOf(doc), 1)
+ let index = value.indexOf(doc);
+ if (index !== -1) {
+ value.splice(index, 1)
SelectionManager.DeselectAll()
ContextMenu.Instance.clearItems()
+ return true;
}
+ return false
}
} \ No newline at end of file
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index a111a9936..0defc8f1d 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -10,6 +10,7 @@ import { ContextMenu } from "../ContextMenu";
import "./NodeView.scss";
import React = require("react");
import { DocumentView, DocumentViewProps } from "./DocumentView";
+import { Transform } from "../../util/Transform";
@observer
@@ -204,6 +205,10 @@ export class CollectionFreeFormDocumentView extends DocumentView {
}
}
+ getTransform = (): Transform => {
+ return this.props.GetTransform().translated(this.x, this.y);
+ }
+
render() {
var freestyling = this.props.ContainingCollectionView instanceof CollectionFreeFormView;
return (
@@ -217,7 +222,7 @@ export class CollectionFreeFormDocumentView extends DocumentView {
onContextMenu={this.onContextMenu}
onPointerDown={this.onPointerDown}>
- <DocumentView {...this.props} DocumentView={this.props.DocumentView} />
+ <DocumentView {...this.props} GetTransform={this.getTransform} DocumentView={this.props.DocumentView} />
</div>
);
}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 730ce62f2..ce23a70a6 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -15,13 +15,19 @@ import { FormattedTextBox } from "../nodes/FormattedTextBox";
import { ImageBox } from "../nodes/ImageBox";
import "./NodeView.scss";
import React = require("react");
+import { Transform } from "../../util/Transform";
const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this?
export interface DocumentViewProps {
- Document: Document;
DocumentView: Opt<DocumentView> // needed only to set ContainingDocumentView on CollectionViewProps when invoked from JsxParser -- is there a better way?
ContainingCollectionView: Opt<CollectionViewBase>;
+
+ Document: Document;
+ AddDocument?: (doc: Document) => void;
+ RemoveDocument?: (doc: Document) => boolean;
+ GetTransform: () => Transform;
}
+
@observer
export class DocumentView extends React.Component<DocumentViewProps> {