diff options
-rw-r--r-- | src/Utils.ts | 9 | ||||
-rw-r--r-- | src/util/DragManager.ts | 17 | ||||
-rw-r--r-- | src/views/freeformcanvas/CollectionFreeFormView.tsx | 107 | ||||
-rw-r--r-- | src/views/nodes/DocumentView.tsx | 40 |
4 files changed, 110 insertions, 63 deletions
diff --git a/src/Utils.ts b/src/Utils.ts index f352b87e3..948b6176e 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -10,4 +10,13 @@ export class Utils { public static GenerateDeterministicGuid(seed: string): string { return v5(seed, v5.URL); } + + public static GetScreenTransform(ele: HTMLElement): { scale: number, translateX: number, translateY: number } { + const rect = ele.getBoundingClientRect(); + const scale = rect.width / ele.offsetWidth; + const translateX = rect.left; + const translateY = rect.top; + + return { scale, translateX, translateY }; + } }
\ No newline at end of file diff --git a/src/util/DragManager.ts b/src/util/DragManager.ts index 3111d589f..7a8362471 100644 --- a/src/util/DragManager.ts +++ b/src/util/DragManager.ts @@ -23,6 +23,8 @@ export namespace DragManager { get cancelled() { return this._cancelled }; cancel() { this._cancelled = true; }; + + constructor(readonly x:number, readonly y:number, readonly data: { [id: string]: any }) { } } export class DragCompleteEvent { @@ -39,7 +41,7 @@ export namespace DragManager { } export class DropEvent { - constructor(readonly x: number, readonly y: number) { } + constructor(readonly x: number, readonly y: number, readonly data: { [id: string]: any }) { } } export interface DropHandlers { @@ -56,7 +58,7 @@ export namespace DragManager { document.removeEventListener("pointermove", startDragHandler); } const startDragHandler = (e: PointerEvent) => { - e.stopPropagation(); + e.stopImmediatePropagation(); e.preventDefault(); dispose(); StartDrag(element, e, options); @@ -65,7 +67,6 @@ export namespace DragManager { dispose(); }; const downHandler = (e: PointerEvent) => { - e.stopPropagation(); document.addEventListener("pointermove", startDragHandler); document.addEventListener("pointerup", upHandler); }; @@ -105,7 +106,10 @@ export namespace DragManager { if ((e.buttons & options.buttons) === 0) { return; } - let event = new DragStartEvent(); + e.stopPropagation(); + e.preventDefault(); + let dragData = {}; + let event = new DragStartEvent(e.x, e.y, dragData); options.handlers.dragStart(event); if (event.cancelled) { return; @@ -132,13 +136,13 @@ export namespace DragManager { const upHandler = (e: PointerEvent) => { document.removeEventListener("pointermove", moveHandler, true); document.removeEventListener("pointerup", upHandler); - FinishDrag(dragElement, e, options); + FinishDrag(dragElement, e, options, dragData); }; document.addEventListener("pointermove", moveHandler, true); document.addEventListener("pointerup", upHandler); } - function FinishDrag(ele: HTMLElement, e: PointerEvent, options: DragOptions) { + function FinishDrag(ele: HTMLElement, e: PointerEvent, options: DragOptions, dragData: { [index: string]: any }) { dragDiv.removeChild(ele); const target = document.elementFromPoint(e.x, e.y); if (!target) { @@ -149,6 +153,7 @@ export namespace DragManager { detail: { x: e.x, y: e.y, + data: dragData } })); } diff --git a/src/views/freeformcanvas/CollectionFreeFormView.tsx b/src/views/freeformcanvas/CollectionFreeFormView.tsx index 383d71d83..53c5def52 100644 --- a/src/views/freeformcanvas/CollectionFreeFormView.tsx +++ b/src/views/freeformcanvas/CollectionFreeFormView.tsx @@ -13,6 +13,8 @@ import { SelectionManager } from "../../util/SelectionManager"; import { Documents } from "../../documents/Documents"; import { ContextMenu } from "../ContextMenu"; import { Opt } from "../../fields/Field"; +import { DragManager } from "../../util/DragManager"; +import { Utils } from "../../Utils"; interface IProps { fieldKey: Key; @@ -22,25 +24,50 @@ interface IProps { @observer export class CollectionFreeFormView extends React.Component<IProps> { + private _ref = React.createRef<HTMLDivElement>(); constructor(props: IProps) { super(props); } @computed - public get active():boolean { - var isSelected = (this.props.ContainingDocumentView != undefined && SelectionManager.IsSelected(this.props.ContainingDocumentView)); - var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == this ); - var topMost = this.props.ContainingDocumentView != undefined && this.props.ContainingDocumentView.props.ContainingCollectionView == undefined; + public get active(): boolean { + var isSelected = (this.props.ContainingDocumentView != undefined && SelectionManager.IsSelected(this.props.ContainingDocumentView)); + var childSelected = SelectionManager.SelectedDocuments().some(view => view.props.ContainingCollectionView == this); + var topMost = this.props.ContainingDocumentView != undefined && this.props.ContainingDocumentView.props.ContainingCollectionView == undefined; return isSelected || childSelected || topMost; } + componentDidMount() { + if (this._ref.current) { + const ele = this._ref.current; + DragManager.MakeDropTarget(this._ref.current, { + handlers: { + drop: (e: DragManager.DropEvent) => { + const doc = e.data["document"]; + const xOffset = e.data["xOffset"] as number || 0; + const yOffset = e.data["yOffset"] as number || 0; + if (doc instanceof DocumentView) { + const { scale, translateX, translateY } = Utils.GetScreenTransform(ele.children[0] as HTMLElement); + console.log(`${scale} ${translateX} ${translateY}`) + const screenX = e.x - xOffset; + const screenY = e.y - yOffset; + const docX = (screenX - translateX) / scale; + const docY = (screenY - translateY) / scale; + doc.x = docX; + doc.y = docY; + } + } + } + }); + } + } + _lastX: number = 0; - _lastY:number = 0; + _lastY: number = 0; @action - onPointerDown = (e: React.PointerEvent): void => - { - if (this.active && e.button === 2) { + onPointerDown = (e: React.PointerEvent): void => { + if (e.button === 2 && this.active) { e.stopPropagation(); e.preventDefault(); document.removeEventListener("pointermove", this.onPointerMove); @@ -65,22 +92,21 @@ export class CollectionFreeFormView extends React.Component<IProps> { } @action - onPointerMove = (e: PointerEvent): void => - { + onPointerMove = (e: PointerEvent): void => { if (!e.cancelBubble) { e.preventDefault(); e.stopPropagation(); const doc = this.props.Document; let me = this; - let currScale:number = this.props.Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1)); + let currScale: number = this.props.Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1)); if (me.props.ContainingDocumentView!.props.ContainingDocumentView != undefined) { let pme = me.props.ContainingDocumentView!.props.ContainingDocumentView!.props.Document; currScale = pme.GetFieldValue(KeyStore.Scale, NumberField, Number(0)); - } + } let x = doc.GetFieldValue(KeyStore.PanX, NumberField, Number(0)); let y = doc.GetFieldValue(KeyStore.PanY, NumberField, Number(0)); - doc.SetFieldValue(KeyStore.PanX, x + (e.pageX - this._lastX)/currScale, NumberField); - doc.SetFieldValue(KeyStore.PanY, y + (e.pageY - this._lastY)/currScale, NumberField); + doc.SetFieldValue(KeyStore.PanX, x + (e.pageX - this._lastX) / currScale, NumberField); + doc.SetFieldValue(KeyStore.PanY, y + (e.pageY - this._lastY) / currScale, NumberField); this._lastX = e.pageX; this._lastY = e.pageY; @@ -89,46 +115,45 @@ export class CollectionFreeFormView extends React.Component<IProps> { } - private getLocalPoint(me:DocumentView, inputX: number, inputY: number) { + private getLocalPoint(me: DocumentView, inputX: number, inputY: number) { let ContainerX = inputX; let ContainerY = inputY; if (me.props.ContainingDocumentView != undefined) { let pme = me.props.ContainingDocumentView!; - let {LocalX, Ss, W, Panxx, Xx, LocalY, Panyy, Yy} = this.getLocalPoint(pme, ContainerX, ContainerY); + let { LocalX, LocalY } = this.getLocalPoint(pme, ContainerX, ContainerY); ContainerX = LocalX; ContainerY = LocalY; - } - - let W = me.props.Document.GetFieldValue(KeyStore.Width, NumberField, Number(0)); - let Xx = me.props.Document.GetFieldValue(KeyStore.X, NumberField, Number(0)); - let Yy = me.props.Document.GetFieldValue(KeyStore.Y, NumberField, Number(0)); - let Ss = me.props.Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1)); - let Panxx = me.props.Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0)); - let Panyy = me.props.Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0)); + } + + let W = me.props.Document.GetFieldValue(KeyStore.Width, NumberField, Number(0)); + let Xx = me.props.Document.GetFieldValue(KeyStore.X, NumberField, Number(0)); + let Yy = me.props.Document.GetFieldValue(KeyStore.Y, NumberField, Number(0)); + let Ss = me.props.Document.GetFieldValue(KeyStore.Scale, NumberField, Number(1)); + let Panxx = me.props.Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0)); + let Panyy = me.props.Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0)); let LocalX = W / 2 - (Xx + Panxx) / Ss + (ContainerX - W / 2) / Ss; let LocalY = -(Yy + Panyy) / Ss + ContainerY / Ss; - return {LocalX, Ss, W, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY}; + return { LocalX, Ss, W, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY }; } @action - onPointerWheel = (e: React.WheelEvent): void => - { + onPointerWheel = (e: React.WheelEvent): void => { e.stopPropagation(); - let {LocalX, Ss, W, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY} = this.getLocalPoint(this.props.ContainingDocumentView!, e.pageX, e.pageY); + let { LocalX, Ss, W, Panxx, Xx, LocalY, Panyy, Yy, ContainerX, ContainerY } = this.getLocalPoint(this.props.ContainingDocumentView!, e.pageX, e.pageY); - var deltaScale = (1 - (e.deltaY / 1000)) * Ss; + var deltaScale = (1 - (e.deltaY / 1000)) * Ss; - var newContainerX = LocalX * deltaScale + W/2-W/2 * deltaScale + Panxx + Xx; - var newContainerY = LocalY * deltaScale + Panyy+ Yy; + var newContainerX = LocalX * deltaScale + W / 2 - W / 2 * deltaScale + Panxx + Xx; + var newContainerY = LocalY * deltaScale + Panyy + Yy; let dx = ContainerX - newContainerX; let dy = ContainerY - newContainerY; this.props.Document.SetField(KeyStore.Scale, new NumberField(deltaScale)); - this.props.Document.SetFieldValue(KeyStore.PanX, Panxx+dx, NumberField); - this.props.Document.SetFieldValue(KeyStore.PanY, Panyy+dy, NumberField); + this.props.Document.SetFieldValue(KeyStore.PanX, Panxx + dx, NumberField); + this.props.Document.SetFieldValue(KeyStore.PanY, Panyy + dy, NumberField); DocumentDecorations.Instance.forceUpdate() } @@ -180,7 +205,7 @@ export class CollectionFreeFormView extends React.Component<IProps> { } render() { const { fieldKey, Document: Document } = this.props; - + const value: Document[] = Document.GetFieldValue(fieldKey, ListField, []); const panx: number = Document.GetFieldValue(KeyStore.PanX, NumberField, Number(0)); const pany: number = Document.GetFieldValue(KeyStore.PanY, NumberField, Number(0)); @@ -188,19 +213,19 @@ export class CollectionFreeFormView extends React.Component<IProps> { // DocumentDecorations.Instance.forceUpdate() return ( <div className="border" style={{ - borderStyle: "solid", - borderWidth: "2px" - }}> + borderStyle: "solid", + borderWidth: "2px" + }}> <div className="collectionfreeformview-container" onPointerDown={this.onPointerDown} onWheel={this.onPointerWheel} onContextMenu={(e) => e.preventDefault()} style={{ width: "100%", height: "calc(100% - 4px)", overflow: "hidden" - }} onDrop={this.onDrop} onDragOver={this.onDragOver}> - <div className="collectionfreeformview" style={{ transform: `translate(${panx}px, ${pany}px) scale(${currScale}, ${currScale})` , transformOrigin: `left, top`}}> - + }} onDrop={this.onDrop} onDragOver={this.onDragOver} ref={this._ref}> + <div className="collectionfreeformview" style={{ transform: `translate(${panx}px, ${pany}px) scale(${currScale}, ${currScale})`, transformOrigin: `left, top` }}> + <div className="node-container"> {value.map(doc => { - return (<DocumentView key={doc.Id} ContainingCollectionView={this} Document={doc} ContainingDocumentView={this.props.ContainingDocumentView}/>); + return (<DocumentView key={doc.Id} ContainingCollectionView={this} Document={doc} ContainingDocumentView={this.props.ContainingDocumentView} />); })} </div> </div> diff --git a/src/views/nodes/DocumentView.tsx b/src/views/nodes/DocumentView.tsx index 33a126a7b..05f0928fb 100644 --- a/src/views/nodes/DocumentView.tsx +++ b/src/views/nodes/DocumentView.tsx @@ -14,6 +14,7 @@ import { SelectionManager } from "../../util/SelectionManager"; import { DocumentDecorations } from "../../DocumentDecorations"; import { ContextMenu } from "../ContextMenu"; import { Opt } from "../../fields/Field"; +import { DragManager } from "../../util/DragManager"; const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this? interface IProps { @@ -41,10 +42,7 @@ class DocumentContents extends React.Component<IProps> { } render() { let doc = this.props.Document; - let bindings: any = { - doc: doc, - // isSelected: this.props.isSelected - }; + let bindings = {...this.props} as any; for (const key of this.layoutKeys) { bindings[key.Name + "Key"] = key; } @@ -125,15 +123,25 @@ export class DocumentView extends React.Component<IProps> { } componentDidMount() { - // if(this._mainCont.current) { - // DragManager.MakeDraggable(this._mainCont.current, { - // buttons: 2, - // handlers: { - // dragComplete: () => {}, - // dragStart: () => {} - // } - // }) - // } + const that = this; + if(this._mainCont.current) { + DragManager.MakeDraggable(this._mainCont.current, { + buttons: 2, + handlers: { + dragComplete: () => {}, + dragStart: (e: DragManager.DragStartEvent) => { + if(!this.props.ContainingCollectionView) { + e.cancel(); + return; + } + const rect = this.screenRect; + e.data["document"] = this; + e.data["xOffset"] = e.x - rect.left; + e.data["yOffset"] = e.y - rect.top; + } + } + }) + } } @computed @@ -147,8 +155,8 @@ export class DocumentView extends React.Component<IProps> { this._lastX = e.pageX; this._lastY = e.pageY; this._contextMenuCanOpen = e.button == 2; - document.removeEventListener("pointermove", this.onPointerMove); - document.addEventListener("pointermove", this.onPointerMove); + // document.removeEventListener("pointermove", this.onPointerMove); + // document.addEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointerup", this.onPointerUp); } @@ -238,7 +246,7 @@ export class DocumentView extends React.Component<IProps> { onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick}> - <DocumentContents {...this.props} /> + <DocumentContents {...this.props} ContainingDocumentView={this} /> </div> ); } |