aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx92
1 files changed, 62 insertions, 30 deletions
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index e57e5eb26..d2209224f 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -16,16 +16,13 @@ import ResizeBar from './MulticolumnResizer';
type MulticolumnDocument = makeInterface<[typeof documentSchema]>;
const MulticolumnDocument = makeInterface(documentSchema);
-interface Unresolved {
- target: Doc;
+interface WidthSpecifier {
magnitude: number;
unit: string;
}
interface LayoutData {
- unresolved: Unresolved[];
- numFixed: number;
- numRatio: number;
+ widthSpecifiers: WidthSpecifier[];
starSum: number;
}
@@ -35,42 +32,57 @@ const resizerWidth = 4;
@observer
export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocument) {
+ /**
+ * @returns the list of layout documents whose width unit is
+ * *, denoting that it will be displayed with a ratio, not fixed pixel, value
+ */
@computed
private get ratioDefinedDocs() {
return this.childLayoutPairs.map(({ layout }) => layout).filter(({ widthUnit }) => StrCast(widthUnit) === "*");
}
+ /**
+ * This loops through all childLayoutPairs and extracts the values for widthUnit
+ * and widthMagnitude, ignoring any that are malformed. Additionally, it then
+ * normalizes the ratio values so that one * value is always 1, with the remaining
+ * values proportionate to that easily readable metric.
+ * @returns the list of the resolved width specifiers (unit and magnitude pairs)
+ * as well as the sum of the * coefficients, i.e. the ratio magnitudes
+ */
@computed
private get resolvedLayoutInformation(): LayoutData {
- const unresolved: Unresolved[] = [];
- let starSum = 0, numFixed = 0, numRatio = 0;
-
- for (const { layout } of this.childLayoutPairs) {
- const unit = StrCast(layout.widthUnit);
- const magnitude = NumCast(layout.widthMagnitude);
+ let starSum = 0;
+ const widthSpecifiers: WidthSpecifier[] = [];
+ this.childLayoutPairs.map(({ layout: { widthUnit, widthMagnitude } }) => {
+ const unit = StrCast(widthUnit);
+ const magnitude = NumCast(widthMagnitude);
if (unit && magnitude && magnitude > 0 && resolvedUnits.includes(unit)) {
- if (unit === "*") {
- starSum += magnitude;
- numRatio++;
- } else {
- numFixed++;
- }
- unresolved.push({ target: layout, magnitude, unit });
+ (unit === "*") && (starSum += magnitude);
+ widthSpecifiers.push({ 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
- }
-
+ /**
+ * Otherwise, the child document is ignored and the remaining
+ * space is allocated as if the document were absent from the child list
+ */
+ });
+ /**
+ * Here, since these values are all relative, adjustments during resizing or
+ * manual updating can, though their ratios remain the same, cause the values
+ * themselves to drift toward zero. Thus, whenever we change any of the values,
+ * we normalize everything (dividing by the smallest magnitude).
+ */
setTimeout(() => {
const { ratioDefinedDocs } = this;
if (ratioDefinedDocs.length > 1) {
const minimum = Math.min(...ratioDefinedDocs.map(({ widthMagnitude }) => NumCast(widthMagnitude)));
- ratioDefinedDocs.forEach(layout => layout.widthMagnitude = NumCast(layout.widthMagnitude) / minimum);
+ if (minimum !== 0) {
+ ratioDefinedDocs.forEach(layout => layout.widthMagnitude = NumCast(layout.widthMagnitude) / minimum);
+ }
}
});
- return { unresolved, numRatio, numFixed, starSum };
+ return { widthSpecifiers, starSum };
}
/**
@@ -83,12 +95,12 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
*/
@computed
private get totalFixedAllocation(): number | undefined {
- return this.resolvedLayoutInformation?.unresolved.reduce(
+ return this.resolvedLayoutInformation?.widthSpecifiers.reduce(
(sum, { magnitude, unit }) => sum + (unit === "px" ? magnitude : 0), 0);
}
/**
- * This returns the total quantity, in pixels, that this
+ * @returns the total quantity, in pixels, that this
* view needs to reserve for child documents that have
* (with lower priority) requested a certain relative proportion of the
* remaining pixel width not allocated for fixed widths.
@@ -98,14 +110,14 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
*/
@computed
private get totalRatioAllocation(): number | undefined {
- const layoutInfoLen = this.resolvedLayoutInformation?.unresolved.length;
+ const layoutInfoLen = this.ratioDefinedDocs.length;
if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) {
return this.props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1));
}
}
/**
- * This returns the total quantity, in pixels, that
+ * @returns the total quantity, in pixels, that
* 1* (relative / star unit) is worth. For example,
* if the configuration has three documents, with, respectively,
* widths of 2*, 2* and 1*, and the panel width returns 1000px,
@@ -123,8 +135,19 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
}
}
+ /**
+ * This wrapper function exists to prevent mobx from
+ * needlessly rerendering the internal ContentFittingDocumentViews
+ */
private getColumnUnitLength = () => this.columnUnitLength;
+ /**
+ * @param layout the document whose transform we'd like to compute
+ * Given a layout document, this function
+ * returns the resolved width it has requested, in pixels.
+ * @returns the stored column width if already in pixels,
+ * or the ratio width evaluated to a pixel value
+ */
private lookupPixels = (layout: Doc): number => {
const columnUnitLength = this.columnUnitLength;
if (columnUnitLength === undefined) {
@@ -137,6 +160,12 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
return width;
}
+ /**
+ * @returns the transform that will correctly place
+ * the document decorations box, shifted to the right by
+ * the sum of all the resolved column widths of the
+ * documents before the target.
+ */
private lookupIndividualTransform = (layout: Doc) => {
const columnUnitLength = this.columnUnitLength;
if (columnUnitLength === undefined) {
@@ -145,14 +174,17 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
let offset = 0;
for (const { layout: candidate } of this.childLayoutPairs) {
if (candidate === layout) {
- const shift = offset;
- return this.props.ScreenToLocalTransform().translate(-shift, 0);
+ return this.props.ScreenToLocalTransform().translate(-offset, 0);
}
offset += this.lookupPixels(candidate) + resizerWidth;
}
return Transform.Identity(); // type coersion, this case should never be hit
}
+ /**
+ * @returns the resolved list of rendered child documents, displayed
+ * at their resolved pixel widths, each separated by a resizer.
+ */
@computed
private get contents(): JSX.Element[] | null {
const { childLayoutPairs } = this;