aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSam Wilkins <samwilkins333@gmail.com>2020-01-17 13:14:22 -0500
committerSam Wilkins <samwilkins333@gmail.com>2020-01-17 13:14:22 -0500
commit203ec5b3570c96f22b1d9517770e36c695677f5e (patch)
tree12159cc0caa3f06962e7f9d45e73271e86315250 /src
parentc0de8569d4d4dea83174a9d79e780d9d9f5692d7 (diff)
multicolumn performance improvements and refactor
Diffstat (limited to 'src')
-rw-r--r--src/client/views/collections/CollectionMulticolumnView.scss2
-rw-r--r--src/client/views/collections/CollectionMulticolumnView.tsx149
2 files changed, 105 insertions, 46 deletions
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(
- <div className={"fish"}>
+ <div className={"document-wrapper"}>
<ContentFittingDocumentView
{...this.props}
key={Utils.GenerateGuid()}
- Document={target}
- DataDocument={target.resolvedDataDoc as Doc}
- PanelWidth={() => 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)}
+ />
+ <WidthLabel
+ layout={layout}
+ collectionDoc={Document}
/>
- <span className={"display"}>{NumCast(target.widthMagnitude).toFixed(3)} {StrCast(target.widthUnit)}</span>
</div>,
<ResizeBar
width={resizerWidth}
key={Utils.GenerateGuid()}
- columnUnitLength={columnUnitLength}
- toLeft={target}
- toRight={resolved[i + 1]?.target}
+ columnUnitLength={this.getColumnUnitLength}
+ toLeft={layout}
+ toRight={childLayoutPairs[i + 1]?.layout}
/>
);
- 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<WidthLabelProps> {
+
+ @computed
+ private get contents() {
+ const { layout, decimals } = this.props;
+ const magnitude = NumCast(layout.widthMagnitude).toFixed(decimals ?? 3);
+ const unit = StrCast(layout.widthUnit);
+ return <span className={"display"}>{magnitude} {unit}</span>;
+ }
+
+ render() {
+ return BoolCast(this.props.collectionDoc.showWidthLabels) ? this.contents : (null);
+ }
+
+}
+
+@observer
class ResizeBar extends React.Component<SpacerProps> {
private registerResizing = (e: React.PointerEvent<HTMLDivElement>) => {
@@ -190,33 +248,34 @@ class ResizeBar extends React.Component<SpacerProps> {
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<SpacerProps> {
className={"resizer"}
style={{
width: this.props.width,
- opacity: this.opacity
+ opacity: this.isActivated ? resizerOpacity : 0
}}
onPointerDown={this.registerResizing}
/>