From c67608a7eeeb6bdee27a8e7b4a8f6f8561db6004 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Mon, 21 Jan 2019 22:25:52 -0500 Subject: Small fixes and start of drag drop --- src/DocumentDecorations.scss | 51 +++++----- src/DocumentDecorations.tsx | 40 ++------ src/Main.scss | 5 + src/Main.tsx | 23 +---- src/documents/Documents.ts | 1 + src/util/DragManager.ts | 109 +++++++++++++++++++++ .../freeformcanvas/CollectionFreeFormView.tsx | 4 +- src/views/nodes/DocumentView.tsx | 49 ++++++--- src/views/nodes/FieldTextBox.scss | 3 + src/views/nodes/FieldTextBox.tsx | 3 +- 10 files changed, 194 insertions(+), 94 deletions(-) create mode 100644 src/util/DragManager.ts create mode 100644 src/views/nodes/FieldTextBox.scss (limited to 'src') diff --git a/src/DocumentDecorations.scss b/src/DocumentDecorations.scss index fff4d201a..2840d782b 100644 --- a/src/DocumentDecorations.scss +++ b/src/DocumentDecorations.scss @@ -1,34 +1,31 @@ #documentDecorations-container { position: absolute; - z-index: 1000; display: grid; grid-template-rows: 20px 1fr 20px; grid-template-columns: 20px 1fr 20px; pointer-events: none; -} - -#documentDecorations-centerCont { - background: none; -} - -.documentDecorations-resizer { - pointer-events: auto; - background: lightblue; - opacity: 0.8; -} - -#documentDecorations-topLeftResizer, #documentDecorations-bottomRightResizer { - cursor: nwse-resize; -} - -#documentDecorations-topRightResizer, #documentDecorations-bottomLeftResizer { - cursor: nesw-resize; -} - -#documentDecorations-topResizer, #documentDecorations-bottomResizer { - cursor: ns-resize; -} - -#documentDecorations-leftResizer, #documentDecorations-rightResizer { - cursor: ew-resize; + #documentDecorations-centerCont { + background: none; + } + .documentDecorations-resizer { + pointer-events: auto; + background: lightblue; + opacity: 0.8; + } + #documentDecorations-topLeftResizer, + #documentDecorations-bottomRightResizer { + cursor: nwse-resize; + } + #documentDecorations-topRightResizer, + #documentDecorations-bottomLeftResizer { + cursor: nesw-resize; + } + #documentDecorations-topResizer, + #documentDecorations-bottomResizer { + cursor: ns-resize; + } + #documentDecorations-leftResizer, + #documentDecorations-rightResizer { + cursor: ew-resize; + } } \ No newline at end of file diff --git a/src/DocumentDecorations.tsx b/src/DocumentDecorations.tsx index d7466dcac..cf7c6d8b5 100644 --- a/src/DocumentDecorations.tsx +++ b/src/DocumentDecorations.tsx @@ -15,44 +15,21 @@ export class DocumentDecorations extends React.Component { } get x(): number { - let left = Number.MAX_VALUE; - SelectionManager.SelectedDocuments().forEach(element => { - if (element.mainCont.current !== null) { - left = Math.min(element.mainCont.current.getBoundingClientRect().left, left) - } - }); - return left; + return SelectionManager.SelectedDocuments().reduce((left, element) => Math.min(element.screenRect.left, left), Number.MAX_VALUE); } get y(): number { - let top = Number.MAX_VALUE; - SelectionManager.SelectedDocuments().forEach(element => { - if (element.mainCont.current !== null) { - top = Math.min(element.mainCont.current.getBoundingClientRect().top, top) - } - }); - return top; + return SelectionManager.SelectedDocuments().reduce((top, element) => Math.min(element.screenRect.top, top), Number.MAX_VALUE); } get height(): number { - return (SelectionManager.SelectedDocuments().reduce((bottom, element) => { - if (element.mainCont.current !== null) { - return Math.max(element.mainCont.current.getBoundingClientRect().bottom, bottom) - } - else { - return bottom - } - }, Number.MIN_VALUE)) - this.y; + return (SelectionManager.SelectedDocuments().reduce((bottom, element) => Math.max(element.screenRect.bottom, bottom), + Number.MIN_VALUE)) - this.y; } get width(): number { - let right = Number.MIN_VALUE; - SelectionManager.SelectedDocuments().forEach(element => { - if (element.mainCont.current !== null) { - right = Math.max(element.mainCont.current.getBoundingClientRect().right, right) - } - }); - return right - this.x; + return SelectionManager.SelectedDocuments().reduce((right, element) => Math.max(element.screenRect.right, right), + Number.MIN_VALUE) - this.x; } private _resizer = "" @@ -129,8 +106,9 @@ export class DocumentDecorations extends React.Component { } SelectionManager.SelectedDocuments().forEach(element => { - if (element.mainCont.current !== null) { - let scale = element.width / element.mainCont.current.getBoundingClientRect().width; + const rect = element.screenRect; + if (rect.width !== 0) { + let scale = element.width / rect.width; let actualdW = Math.max(element.width + (dW * scale), 20); let actualdH = Math.max(element.height + (dH * scale), 20); element.x += dX * (actualdW - element.width); diff --git a/src/Main.scss b/src/Main.scss index f986d2c96..5fa5b2728 100644 --- a/src/Main.scss +++ b/src/Main.scss @@ -22,4 +22,9 @@ h1 { -moz-user-select: none; -ms-user-select: none; user-select: none; +} + +p { + margin: 0px; + padding: 0px; } \ No newline at end of file diff --git a/src/Main.tsx b/src/Main.tsx index 9ce1dd4e9..7c132f179 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -21,40 +21,27 @@ configure({ const mainNodeCollection = new NodeCollectionStore(); ReactDOM.render((
-

