diff options
author | Monika Hedman <monika_hedman@brown.edu> | 2019-02-18 19:03:34 -0500 |
---|---|---|
committer | Monika Hedman <monika_hedman@brown.edu> | 2019-02-18 19:03:34 -0500 |
commit | eaeb373ed90d35ab1c29cd9c3e4a79f6c8fa30b0 (patch) | |
tree | 2adb423bf0f782fce6861d703114bc0140520766 /src | |
parent | 30986620c34c93e12509b2875e90cf5876838403 (diff) | |
parent | 842f571bfb4952d12804a8dbdc66aedbf2bf6b81 (diff) |
transforms update
Diffstat (limited to 'src')
-rw-r--r-- | src/client/util/DragManager.ts | 14 | ||||
-rw-r--r-- | src/client/util/Transform.ts | 8 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 4 | ||||
-rw-r--r-- | src/client/views/EditableView.tsx | 6 | ||||
-rw-r--r-- | src/client/views/Main.tsx | 15 | ||||
-rw-r--r-- | src/client/views/collections/CollectionDockingView.tsx | 116 | ||||
-rw-r--r-- | src/client/views/collections/CollectionFreeFormView.tsx | 24 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSchemaView.scss | 59 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSchemaView.tsx | 84 | ||||
-rw-r--r-- | src/client/views/collections/CollectionViewBase.tsx | 8 | ||||
-rw-r--r-- | src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 42 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.scss (renamed from src/client/views/nodes/NodeView.scss) | 2 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 29 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.scss | 2 | ||||
-rw-r--r-- | src/client/views/nodes/ImageBox.scss | 8 |
15 files changed, 242 insertions, 179 deletions
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 93b927f8b..337ec855a 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -78,11 +78,13 @@ export namespace DragManager { dragElement.style.transformOrigin = "0 0"; dragElement.style.zIndex = "1000"; dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; - dragElement.style.width = `${rect.width}px`; - dragElement.style.height = `${rect.height}px`; + dragElement.style.width = `${rect.width / scaleX}px`; + dragElement.style.height = `${rect.height / scaleY}px`; + // It seems like the above code should be able to just be this: + // dragElement.style.transform = `translate(${x}px, ${y}px)`; + // dragElement.style.width = `${rect.width}px`; + // dragElement.style.height = `${rect.height}px`; dragDiv.appendChild(dragElement); - _lastPointerX = dragData["xOffset"] + rect.left; - _lastPointerY = dragData["yOffset"] + rect.top; let hideSource = false; if (typeof options.hideSource === "boolean") { @@ -98,8 +100,8 @@ export namespace DragManager { const moveHandler = (e: PointerEvent) => { e.stopPropagation(); e.preventDefault(); - x += e.clientX - _lastPointerX; _lastPointerX = e.clientX; - y += e.clientY - _lastPointerY; _lastPointerY = e.clientY; + x += e.movementX; + y += e.movementY; dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; }; const upHandler = (e: PointerEvent) => { diff --git a/src/client/util/Transform.ts b/src/client/util/Transform.ts index aa922f358..9a66727a2 100644 --- a/src/client/util/Transform.ts +++ b/src/client/util/Transform.ts @@ -38,8 +38,8 @@ export class Transform { } transform = (transform: Transform): Transform => { - this._translateX += transform._translateX * this._scale; - this._translateY += transform._translateY * this._scale; + this._translateX = transform._translateX + transform._scale * this._translateX; + this._translateY = transform._translateY + transform._scale * this._translateY; this._scale *= transform._scale; return this; } @@ -63,8 +63,8 @@ export class Transform { } preTransform = (transform: Transform): Transform => { - this._translateX = transform._translateX + this._translateX * transform._scale; - this._translateY = transform._translateY + this._translateY * transform._scale; + this._translateX += transform._translateX * this._scale; + this._translateY += transform._translateY * this._scale; this._scale *= transform._scale; return this; } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 5abe3f5b2..d385bcdef 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -4,7 +4,7 @@ import { SelectionManager } from "../util/SelectionManager"; import { observer } from "mobx-react"; import './DocumentDecorations.scss' import { CollectionFreeFormView } from "./collections/CollectionFreeFormView"; -import { KeyStore } from "../../fields/Key"; +import { KeyStore } from '../../fields/Key' import { NumberField } from "../../fields/NumberField"; @observer @@ -27,7 +27,7 @@ export class DocumentDecorations extends React.Component { !(element.props.ContainingCollectionView instanceof CollectionFreeFormView)) { return bounds; } - let transform = element.props.GetTransform().inverse(); + let transform = element.props.ScreenToLocalTransform().inverse(); var [sptX, sptY] = transform.transformPoint(0, 0); // var [bptX, bptY] = transform.transformDirection(element.width, element.height); let doc = element.props.Document; diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index 2e784d3f9..3d1c2ebf4 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -6,6 +6,7 @@ export interface EditableProps { GetValue(): string; SetValue(value: string): boolean; contents: any; + height: number } @observer @@ -29,9 +30,10 @@ export class EditableView extends React.Component<EditableProps> { style={{ width: "100%" }}></input> } else { return ( - <div> + <div style={{ alignItems: "center", display: "flex", height: "100%", maxHeight: `${this.props.height}` }} + onClick={action(() => this.editing = true)} + > {this.props.contents} - <button onClick={action(() => this.editing = true)}>Edit</button> </div> ) } diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 38e353055..0532cbc1f 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -46,12 +46,13 @@ let doc2 = doc1.MakeDelegate(); doc2.Set(KS.X, new NumberField(150)); doc2.Set(KS.Y, new NumberField(20)); let doc3 = Documents.ImageDocument("https://psmag.com/.image/t_share/MTMyNzc2NzM1MDY1MjgzMDM4/shutterstock_151341212jpg.jpg", { - x: 450, y: 100, title: "cat 1", width: 606, height: 386, nativeWidth: 606, nativeHeight: 386 + x: 450, y: 100, title: "dog", width: 606, height: 386, nativeWidth: 606, nativeHeight: 386 }); //doc3.Set(KeyStore.Data, new ImageField); const schemaDocs = Array.from(Array(5).keys()).map(v => Documents.ImageDocument("https://psmag.com/.image/t_share/MTMyNzc2NzM1MDY1MjgzMDM4/shutterstock_151341212jpg.jpg", { x: 50 + 100 * v, y: 50, width: 100, height: 100, title: "cat" + v, nativeWidth: 606, nativeHeight: 386 })); +schemaDocs.push(doc3); schemaDocs[0].SetData(KS.Author, "Tyler", TextField); schemaDocs[4].SetData(KS.Author, "Bob", TextField); schemaDocs.push(doc2); @@ -63,10 +64,10 @@ let doc4 = Documents.CollectionDocument(docset, { // let doc5 = Documents.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { // x: 650, y: 500, width: 600, height: 600, title: "cat 2" // }); -let docset2 = [doc3, doc1, doc2]; -// let doc6 = Documents.CollectionDocument(docset2, { -// x: 350, y: 100, width: 600, height: 600, title: "docking collection" -// }); +let docset2 = [doc3, doc4, doc2]; +let doc6 = Documents.CollectionDocument(docset2, { + x: 350, y: 100, width: 600, height: 600, title: "docking collection" +}); let mainNodes = mainContainer.GetOrCreate<ListField<Document>>(KeyStore.Data, ListField); // mainNodes.Data.push(doc6); // mainNodes.Data.push(doc2); @@ -75,7 +76,7 @@ mainNodes.Data.push(doc3); // mainNodes.Data.push(doc5); // mainNodes.Data.push(doc1); // mainNodes.Data.push(doc2); -//mainNodes.Data.push(doc6); +mainNodes.Data.push(doc6); //} //); @@ -83,7 +84,7 @@ mainNodes.Data.push(doc3); ReactDOM.render(( <div style={{ position: "absolute", width: "100%", height: "100%" }}> <DocumentView Document={mainContainer} - AddDocument={undefined} RemoveDocument={undefined} GetTransform={() => Transform.Identity} + AddDocument={undefined} RemoveDocument={undefined} ScreenToLocalTransform={() => Transform.Identity} Scaling={1} isTopMost={true} ContainingCollectionView={undefined} DocumentView={undefined} /> diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 310933275..472f8a4d2 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -4,18 +4,17 @@ import 'golden-layout/src/css/goldenlayout-base.css'; import 'golden-layout/src/css/goldenlayout-dark-theme.css'; import { action, computed, reaction, observable } from "mobx"; import { observer } from "mobx-react"; -import * as ReactDOM from 'react-dom'; import { Document } from "../../../fields/Document"; import { KeyStore } from "../../../fields/Key"; import { ListField } from "../../../fields/ListField"; -import { NumberField } from "../../../fields/NumberField"; import { DragManager } from "../../util/DragManager"; import { Transform } from "../../util/Transform"; import { DocumentView } from "../nodes/DocumentView"; import "./CollectionDockingView.scss"; import { CollectionViewBase, CollectionViewProps, COLLECTION_BORDER_WIDTH } from "./CollectionViewBase"; import React = require("react"); -import { changeDependenciesStateTo0 } from "mobx/lib/internal"; +import * as ReactDOM from 'react-dom'; +import Measure from "react-measure"; import { Utils } from "../../../Utils"; @observer @@ -68,7 +67,6 @@ export class CollectionDockingView extends CollectionViewBase { } private nextId = (function () { var _next_id = 0; return function () { return _next_id++; } })(); - @action onResize = (event: any) => { var cur = this.props.ContainingDocumentView!.MainContent.current; @@ -100,7 +98,7 @@ export class CollectionDockingView extends CollectionViewBase { if (value[i].Id === component) { return (<DocumentView key={value[i].Id} Document={value[i]} AddDocument={this.addDocument} RemoveDocument={this.removeDocument} - GetTransform={() => Transform.Identity} + ScreenToLocalTransform={() => Transform.Identity} isTopMost={true} Scaling={1} ContainingCollectionView={this} DocumentView={undefined} />); @@ -113,7 +111,6 @@ export class CollectionDockingView extends CollectionViewBase { public static myLayout: any = null; - public rcs: Array<RenderClass> = new Array(); private static _dragDiv: any = null; private static _dragParent: HTMLElement | null = null; private static _dragElement: HTMLDivElement; @@ -244,10 +241,19 @@ export class CollectionDockingView extends CollectionViewBase { var containingDiv = "component_" + me.nextId(); container.getElement().html("<div id='" + containingDiv + "'></div>"); setTimeout(function () { - state.rc = new RenderClass(containingDiv, state.doc, me, container); - me.rcs.push(state.rc); - if (CollectionDockingView.myLayout._maxstack != null) { - CollectionDockingView.myLayout._maxstack.click(); + let divContainer = document.getElementById(containingDiv) as HTMLDivElement; + if (divContainer) { + let props: DockingProps = { + ContainingDiv: containingDiv, + Document: state.doc, + Container: container, + CollectionDockingView: me, + HtmlElement: divContainer, + } + ReactDOM.render((<RenderClass {...props} />), divContainer); + if (CollectionDockingView.myLayout._maxstack) { + CollectionDockingView.myLayout._maxstack.click(); + } } }, 0); }); @@ -261,8 +267,8 @@ export class CollectionDockingView extends CollectionViewBase { const value: Document[] = Document.GetData(fieldKey, ListField, []); // bcz: not sure why, but I need these to force the flexlayout to update when the collection size changes. var s = this.props.ContainingDocumentView != undefined ? this.props.ContainingDocumentView!.ScalingToScreenSpace : 1; - var w = Document.GetData(KeyStore.Width, NumberField, Number(0)) / s; - var h = Document.GetData(KeyStore.Height, NumberField, Number(0)) / s; + var w = Document.GetNumber(KeyStore.Width, 0) / s; + var h = Document.GetNumber(KeyStore.Height, 0) / s; var chooseLayout = () => { if (!CollectionDockingView.UseGoldenLayout) @@ -270,60 +276,54 @@ export class CollectionDockingView extends CollectionViewBase { } return ( - <div className="border" style={{ - borderStyle: "solid", - borderWidth: `${COLLECTION_BORDER_WIDTH}px`, - }}> - <div className="collectiondockingview-container" id="menuContainer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()} ref={this._containerRef} - style={{ - width: CollectionDockingView.UseGoldenLayout || s > 1 ? "100%" : w - 2 * COLLECTION_BORDER_WIDTH, - height: CollectionDockingView.UseGoldenLayout || s > 1 ? "100%" : h - 2 * COLLECTION_BORDER_WIDTH - }} > - {chooseLayout()} - </div> + <div className="collectiondockingview-container" id="menuContainer" + onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()} ref={this._containerRef} + style={{ + width: CollectionDockingView.UseGoldenLayout || s > 1 ? "100%" : w - 2 * COLLECTION_BORDER_WIDTH, + height: CollectionDockingView.UseGoldenLayout || s > 1 ? "100%" : h - 2 * COLLECTION_BORDER_WIDTH, + borderStyle: "solid", + borderWidth: `${COLLECTION_BORDER_WIDTH}px`, + }} > + {chooseLayout()} </div> ); } } -class RenderClass { - - @observable _resizeCount: number = 0; - - _collectionDockingView: CollectionDockingView; - _htmlElement: any; - _document: Document; - constructor(containingDiv: string, doc: Document, me: CollectionDockingView, container: any) { - this._collectionDockingView = me; - this._htmlElement = document.getElementById(containingDiv); - this._document = doc; - container.on('resize', action((e: any) => { - var nativeWidth = doc.GetNumber(KeyStore.NativeWidth, 0); - if (this._htmlElement != null && this._htmlElement.childElementCount > 0 && nativeWidth > 0) { - let scaling = nativeWidth > 0 ? this._htmlElement!.clientWidth / nativeWidth : 1; - (this._htmlElement!.children[0] as any).style.transformOrigin = "0px 0px"; - (this._htmlElement!.children[0] as any).style.transform = `translate(0px,0px) scale(${scaling}, ${scaling}) `; - (this._htmlElement!.children[0] as any).style.width = nativeWidth.toString() + "px"; - } - })); +interface DockingProps { + ContainingDiv: string, + Document: Document, + Container: any, + HtmlElement: HTMLElement, + CollectionDockingView: CollectionDockingView, +} +@observer +export class RenderClass extends React.Component<DockingProps> { + @observable + private _parentScaling = 1; // used to transfer the dimensions of the content pane in the DOM to the ParentScaling prop of the DocumentView - this.render(); - } render() { - let nativeWidth = this._document.GetNumber(KeyStore.NativeWidth, 0); - let scaling = nativeWidth > 0 ? this._htmlElement!.clientWidth / nativeWidth : 1; - ReactDOM.render(( - <DocumentView key={this._document.Id} Document={this._document} - AddDocument={this._collectionDockingView.addDocument} RemoveDocument={this._collectionDockingView.removeDocument} - GetTransform={() => { - let { scale, translateX, translateY } = Utils.GetScreenTransform(this._htmlElement); - return this._collectionDockingView.props.GetTransform().scale(scale).translate(-translateX, -translateY) + let nativeWidth = this.props.Document.GetNumber(KeyStore.NativeWidth, 0); + var layout = this.props.Document.GetText(KeyStore.Layout, ""); + var content = + <DocumentView key={this.props.Document.Id} Document={this.props.Document} + AddDocument={this.props.CollectionDockingView.addDocument} + RemoveDocument={this.props.CollectionDockingView.removeDocument} + Scaling={this._parentScaling} + ScreenToLocalTransform={() => { + let { scale, translateX, translateY } = Utils.GetScreenTransform(this.props.HtmlElement); + return this.props.CollectionDockingView.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale) }} isTopMost={true} - Scaling={scaling} - ContainingCollectionView={this._collectionDockingView} DocumentView={undefined} /> - ), - this._htmlElement - ); + ContainingCollectionView={this.props.CollectionDockingView} DocumentView={undefined} /> + + if (nativeWidth > 0 && (layout.indexOf("CollectionFreeForm") == -1 || layout.indexOf("AnnotationsKey") != -1)) { + return <Measure onResize={ + action((r: any) => this._parentScaling = nativeWidth > 0 ? r.entry.width / nativeWidth : 1)} + > + {({ measureRef }) => <div ref={measureRef}> {content} </div>} + </Measure> + } + return <div> {content} </div> } }
\ No newline at end of file diff --git a/src/client/views/collections/CollectionFreeFormView.tsx b/src/client/views/collections/CollectionFreeFormView.tsx index b81975d3d..26c8517b3 100644 --- a/src/client/views/collections/CollectionFreeFormView.tsx +++ b/src/client/views/collections/CollectionFreeFormView.tsx @@ -55,7 +55,8 @@ export class CollectionFreeFormView extends CollectionViewBase { } const xOffset = de.data["xOffset"] as number || 0; const yOffset = de.data["yOffset"] as number || 0; - const transform = doc.props.GetTransform(); + //this should be able to use translate and scale methods on an Identity transform, no? + const transform = me.getTransform(); const screenX = de.x - xOffset; const screenY = de.y - yOffset; const [x, y] = transform.transformPoint(screenX, screenY); @@ -107,7 +108,7 @@ export class CollectionFreeFormView extends CollectionViewBase { e.stopPropagation(); let x = this.props.DocumentForCollection.GetNumber(KeyStore.PanX, 0); let y = this.props.DocumentForCollection.GetNumber(KeyStore.PanY, 0); - let [dx, dy] = this.props.GetTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); + let [dx, dy] = this.props.ScreenToLocalTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); this.SetPan(x + dx, y + dy); } @@ -129,7 +130,7 @@ export class CollectionFreeFormView extends CollectionViewBase { let [x, y] = transform.transformPoint(e.clientX, e.clientY); let localTransform = this.getLocalTransform(); - localTransform.scaleAbout(deltaScale, x, y); + localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y) this.props.DocumentForCollection.SetNumber(KeyStore.Scale, localTransform.Scale); this.SetPan(localTransform.TranslateX, localTransform.TranslateY); @@ -137,8 +138,8 @@ export class CollectionFreeFormView extends CollectionViewBase { @action private SetPan(panX: number, panY: number) { - const newPanX = Math.max(-(this.resizeScaling * this.zoomScaling - this.resizeScaling) * this.nativeWidth, Math.min(0, panX)); - const newPanY = Math.max(-(this.resizeScaling * this.zoomScaling - this.resizeScaling) * this.nativeHeight, Math.min(0, panY)); + const newPanX = Math.max((1 - this.zoomScaling) * this.nativeWidth, Math.min(0, panX)); + const newPanY = Math.max((1 - this.zoomScaling) * this.nativeHeight, Math.min(0, panY)); this.props.DocumentForCollection.SetNumber(KeyStore.PanX, this.isAnnotationOverlay ? newPanX : panX); this.props.DocumentForCollection.SetNumber(KeyStore.PanY, this.isAnnotationOverlay ? newPanY : panY); } @@ -150,8 +151,8 @@ export class CollectionFreeFormView extends CollectionViewBase { let fReader = new FileReader() let file = e.dataTransfer.items[0].getAsFile(); let that = this; - const panx: number = this.props.DocumentForCollection.GetData(KeyStore.PanX, NumberField, Number(0)); - const pany: number = this.props.DocumentForCollection.GetData(KeyStore.PanY, NumberField, Number(0)); + const panx: number = this.props.DocumentForCollection.GetNumber(KeyStore.PanX, 0); + const pany: number = this.props.DocumentForCollection.GetNumber(KeyStore.PanY, 0); let x = e.pageX - panx let y = e.pageY - pany @@ -211,13 +212,12 @@ export class CollectionFreeFormView extends CollectionViewBase { } getTransform = (): Transform => { - const [x, y] = this.translate; - return this.getLocalTransform().inverse().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).transform(this.props.GetTransform()) + return this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).transform(this.getLocalTransform()) } getLocalTransform = (): Transform => { const [x, y] = this.translate; - return Transform.Identity.scale(this.scale).translate(x, y); + return Transform.Identity.translate(-x, -y).scale(1 / this.scale); } render() { @@ -242,12 +242,12 @@ export class CollectionFreeFormView extends CollectionViewBase { style={{ width: "100%", transformOrigin: "left top", transform: ` translate(${panx}px, ${pany}px) scale(${this.zoomScaling}, ${this.zoomScaling})` }} ref={this._canvasRef}> - {this.props.BackgroundView} + {this.props.BackgroundView ? this.props.BackgroundView() : null} {value.map(doc => { return (<CollectionFreeFormDocumentView key={doc.Id} Document={doc} AddDocument={this.addDocument} RemoveDocument={this.removeDocument} - GetTransform={this.getTransform} + ScreenToLocalTransform={this.getTransform} isTopMost={false} Scaling={1} ContainingCollectionView={this} DocumentView={this.props.ContainingDocumentView} />); diff --git a/src/client/views/collections/CollectionSchemaView.scss b/src/client/views/collections/CollectionSchemaView.scss index 707b44db6..633e3ca1b 100644 --- a/src/client/views/collections/CollectionSchemaView.scss +++ b/src/client/views/collections/CollectionSchemaView.scss @@ -1,3 +1,62 @@ + +.collectionSchemaView-container { + border-style: solid; + box-sizing: border-box; + position: absolute; + width: 100%; + height: 100%; + .collectionfreeformview-container { + border-width: 0px; + .collectionfreeformview > .jsx-parser{ + position:absolute + } + } + .imageBox-cont { + position:relative; + max-height:100%; + } + .ReactTable { + position: absolute; + display: inline-block; + width: 100%; + overflow: auto; + height: 100%; + background: white; + box-sizing: border-box; + } + .ReactTable .rt-thead.-header { + background:grey; + } + .ReactTable .rt-th, .ReactTable .rt-td { + max-height: 75px; + } + .ReactTable .rt-tbody .rt-tr-group:last-child { + border-bottom: grey; + border-bottom-style: solid; + border-bottom-width: 1; + } + .ReactTable .rt-td { + border-width: 1; + border-right-color: #aaa + } + .ReactTable .rt-tr-group { + border-width: 1; + border-bottom-color: #aaa + } + .imageBox-cont img { + object-fit: contain; + height: 100% + } + .documentView-node:first-child { + background: grey; + .imageBox-cont img { + object-fit: contain; + max-width: 100%; + height: 100% + } + } +} + .Resizer { box-sizing: border-box; background: #000; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index adae8560e..9a0ce0782 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -7,14 +7,15 @@ import { observable, action, computed } from "mobx"; import SplitPane from "react-split-pane" import "./CollectionSchemaView.scss" import { ScrollBox } from "../../util/ScrollBox"; -import { CollectionViewBase } from "./CollectionViewBase"; +import { CollectionViewBase, COLLECTION_BORDER_WIDTH } from "./CollectionViewBase"; import { DocumentView } from "../nodes/DocumentView"; import { EditableView } from "../EditableView"; import { CompileScript, ToField } from "../../util/Scripting"; -import { KeyStore as KS, Key } from "../../../fields/Key"; +import { KeyStore as KS, Key, KeyStore } from "../../../fields/Key"; import { Document } from "../../../fields/Document"; import { Field } from "../../../fields/Field"; import { Transform } from "../../util/Transform"; +import Measure from "react-measure"; @observer export class CollectionSchemaView extends CollectionViewBase { @@ -34,7 +35,7 @@ export class CollectionSchemaView extends CollectionViewBase { <FieldView {...props} /> ) return ( - <EditableView contents={contents} GetValue={() => { + <EditableView contents={contents} height={36} GetValue={() => { let field = props.doc.Get(props.fieldKey); if (field && field instanceof Field) { return field.ToScriptString(); @@ -99,52 +100,63 @@ export class CollectionSchemaView extends CollectionViewBase { } } + + @observable + private _parentScaling = 1; // used to transfer the dimensions of the content pane in the DOM to the ParentScaling prop of the DocumentView render() { const { DocumentForCollection: Document, CollectionFieldKey: fieldKey } = this.props; const children = Document.GetList<Document>(fieldKey, []); const columns = Document.GetList(KS.ColumnsKey, [KS.Title, KS.Data, KS.Author]) let content; + var me = this; if (this.selectedIndex != -1) { content = ( - <DocumentView Document={children[this.selectedIndex]} - AddDocument={this.addDocument} RemoveDocument={this.removeDocument} - GetTransform={() => Transform.Identity}//TODO This should probably be an actual transform - Scaling={1} - isTopMost={false} - DocumentView={undefined} ContainingCollectionView={this} /> + <Measure onResize={action((r: any) => { + var doc = children[this.selectedIndex]; + var n = doc.GetNumber(KeyStore.NativeWidth, 0); + if (n > 0 && r.entry.width > 0) { + this._parentScaling = r.entry.width / n; + } + })}> + {({ measureRef }) => + <div ref={measureRef}> + <DocumentView Document={children[this.selectedIndex]} + AddDocument={this.addDocument} RemoveDocument={this.removeDocument} + ScreenToLocalTransform={() => Transform.Identity}//TODO This should probably be an actual transform + Scaling={this._parentScaling} + isTopMost={false} + DocumentView={undefined} ContainingCollectionView={me} /> + </div> + } + </Measure> ) } else { content = <div /> } return ( - <div onPointerDown={this.onPointerDown} > - <SplitPane split={"vertical"} defaultSize="60%"> - <ScrollBox> - <ReactTable - data={children} - pageSize={children.length} - page={0} - showPagination={false} - style={{ - display: "inline-block", - width: "100%" - }} - columns={columns.map(col => { - return ( - { - Header: col.Name, - accessor: (doc: Document) => [doc, col], - id: col.Id - }) - })} - column={{ - ...ReactTableDefaults.column, - Cell: this.renderCell - }} - getTrProps={this.getTrProps} - /> - </ScrollBox> + <div onPointerDown={this.onPointerDown} className="collectionSchemaView-container" + style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px`, }} > + <SplitPane split={"vertical"} defaultSize="60%" style={{ height: "100%", position: "relative", overflow: "none" }}> + <ReactTable + data={children} + pageSize={children.length} + page={0} + showPagination={false} + columns={columns.map(col => { + return ( + { + Header: col.Name, + accessor: (doc: Document) => [doc, col], + id: col.Id + }) + })} + column={{ + ...ReactTableDefaults.column, + Cell: this.renderCell + }} + getTrProps={this.getTrProps} + /> {content} </SplitPane> </div> diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 2c950c8ae..4cbafe950 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -17,12 +17,12 @@ export interface CollectionViewProps { CollectionFieldKey: Key; DocumentForCollection: Document; ContainingDocumentView: Opt<DocumentView>; - GetTransform: () => Transform; + ScreenToLocalTransform: () => Transform; isSelected: () => boolean; isTopMost: boolean; select: (ctrlPressed: boolean) => void; - BackgroundView: Opt<DocumentView>; - Scaling: number; + BackgroundView?: () => JSX.Element; + ParentScaling: number; } export const COLLECTION_BORDER_WIDTH = 2; @@ -32,7 +32,7 @@ export class CollectionViewBase extends React.Component<CollectionViewProps> { public static LayoutString(collectionType: string, fieldKey: string = "DataKey") { return `<${collectionType} Scaling={Scaling} DocumentForCollection={Document} - GetTransform={GetTransform} CollectionFieldKey={${fieldKey}} isSelected={isSelected} select={select} + ScreenToLocalTransform={ScreenToLocalTransform} CollectionFieldKey={${fieldKey}} isSelected={isSelected} select={select} isTopMost={isTopMost} ContainingDocumentView={DocumentView} BackgroundView={BackgroundView} />`; } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index f10d8680f..57527076b 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -7,7 +7,7 @@ import { SelectionManager } from "../../util/SelectionManager"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import { CollectionFreeFormView } from "../collections/CollectionFreeFormView"; import { ContextMenu } from "../ContextMenu"; -import "./NodeView.scss"; +import "./DocumentView.scss"; import React = require("react"); import { DocumentView, DocumentViewProps } from "./DocumentView"; import { Transform } from "../../util/Transform"; @@ -28,26 +28,8 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView } @computed - get x(): number { - return this.props.Document.GetData(KeyStore.X, NumberField, Number(0)); - } - - @computed - get y(): number { - return this.props.Document.GetData(KeyStore.Y, NumberField, Number(0)); - } - - set x(x: number) { - this.props.Document.SetData(KeyStore.X, x, NumberField) - } - - set y(y: number) { - this.props.Document.SetData(KeyStore.Y, y, NumberField) - } - - @computed get transform(): string { - return `scale(${this.props.Scaling}, ${this.props.Scaling}) translate(${this.x}px, ${this.y}px)`; + return `scale(${this.props.Scaling}, ${this.props.Scaling}) translate(${this.props.Document.GetNumber(KeyStore.X, 0)}px, ${this.props.Document.GetNumber(KeyStore.Y, 0)}px)`; } @computed @@ -85,7 +67,7 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView @computed get zIndex(): number { - return this.props.Document.GetData(KeyStore.ZIndex, NumberField, Number(0)); + return this.props.Document.GetNumber(KeyStore.ZIndex, 0); } set zIndex(h: number) { @@ -94,23 +76,23 @@ export class CollectionFreeFormDocumentView extends React.Component<DocumentView getTransform = (): Transform => { - return new Transform(-this.x, -this.y, 1).transform(this.props.GetTransform()); + return this.props.ScreenToLocalTransform().translate(-this.props.Document.GetNumber(KeyStore.X, 0), -this.props.Document.GetNumber(KeyStore.Y, 0)); } render() { - var freestyling = this.props.ContainingCollectionView instanceof CollectionFreeFormView; + var parentScaling = this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; return ( - <div className="node" ref={this._mainCont} style={{ + <div ref={this._mainCont} style={{ transformOrigin: "left top", - transform: freestyling ? this.transform : "", - width: freestyling ? this.width : "100%", - height: freestyling ? this.height : "100%", - position: freestyling ? "absolute" : "relative", - zIndex: freestyling ? this.zIndex : 0, + transform: this.transform, + width: this.width, + height: this.height, + position: "absolute", + zIndex: this.zIndex, backgroundColor: "transparent" }} > - <DocumentView {...this.props} Scaling={this.width / this.nativeWidth} GetTransform={this.getTransform} /> + <DocumentView {...this.props} Scaling={this.width / this.nativeWidth} ScreenToLocalTransform={this.getTransform} /> </div> ); } diff --git a/src/client/views/nodes/NodeView.scss b/src/client/views/nodes/DocumentView.scss index 5615ecafd..5f7e6ff17 100644 --- a/src/client/views/nodes/NodeView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -1,4 +1,4 @@ -.node { +.documentView-node { position: absolute; background: #cdcdcd; overflow: hidden; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 8dc54f22a..9bd8c0288 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -5,8 +5,6 @@ import { Document } from "../../../fields/Document"; import { Opt, FieldWaiting } from "../../../fields/Field"; import { Key, KeyStore } from "../../../fields/Key"; import { ListField } from "../../../fields/ListField"; -import { NumberField } from "../../../fields/NumberField"; -import { TextField } from "../../../fields/TextField"; import { Utils } from "../../../Utils"; import { CollectionDockingView } from "../collections/CollectionDockingView"; import { CollectionFreeFormView } from "../collections/CollectionFreeFormView"; @@ -14,13 +12,14 @@ import { CollectionSchemaView } from "../collections/CollectionSchemaView"; import { CollectionViewBase, COLLECTION_BORDER_WIDTH } from "../collections/CollectionViewBase"; import { FormattedTextBox } from "../nodes/FormattedTextBox"; import { ImageBox } from "../nodes/ImageBox"; -import "./NodeView.scss"; +import "./DocumentView.scss"; import React = require("react"); import { Transform } from "../../util/Transform"; import { DocumentManager } from "../DocumentManager"; import { SelectionManager } from "../../util/SelectionManager"; import { DragManager } from "../../util/DragManager"; import { ContextMenu } from "../ContextMenu"; +import { TextField } from "../../../fields/TextField"; const JsxParser = require('react-jsx-parser').default;//TODO Why does this need to be imported like this? export interface DocumentViewProps { @@ -30,7 +29,7 @@ export interface DocumentViewProps { Document: Document; AddDocument?: (doc: Document) => void; RemoveDocument?: (doc: Document) => boolean; - GetTransform: () => Transform; + ScreenToLocalTransform: () => Transform; isTopMost: boolean; Scaling: number; } @@ -60,7 +59,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { } @computed get layout(): string { - return this.props.Document.GetData(KeyStore.Layout, TextField, String("<p>Error loading layout data</p>")); + return this.props.Document.GetText(KeyStore.Layout, "<p>Error loading layout data</p>"); } @computed @@ -130,7 +129,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { this._contextMenuCanOpen = false; if (this._mainCont.current != null && !this.topMost) { this._contextMenuCanOpen = false; - const [left, top] = this.props.GetTransform().inverse().transformPoint(0, 0); + const [left, top] = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); let dragData: { [id: string]: any } = {}; dragData["document"] = this; dragData["xOffset"] = e.x - left; @@ -251,7 +250,6 @@ export class DocumentView extends React.Component<DocumentViewProps> { SelectionManager.SelectDoc(this, ctrlPressed) } - render() { let bindings = { ...this.props } as any; bindings.isSelected = this.isSelected; @@ -259,32 +257,33 @@ export class DocumentView extends React.Component<DocumentViewProps> { for (const key of this.layoutKeys) { bindings[key.Name + "Key"] = key; // this maps string values of the form <keyname>Key to an actual key Kestore.keyname e.g, "DataKey" => KeyStore.Data } - if (!bindings.GetTransform) { - console.log("test"); - } for (const key of this.layoutFields) { let field = this.props.Document.Get(key); bindings[key.Name] = field && field != FieldWaiting ? field.GetValue() : field; } - let annotated = null; + /* + Should this be moved to CollectionFreeformView or another component that renders + Document backgrounds (or contents based on a layout key, which could be used here as well) + that CollectionFreeformView uses? It seems like a lot for it to be here considering only one view currently uses it... + */ let backgroundLayout = this.backgroundLayout; if (backgroundLayout) { - annotated = <JsxParser + let backgroundView = () => (<JsxParser components={{ FormattedTextBox, ImageBox, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView }} bindings={bindings} jsx={this.backgroundLayout} showWarnings={true} onError={(test: any) => { console.log(test) }} - />; + />); + bindings.BackgroundView = backgroundView; } - bindings.BackgroundView = annotated; var width = this.props.Document.GetNumber(KeyStore.NativeWidth, 0); var strwidth = width > 0 ? width.toString() + "px" : "100%"; var height = this.props.Document.GetNumber(KeyStore.NativeHeight, 0); var strheight = height > 0 ? height.toString() + "px" : "100%"; return ( - <div className="node" ref={this._mainCont} style={{ borderColor: this.Border, width: strwidth, height: strheight, transformOrigin: "left top", transform: `scale(${this.props.Scaling},${this.props.Scaling})` }} + <div className="documentView-node" ref={this._mainCont} style={{ borderColor: this.Border, width: strwidth, height: strheight, transformOrigin: "left top", transform: `scale(${this.props.Scaling},${this.props.Scaling})` }} onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} > <JsxParser diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss index 492367fce..5139d5d6b 100644 --- a/src/client/views/nodes/FormattedTextBox.scss +++ b/src/client/views/nodes/FormattedTextBox.scss @@ -9,6 +9,6 @@ } .formattedTextBox-cont { - background: white; + background: beige; padding: 1vw; }
\ No newline at end of file diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss index 2bd8b1d3c..36f5e0fe0 100644 --- a/src/client/views/nodes/ImageBox.scss +++ b/src/client/views/nodes/ImageBox.scss @@ -2,7 +2,13 @@ .imageBox-cont { padding: 0vw; position: absolute; - width: 100% + width: 100%; + max-width: 100%; + max-height: 100% +} +.imageBox-cont img { + max-width: 100%; + max-height: 100% } .imageBox-button { |