From f783e6cd66d4a7e303bd327d028076e3d76815bc Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 17 Jan 2020 11:45:49 -0500 Subject: drop target added to mc view --- src/client/views/collections/CollectionMulticolumnView.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMulticolumnView.tsx b/src/client/views/collections/CollectionMulticolumnView.tsx index 157c5e367..4744de34c 100644 --- a/src/client/views/collections/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/CollectionMulticolumnView.tsx @@ -36,6 +36,7 @@ const resizerWidth = 2; @observer export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) { + @computed private get resolvedLayoutInformation(): LayoutData { const unresolved: Unresolved[] = []; @@ -84,8 +85,9 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu @computed private get totalRatioAllocation(): number | undefined { const layoutInfoLen = this.resolvedLayoutInformation?.unresolved.length; - if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) + if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) { return this.props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)); + } } /** @@ -153,7 +155,10 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu render(): JSX.Element { return ( -
+
{this.contents}
); -- cgit v1.2.3-70-g09d2 From 203ec5b3570c96f22b1d9517770e36c695677f5e Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 17 Jan 2020 13:14:22 -0500 Subject: multicolumn performance improvements and refactor --- .../collections/CollectionMulticolumnView.scss | 2 +- .../collections/CollectionMulticolumnView.tsx | 149 ++++++++++++++------- 2 files changed, 105 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMulticolumnView.scss b/src/client/views/collections/CollectionMulticolumnView.scss index 120603a0b..a54af748b 100644 --- a/src/client/views/collections/CollectionMulticolumnView.scss +++ b/src/client/views/collections/CollectionMulticolumnView.scss @@ -4,7 +4,7 @@ height: 100%; overflow: hidden; - .fish { + .document-wrapper { display: flex; flex-direction: column; diff --git a/src/client/views/collections/CollectionMulticolumnView.tsx b/src/client/views/collections/CollectionMulticolumnView.tsx index 51064d5c3..2cb91f239 100644 --- a/src/client/views/collections/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/CollectionMulticolumnView.tsx @@ -4,11 +4,12 @@ import { documentSchema } from '../../../new_fields/documentSchemas'; import { CollectionSubView } from './CollectionSubView'; import * as React from "react"; import { Doc } from '../../../new_fields/Doc'; -import { NumCast, StrCast } from '../../../new_fields/Types'; +import { NumCast, StrCast, BoolCast } from '../../../new_fields/Types'; import { ContentFittingDocumentView } from './../nodes/ContentFittingDocumentView'; import { Utils } from '../../../Utils'; import "./collectionMulticolumnView.scss"; -import { computed } from 'mobx'; +import { computed, trace } from 'mobx'; +import { Transform } from '../../util/Transform'; type MulticolumnDocument = makeInterface<[typeof documentSchema]>; const MulticolumnDocument = makeInterface(documentSchema); @@ -33,17 +34,24 @@ interface LayoutData { const resolvedUnits = ["*", "px"]; const resizerWidth = 2; +const resizerOpacity = 0.4; @observer export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) { + @computed + private get ratioDefinedDocs() { + return this.childLayoutPairs.map(({ layout }) => layout).filter(({ widthUnit }) => StrCast(widthUnit) === "*"); + } + @computed private get resolvedLayoutInformation(): LayoutData { const unresolved: Unresolved[] = []; let starSum = 0, numFixed = 0, numRatio = 0; - for (const pair of this.childLayoutPairs) { - const unit = StrCast(pair.layout.widthUnit); - const magnitude = NumCast(pair.layout.widthMagnitude); + + for (const { layout } of this.childLayoutPairs) { + const unit = StrCast(layout.widthUnit); + const magnitude = NumCast(layout.widthMagnitude); if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) { if (unit === "*") { starSum += magnitude; @@ -51,11 +59,17 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu } else { numFixed++; } - unresolved.push({ target: pair.layout, magnitude, unit }); + unresolved.push({ target: layout, magnitude, unit }); } // otherwise, the particular configuration entry is ignored and the remaining // space is allocated as if the document were absent from the configuration list } + + setTimeout(() => { + const minimum = Math.min(...this.ratioDefinedDocs.map(({ widthMagnitude }) => NumCast(widthMagnitude))); + this.ratioDefinedDocs.forEach(layout => layout.widthMagnitude = NumCast(layout.widthMagnitude) / minimum); + }); + return { unresolved, numRatio, numFixed, starSum }; } @@ -109,48 +123,68 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu } } - @computed - private get contents(): JSX.Element[] | null { - const layout = this.resolvedLayoutInformation; + private getColumnUnitLength = () => this.columnUnitLength; + + private lookupPixels = (layout: Doc): number => { const columnUnitLength = this.columnUnitLength; - if (layout === null || columnUnitLength === undefined) { - return (null); // we're still waiting on promises to resolve + if (columnUnitLength === undefined) { + return 0; // we're still waiting on promises to resolve } - const resolved: Resolved[] = []; - layout.unresolved.forEach(item => { - const { unit, magnitude, ...remaining } = item; - let width = magnitude; - if (unit === "*") { - width = magnitude * columnUnitLength; + let width = NumCast(layout.widthMagnitude); + if (StrCast(layout.widthUnit) === "*") { + width *= columnUnitLength; + } + return width; + } + + private lookupIndividualTransform = (layout: Doc) => { + const columnUnitLength = this.columnUnitLength; + if (columnUnitLength === undefined) { + return Transform.Identity(); // we're still waiting on promises to resolve + } + let offset = 0; + for (const { layout: candidate } of this.childLayoutPairs) { + if (candidate === layout) { + const shift = offset; + return this.props.ScreenToLocalTransform().translate(-shift, 0); } - resolved.push({ pixels: width, ...remaining }); - }); + offset += this.lookupPixels(candidate) + resizerWidth; + } + return Transform.Identity(); // type coersion, this case should never be hit + } + + @computed + private get contents(): JSX.Element[] | null { + trace(); + const { childLayoutPairs } = this; + const { Document, PanelHeight } = this.props; const collector: JSX.Element[] = []; - let offset = 0; - for (let i = 0; i < resolved.length; i++) { - const { target, pixels } = resolved[i]; - const shiftX = offset; + for (let i = 0; i < childLayoutPairs.length; i++) { + const { layout } = childLayoutPairs[i]; collector.push( -
+
pixels} - getTransform={() => this.props.ScreenToLocalTransform().translate(-shiftX, 0)} + Document={layout} + DataDocument={layout.resolvedDataDoc as Doc} + PanelWidth={() => this.lookupPixels(layout)} + PanelHeight={() => PanelHeight() - (BoolCast(Document.showWidthLabels) ? 20 : 0)} + getTransform={() => this.lookupIndividualTransform(layout)} + /> + - {NumCast(target.widthMagnitude).toFixed(3)} {StrCast(target.widthUnit)}
, ); - offset += pixels + resizerWidth; } collector.pop(); // removes the final extraneous resize bar return collector; @@ -171,11 +205,35 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu interface SpacerProps { width: number; - columnUnitLength: number; + columnUnitLength(): number | undefined; toLeft?: Doc; toRight?: Doc; } +interface WidthLabelProps { + layout: Doc; + collectionDoc: Doc; + decimals?: number; +} + +@observer +class WidthLabel extends React.Component { + + @computed + private get contents() { + const { layout, decimals } = this.props; + const magnitude = NumCast(layout.widthMagnitude).toFixed(decimals ?? 3); + const unit = StrCast(layout.widthUnit); + return {magnitude} {unit}; + } + + render() { + return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : (null); + } + +} + +@observer class ResizeBar extends React.Component { private registerResizing = (e: React.PointerEvent) => { @@ -190,33 +248,34 @@ class ResizeBar extends React.Component { private onPointerMove = ({ movementX }: PointerEvent) => { const { toLeft, toRight, columnUnitLength } = this.props; const target = movementX > 0 ? toRight : toLeft; - if (target) { + const unitLength = columnUnitLength(); + if (target && unitLength) { const { widthUnit, widthMagnitude } = target; if (widthUnit === "*") { - target.widthMagnitude = NumCast(widthMagnitude) - Math.abs(movementX) / columnUnitLength; + target.widthMagnitude = NumCast(widthMagnitude) - Math.abs(movementX) / unitLength; } } } - private get opacity() { + private get isActivated() { const { toLeft, toRight } = this.props; if (toLeft && toRight) { if (StrCast(toLeft.widthUnit) === "px" && StrCast(toRight.widthUnit) === "px") { - return 0; + return false; } - return 0.4; + return true; } else if (toLeft) { if (StrCast(toLeft.widthUnit) === "px") { - return 0; + return false; } - return 0.4; + return true; } else if (toRight) { if (StrCast(toRight.widthUnit) === "px") { - return 0; + return false; } - return 0.4; + return true; } - return 0; + return false; } private onPointerUp = () => { @@ -230,7 +289,7 @@ class ResizeBar extends React.Component { className={"resizer"} style={{ width: this.props.width, - opacity: this.opacity + opacity: this.isActivated ? resizerOpacity : 0 }} onPointerDown={this.registerResizing} /> -- cgit v1.2.3-70-g09d2 From 9620d149a2051bc9b42a037b1c65b61deebd11fa Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 17 Jan 2020 15:27:39 -0500 Subject: scale mc view --- src/client/views/collections/CollectionMulticolumnView.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMulticolumnView.tsx b/src/client/views/collections/CollectionMulticolumnView.tsx index 2cb91f239..955e87f13 100644 --- a/src/client/views/collections/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/CollectionMulticolumnView.tsx @@ -248,12 +248,11 @@ class ResizeBar extends React.Component { private onPointerMove = ({ movementX }: PointerEvent) => { const { toLeft, toRight, columnUnitLength } = this.props; const target = movementX > 0 ? toRight : toLeft; - const unitLength = columnUnitLength(); - if (target && unitLength) { + let scale = columnUnitLength(); + if (target && scale) { const { widthUnit, widthMagnitude } = target; - if (widthUnit === "*") { - target.widthMagnitude = NumCast(widthMagnitude) - Math.abs(movementX) / unitLength; - } + scale = widthUnit === "*" ? scale : 1; + target.widthMagnitude = NumCast(widthMagnitude) - Math.abs(movementX) / scale; } } -- cgit v1.2.3-70-g09d2 From d4068447e5b6aab667930398bfe8b285282cffdb Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 17 Jan 2020 15:58:40 -0500 Subject: show resizers on hover --- .../collections/CollectionMulticolumnView.scss | 1 + .../collections/CollectionMulticolumnView.tsx | 62 ++++++++++++---------- 2 files changed, 36 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionMulticolumnView.scss b/src/client/views/collections/CollectionMulticolumnView.scss index a54af748b..acb194983 100644 --- a/src/client/views/collections/CollectionMulticolumnView.scss +++ b/src/client/views/collections/CollectionMulticolumnView.scss @@ -18,6 +18,7 @@ .resizer { background: black; cursor: ew-resize; + transition: 0.5s opacity ease; } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionMulticolumnView.tsx b/src/client/views/collections/CollectionMulticolumnView.tsx index 955e87f13..ebe033d1f 100644 --- a/src/client/views/collections/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/CollectionMulticolumnView.tsx @@ -1,14 +1,14 @@ import { observer } from 'mobx-react'; import { makeInterface } from '../../../new_fields/Schema'; import { documentSchema } from '../../../new_fields/documentSchemas'; -import { CollectionSubView } from './CollectionSubView'; +import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView'; import * as React from "react"; import { Doc } from '../../../new_fields/Doc'; import { NumCast, StrCast, BoolCast } from '../../../new_fields/Types'; import { ContentFittingDocumentView } from './../nodes/ContentFittingDocumentView'; import { Utils } from '../../../Utils'; import "./collectionMulticolumnView.scss"; -import { computed, trace } from 'mobx'; +import { computed, trace, observable, action } from 'mobx'; import { Transform } from '../../util/Transform'; type MulticolumnDocument = makeInterface<[typeof documentSchema]>; @@ -34,7 +34,7 @@ interface LayoutData { const resolvedUnits = ["*", "px"]; const resizerWidth = 2; -const resizerOpacity = 0.4; +const resizerOpacity = 1; @observer export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) { @@ -210,31 +210,10 @@ interface SpacerProps { toRight?: Doc; } -interface WidthLabelProps { - layout: Doc; - collectionDoc: Doc; - decimals?: number; -} - -@observer -class WidthLabel extends React.Component { - - @computed - private get contents() { - const { layout, decimals } = this.props; - const magnitude = NumCast(layout.widthMagnitude).toFixed(decimals ?? 3); - const unit = StrCast(layout.widthUnit); - return {magnitude} {unit}; - } - - render() { - return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : (null); - } - -} - @observer class ResizeBar extends React.Component { + @observable private isHoverActive = false; + private isResizingActive = false; private registerResizing = (e: React.PointerEvent) => { e.stopPropagation(); @@ -257,6 +236,7 @@ class ResizeBar extends React.Component { } private get isActivated() { + this.isResizingActive = true; const { toLeft, toRight } = this.props; if (toLeft && toRight) { if (StrCast(toLeft.widthUnit) === "px" && StrCast(toRight.widthUnit) === "px") { @@ -277,7 +257,10 @@ class ResizeBar extends React.Component { return false; } + @action private onPointerUp = () => { + this.isResizingActive = false; + this.isHoverActive = false; window.removeEventListener("pointermove", this.onPointerMove); window.removeEventListener("pointerup", this.onPointerUp); } @@ -288,11 +271,36 @@ class ResizeBar extends React.Component { className={"resizer"} style={{ width: this.props.width, - opacity: this.isActivated ? resizerOpacity : 0 + opacity: this.isActivated && this.isHoverActive ? resizerOpacity : 0 }} onPointerDown={this.registerResizing} + onPointerEnter={action(() => this.isHoverActive = true)} + onPointerLeave={action(() => !this.isResizingActive && (this.isHoverActive = false))} /> ); } +} + +interface WidthLabelProps { + layout: Doc; + collectionDoc: Doc; + decimals?: number; +} + +@observer +class WidthLabel extends React.Component { + + @computed + private get contents() { + const { layout, decimals } = this.props; + const magnitude = NumCast(layout.widthMagnitude).toFixed(decimals ?? 3); + const unit = StrCast(layout.widthUnit); + return {magnitude} {unit}; + } + + render() { + return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : (null); + } + } \ No newline at end of file -- cgit v1.2.3-70-g09d2