Dash Web

- + +
), document.getElementById('root')); +function minus() { - -// create a bunch of text and video nodes (you probably want to delete this at some point) -let numNodes = 300; -let maxX = 10000; -let maxY = 10000; -let nodes:NodeStore[] = [] -for (let i = 0; i < numNodes; i++) { - nodes.push(new StaticTextNodeStore({ X: Math.random() * maxX, Y: Math.random() * maxY, Title: "Text Node Title", Text: "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?" })); } - -for (let i = 0; i < 20; i++) { - nodes.push(new VideoNodeStore({ X: Math.random() * maxX, Y: Math.random() * maxY, Title: "Video Node Title", Url: "http://cs.brown.edu/people/peichman/downloads/cted.mp4" })); -} - runInAction(() => { - mainNodeCollection.AddNodes(nodes); let doc1 = Documents.TextDocument("Hello world"); let doc2 = doc1.MakeDelegate(); doc2.SetField(KS.X, new NumberField(150)); doc2.SetField(KS.Y, new NumberField(20)); - let doc3 = Documents.ImageDocument("https://static.boredpanda.com/blog/wp-content/uploads/2018/04/5acb63d83493f__700-png.jpg", { + let doc3 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { x: 450, y: 500 }); let docset = new Array(doc1, doc2); let doc4 = Documents.CollectionDocument(docset, { x: 100, y: 400 }); - let doc5 = Documents.ImageDocument("https://static.boredpanda.com/blog/wp-content/uploads/2018/04/5acb63d83493f__700-png.jpg", { + let doc5 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { x: 650, y: 500 }); mainNodeCollection.Docs.push(doc1); diff --git a/src/documents/Documents.ts b/src/documents/Documents.ts index cc08f4123..084666b95 100644 --- a/src/documents/Documents.ts +++ b/src/documents/Documents.ts @@ -57,6 +57,7 @@ export namespace Documents { imageProto.SetField(KeyStore.Width, new NumberField(300)); imageProto.SetField(KeyStore.Height, new NumberField(300)); imageProto.SetField(KeyStore.Layout, new TextField('Image not found')); + // imageProto.SetField(KeyStore.Layout, new TextField('
')); imageProto.SetField(KeyStore.LayoutFields, new ListField([KeyStore.Data])); } return imageProto; diff --git a/src/util/DragManager.ts b/src/util/DragManager.ts new file mode 100644 index 000000000..1da590072 --- /dev/null +++ b/src/util/DragManager.ts @@ -0,0 +1,109 @@ +import { Opt } from "../fields/Field"; + +export namespace DragManager { + export let rootId = "root"; + let dragDiv: HTMLDivElement; + + export enum DragButtons { + Left = 1, Right = 2, Both = Left | Right + } + + interface DragOptions { + handlers: DragHandlers; + + buttons: number; + } + + export interface DragDisposer { + (): void; + } + + export class DragStartEvent { + private _cancelled: boolean = false; + get cancelled() { return this._cancelled }; + + cancel() { this._cancelled = true; }; + } + + export class DragCompleteEvent { + + } + + export interface DragHandlers { + dragStart: (e: DragStartEvent) => void; + dragComplete: (e: DragCompleteEvent) => void; + } + + export function MakeDraggable(element: HTMLElement, options: DragOptions): DragDisposer { + if ("draggable" in element.dataset) { + throw new Error("Element is already draggable, can't make it draggable again"); + } + element.dataset["draggable"] = "true"; + const dispose = () => { + document.removeEventListener("pointerup", upHandler); + document.removeEventListener("pointermove", startDragHandler); + } + const startDragHandler = (e: PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); + dispose(); + StartDrag(element, e, options); + } + const upHandler = (e: PointerEvent) => { + dispose(); + }; + const downHandler = (e: PointerEvent) => { + document.addEventListener("pointermove", startDragHandler); + document.addEventListener("pointerup", upHandler); + }; + element.addEventListener("pointerdown", downHandler); + + return () => { + element.removeEventListener("pointerdown", downHandler); + element.dataset["draggable"] = undefined; + } + } + + function StartDrag(ele: HTMLElement, e: PointerEvent, options: DragOptions) { + if (!dragDiv) { + const root = document.getElementById(rootId); + if (!root) { + throw new Error("No root element found"); + } + dragDiv = document.createElement("div"); + root.appendChild(dragDiv); + } + if ((e.buttons & options.buttons) === 0) { + return; + } + let event = new DragStartEvent(); + options.handlers.dragStart(event); + if (event.cancelled) { + return; + } + let x = e.x, y = e.y; + let dragElement = ele.cloneNode(true) as HTMLElement; + dragElement.style.position = "absolute"; + dragElement.style.transform = `translate(${x}px, ${y}px)`; + dragDiv.appendChild(dragElement); + + const moveHandler = (e: PointerEvent) => { + e.stopPropagation(); + e.preventDefault(); + x += e.movementX; + y += e.movementY; + dragElement.style.transform = `translate(${x}px, ${y}px)`; + }; + const upHandler = (e: PointerEvent) => { + document.removeEventListener("pointermove", moveHandler, true); + document.removeEventListener("pointerup", upHandler); + FinishDrag(dragElement, options); + }; + document.addEventListener("pointermove", moveHandler, true); + document.addEventListener("pointerup", upHandler); + } + + function FinishDrag(ele: HTMLElement, options: DragOptions) { + dragDiv.removeChild(ele); + } +} \ No newline at end of file diff --git a/src/views/freeformcanvas/CollectionFreeFormView.tsx b/src/views/freeformcanvas/CollectionFreeFormView.tsx index 4e9e0cd21..d9a88fcd3 100644 --- a/src/views/freeformcanvas/CollectionFreeFormView.tsx +++ b/src/views/freeformcanvas/CollectionFreeFormView.tsx @@ -14,7 +14,7 @@ import { DocumentDecorations } from "../../DocumentDecorations"; interface IProps { fieldKey: Key; doc: Document; - isSelected: boolean; + isSelected: () => boolean; } @observer @@ -28,7 +28,7 @@ export class CollectionFreeFormView extends React.Component { @action onPointerDown = (e: React.PointerEvent): void => { - if (!this.props.isSelected) { + if (!this.props.isSelected()) { return; } diff --git a/src/views/nodes/DocumentView.tsx b/src/views/nodes/DocumentView.tsx index e37172943..cdc20cdfe 100644 --- a/src/views/nodes/DocumentView.tsx +++ b/src/views/nodes/DocumentView.tsx @@ -12,6 +12,8 @@ import { CollectionFreeFormView } from "../freeformcanvas/CollectionFreeFormView import "./NodeView.scss" import { SelectionManager } from "../../util/SelectionManager"; import { DocumentDecorations } from "../../DocumentDecorations"; +import { SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS } from "constants"; +import { DragManager } from "../../util/DragManager"; const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this? interface IProps { @@ -22,8 +24,11 @@ interface IProps { export class DocumentView extends React.Component { private _mainCont = React.createRef(); - get mainCont(): React.RefObject { - return this._mainCont + get screenRect(): ClientRect | DOMRect { + if(this._mainCont.current) { + return this._mainCont.current.getBoundingClientRect(); + } + return new DOMRect(); } @computed @@ -83,13 +88,26 @@ export class DocumentView extends React.Component { } @computed - get selected() : boolean { + get selected(): boolean { return SelectionManager.IsSelected(this) } private _isPointerDown = false; + componentDidMount() { + if(this._mainCont.current) { + DragManager.MakeDraggable(this._mainCont.current, { + buttons: 3, + handlers: { + dragComplete: () => {}, + dragStart: () => {} + } + }) + } + } + onPointerDown = (e: React.PointerEvent): void => { + return; e.stopPropagation(); if (e.button === 2) { this._isPointerDown = true; @@ -97,8 +115,9 @@ export class DocumentView extends React.Component { document.addEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointerup", this.onPointerUp); + } else { + SelectionManager.SelectDoc(this, e.ctrlKey) } - SelectionManager.SelectDoc(this, e.ctrlKey) } onPointerUp = (e: PointerEvent): void => { @@ -108,8 +127,6 @@ export class DocumentView extends React.Component { this._isPointerDown = false; document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); - console.log(this.x); - console.log(this.y) DocumentDecorations.Instance.opacity = 1 } } @@ -126,8 +143,8 @@ export class DocumentView extends React.Component { } onDragStart = (e: React.DragEvent): void => { - if (this.mainCont.current !== null) { - this.mainCont.current.style.opacity = "0"; + if (this._mainCont.current !== null) { + this._mainCont.current.style.opacity = "0"; // e.dataTransfer.setDragImage() } } @@ -136,7 +153,7 @@ export class DocumentView extends React.Component { let doc = this.props.dvm.Doc; let bindings: any = { doc: doc, - isSelected: this.selected + isSelected: () => this.selected }; for (const key of this.layoutKeys) { bindings[key.Name + "Key"] = key; @@ -147,22 +164,24 @@ export class DocumentView extends React.Component { bindings[key.Name] = field.GetValue(); } } - + return (
{ e.preventDefault() - }} + }} onPointerDown={this.onPointerDown}> { console.log(test) }} />
); diff --git a/src/views/nodes/FieldTextBox.scss b/src/views/nodes/FieldTextBox.scss new file mode 100644 index 000000000..2885caa4c --- /dev/null +++ b/src/views/nodes/FieldTextBox.scss @@ -0,0 +1,3 @@ +.ProseMirror:focus { + outline: none !important +} \ No newline at end of file diff --git a/src/views/nodes/FieldTextBox.tsx b/src/views/nodes/FieldTextBox.tsx index dbac3906a..2cd55e26e 100644 --- a/src/views/nodes/FieldTextBox.tsx +++ b/src/views/nodes/FieldTextBox.tsx @@ -13,6 +13,8 @@ import {baseKeymap} from "prosemirror-commands" import {undo, redo, history} from "prosemirror-history" import { Opt } from "../../fields/Field"; +import "./FieldTextBox.scss" + interface IProps { fieldKey:Key; doc:Document; @@ -34,7 +36,6 @@ interface IProps { // specified Key and assigns it to an HTML input node. When changes are made tot his node, // this will edit the document and assign the new value to that field. // -@observer export class FieldTextBox extends React.Component { private _ref: React.RefObject; private _editorView: Opt; -- cgit v1.2.3-70-g09d2 From 8a1915a73d1d1173059a212db3b79f8efcdd9e9e Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Tue, 22 Jan 2019 20:31:32 -0500 Subject: Temporarily got rid of dvm to draastically improve performance and reduce number of re-renders --- src/Main.tsx | 4 - src/documents/Documents.ts | 2 +- .../freeformcanvas/CollectionFreeFormView.tsx | 3 +- src/views/freeformcanvas/FreeFormCanvas.tsx | 2 +- src/views/nodes/DocumentView.tsx | 130 ++++++++++++--------- test/test.ts | 4 + 6 files changed, 79 insertions(+), 66 deletions(-) (limited to 'src') diff --git a/src/Main.tsx b/src/Main.tsx index 7c132f179..5482314ae 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -23,12 +23,8 @@ ReactDOM.render((
-
), document.getElementById('root')); -function minus() { - -} runInAction(() => { let doc1 = Documents.TextDocument("Hello world"); let doc2 = doc1.MakeDelegate(); diff --git a/src/documents/Documents.ts b/src/documents/Documents.ts index 084666b95..a2d2218af 100644 --- a/src/documents/Documents.ts +++ b/src/documents/Documents.ts @@ -56,7 +56,7 @@ export namespace Documents { imageProto.SetField(KeyStore.Y, new NumberField(0)); imageProto.SetField(KeyStore.Width, new NumberField(300)); imageProto.SetField(KeyStore.Height, new NumberField(300)); - imageProto.SetField(KeyStore.Layout, new TextField('Image not found')); + imageProto.SetField(KeyStore.Layout, new TextField('Image not found')); // imageProto.SetField(KeyStore.Layout, new TextField('
')); imageProto.SetField(KeyStore.LayoutFields, new ListField([KeyStore.Data])); } diff --git a/src/views/freeformcanvas/CollectionFreeFormView.tsx b/src/views/freeformcanvas/CollectionFreeFormView.tsx index d9a88fcd3..e1aeff534 100644 --- a/src/views/freeformcanvas/CollectionFreeFormView.tsx +++ b/src/views/freeformcanvas/CollectionFreeFormView.tsx @@ -54,7 +54,6 @@ export class CollectionFreeFormView extends React.Component { @action onPointerMove = (e: PointerEvent): void => { - e.preventDefault(); e.stopPropagation(); if (!this._isPointerDown) { return; @@ -97,7 +96,7 @@ export class CollectionFreeFormView extends React.Component {
{value.map(doc => { - return (); + return (); })}
diff --git a/src/views/freeformcanvas/FreeFormCanvas.tsx b/src/views/freeformcanvas/FreeFormCanvas.tsx index de5e88fa1..e051fd97c 100644 --- a/src/views/freeformcanvas/FreeFormCanvas.tsx +++ b/src/views/freeformcanvas/FreeFormCanvas.tsx @@ -80,7 +80,7 @@ export class FreeFormCanvas extends React.Component {
{this.props.store.Docs.map(doc => { - return (); + return (); })}
diff --git a/src/views/nodes/DocumentView.tsx b/src/views/nodes/DocumentView.tsx index cdc20cdfe..648ea7f50 100644 --- a/src/views/nodes/DocumentView.tsx +++ b/src/views/nodes/DocumentView.tsx @@ -14,10 +14,56 @@ import { SelectionManager } from "../../util/SelectionManager"; import { DocumentDecorations } from "../../DocumentDecorations"; import { SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS } from "constants"; import { DragManager } from "../../util/DragManager"; +import { Document } from "../../fields/Document"; const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this? interface IProps { - dvm: DocumentViewModel; + dvm: Document; +} + +@observer +class DocumentContents extends React.Component boolean}> { + + @computed + get layout(): string { + return this.props.dvm.GetFieldValue(KeyStore.Layout, TextField, String("

Error loading layout data

")); + } + + @computed + get layoutKeys(): Key[] { + return this.props.dvm.GetFieldValue(KeyStore.LayoutKeys, ListField, new Array()); + } + + @computed + get layoutFields(): Key[] { + return this.props.dvm.GetFieldValue(KeyStore.LayoutFields, ListField, new Array()); + } + render() { + let doc = this.props.dvm; + let bindings: any = { + doc: doc, + isSelected: this.props.isSelected + }; + for (const key of this.layoutKeys) { + bindings[key.Name + "Key"] = key; + } + for (const key of this.layoutFields) { + let field = doc.GetField(key); + if (field) { + bindings[key.Name] = field.GetValue(); + } + } + return { console.log(test) }} + /> + + + } + } @observer @@ -25,7 +71,7 @@ export class DocumentView extends React.Component { private _mainCont = React.createRef(); get screenRect(): ClientRect | DOMRect { - if(this._mainCont.current) { + if (this._mainCont.current) { return this._mainCont.current.getBoundingClientRect(); } return new DOMRect(); @@ -33,20 +79,20 @@ export class DocumentView extends React.Component { @computed get x(): number { - return this.props.dvm.Doc.GetFieldValue(KeyStore.X, NumberField, Number(0)); + return this.props.dvm.GetFieldValue(KeyStore.X, NumberField, Number(0)); } @computed get y(): number { - return this.props.dvm.Doc.GetFieldValue(KeyStore.Y, NumberField, Number(0)); + return this.props.dvm.GetFieldValue(KeyStore.Y, NumberField, Number(0)); } set x(x: number) { - this.props.dvm.Doc.SetFieldValue(KeyStore.X, x, NumberField) + this.props.dvm.SetFieldValue(KeyStore.X, x, NumberField) } set y(y: number) { - this.props.dvm.Doc.SetFieldValue(KeyStore.Y, y, NumberField) + this.props.dvm.SetFieldValue(KeyStore.Y, y, NumberField) } @computed @@ -56,35 +102,20 @@ export class DocumentView extends React.Component { @computed get width(): number { - return this.props.dvm.Doc.GetFieldValue(KeyStore.Width, NumberField, Number(0)); + return this.props.dvm.GetFieldValue(KeyStore.Width, NumberField, Number(0)); } set width(w: number) { - this.props.dvm.Doc.SetFieldValue(KeyStore.Width, w, NumberField) + this.props.dvm.SetFieldValue(KeyStore.Width, w, NumberField) } @computed get height(): number { - return this.props.dvm.Doc.GetFieldValue(KeyStore.Height, NumberField, Number(0)); + return this.props.dvm.GetFieldValue(KeyStore.Height, NumberField, Number(0)); } set height(h: number) { - this.props.dvm.Doc.SetFieldValue(KeyStore.Height, h, NumberField) - } - - @computed - get layout(): string { - return this.props.dvm.Doc.GetFieldValue(KeyStore.Layout, TextField, String("

Error loading layout data

")); - } - - @computed - get layoutKeys(): Key[] { - return this.props.dvm.Doc.GetFieldValue(KeyStore.LayoutKeys, ListField, new Array()); - } - - @computed - get layoutFields(): Key[] { - return this.props.dvm.Doc.GetFieldValue(KeyStore.LayoutFields, ListField, new Array()); + this.props.dvm.SetFieldValue(KeyStore.Height, h, NumberField) } @computed @@ -92,22 +123,26 @@ export class DocumentView extends React.Component { return SelectionManager.IsSelected(this) } + isSelected = (): boolean => { + return this.selected + } + private _isPointerDown = false; componentDidMount() { - if(this._mainCont.current) { - DragManager.MakeDraggable(this._mainCont.current, { - buttons: 3, - handlers: { - dragComplete: () => {}, - dragStart: () => {} - } - }) - } + return; + // if(this._mainCont.current) { + // DragManager.MakeDraggable(this._mainCont.current, { + // buttons: 2, + // handlers: { + // dragComplete: () => {}, + // dragStart: () => {} + // } + // }) + // } } onPointerDown = (e: React.PointerEvent): void => { - return; e.stopPropagation(); if (e.button === 2) { this._isPointerDown = true; @@ -139,7 +174,7 @@ export class DocumentView extends React.Component { } this.x += e.movementX; this.y += e.movementY; - DocumentDecorations.Instance.opacity = 0 + //DocumentDecorations.Instance.opacity = 0 } onDragStart = (e: React.DragEvent): void => { @@ -150,21 +185,6 @@ export class DocumentView extends React.Component { } render() { - let doc = this.props.dvm.Doc; - let bindings: any = { - doc: doc, - isSelected: () => this.selected - }; - for (const key of this.layoutKeys) { - bindings[key.Name + "Key"] = key; - } - for (const key of this.layoutFields) { - let field = doc.GetField(key); - if (field) { - bindings[key.Name] = field.GetValue(); - } - } - return (
{ e.preventDefault() }} onPointerDown={this.onPointerDown}> - { console.log(test) }} - /> +
); } diff --git a/test/test.ts b/test/test.ts index 8c1740ba6..3c8fae8d7 100644 --- a/test/test.ts +++ b/test/test.ts @@ -40,10 +40,14 @@ describe("Document", () =>{ it('should update', () => { let doc = new Document(); let key = new Key("Test"); + let key2 = new Key("Test2"); let ran = false; reaction(() => doc.GetField(key), (field) => {ran = true}); expect(ran).to.equal(false); + doc.SetField(key2, new NumberField(4)); + expect(ran).to.equal(false); + doc.SetField(key, new NumberField(5)); expect(ran).to.equal(true); -- cgit v1.2.3-70-g09d2 From 122076af3edfd432e6abe3b2571f21034d5c16e5 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Wed, 23 Jan 2019 01:21:15 -0500 Subject: Small changes and more work on drag drop stuff --- src/stores/NodeCollectionStore.ts | 3 +- src/util/DragManager.ts | 62 +++++++++++++++++++++++++---- src/views/freeformcanvas/FreeFormCanvas.tsx | 2 +- src/views/nodes/DocumentView.tsx | 2 +- 4 files changed, 58 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/stores/NodeCollectionStore.ts b/src/stores/NodeCollectionStore.ts index ac4f515f1..7fac83d51 100644 --- a/src/stores/NodeCollectionStore.ts +++ b/src/stores/NodeCollectionStore.ts @@ -15,7 +15,8 @@ export class NodeCollectionStore extends NodeStore { @computed public get Transform(): string { - return "translate(" + this.X + "px," + this.Y + "px) scale(" + this.Scale + "," + this.Scale + ")"; + const halfWidth = window.innerWidth / 2, halfHeight = window.innerHeight / 2; + return `translate(${this.X + halfWidth}px, ${this.Y + halfHeight}px) scale(${this.Scale}) translate(${-halfWidth}px, ${-halfHeight}px)`; } @action diff --git a/src/util/DragManager.ts b/src/util/DragManager.ts index 1da590072..3111d589f 100644 --- a/src/util/DragManager.ts +++ b/src/util/DragManager.ts @@ -14,7 +14,7 @@ export namespace DragManager { buttons: number; } - export interface DragDisposer { + export interface DragDropDisposer { (): void; } @@ -34,7 +34,19 @@ export namespace DragManager { dragComplete: (e: DragCompleteEvent) => void; } - export function MakeDraggable(element: HTMLElement, options: DragOptions): DragDisposer { + export interface DropOptions { + handlers: DropHandlers; + } + + export class DropEvent { + constructor(readonly x: number, readonly y: number) { } + } + + export interface DropHandlers { + drop: (e: DropEvent) => void; + } + + export function MakeDraggable(element: HTMLElement, options: DragOptions): DragDropDisposer { if ("draggable" in element.dataset) { throw new Error("Element is already draggable, can't make it draggable again"); } @@ -53,6 +65,7 @@ export namespace DragManager { dispose(); }; const downHandler = (e: PointerEvent) => { + e.stopPropagation(); document.addEventListener("pointermove", startDragHandler); document.addEventListener("pointerup", upHandler); }; @@ -60,10 +73,26 @@ export namespace DragManager { return () => { element.removeEventListener("pointerdown", downHandler); - element.dataset["draggable"] = undefined; + delete element.dataset["draggable"]; } } + export function MakeDropTarget(element: HTMLElement, options: DropOptions): DragDropDisposer { + if ("draggable" in element.dataset) { + throw new Error("Element is already droppable, can't make it droppable again"); + } + element.dataset["canDrop"] = "true"; + const handler = (e: Event) => { + const ce = e as CustomEvent; + options.handlers.drop(ce.detail); + }; + element.addEventListener("dashOnDrop", handler); + return () => { + element.removeEventListener("dashOnDrop", handler); + delete element.dataset["canDrop"] + }; + } + function StartDrag(ele: HTMLElement, e: PointerEvent, options: DragOptions) { if (!dragDiv) { const root = document.getElementById(rootId); @@ -81,10 +110,16 @@ export namespace DragManager { if (event.cancelled) { return; } - let x = e.x, y = e.y; + const w = ele.offsetWidth, h = ele.offsetHeight; + const rect = ele.getBoundingClientRect(); + const scaleX = rect.width / w, scaleY = rect.height / h; + let x = rect.left, y = rect.top; + // const offsetX = e.x - rect.left, offsetY = e.y - rect.top; let dragElement = ele.cloneNode(true) as HTMLElement; + dragElement.style.opacity = "0.7"; dragElement.style.position = "absolute"; - dragElement.style.transform = `translate(${x}px, ${y}px)`; + dragElement.style.transformOrigin = "0 0"; + dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; dragDiv.appendChild(dragElement); const moveHandler = (e: PointerEvent) => { @@ -92,18 +127,29 @@ export namespace DragManager { e.preventDefault(); x += e.movementX; y += e.movementY; - dragElement.style.transform = `translate(${x}px, ${y}px)`; + dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; }; const upHandler = (e: PointerEvent) => { document.removeEventListener("pointermove", moveHandler, true); document.removeEventListener("pointerup", upHandler); - FinishDrag(dragElement, options); + FinishDrag(dragElement, e, options); }; document.addEventListener("pointermove", moveHandler, true); document.addEventListener("pointerup", upHandler); } - function FinishDrag(ele: HTMLElement, options: DragOptions) { + function FinishDrag(ele: HTMLElement, e: PointerEvent, options: DragOptions) { dragDiv.removeChild(ele); + const target = document.elementFromPoint(e.x, e.y); + if (!target) { + return; + } + target.dispatchEvent(new CustomEvent("dashOnDrop", { + bubbles: true, + detail: { + x: e.x, + y: e.y, + } + })); } } \ No newline at end of file diff --git a/src/views/freeformcanvas/FreeFormCanvas.tsx b/src/views/freeformcanvas/FreeFormCanvas.tsx index e051fd97c..13e923736 100644 --- a/src/views/freeformcanvas/FreeFormCanvas.tsx +++ b/src/views/freeformcanvas/FreeFormCanvas.tsx @@ -77,7 +77,7 @@ export class FreeFormCanvas extends React.Component { let store = this.props.store; return (
e.preventDefault()}> -
+
{this.props.store.Docs.map(doc => { return (); diff --git a/src/views/nodes/DocumentView.tsx b/src/views/nodes/DocumentView.tsx index 648ea7f50..772c272bd 100644 --- a/src/views/nodes/DocumentView.tsx +++ b/src/views/nodes/DocumentView.tsx @@ -130,7 +130,6 @@ export class DocumentView extends React.Component { private _isPointerDown = false; componentDidMount() { - return; // if(this._mainCont.current) { // DragManager.MakeDraggable(this._mainCont.current, { // buttons: 2, @@ -143,6 +142,7 @@ export class DocumentView extends React.Component { } onPointerDown = (e: React.PointerEvent): void => { + // return; e.stopPropagation(); if (e.button === 2) { this._isPointerDown = true; -- cgit v1.2.3-70-g09d2