@macrostrat/column-views 3.8.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +100 -0
- package/dist/animated-age-window.cjs +51 -0
- package/dist/animated-age-window.cjs.map +1 -0
- package/dist/animated-age-window.d.ts +51 -0
- package/dist/animated-age-window.js +51 -0
- package/dist/animated-age-window.js.map +1 -0
- package/dist/column.cjs +11 -1
- package/dist/column.cjs.map +1 -1
- package/dist/column.d.ts +11 -0
- package/dist/column.js +11 -1
- package/dist/column.js.map +1 -1
- package/dist/correlation-chart/main.cjs +24 -12
- package/dist/correlation-chart/main.cjs.map +1 -1
- package/dist/correlation-chart/main.d.ts +8 -1
- package/dist/correlation-chart/main.js +24 -12
- package/dist/correlation-chart/main.js.map +1 -1
- package/dist/data-provider/store.cjs +17 -4
- package/dist/data-provider/store.cjs.map +1 -1
- package/dist/data-provider/store.d.ts +6 -1
- package/dist/data-provider/store.js +17 -4
- package/dist/data-provider/store.js.map +1 -1
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/prepare-units/composite-scale.cjs +94 -8
- package/dist/prepare-units/composite-scale.cjs.map +1 -1
- package/dist/prepare-units/composite-scale.d.ts +39 -0
- package/dist/prepare-units/composite-scale.js +96 -10
- package/dist/prepare-units/composite-scale.js.map +1 -1
- package/dist/prepare-units/helpers.cjs +0 -1
- package/dist/prepare-units/helpers.cjs.map +1 -1
- package/dist/prepare-units/helpers.js +0 -1
- package/dist/prepare-units/helpers.js.map +1 -1
- package/dist/prepare-units/index.cjs +33 -12
- package/dist/prepare-units/index.cjs.map +1 -1
- package/dist/prepare-units/index.js +34 -13
- package/dist/prepare-units/index.js.map +1 -1
- package/dist/prepare-units/types.cjs.map +1 -1
- package/dist/prepare-units/types.d.ts +13 -0
- package/dist/prepare-units/types.js.map +1 -1
- package/dist/section.cjs +4 -2
- package/dist/section.cjs.map +1 -1
- package/dist/section.d.ts +4 -1
- package/dist/section.js +4 -2
- package/dist/section.js.map +1 -1
- package/dist/units/boxes.cjs +19 -36
- package/dist/units/boxes.cjs.map +1 -1
- package/dist/units/boxes.js +21 -38
- package/dist/units/boxes.js.map +1 -1
- package/dist/units/composite.cjs +12 -12
- package/dist/units/composite.cjs.map +1 -1
- package/dist/units/composite.js +12 -12
- package/dist/units/composite.js.map +1 -1
- package/package.json +6 -6
- package/src/animated-age-window.ts +120 -0
- package/src/column.ts +24 -0
- package/src/correlation-chart/main.ts +30 -8
- package/src/data-provider/store.ts +21 -2
- package/src/index.ts +1 -0
- package/src/prepare-units/composite-scale.ts +210 -10
- package/src/prepare-units/helpers.ts +0 -2
- package/src/prepare-units/index.ts +68 -14
- package/src/prepare-units/types.ts +13 -0
- package/src/section.ts +6 -0
- package/src/units/boxes.ts +30 -52
- package/src/units/composite.ts +21 -12
|
@@ -19,6 +19,12 @@ const unitSelection = require("../data-provider/unit-selection.cjs");
|
|
|
19
19
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
20
20
|
const classNames__default = /* @__PURE__ */ _interopDefault(classNames);
|
|
21
21
|
const chartPaddingH = 4;
|
|
22
|
+
const defaultCorrelationChartScaleProps = {
|
|
23
|
+
targetUnitHeight: 10,
|
|
24
|
+
unconformityHeight: 60,
|
|
25
|
+
minSectionHeight: 60,
|
|
26
|
+
collapseSmallUnconformities: true
|
|
27
|
+
};
|
|
22
28
|
function MainChartArea({ children }) {
|
|
23
29
|
const columnRef = unitSelection.useColumnRef();
|
|
24
30
|
return main_module.default("div.main-chart", { ref: columnRef }, children);
|
|
@@ -43,18 +49,14 @@ function CorrelationChart({
|
|
|
43
49
|
onClickTimescaleInterval,
|
|
44
50
|
onColumnMouseOver,
|
|
45
51
|
onColumnClick,
|
|
52
|
+
isTransitioning = false,
|
|
53
|
+
hideLabelsWhileTransitioning = false,
|
|
46
54
|
...scaleProps
|
|
47
55
|
}) {
|
|
48
|
-
const defaultScaleProps = {
|
|
49
|
-
targetUnitHeight: 10,
|
|
50
|
-
unconformityHeight: 60,
|
|
51
|
-
minSectionHeight: 60,
|
|
52
|
-
collapseSmallUnconformities: true
|
|
53
|
-
};
|
|
54
56
|
const chartData = React.useMemo(() => {
|
|
55
57
|
if (!data) return null;
|
|
56
58
|
return prepareData.buildCorrelationChartData(data, {
|
|
57
|
-
...
|
|
59
|
+
...defaultCorrelationChartScaleProps,
|
|
58
60
|
...scaleProps
|
|
59
61
|
});
|
|
60
62
|
}, [data, ...Object.values(scaleProps)]);
|
|
@@ -103,7 +105,9 @@ function CorrelationChart({
|
|
|
103
105
|
pixelScale,
|
|
104
106
|
scale,
|
|
105
107
|
unitComponent,
|
|
106
|
-
onColumnMouseOver
|
|
108
|
+
onColumnMouseOver,
|
|
109
|
+
isTransitioning,
|
|
110
|
+
hideLabelsWhileTransitioning
|
|
107
111
|
});
|
|
108
112
|
})
|
|
109
113
|
),
|
|
@@ -137,7 +141,9 @@ function Package({
|
|
|
137
141
|
domain,
|
|
138
142
|
pixelScale,
|
|
139
143
|
scale,
|
|
140
|
-
onColumnMouseOver
|
|
144
|
+
onColumnMouseOver,
|
|
145
|
+
isTransitioning,
|
|
146
|
+
hideLabelsWhileTransitioning
|
|
141
147
|
}) {
|
|
142
148
|
return main_module.default("g.package", { transform: `translate(0 ${offset})` }, [
|
|
143
149
|
// Disable the SVG overlay for now
|
|
@@ -154,7 +160,9 @@ function Package({
|
|
|
154
160
|
pixelScale,
|
|
155
161
|
scale,
|
|
156
162
|
offsetLeft: i * (columnWidth + columnSpacing),
|
|
157
|
-
onColumnMouseOver
|
|
163
|
+
onColumnMouseOver,
|
|
164
|
+
isTransitioning,
|
|
165
|
+
hideLabelsWhileTransitioning
|
|
158
166
|
});
|
|
159
167
|
})
|
|
160
168
|
])
|
|
@@ -170,7 +178,9 @@ function Column(props) {
|
|
|
170
178
|
pixelScale,
|
|
171
179
|
scale,
|
|
172
180
|
unitComponent = index.ColoredUnitComponent,
|
|
173
|
-
onColumnMouseOver
|
|
181
|
+
onColumnMouseOver,
|
|
182
|
+
isTransitioning,
|
|
183
|
+
hideLabelsWhileTransitioning
|
|
174
184
|
} = props;
|
|
175
185
|
const columnWidth = width;
|
|
176
186
|
if (units.length == 0) {
|
|
@@ -195,7 +205,9 @@ function Column(props) {
|
|
|
195
205
|
scale,
|
|
196
206
|
pixelsPerMeter: pixelScale,
|
|
197
207
|
// Actually pixels per myr
|
|
198
|
-
axisType: columnComponents.ColumnAxisType.AGE
|
|
208
|
+
axisType: columnComponents.ColumnAxisType.AGE,
|
|
209
|
+
isTransitioning,
|
|
210
|
+
hideLabelsWhileTransitioning
|
|
199
211
|
},
|
|
200
212
|
main_module.default(boxes.UnitBoxes, {
|
|
201
213
|
unitComponent,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.cjs","sources":["../../src/correlation-chart/main.ts"],"sourcesContent":["/** Correlation chart */\nimport {\n UnitSelectionProvider,\n UnitKeyboardNavigation,\n useUnitSelectionDispatch,\n useColumnRef,\n} from \"../data-provider\";\nimport { UnitDetailsFeature, UnitSelectionPopover } from \"../unit-details\";\nimport h from \"./main.module.sass\";\nimport { useMemo } from \"react\";\nimport { useInDarkMode } from \"@macrostrat/ui-components\";\nimport { CompositeTimescaleCore } from \"../section\";\nimport classNames from \"classnames\";\nimport {\n findLaterallyExtensiveUnits,\n splitStratIntoBoxes,\n UnitGroupBox,\n CorrelationChartSettings,\n buildCorrelationChartData,\n} from \"./prepare-data\";\nimport {\n CompositeAgeAxisCore,\n CompositeStratigraphicScaleInfo,\n} from \"../age-axis\";\nimport {\n ColumnAxisType,\n ColumnProvider,\n SVG,\n} from \"@macrostrat/column-components\";\nimport { ColoredUnitComponent } from \"../units\";\nimport { UnitBoxes } from \"../units/boxes\";\nimport { ColumnContainer } from \"../column\";\nimport type { ColumnData } from \"@macrostrat/data-provider\";\nimport { BaseUnit } from \"@macrostrat/api-types\";\nimport { ScaleContinuousNumeric } from \"d3-scale\";\nimport { ExtUnit } from \"../prepare-units/types\";\nimport type { TimescaleClickHandler } from \"@macrostrat/timescale\";\nimport { useMacrostratColumnInfo } from \"@macrostrat/data-provider\";\n\n/** Standard props passed to a `columnHeaderComponent`. Everything a header\n * needs is provided here, so the component can be a pure function of its props\n * (no hooks required). Column-level hover/click are handled by the chart. */\nexport interface ColumnHeaderProps {\n /** The column data (units + identifier) for this column */\n column: ColumnData;\n /** The column's ID (col_id) */\n columnID: number;\n /** The column's index (left-to-right) within the chart */\n columnIndex: number;\n /** The units within the column */\n units: ExtUnit[];\n /** The rendered width of the column, in pixels */\n width: number;\n /** The column's name, resolved from column metadata when available */\n columnName?: string | null;\n}\n\nexport interface CorrelationChartProps extends CorrelationChartSettings {\n data: ColumnData[];\n columnWidth?: number;\n columnSpacing?: number;\n targetUnitHeight?: number;\n unconformityLabels?: boolean;\n selectedUnit?: number | null;\n showUnitPopover?: boolean;\n unitComponent?: any;\n /** Arbitrary content (e.g. column title and/or ID) rendered above each column */\n columnHeaderComponent?: React.ComponentType<ColumnHeaderProps>;\n /** Content rendered above the timescale axis (top-left), beside the column\n * headers — e.g. a zoom/filter indicator. */\n axisTopContent?: React.ReactNode;\n onUnitSelected?: (unitID: number | null, unit: BaseUnit | null) => void;\n /** Called when a timescale interval is clicked (e.g. to zoom the age range) */\n onClickTimescaleInterval?: TimescaleClickHandler;\n /** Called when the pointer enters/leaves a column (header or body). Passes\n * the column ID, or null on leave. */\n onColumnMouseOver?: (columnID: number | null) => void;\n /** Called when a column header is clicked (e.g. to frame it on a map) */\n onColumnClick?: (columnID: number) => void;\n}\n\n/** Horizontal padding of the main chart SVG. Column headers are aligned to\n * this so that they line up with the columns beneath them. */\nconst chartPaddingH = 4;\n\nfunction MainChartArea({ children }) {\n const columnRef = useColumnRef();\n return h(\"div.main-chart\", { ref: columnRef }, children);\n}\n\nconst unitPopoverFeatures = new Set([\n UnitDetailsFeature.AdjacentUnits,\n UnitDetailsFeature.OutcropType,\n UnitDetailsFeature.DepthRange,\n UnitDetailsFeature.ColumnName,\n]);\n\nexport function CorrelationChart({\n data,\n columnSpacing = 0,\n columnWidth = 130,\n unconformityLabels = true,\n showUnitPopover = true,\n selectedUnit,\n onUnitSelected,\n unitComponent,\n columnHeaderComponent,\n axisTopContent,\n onClickTimescaleInterval,\n onColumnMouseOver,\n onColumnClick,\n ...scaleProps\n}: CorrelationChartProps) {\n const defaultScaleProps = {\n targetUnitHeight: 10,\n unconformityHeight: 60,\n minSectionHeight: 60,\n collapseSmallUnconformities: true,\n };\n\n const chartData = useMemo(() => {\n if (!data) return null;\n return buildCorrelationChartData(data, {\n ...defaultScaleProps,\n ...scaleProps,\n });\n }, [data, ...Object.values(scaleProps)]);\n\n // A flattened units array is used to support keyboard navigation\n const units = useMemo(() => {\n return data?.map((d0) => d0.units).flat() ?? [];\n }, [data]);\n\n const inDarkMode = useInDarkMode();\n\n const className = classNames({\n \"dark-mode\": inDarkMode,\n });\n\n if (chartData == null) {\n return null;\n }\n\n const { packages, scaleInfo, nColumns } = chartData;\n\n const mainWidth = (columnWidth + columnSpacing) * nColumns;\n\n return h(\n ColumnContainer,\n { className: \"correlation-diagram\" },\n h(\n UnitSelectionProvider,\n { selectedUnit, onUnitSelected, units },\n h(ChartArea, [\n h(TimescaleColumn, {\n scaleInfo,\n unconformityLabels,\n onClickInterval: onClickTimescaleInterval,\n }),\n h(MainChartArea, [\n h(\n SVG,\n {\n className,\n innerWidth: mainWidth,\n height: scaleInfo.totalHeight,\n paddingH: chartPaddingH,\n },\n packages.map((pkg, i) => {\n const { offset, domain, pixelScale, scale, key } =\n scaleInfo.packages[i];\n return h(Package, {\n columnData: pkg.columnData,\n key,\n columnWidth,\n columnSpacing,\n offset,\n domain,\n pixelScale,\n scale,\n unitComponent,\n onColumnMouseOver,\n });\n }),\n ),\n h.if(showUnitPopover)(UnitSelectionPopover, {\n features: unitPopoverFeatures,\n }),\n // Navigation only works within a column for now...\n h(UnitKeyboardNavigation, { columnData: data }),\n ]),\n // Rendered last so the sticky header paints above the unit boxes\n // (positioned siblings paint in document order at the same z-index)\n h(ColumnHeaderRow, {\n data,\n columnWidth,\n columnSpacing,\n columnHeaderComponent,\n axisTopContent,\n onColumnMouseOver,\n onColumnClick,\n }),\n ]),\n ),\n );\n}\n\nfunction Package({\n columnData,\n columnSpacing,\n columnWidth,\n unitComponent,\n offset,\n domain,\n pixelScale,\n scale,\n onColumnMouseOver,\n}) {\n return h(\"g.package\", { transform: `translate(0 ${offset})` }, [\n // Disable the SVG overlay for now\n //h(PackageSVGOverlay, { columnData, columnSpacing }),\n h(\"g.column-units\", [\n columnData.map((data, i) => {\n return h(Column, {\n units: data.units,\n columnID: data.columnID,\n unitComponent,\n width: columnWidth,\n key: i,\n domain,\n pixelScale,\n scale,\n offsetLeft: i * (columnWidth + columnSpacing),\n onColumnMouseOver,\n });\n }),\n ]),\n ]);\n}\n\ninterface ColumnProps {\n units: ExtUnit[];\n columnID?: number;\n unitComponent?: React.FunctionComponent<any>;\n unitComponentProps?: any;\n showLabels?: boolean;\n width?: number;\n columnWidth?: number;\n columnSpacing?: number;\n targetUnitHeight?: number;\n offsetLeft?: number;\n domain: [number, number];\n pixelScale: number;\n scale?: ScaleContinuousNumeric<number, number>;\n onColumnMouseOver?: (columnID: number | null) => void;\n}\n\nfunction Column(props: ColumnProps) {\n const {\n units,\n columnID,\n width = 150,\n offsetLeft,\n domain,\n pixelScale,\n scale,\n unitComponent = ColoredUnitComponent,\n onColumnMouseOver,\n } = props;\n\n const columnWidth = width;\n\n if (units.length == 0) {\n return null;\n }\n\n const hoverHandlers =\n onColumnMouseOver != null && columnID != null\n ? {\n onMouseEnter: () => onColumnMouseOver(columnID),\n onMouseLeave: () => onColumnMouseOver(null),\n }\n : {};\n\n return h(\n \"g.section\",\n {\n transform: `translate(${offsetLeft} 0)`,\n ...hoverHandlers,\n },\n h(\n ColumnProvider,\n {\n // Need to tighten up types here...\n divisions: units as any[],\n range: domain,\n scale,\n pixelsPerMeter: pixelScale, // Actually pixels per myr\n axisType: ColumnAxisType.AGE,\n },\n h(UnitBoxes, {\n unitComponent,\n unitComponentProps: {\n width: columnWidth,\n showLabel: true,\n },\n }),\n ),\n );\n}\n\nfunction PackageSVGOverlay({ data, columnWidth = 100, columnSpacing = 0 }) {\n const { b_age, t_age, bestPixelScale, columnData } = data;\n\n const width = (columnWidth + columnSpacing) * columnData.length;\n const height = Math.ceil((b_age - t_age) * bestPixelScale) + 2;\n\n const extensiveUnits = findLaterallyExtensiveUnits(data);\n\n const scale = (val: number) => {\n return (val - t_age) * bestPixelScale;\n };\n\n return h(\n \"div.package-overlay\",\n { style: { width, height } },\n extensiveUnits.map((d) => {\n return h(LaterallyExtensiveUnit, {\n data: d,\n scale,\n pixelScale: bestPixelScale,\n columnSpacing,\n });\n }),\n );\n}\n\nfunction LaterallyExtensiveUnit({ data, scale, pixelScale, columnSpacing }) {\n const { b_age, t_age, strat_name_long, units } = data;\n // Build boxes by column groups\n const boxes: UnitGroupBox[] = splitStratIntoBoxes(data);\n\n return h(\n \"div.laterally-extensive-unit\",\n boxes.map((d, i) => {\n return h(StratColSpan, {\n scale,\n data: d,\n pixelScale,\n key: i,\n columnSpacing,\n });\n }),\n );\n}\n\nfunction StratColSpan({\n data,\n scale,\n columnWidth = 100,\n columnSpacing = 0,\n pixelScale = 1,\n}) {\n const { startCol, endCol, strat_name_long, t_age, b_age } = data;\n const top = scale(t_age);\n const left = startCol * (columnWidth + columnSpacing);\n const width = (endCol - startCol + 1) * (columnWidth + columnSpacing);\n const height = (b_age - t_age) * pixelScale;\n return h(\n \"div.strat-col-span\",\n { style: { top, height, width, left } },\n strat_name_long,\n );\n}\n\nfunction ChartArea({ children }) {\n const setSelectedUnit = useUnitSelectionDispatch();\n\n return h(\n \"div.correlation-chart-inner\",\n {\n onClick() {\n setSelectedUnit(null, null);\n },\n },\n children,\n );\n}\n\ninterface ColumnHeaderRowProps {\n data: ColumnData[];\n columnWidth: number;\n columnSpacing: number;\n columnHeaderComponent?: React.ComponentType<ColumnHeaderProps>;\n axisTopContent?: React.ReactNode;\n onColumnMouseOver?: (columnID: number | null) => void;\n onColumnClick?: (columnID: number) => void;\n}\n\nfunction ColumnHeaderRow({\n data,\n columnWidth,\n columnSpacing,\n columnHeaderComponent,\n axisTopContent,\n onColumnMouseOver,\n onColumnClick,\n}: ColumnHeaderRowProps) {\n /** The top grid row: arbitrary content above the timescale axis (top-left)\n * and, when a header component is provided, per-column headers aligned with\n * the columns. Collapses to nothing when neither is present. */\n const Component = columnHeaderComponent;\n if (Component == null && axisTopContent == null) {\n return null;\n }\n\n return h([\n h(\"div.column-header-spacer\", axisTopContent),\n h.if(Component != null)(\n \"div.column-header-row\",\n {\n style: {\n paddingLeft: chartPaddingH,\n paddingRight: chartPaddingH,\n gap: columnSpacing,\n },\n },\n data.map((column, i) => {\n return h(ColumnHeaderCell, {\n key: column.columnID ?? i,\n column,\n columnIndex: i,\n columnWidth,\n Component: Component!,\n onColumnMouseOver,\n onColumnClick,\n });\n }),\n ),\n ]);\n}\n\nfunction ColumnHeaderCell({\n column,\n columnIndex,\n columnWidth,\n Component,\n onColumnMouseOver,\n onColumnClick,\n}: {\n column: ColumnData;\n columnIndex: number;\n columnWidth: number;\n Component: React.ComponentType<ColumnHeaderProps>;\n onColumnMouseOver?: (columnID: number | null) => void;\n onColumnClick?: (columnID: number) => void;\n}) {\n /** Resolves the column name and wires column-level hover/click so the header\n * component itself can stay a pure function of props. */\n const columnID = column.columnID;\n const info = useMacrostratColumnInfo(columnID);\n\n return h(\n \"div.column-header-cell\",\n {\n style: {\n width: columnWidth,\n minWidth: columnWidth,\n maxWidth: columnWidth,\n },\n onMouseEnter: () => onColumnMouseOver?.(columnID),\n onMouseLeave: () => onColumnMouseOver?.(null),\n onClick: onColumnClick\n ? (e: React.MouseEvent) => {\n e.stopPropagation();\n onColumnClick(columnID);\n }\n : undefined,\n },\n h(Component, {\n column,\n columnID,\n columnIndex,\n units: column.units as ExtUnit[],\n width: columnWidth,\n columnName: info?.col_name ?? null,\n }),\n );\n}\n\ninterface TimescaleColumnProps {\n scaleInfo: CompositeStratigraphicScaleInfo;\n showLabels?: boolean;\n unconformityLabels?: boolean;\n onClickInterval?: TimescaleClickHandler;\n}\n\nfunction TimescaleColumn(props: TimescaleColumnProps) {\n const { scaleInfo, unconformityLabels = true, onClickInterval } = props;\n return h(\"div.column-container.age-axis-container\", [\n h(CompositeAgeAxisCore, { ...scaleInfo }),\n h(CompositeTimescaleCore, {\n ...scaleInfo,\n unconformityLabels,\n onClickInterval,\n }),\n ]);\n}\n"],"names":["useColumnRef","h","UnitDetailsFeature","useMemo","buildCorrelationChartData","useInDarkMode","classNames","ColumnContainer","UnitSelectionProvider","SVG","UnitSelectionPopover","UnitKeyboardNavigation","ColoredUnitComponent","ColumnProvider","ColumnAxisType","UnitBoxes","useUnitSelectionDispatch","column","useMacrostratColumnInfo","CompositeAgeAxisCore","CompositeTimescaleCore"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"main.cjs","sources":["../../src/correlation-chart/main.ts"],"sourcesContent":["/** Correlation chart */\nimport {\n UnitSelectionProvider,\n UnitKeyboardNavigation,\n useUnitSelectionDispatch,\n useColumnRef,\n} from \"../data-provider\";\nimport { UnitDetailsFeature, UnitSelectionPopover } from \"../unit-details\";\nimport h from \"./main.module.sass\";\nimport { useMemo } from \"react\";\nimport { useInDarkMode } from \"@macrostrat/ui-components\";\nimport { CompositeTimescaleCore } from \"../section\";\nimport classNames from \"classnames\";\nimport {\n findLaterallyExtensiveUnits,\n splitStratIntoBoxes,\n UnitGroupBox,\n CorrelationChartSettings,\n buildCorrelationChartData,\n} from \"./prepare-data\";\nimport {\n CompositeAgeAxisCore,\n CompositeStratigraphicScaleInfo,\n} from \"../age-axis\";\nimport {\n ColumnAxisType,\n ColumnProvider,\n SVG,\n} from \"@macrostrat/column-components\";\nimport { ColoredUnitComponent } from \"../units\";\nimport { UnitBoxes } from \"../units/boxes\";\nimport { ColumnContainer } from \"../column\";\nimport type { ColumnData } from \"@macrostrat/data-provider\";\nimport { BaseUnit } from \"@macrostrat/api-types\";\nimport { ScaleContinuousNumeric } from \"d3-scale\";\nimport { ExtUnit } from \"../prepare-units/types\";\nimport type { TimescaleClickHandler } from \"@macrostrat/timescale\";\nimport { useMacrostratColumnInfo } from \"@macrostrat/data-provider\";\n\n/** Standard props passed to a `columnHeaderComponent`. Everything a header\n * needs is provided here, so the component can be a pure function of its props\n * (no hooks required). Column-level hover/click are handled by the chart. */\nexport interface ColumnHeaderProps {\n /** The column data (units + identifier) for this column */\n column: ColumnData;\n /** The column's ID (col_id) */\n columnID: number;\n /** The column's index (left-to-right) within the chart */\n columnIndex: number;\n /** The units within the column */\n units: ExtUnit[];\n /** The rendered width of the column, in pixels */\n width: number;\n /** The column's name, resolved from column metadata when available */\n columnName?: string | null;\n}\n\nexport interface CorrelationChartProps extends CorrelationChartSettings {\n data: ColumnData[];\n columnWidth?: number;\n columnSpacing?: number;\n targetUnitHeight?: number;\n unconformityLabels?: boolean;\n selectedUnit?: number | null;\n showUnitPopover?: boolean;\n unitComponent?: any;\n /** Arbitrary content (e.g. column title and/or ID) rendered above each column */\n columnHeaderComponent?: React.ComponentType<ColumnHeaderProps>;\n /** Content rendered above the timescale axis (top-left), beside the column\n * headers — e.g. a zoom/filter indicator. */\n axisTopContent?: React.ReactNode;\n /** True while the age window is animating (e.g. from `useAnimatedAgeWindow`).\n * Propagated to each column's context so per-frame label/pattern work can be\n * skipped during the transition. */\n isTransitioning?: boolean;\n /** Hide unit labels while transitioning (perf escape hatch; default false —\n * labels stay visible through the animation). */\n hideLabelsWhileTransitioning?: boolean;\n onUnitSelected?: (unitID: number | null, unit: BaseUnit | null) => void;\n /** Called when a timescale interval is clicked (e.g. to zoom the age range) */\n onClickTimescaleInterval?: TimescaleClickHandler;\n /** Called when the pointer enters/leaves a column (header or body). Passes\n * the column ID, or null on leave. */\n onColumnMouseOver?: (columnID: number | null) => void;\n /** Called when a column header is clicked (e.g. to frame it on a map) */\n onColumnClick?: (columnID: number) => void;\n}\n\n/** Horizontal padding of the main chart SVG. Column headers are aligned to\n * this so that they line up with the columns beneath them. */\nconst chartPaddingH = 4;\n\n/** Default scale settings for the correlation chart. */\nconst defaultCorrelationChartScaleProps = {\n targetUnitHeight: 10,\n unconformityHeight: 60,\n minSectionHeight: 60,\n collapseSmallUnconformities: true,\n};\n\nfunction MainChartArea({ children }) {\n const columnRef = useColumnRef();\n return h(\"div.main-chart\", { ref: columnRef }, children);\n}\n\nconst unitPopoverFeatures = new Set([\n UnitDetailsFeature.AdjacentUnits,\n UnitDetailsFeature.OutcropType,\n UnitDetailsFeature.DepthRange,\n UnitDetailsFeature.ColumnName,\n]);\n\nexport function CorrelationChart({\n data,\n columnSpacing = 0,\n columnWidth = 130,\n unconformityLabels = true,\n showUnitPopover = true,\n selectedUnit,\n onUnitSelected,\n unitComponent,\n columnHeaderComponent,\n axisTopContent,\n onClickTimescaleInterval,\n onColumnMouseOver,\n onColumnClick,\n isTransitioning = false,\n hideLabelsWhileTransitioning = false,\n ...scaleProps\n}: CorrelationChartProps) {\n const chartData = useMemo(() => {\n if (!data) return null;\n return buildCorrelationChartData(data, {\n ...defaultCorrelationChartScaleProps,\n ...scaleProps,\n });\n }, [data, ...Object.values(scaleProps)]);\n\n // A flattened units array is used to support keyboard navigation\n const units = useMemo(() => {\n return data?.map((d0) => d0.units).flat() ?? [];\n }, [data]);\n\n const inDarkMode = useInDarkMode();\n\n const className = classNames({\n \"dark-mode\": inDarkMode,\n });\n\n if (chartData == null) {\n return null;\n }\n\n const { packages, scaleInfo, nColumns } = chartData;\n\n const mainWidth = (columnWidth + columnSpacing) * nColumns;\n\n return h(\n ColumnContainer,\n { className: \"correlation-diagram\" },\n h(\n UnitSelectionProvider,\n { selectedUnit, onUnitSelected, units },\n h(ChartArea, [\n h(TimescaleColumn, {\n scaleInfo,\n unconformityLabels,\n onClickInterval: onClickTimescaleInterval,\n }),\n h(MainChartArea, [\n h(\n SVG,\n {\n className,\n innerWidth: mainWidth,\n height: scaleInfo.totalHeight,\n paddingH: chartPaddingH,\n },\n packages.map((pkg, i) => {\n const { offset, domain, pixelScale, scale, key } =\n scaleInfo.packages[i];\n return h(Package, {\n columnData: pkg.columnData,\n key,\n columnWidth,\n columnSpacing,\n offset,\n domain,\n pixelScale,\n scale,\n unitComponent,\n onColumnMouseOver,\n isTransitioning,\n hideLabelsWhileTransitioning,\n });\n }),\n ),\n h.if(showUnitPopover)(UnitSelectionPopover, {\n features: unitPopoverFeatures,\n }),\n // Navigation only works within a column for now...\n h(UnitKeyboardNavigation, { columnData: data }),\n ]),\n // Rendered last so the sticky header paints above the unit boxes\n // (positioned siblings paint in document order at the same z-index)\n h(ColumnHeaderRow, {\n data,\n columnWidth,\n columnSpacing,\n columnHeaderComponent,\n axisTopContent,\n onColumnMouseOver,\n onColumnClick,\n }),\n ]),\n ),\n );\n}\n\nfunction Package({\n columnData,\n columnSpacing,\n columnWidth,\n unitComponent,\n offset,\n domain,\n pixelScale,\n scale,\n onColumnMouseOver,\n isTransitioning,\n hideLabelsWhileTransitioning,\n}) {\n return h(\"g.package\", { transform: `translate(0 ${offset})` }, [\n // Disable the SVG overlay for now\n //h(PackageSVGOverlay, { columnData, columnSpacing }),\n h(\"g.column-units\", [\n columnData.map((data, i) => {\n return h(Column, {\n units: data.units,\n columnID: data.columnID,\n unitComponent,\n width: columnWidth,\n key: i,\n domain,\n pixelScale,\n scale,\n offsetLeft: i * (columnWidth + columnSpacing),\n onColumnMouseOver,\n isTransitioning,\n hideLabelsWhileTransitioning,\n });\n }),\n ]),\n ]);\n}\n\ninterface ColumnProps {\n units: ExtUnit[];\n columnID?: number;\n unitComponent?: React.FunctionComponent<any>;\n unitComponentProps?: any;\n showLabels?: boolean;\n width?: number;\n columnWidth?: number;\n columnSpacing?: number;\n targetUnitHeight?: number;\n offsetLeft?: number;\n domain: [number, number];\n pixelScale: number;\n scale?: ScaleContinuousNumeric<number, number>;\n onColumnMouseOver?: (columnID: number | null) => void;\n isTransitioning?: boolean;\n hideLabelsWhileTransitioning?: boolean;\n}\n\nfunction Column(props: ColumnProps) {\n const {\n units,\n columnID,\n width = 150,\n offsetLeft,\n domain,\n pixelScale,\n scale,\n unitComponent = ColoredUnitComponent,\n onColumnMouseOver,\n isTransitioning,\n hideLabelsWhileTransitioning,\n } = props;\n\n const columnWidth = width;\n\n if (units.length == 0) {\n return null;\n }\n\n const hoverHandlers =\n onColumnMouseOver != null && columnID != null\n ? {\n onMouseEnter: () => onColumnMouseOver(columnID),\n onMouseLeave: () => onColumnMouseOver(null),\n }\n : {};\n\n return h(\n \"g.section\",\n {\n transform: `translate(${offsetLeft} 0)`,\n ...hoverHandlers,\n },\n h(\n ColumnProvider,\n {\n // Need to tighten up types here...\n divisions: units as any[],\n range: domain,\n scale,\n pixelsPerMeter: pixelScale, // Actually pixels per myr\n axisType: ColumnAxisType.AGE,\n isTransitioning,\n hideLabelsWhileTransitioning,\n },\n h(UnitBoxes, {\n unitComponent,\n unitComponentProps: {\n width: columnWidth,\n showLabel: true,\n },\n }),\n ),\n );\n}\n\nfunction PackageSVGOverlay({ data, columnWidth = 100, columnSpacing = 0 }) {\n const { b_age, t_age, bestPixelScale, columnData } = data;\n\n const width = (columnWidth + columnSpacing) * columnData.length;\n const height = Math.ceil((b_age - t_age) * bestPixelScale) + 2;\n\n const extensiveUnits = findLaterallyExtensiveUnits(data);\n\n const scale = (val: number) => {\n return (val - t_age) * bestPixelScale;\n };\n\n return h(\n \"div.package-overlay\",\n { style: { width, height } },\n extensiveUnits.map((d) => {\n return h(LaterallyExtensiveUnit, {\n data: d,\n scale,\n pixelScale: bestPixelScale,\n columnSpacing,\n });\n }),\n );\n}\n\nfunction LaterallyExtensiveUnit({ data, scale, pixelScale, columnSpacing }) {\n const { b_age, t_age, strat_name_long, units } = data;\n // Build boxes by column groups\n const boxes: UnitGroupBox[] = splitStratIntoBoxes(data);\n\n return h(\n \"div.laterally-extensive-unit\",\n boxes.map((d, i) => {\n return h(StratColSpan, {\n scale,\n data: d,\n pixelScale,\n key: i,\n columnSpacing,\n });\n }),\n );\n}\n\nfunction StratColSpan({\n data,\n scale,\n columnWidth = 100,\n columnSpacing = 0,\n pixelScale = 1,\n}) {\n const { startCol, endCol, strat_name_long, t_age, b_age } = data;\n const top = scale(t_age);\n const left = startCol * (columnWidth + columnSpacing);\n const width = (endCol - startCol + 1) * (columnWidth + columnSpacing);\n const height = (b_age - t_age) * pixelScale;\n return h(\n \"div.strat-col-span\",\n { style: { top, height, width, left } },\n strat_name_long,\n );\n}\n\nfunction ChartArea({ children }) {\n const setSelectedUnit = useUnitSelectionDispatch();\n\n return h(\n \"div.correlation-chart-inner\",\n {\n onClick() {\n setSelectedUnit(null, null);\n },\n },\n children,\n );\n}\n\ninterface ColumnHeaderRowProps {\n data: ColumnData[];\n columnWidth: number;\n columnSpacing: number;\n columnHeaderComponent?: React.ComponentType<ColumnHeaderProps>;\n axisTopContent?: React.ReactNode;\n onColumnMouseOver?: (columnID: number | null) => void;\n onColumnClick?: (columnID: number) => void;\n}\n\nfunction ColumnHeaderRow({\n data,\n columnWidth,\n columnSpacing,\n columnHeaderComponent,\n axisTopContent,\n onColumnMouseOver,\n onColumnClick,\n}: ColumnHeaderRowProps) {\n /** The top grid row: arbitrary content above the timescale axis (top-left)\n * and, when a header component is provided, per-column headers aligned with\n * the columns. Collapses to nothing when neither is present. */\n const Component = columnHeaderComponent;\n if (Component == null && axisTopContent == null) {\n return null;\n }\n\n return h([\n h(\"div.column-header-spacer\", axisTopContent),\n h.if(Component != null)(\n \"div.column-header-row\",\n {\n style: {\n paddingLeft: chartPaddingH,\n paddingRight: chartPaddingH,\n gap: columnSpacing,\n },\n },\n data.map((column, i) => {\n return h(ColumnHeaderCell, {\n key: column.columnID ?? i,\n column,\n columnIndex: i,\n columnWidth,\n Component: Component!,\n onColumnMouseOver,\n onColumnClick,\n });\n }),\n ),\n ]);\n}\n\nfunction ColumnHeaderCell({\n column,\n columnIndex,\n columnWidth,\n Component,\n onColumnMouseOver,\n onColumnClick,\n}: {\n column: ColumnData;\n columnIndex: number;\n columnWidth: number;\n Component: React.ComponentType<ColumnHeaderProps>;\n onColumnMouseOver?: (columnID: number | null) => void;\n onColumnClick?: (columnID: number) => void;\n}) {\n /** Resolves the column name and wires column-level hover/click so the header\n * component itself can stay a pure function of props. */\n const columnID = column.columnID;\n const info = useMacrostratColumnInfo(columnID);\n\n return h(\n \"div.column-header-cell\",\n {\n style: {\n width: columnWidth,\n minWidth: columnWidth,\n maxWidth: columnWidth,\n },\n onMouseEnter: () => onColumnMouseOver?.(columnID),\n onMouseLeave: () => onColumnMouseOver?.(null),\n onClick: onColumnClick\n ? (e: React.MouseEvent) => {\n e.stopPropagation();\n onColumnClick(columnID);\n }\n : undefined,\n },\n h(Component, {\n column,\n columnID,\n columnIndex,\n units: column.units as ExtUnit[],\n width: columnWidth,\n columnName: info?.col_name ?? null,\n }),\n );\n}\n\ninterface TimescaleColumnProps {\n scaleInfo: CompositeStratigraphicScaleInfo;\n showLabels?: boolean;\n unconformityLabels?: boolean;\n onClickInterval?: TimescaleClickHandler;\n}\n\nfunction TimescaleColumn(props: TimescaleColumnProps) {\n const { scaleInfo, unconformityLabels = true, onClickInterval } = props;\n return h(\"div.column-container.age-axis-container\", [\n h(CompositeAgeAxisCore, { ...scaleInfo }),\n h(CompositeTimescaleCore, {\n ...scaleInfo,\n unconformityLabels,\n onClickInterval,\n }),\n ]);\n}\n"],"names":["useColumnRef","h","UnitDetailsFeature","useMemo","buildCorrelationChartData","useInDarkMode","classNames","ColumnContainer","UnitSelectionProvider","SVG","UnitSelectionPopover","UnitKeyboardNavigation","ColoredUnitComponent","ColumnProvider","ColumnAxisType","UnitBoxes","useUnitSelectionDispatch","column","useMacrostratColumnInfo","CompositeAgeAxisCore","CompositeTimescaleCore"],"mappings":"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"}
|
|
@@ -34,6 +34,13 @@ export interface CorrelationChartProps extends CorrelationChartSettings {
|
|
|
34
34
|
/** Content rendered above the timescale axis (top-left), beside the column
|
|
35
35
|
* headers — e.g. a zoom/filter indicator. */
|
|
36
36
|
axisTopContent?: React.ReactNode;
|
|
37
|
+
/** True while the age window is animating (e.g. from `useAnimatedAgeWindow`).
|
|
38
|
+
* Propagated to each column's context so per-frame label/pattern work can be
|
|
39
|
+
* skipped during the transition. */
|
|
40
|
+
isTransitioning?: boolean;
|
|
41
|
+
/** Hide unit labels while transitioning (perf escape hatch; default false —
|
|
42
|
+
* labels stay visible through the animation). */
|
|
43
|
+
hideLabelsWhileTransitioning?: boolean;
|
|
37
44
|
onUnitSelected?: (unitID: number | null, unit: BaseUnit | null) => void;
|
|
38
45
|
/** Called when a timescale interval is clicked (e.g. to zoom the age range) */
|
|
39
46
|
onClickTimescaleInterval?: TimescaleClickHandler;
|
|
@@ -43,4 +50,4 @@ export interface CorrelationChartProps extends CorrelationChartSettings {
|
|
|
43
50
|
/** Called when a column header is clicked (e.g. to frame it on a map) */
|
|
44
51
|
onColumnClick?: (columnID: number) => void;
|
|
45
52
|
}
|
|
46
|
-
export declare function CorrelationChart({ data, columnSpacing, columnWidth, unconformityLabels, showUnitPopover, selectedUnit, onUnitSelected, unitComponent, columnHeaderComponent, axisTopContent, onClickTimescaleInterval, onColumnMouseOver, onColumnClick, ...scaleProps }: CorrelationChartProps): import('react').FunctionComponentElement<import('..').ColumnContainerProps> | null;
|
|
53
|
+
export declare function CorrelationChart({ data, columnSpacing, columnWidth, unconformityLabels, showUnitPopover, selectedUnit, onUnitSelected, unitComponent, columnHeaderComponent, axisTopContent, onClickTimescaleInterval, onColumnMouseOver, onColumnClick, isTransitioning, hideLabelsWhileTransitioning, ...scaleProps }: CorrelationChartProps): import('react').FunctionComponentElement<import('..').ColumnContainerProps> | null;
|
|
@@ -15,6 +15,12 @@ import { UnitDetailsFeature } from "../unit-details/panel.js";
|
|
|
15
15
|
import { UnitSelectionPopover } from "../unit-details/popover.js";
|
|
16
16
|
import { UnitKeyboardNavigation, useUnitSelectionDispatch, useColumnRef } from "../data-provider/unit-selection.js";
|
|
17
17
|
const chartPaddingH = 4;
|
|
18
|
+
const defaultCorrelationChartScaleProps = {
|
|
19
|
+
targetUnitHeight: 10,
|
|
20
|
+
unconformityHeight: 60,
|
|
21
|
+
minSectionHeight: 60,
|
|
22
|
+
collapseSmallUnconformities: true
|
|
23
|
+
};
|
|
18
24
|
function MainChartArea({ children }) {
|
|
19
25
|
const columnRef = useColumnRef();
|
|
20
26
|
return h("div.main-chart", { ref: columnRef }, children);
|
|
@@ -39,18 +45,14 @@ function CorrelationChart({
|
|
|
39
45
|
onClickTimescaleInterval,
|
|
40
46
|
onColumnMouseOver,
|
|
41
47
|
onColumnClick,
|
|
48
|
+
isTransitioning = false,
|
|
49
|
+
hideLabelsWhileTransitioning = false,
|
|
42
50
|
...scaleProps
|
|
43
51
|
}) {
|
|
44
|
-
const defaultScaleProps = {
|
|
45
|
-
targetUnitHeight: 10,
|
|
46
|
-
unconformityHeight: 60,
|
|
47
|
-
minSectionHeight: 60,
|
|
48
|
-
collapseSmallUnconformities: true
|
|
49
|
-
};
|
|
50
52
|
const chartData = useMemo(() => {
|
|
51
53
|
if (!data) return null;
|
|
52
54
|
return buildCorrelationChartData(data, {
|
|
53
|
-
...
|
|
55
|
+
...defaultCorrelationChartScaleProps,
|
|
54
56
|
...scaleProps
|
|
55
57
|
});
|
|
56
58
|
}, [data, ...Object.values(scaleProps)]);
|
|
@@ -99,7 +101,9 @@ function CorrelationChart({
|
|
|
99
101
|
pixelScale,
|
|
100
102
|
scale,
|
|
101
103
|
unitComponent,
|
|
102
|
-
onColumnMouseOver
|
|
104
|
+
onColumnMouseOver,
|
|
105
|
+
isTransitioning,
|
|
106
|
+
hideLabelsWhileTransitioning
|
|
103
107
|
});
|
|
104
108
|
})
|
|
105
109
|
),
|
|
@@ -133,7 +137,9 @@ function Package({
|
|
|
133
137
|
domain,
|
|
134
138
|
pixelScale,
|
|
135
139
|
scale,
|
|
136
|
-
onColumnMouseOver
|
|
140
|
+
onColumnMouseOver,
|
|
141
|
+
isTransitioning,
|
|
142
|
+
hideLabelsWhileTransitioning
|
|
137
143
|
}) {
|
|
138
144
|
return h("g.package", { transform: `translate(0 ${offset})` }, [
|
|
139
145
|
// Disable the SVG overlay for now
|
|
@@ -150,7 +156,9 @@ function Package({
|
|
|
150
156
|
pixelScale,
|
|
151
157
|
scale,
|
|
152
158
|
offsetLeft: i * (columnWidth + columnSpacing),
|
|
153
|
-
onColumnMouseOver
|
|
159
|
+
onColumnMouseOver,
|
|
160
|
+
isTransitioning,
|
|
161
|
+
hideLabelsWhileTransitioning
|
|
154
162
|
});
|
|
155
163
|
})
|
|
156
164
|
])
|
|
@@ -166,7 +174,9 @@ function Column(props) {
|
|
|
166
174
|
pixelScale,
|
|
167
175
|
scale,
|
|
168
176
|
unitComponent = ColoredUnitComponent,
|
|
169
|
-
onColumnMouseOver
|
|
177
|
+
onColumnMouseOver,
|
|
178
|
+
isTransitioning,
|
|
179
|
+
hideLabelsWhileTransitioning
|
|
170
180
|
} = props;
|
|
171
181
|
const columnWidth = width;
|
|
172
182
|
if (units.length == 0) {
|
|
@@ -191,7 +201,9 @@ function Column(props) {
|
|
|
191
201
|
scale,
|
|
192
202
|
pixelsPerMeter: pixelScale,
|
|
193
203
|
// Actually pixels per myr
|
|
194
|
-
axisType: ColumnAxisType.AGE
|
|
204
|
+
axisType: ColumnAxisType.AGE,
|
|
205
|
+
isTransitioning,
|
|
206
|
+
hideLabelsWhileTransitioning
|
|
195
207
|
},
|
|
196
208
|
h(UnitBoxes, {
|
|
197
209
|
unitComponent,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sources":["../../src/correlation-chart/main.ts"],"sourcesContent":["/** Correlation chart */\nimport {\n UnitSelectionProvider,\n UnitKeyboardNavigation,\n useUnitSelectionDispatch,\n useColumnRef,\n} from \"../data-provider\";\nimport { UnitDetailsFeature, UnitSelectionPopover } from \"../unit-details\";\nimport h from \"./main.module.sass\";\nimport { useMemo } from \"react\";\nimport { useInDarkMode } from \"@macrostrat/ui-components\";\nimport { CompositeTimescaleCore } from \"../section\";\nimport classNames from \"classnames\";\nimport {\n findLaterallyExtensiveUnits,\n splitStratIntoBoxes,\n UnitGroupBox,\n CorrelationChartSettings,\n buildCorrelationChartData,\n} from \"./prepare-data\";\nimport {\n CompositeAgeAxisCore,\n CompositeStratigraphicScaleInfo,\n} from \"../age-axis\";\nimport {\n ColumnAxisType,\n ColumnProvider,\n SVG,\n} from \"@macrostrat/column-components\";\nimport { ColoredUnitComponent } from \"../units\";\nimport { UnitBoxes } from \"../units/boxes\";\nimport { ColumnContainer } from \"../column\";\nimport type { ColumnData } from \"@macrostrat/data-provider\";\nimport { BaseUnit } from \"@macrostrat/api-types\";\nimport { ScaleContinuousNumeric } from \"d3-scale\";\nimport { ExtUnit } from \"../prepare-units/types\";\nimport type { TimescaleClickHandler } from \"@macrostrat/timescale\";\nimport { useMacrostratColumnInfo } from \"@macrostrat/data-provider\";\n\n/** Standard props passed to a `columnHeaderComponent`. Everything a header\n * needs is provided here, so the component can be a pure function of its props\n * (no hooks required). Column-level hover/click are handled by the chart. */\nexport interface ColumnHeaderProps {\n /** The column data (units + identifier) for this column */\n column: ColumnData;\n /** The column's ID (col_id) */\n columnID: number;\n /** The column's index (left-to-right) within the chart */\n columnIndex: number;\n /** The units within the column */\n units: ExtUnit[];\n /** The rendered width of the column, in pixels */\n width: number;\n /** The column's name, resolved from column metadata when available */\n columnName?: string | null;\n}\n\nexport interface CorrelationChartProps extends CorrelationChartSettings {\n data: ColumnData[];\n columnWidth?: number;\n columnSpacing?: number;\n targetUnitHeight?: number;\n unconformityLabels?: boolean;\n selectedUnit?: number | null;\n showUnitPopover?: boolean;\n unitComponent?: any;\n /** Arbitrary content (e.g. column title and/or ID) rendered above each column */\n columnHeaderComponent?: React.ComponentType<ColumnHeaderProps>;\n /** Content rendered above the timescale axis (top-left), beside the column\n * headers — e.g. a zoom/filter indicator. */\n axisTopContent?: React.ReactNode;\n onUnitSelected?: (unitID: number | null, unit: BaseUnit | null) => void;\n /** Called when a timescale interval is clicked (e.g. to zoom the age range) */\n onClickTimescaleInterval?: TimescaleClickHandler;\n /** Called when the pointer enters/leaves a column (header or body). Passes\n * the column ID, or null on leave. */\n onColumnMouseOver?: (columnID: number | null) => void;\n /** Called when a column header is clicked (e.g. to frame it on a map) */\n onColumnClick?: (columnID: number) => void;\n}\n\n/** Horizontal padding of the main chart SVG. Column headers are aligned to\n * this so that they line up with the columns beneath them. */\nconst chartPaddingH = 4;\n\nfunction MainChartArea({ children }) {\n const columnRef = useColumnRef();\n return h(\"div.main-chart\", { ref: columnRef }, children);\n}\n\nconst unitPopoverFeatures = new Set([\n UnitDetailsFeature.AdjacentUnits,\n UnitDetailsFeature.OutcropType,\n UnitDetailsFeature.DepthRange,\n UnitDetailsFeature.ColumnName,\n]);\n\nexport function CorrelationChart({\n data,\n columnSpacing = 0,\n columnWidth = 130,\n unconformityLabels = true,\n showUnitPopover = true,\n selectedUnit,\n onUnitSelected,\n unitComponent,\n columnHeaderComponent,\n axisTopContent,\n onClickTimescaleInterval,\n onColumnMouseOver,\n onColumnClick,\n ...scaleProps\n}: CorrelationChartProps) {\n const defaultScaleProps = {\n targetUnitHeight: 10,\n unconformityHeight: 60,\n minSectionHeight: 60,\n collapseSmallUnconformities: true,\n };\n\n const chartData = useMemo(() => {\n if (!data) return null;\n return buildCorrelationChartData(data, {\n ...defaultScaleProps,\n ...scaleProps,\n });\n }, [data, ...Object.values(scaleProps)]);\n\n // A flattened units array is used to support keyboard navigation\n const units = useMemo(() => {\n return data?.map((d0) => d0.units).flat() ?? [];\n }, [data]);\n\n const inDarkMode = useInDarkMode();\n\n const className = classNames({\n \"dark-mode\": inDarkMode,\n });\n\n if (chartData == null) {\n return null;\n }\n\n const { packages, scaleInfo, nColumns } = chartData;\n\n const mainWidth = (columnWidth + columnSpacing) * nColumns;\n\n return h(\n ColumnContainer,\n { className: \"correlation-diagram\" },\n h(\n UnitSelectionProvider,\n { selectedUnit, onUnitSelected, units },\n h(ChartArea, [\n h(TimescaleColumn, {\n scaleInfo,\n unconformityLabels,\n onClickInterval: onClickTimescaleInterval,\n }),\n h(MainChartArea, [\n h(\n SVG,\n {\n className,\n innerWidth: mainWidth,\n height: scaleInfo.totalHeight,\n paddingH: chartPaddingH,\n },\n packages.map((pkg, i) => {\n const { offset, domain, pixelScale, scale, key } =\n scaleInfo.packages[i];\n return h(Package, {\n columnData: pkg.columnData,\n key,\n columnWidth,\n columnSpacing,\n offset,\n domain,\n pixelScale,\n scale,\n unitComponent,\n onColumnMouseOver,\n });\n }),\n ),\n h.if(showUnitPopover)(UnitSelectionPopover, {\n features: unitPopoverFeatures,\n }),\n // Navigation only works within a column for now...\n h(UnitKeyboardNavigation, { columnData: data }),\n ]),\n // Rendered last so the sticky header paints above the unit boxes\n // (positioned siblings paint in document order at the same z-index)\n h(ColumnHeaderRow, {\n data,\n columnWidth,\n columnSpacing,\n columnHeaderComponent,\n axisTopContent,\n onColumnMouseOver,\n onColumnClick,\n }),\n ]),\n ),\n );\n}\n\nfunction Package({\n columnData,\n columnSpacing,\n columnWidth,\n unitComponent,\n offset,\n domain,\n pixelScale,\n scale,\n onColumnMouseOver,\n}) {\n return h(\"g.package\", { transform: `translate(0 ${offset})` }, [\n // Disable the SVG overlay for now\n //h(PackageSVGOverlay, { columnData, columnSpacing }),\n h(\"g.column-units\", [\n columnData.map((data, i) => {\n return h(Column, {\n units: data.units,\n columnID: data.columnID,\n unitComponent,\n width: columnWidth,\n key: i,\n domain,\n pixelScale,\n scale,\n offsetLeft: i * (columnWidth + columnSpacing),\n onColumnMouseOver,\n });\n }),\n ]),\n ]);\n}\n\ninterface ColumnProps {\n units: ExtUnit[];\n columnID?: number;\n unitComponent?: React.FunctionComponent<any>;\n unitComponentProps?: any;\n showLabels?: boolean;\n width?: number;\n columnWidth?: number;\n columnSpacing?: number;\n targetUnitHeight?: number;\n offsetLeft?: number;\n domain: [number, number];\n pixelScale: number;\n scale?: ScaleContinuousNumeric<number, number>;\n onColumnMouseOver?: (columnID: number | null) => void;\n}\n\nfunction Column(props: ColumnProps) {\n const {\n units,\n columnID,\n width = 150,\n offsetLeft,\n domain,\n pixelScale,\n scale,\n unitComponent = ColoredUnitComponent,\n onColumnMouseOver,\n } = props;\n\n const columnWidth = width;\n\n if (units.length == 0) {\n return null;\n }\n\n const hoverHandlers =\n onColumnMouseOver != null && columnID != null\n ? {\n onMouseEnter: () => onColumnMouseOver(columnID),\n onMouseLeave: () => onColumnMouseOver(null),\n }\n : {};\n\n return h(\n \"g.section\",\n {\n transform: `translate(${offsetLeft} 0)`,\n ...hoverHandlers,\n },\n h(\n ColumnProvider,\n {\n // Need to tighten up types here...\n divisions: units as any[],\n range: domain,\n scale,\n pixelsPerMeter: pixelScale, // Actually pixels per myr\n axisType: ColumnAxisType.AGE,\n },\n h(UnitBoxes, {\n unitComponent,\n unitComponentProps: {\n width: columnWidth,\n showLabel: true,\n },\n }),\n ),\n );\n}\n\nfunction PackageSVGOverlay({ data, columnWidth = 100, columnSpacing = 0 }) {\n const { b_age, t_age, bestPixelScale, columnData } = data;\n\n const width = (columnWidth + columnSpacing) * columnData.length;\n const height = Math.ceil((b_age - t_age) * bestPixelScale) + 2;\n\n const extensiveUnits = findLaterallyExtensiveUnits(data);\n\n const scale = (val: number) => {\n return (val - t_age) * bestPixelScale;\n };\n\n return h(\n \"div.package-overlay\",\n { style: { width, height } },\n extensiveUnits.map((d) => {\n return h(LaterallyExtensiveUnit, {\n data: d,\n scale,\n pixelScale: bestPixelScale,\n columnSpacing,\n });\n }),\n );\n}\n\nfunction LaterallyExtensiveUnit({ data, scale, pixelScale, columnSpacing }) {\n const { b_age, t_age, strat_name_long, units } = data;\n // Build boxes by column groups\n const boxes: UnitGroupBox[] = splitStratIntoBoxes(data);\n\n return h(\n \"div.laterally-extensive-unit\",\n boxes.map((d, i) => {\n return h(StratColSpan, {\n scale,\n data: d,\n pixelScale,\n key: i,\n columnSpacing,\n });\n }),\n );\n}\n\nfunction StratColSpan({\n data,\n scale,\n columnWidth = 100,\n columnSpacing = 0,\n pixelScale = 1,\n}) {\n const { startCol, endCol, strat_name_long, t_age, b_age } = data;\n const top = scale(t_age);\n const left = startCol * (columnWidth + columnSpacing);\n const width = (endCol - startCol + 1) * (columnWidth + columnSpacing);\n const height = (b_age - t_age) * pixelScale;\n return h(\n \"div.strat-col-span\",\n { style: { top, height, width, left } },\n strat_name_long,\n );\n}\n\nfunction ChartArea({ children }) {\n const setSelectedUnit = useUnitSelectionDispatch();\n\n return h(\n \"div.correlation-chart-inner\",\n {\n onClick() {\n setSelectedUnit(null, null);\n },\n },\n children,\n );\n}\n\ninterface ColumnHeaderRowProps {\n data: ColumnData[];\n columnWidth: number;\n columnSpacing: number;\n columnHeaderComponent?: React.ComponentType<ColumnHeaderProps>;\n axisTopContent?: React.ReactNode;\n onColumnMouseOver?: (columnID: number | null) => void;\n onColumnClick?: (columnID: number) => void;\n}\n\nfunction ColumnHeaderRow({\n data,\n columnWidth,\n columnSpacing,\n columnHeaderComponent,\n axisTopContent,\n onColumnMouseOver,\n onColumnClick,\n}: ColumnHeaderRowProps) {\n /** The top grid row: arbitrary content above the timescale axis (top-left)\n * and, when a header component is provided, per-column headers aligned with\n * the columns. Collapses to nothing when neither is present. */\n const Component = columnHeaderComponent;\n if (Component == null && axisTopContent == null) {\n return null;\n }\n\n return h([\n h(\"div.column-header-spacer\", axisTopContent),\n h.if(Component != null)(\n \"div.column-header-row\",\n {\n style: {\n paddingLeft: chartPaddingH,\n paddingRight: chartPaddingH,\n gap: columnSpacing,\n },\n },\n data.map((column, i) => {\n return h(ColumnHeaderCell, {\n key: column.columnID ?? i,\n column,\n columnIndex: i,\n columnWidth,\n Component: Component!,\n onColumnMouseOver,\n onColumnClick,\n });\n }),\n ),\n ]);\n}\n\nfunction ColumnHeaderCell({\n column,\n columnIndex,\n columnWidth,\n Component,\n onColumnMouseOver,\n onColumnClick,\n}: {\n column: ColumnData;\n columnIndex: number;\n columnWidth: number;\n Component: React.ComponentType<ColumnHeaderProps>;\n onColumnMouseOver?: (columnID: number | null) => void;\n onColumnClick?: (columnID: number) => void;\n}) {\n /** Resolves the column name and wires column-level hover/click so the header\n * component itself can stay a pure function of props. */\n const columnID = column.columnID;\n const info = useMacrostratColumnInfo(columnID);\n\n return h(\n \"div.column-header-cell\",\n {\n style: {\n width: columnWidth,\n minWidth: columnWidth,\n maxWidth: columnWidth,\n },\n onMouseEnter: () => onColumnMouseOver?.(columnID),\n onMouseLeave: () => onColumnMouseOver?.(null),\n onClick: onColumnClick\n ? (e: React.MouseEvent) => {\n e.stopPropagation();\n onColumnClick(columnID);\n }\n : undefined,\n },\n h(Component, {\n column,\n columnID,\n columnIndex,\n units: column.units as ExtUnit[],\n width: columnWidth,\n columnName: info?.col_name ?? null,\n }),\n );\n}\n\ninterface TimescaleColumnProps {\n scaleInfo: CompositeStratigraphicScaleInfo;\n showLabels?: boolean;\n unconformityLabels?: boolean;\n onClickInterval?: TimescaleClickHandler;\n}\n\nfunction TimescaleColumn(props: TimescaleColumnProps) {\n const { scaleInfo, unconformityLabels = true, onClickInterval } = props;\n return h(\"div.column-container.age-axis-container\", [\n h(CompositeAgeAxisCore, { ...scaleInfo }),\n h(CompositeTimescaleCore, {\n ...scaleInfo,\n unconformityLabels,\n onClickInterval,\n }),\n ]);\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"main.js","sources":["../../src/correlation-chart/main.ts"],"sourcesContent":["/** Correlation chart */\nimport {\n UnitSelectionProvider,\n UnitKeyboardNavigation,\n useUnitSelectionDispatch,\n useColumnRef,\n} from \"../data-provider\";\nimport { UnitDetailsFeature, UnitSelectionPopover } from \"../unit-details\";\nimport h from \"./main.module.sass\";\nimport { useMemo } from \"react\";\nimport { useInDarkMode } from \"@macrostrat/ui-components\";\nimport { CompositeTimescaleCore } from \"../section\";\nimport classNames from \"classnames\";\nimport {\n findLaterallyExtensiveUnits,\n splitStratIntoBoxes,\n UnitGroupBox,\n CorrelationChartSettings,\n buildCorrelationChartData,\n} from \"./prepare-data\";\nimport {\n CompositeAgeAxisCore,\n CompositeStratigraphicScaleInfo,\n} from \"../age-axis\";\nimport {\n ColumnAxisType,\n ColumnProvider,\n SVG,\n} from \"@macrostrat/column-components\";\nimport { ColoredUnitComponent } from \"../units\";\nimport { UnitBoxes } from \"../units/boxes\";\nimport { ColumnContainer } from \"../column\";\nimport type { ColumnData } from \"@macrostrat/data-provider\";\nimport { BaseUnit } from \"@macrostrat/api-types\";\nimport { ScaleContinuousNumeric } from \"d3-scale\";\nimport { ExtUnit } from \"../prepare-units/types\";\nimport type { TimescaleClickHandler } from \"@macrostrat/timescale\";\nimport { useMacrostratColumnInfo } from \"@macrostrat/data-provider\";\n\n/** Standard props passed to a `columnHeaderComponent`. Everything a header\n * needs is provided here, so the component can be a pure function of its props\n * (no hooks required). Column-level hover/click are handled by the chart. */\nexport interface ColumnHeaderProps {\n /** The column data (units + identifier) for this column */\n column: ColumnData;\n /** The column's ID (col_id) */\n columnID: number;\n /** The column's index (left-to-right) within the chart */\n columnIndex: number;\n /** The units within the column */\n units: ExtUnit[];\n /** The rendered width of the column, in pixels */\n width: number;\n /** The column's name, resolved from column metadata when available */\n columnName?: string | null;\n}\n\nexport interface CorrelationChartProps extends CorrelationChartSettings {\n data: ColumnData[];\n columnWidth?: number;\n columnSpacing?: number;\n targetUnitHeight?: number;\n unconformityLabels?: boolean;\n selectedUnit?: number | null;\n showUnitPopover?: boolean;\n unitComponent?: any;\n /** Arbitrary content (e.g. column title and/or ID) rendered above each column */\n columnHeaderComponent?: React.ComponentType<ColumnHeaderProps>;\n /** Content rendered above the timescale axis (top-left), beside the column\n * headers — e.g. a zoom/filter indicator. */\n axisTopContent?: React.ReactNode;\n /** True while the age window is animating (e.g. from `useAnimatedAgeWindow`).\n * Propagated to each column's context so per-frame label/pattern work can be\n * skipped during the transition. */\n isTransitioning?: boolean;\n /** Hide unit labels while transitioning (perf escape hatch; default false —\n * labels stay visible through the animation). */\n hideLabelsWhileTransitioning?: boolean;\n onUnitSelected?: (unitID: number | null, unit: BaseUnit | null) => void;\n /** Called when a timescale interval is clicked (e.g. to zoom the age range) */\n onClickTimescaleInterval?: TimescaleClickHandler;\n /** Called when the pointer enters/leaves a column (header or body). Passes\n * the column ID, or null on leave. */\n onColumnMouseOver?: (columnID: number | null) => void;\n /** Called when a column header is clicked (e.g. to frame it on a map) */\n onColumnClick?: (columnID: number) => void;\n}\n\n/** Horizontal padding of the main chart SVG. Column headers are aligned to\n * this so that they line up with the columns beneath them. */\nconst chartPaddingH = 4;\n\n/** Default scale settings for the correlation chart. */\nconst defaultCorrelationChartScaleProps = {\n targetUnitHeight: 10,\n unconformityHeight: 60,\n minSectionHeight: 60,\n collapseSmallUnconformities: true,\n};\n\nfunction MainChartArea({ children }) {\n const columnRef = useColumnRef();\n return h(\"div.main-chart\", { ref: columnRef }, children);\n}\n\nconst unitPopoverFeatures = new Set([\n UnitDetailsFeature.AdjacentUnits,\n UnitDetailsFeature.OutcropType,\n UnitDetailsFeature.DepthRange,\n UnitDetailsFeature.ColumnName,\n]);\n\nexport function CorrelationChart({\n data,\n columnSpacing = 0,\n columnWidth = 130,\n unconformityLabels = true,\n showUnitPopover = true,\n selectedUnit,\n onUnitSelected,\n unitComponent,\n columnHeaderComponent,\n axisTopContent,\n onClickTimescaleInterval,\n onColumnMouseOver,\n onColumnClick,\n isTransitioning = false,\n hideLabelsWhileTransitioning = false,\n ...scaleProps\n}: CorrelationChartProps) {\n const chartData = useMemo(() => {\n if (!data) return null;\n return buildCorrelationChartData(data, {\n ...defaultCorrelationChartScaleProps,\n ...scaleProps,\n });\n }, [data, ...Object.values(scaleProps)]);\n\n // A flattened units array is used to support keyboard navigation\n const units = useMemo(() => {\n return data?.map((d0) => d0.units).flat() ?? [];\n }, [data]);\n\n const inDarkMode = useInDarkMode();\n\n const className = classNames({\n \"dark-mode\": inDarkMode,\n });\n\n if (chartData == null) {\n return null;\n }\n\n const { packages, scaleInfo, nColumns } = chartData;\n\n const mainWidth = (columnWidth + columnSpacing) * nColumns;\n\n return h(\n ColumnContainer,\n { className: \"correlation-diagram\" },\n h(\n UnitSelectionProvider,\n { selectedUnit, onUnitSelected, units },\n h(ChartArea, [\n h(TimescaleColumn, {\n scaleInfo,\n unconformityLabels,\n onClickInterval: onClickTimescaleInterval,\n }),\n h(MainChartArea, [\n h(\n SVG,\n {\n className,\n innerWidth: mainWidth,\n height: scaleInfo.totalHeight,\n paddingH: chartPaddingH,\n },\n packages.map((pkg, i) => {\n const { offset, domain, pixelScale, scale, key } =\n scaleInfo.packages[i];\n return h(Package, {\n columnData: pkg.columnData,\n key,\n columnWidth,\n columnSpacing,\n offset,\n domain,\n pixelScale,\n scale,\n unitComponent,\n onColumnMouseOver,\n isTransitioning,\n hideLabelsWhileTransitioning,\n });\n }),\n ),\n h.if(showUnitPopover)(UnitSelectionPopover, {\n features: unitPopoverFeatures,\n }),\n // Navigation only works within a column for now...\n h(UnitKeyboardNavigation, { columnData: data }),\n ]),\n // Rendered last so the sticky header paints above the unit boxes\n // (positioned siblings paint in document order at the same z-index)\n h(ColumnHeaderRow, {\n data,\n columnWidth,\n columnSpacing,\n columnHeaderComponent,\n axisTopContent,\n onColumnMouseOver,\n onColumnClick,\n }),\n ]),\n ),\n );\n}\n\nfunction Package({\n columnData,\n columnSpacing,\n columnWidth,\n unitComponent,\n offset,\n domain,\n pixelScale,\n scale,\n onColumnMouseOver,\n isTransitioning,\n hideLabelsWhileTransitioning,\n}) {\n return h(\"g.package\", { transform: `translate(0 ${offset})` }, [\n // Disable the SVG overlay for now\n //h(PackageSVGOverlay, { columnData, columnSpacing }),\n h(\"g.column-units\", [\n columnData.map((data, i) => {\n return h(Column, {\n units: data.units,\n columnID: data.columnID,\n unitComponent,\n width: columnWidth,\n key: i,\n domain,\n pixelScale,\n scale,\n offsetLeft: i * (columnWidth + columnSpacing),\n onColumnMouseOver,\n isTransitioning,\n hideLabelsWhileTransitioning,\n });\n }),\n ]),\n ]);\n}\n\ninterface ColumnProps {\n units: ExtUnit[];\n columnID?: number;\n unitComponent?: React.FunctionComponent<any>;\n unitComponentProps?: any;\n showLabels?: boolean;\n width?: number;\n columnWidth?: number;\n columnSpacing?: number;\n targetUnitHeight?: number;\n offsetLeft?: number;\n domain: [number, number];\n pixelScale: number;\n scale?: ScaleContinuousNumeric<number, number>;\n onColumnMouseOver?: (columnID: number | null) => void;\n isTransitioning?: boolean;\n hideLabelsWhileTransitioning?: boolean;\n}\n\nfunction Column(props: ColumnProps) {\n const {\n units,\n columnID,\n width = 150,\n offsetLeft,\n domain,\n pixelScale,\n scale,\n unitComponent = ColoredUnitComponent,\n onColumnMouseOver,\n isTransitioning,\n hideLabelsWhileTransitioning,\n } = props;\n\n const columnWidth = width;\n\n if (units.length == 0) {\n return null;\n }\n\n const hoverHandlers =\n onColumnMouseOver != null && columnID != null\n ? {\n onMouseEnter: () => onColumnMouseOver(columnID),\n onMouseLeave: () => onColumnMouseOver(null),\n }\n : {};\n\n return h(\n \"g.section\",\n {\n transform: `translate(${offsetLeft} 0)`,\n ...hoverHandlers,\n },\n h(\n ColumnProvider,\n {\n // Need to tighten up types here...\n divisions: units as any[],\n range: domain,\n scale,\n pixelsPerMeter: pixelScale, // Actually pixels per myr\n axisType: ColumnAxisType.AGE,\n isTransitioning,\n hideLabelsWhileTransitioning,\n },\n h(UnitBoxes, {\n unitComponent,\n unitComponentProps: {\n width: columnWidth,\n showLabel: true,\n },\n }),\n ),\n );\n}\n\nfunction PackageSVGOverlay({ data, columnWidth = 100, columnSpacing = 0 }) {\n const { b_age, t_age, bestPixelScale, columnData } = data;\n\n const width = (columnWidth + columnSpacing) * columnData.length;\n const height = Math.ceil((b_age - t_age) * bestPixelScale) + 2;\n\n const extensiveUnits = findLaterallyExtensiveUnits(data);\n\n const scale = (val: number) => {\n return (val - t_age) * bestPixelScale;\n };\n\n return h(\n \"div.package-overlay\",\n { style: { width, height } },\n extensiveUnits.map((d) => {\n return h(LaterallyExtensiveUnit, {\n data: d,\n scale,\n pixelScale: bestPixelScale,\n columnSpacing,\n });\n }),\n );\n}\n\nfunction LaterallyExtensiveUnit({ data, scale, pixelScale, columnSpacing }) {\n const { b_age, t_age, strat_name_long, units } = data;\n // Build boxes by column groups\n const boxes: UnitGroupBox[] = splitStratIntoBoxes(data);\n\n return h(\n \"div.laterally-extensive-unit\",\n boxes.map((d, i) => {\n return h(StratColSpan, {\n scale,\n data: d,\n pixelScale,\n key: i,\n columnSpacing,\n });\n }),\n );\n}\n\nfunction StratColSpan({\n data,\n scale,\n columnWidth = 100,\n columnSpacing = 0,\n pixelScale = 1,\n}) {\n const { startCol, endCol, strat_name_long, t_age, b_age } = data;\n const top = scale(t_age);\n const left = startCol * (columnWidth + columnSpacing);\n const width = (endCol - startCol + 1) * (columnWidth + columnSpacing);\n const height = (b_age - t_age) * pixelScale;\n return h(\n \"div.strat-col-span\",\n { style: { top, height, width, left } },\n strat_name_long,\n );\n}\n\nfunction ChartArea({ children }) {\n const setSelectedUnit = useUnitSelectionDispatch();\n\n return h(\n \"div.correlation-chart-inner\",\n {\n onClick() {\n setSelectedUnit(null, null);\n },\n },\n children,\n );\n}\n\ninterface ColumnHeaderRowProps {\n data: ColumnData[];\n columnWidth: number;\n columnSpacing: number;\n columnHeaderComponent?: React.ComponentType<ColumnHeaderProps>;\n axisTopContent?: React.ReactNode;\n onColumnMouseOver?: (columnID: number | null) => void;\n onColumnClick?: (columnID: number) => void;\n}\n\nfunction ColumnHeaderRow({\n data,\n columnWidth,\n columnSpacing,\n columnHeaderComponent,\n axisTopContent,\n onColumnMouseOver,\n onColumnClick,\n}: ColumnHeaderRowProps) {\n /** The top grid row: arbitrary content above the timescale axis (top-left)\n * and, when a header component is provided, per-column headers aligned with\n * the columns. Collapses to nothing when neither is present. */\n const Component = columnHeaderComponent;\n if (Component == null && axisTopContent == null) {\n return null;\n }\n\n return h([\n h(\"div.column-header-spacer\", axisTopContent),\n h.if(Component != null)(\n \"div.column-header-row\",\n {\n style: {\n paddingLeft: chartPaddingH,\n paddingRight: chartPaddingH,\n gap: columnSpacing,\n },\n },\n data.map((column, i) => {\n return h(ColumnHeaderCell, {\n key: column.columnID ?? i,\n column,\n columnIndex: i,\n columnWidth,\n Component: Component!,\n onColumnMouseOver,\n onColumnClick,\n });\n }),\n ),\n ]);\n}\n\nfunction ColumnHeaderCell({\n column,\n columnIndex,\n columnWidth,\n Component,\n onColumnMouseOver,\n onColumnClick,\n}: {\n column: ColumnData;\n columnIndex: number;\n columnWidth: number;\n Component: React.ComponentType<ColumnHeaderProps>;\n onColumnMouseOver?: (columnID: number | null) => void;\n onColumnClick?: (columnID: number) => void;\n}) {\n /** Resolves the column name and wires column-level hover/click so the header\n * component itself can stay a pure function of props. */\n const columnID = column.columnID;\n const info = useMacrostratColumnInfo(columnID);\n\n return h(\n \"div.column-header-cell\",\n {\n style: {\n width: columnWidth,\n minWidth: columnWidth,\n maxWidth: columnWidth,\n },\n onMouseEnter: () => onColumnMouseOver?.(columnID),\n onMouseLeave: () => onColumnMouseOver?.(null),\n onClick: onColumnClick\n ? (e: React.MouseEvent) => {\n e.stopPropagation();\n onColumnClick(columnID);\n }\n : undefined,\n },\n h(Component, {\n column,\n columnID,\n columnIndex,\n units: column.units as ExtUnit[],\n width: columnWidth,\n columnName: info?.col_name ?? null,\n }),\n );\n}\n\ninterface TimescaleColumnProps {\n scaleInfo: CompositeStratigraphicScaleInfo;\n showLabels?: boolean;\n unconformityLabels?: boolean;\n onClickInterval?: TimescaleClickHandler;\n}\n\nfunction TimescaleColumn(props: TimescaleColumnProps) {\n const { scaleInfo, unconformityLabels = true, onClickInterval } = props;\n return h(\"div.column-container.age-axis-container\", [\n h(CompositeAgeAxisCore, { ...scaleInfo }),\n h(CompositeTimescaleCore, {\n ...scaleInfo,\n unconformityLabels,\n onClickInterval,\n }),\n ]);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -70,6 +70,8 @@ function MacrostratColumnDataProvider({
|
|
|
70
70
|
allowUnitSelection,
|
|
71
71
|
onUnitSelected,
|
|
72
72
|
selectedUnit,
|
|
73
|
+
isTransitioning,
|
|
74
|
+
hideLabelsWhileTransitioning,
|
|
73
75
|
ref
|
|
74
76
|
}) {
|
|
75
77
|
const value = React.useMemo(() => {
|
|
@@ -77,9 +79,18 @@ function MacrostratColumnDataProvider({
|
|
|
77
79
|
units,
|
|
78
80
|
sections,
|
|
79
81
|
totalHeight,
|
|
80
|
-
axisType
|
|
82
|
+
axisType,
|
|
83
|
+
isTransitioning,
|
|
84
|
+
hideLabelsWhileTransitioning
|
|
81
85
|
};
|
|
82
|
-
}, [
|
|
86
|
+
}, [
|
|
87
|
+
units,
|
|
88
|
+
sections,
|
|
89
|
+
totalHeight,
|
|
90
|
+
axisType,
|
|
91
|
+
isTransitioning,
|
|
92
|
+
hideLabelsWhileTransitioning
|
|
93
|
+
]);
|
|
83
94
|
return h__default.default(
|
|
84
95
|
MacrostratColumnStateProvider,
|
|
85
96
|
{
|
|
@@ -146,7 +157,7 @@ function useCompositeScale() {
|
|
|
146
157
|
);
|
|
147
158
|
}
|
|
148
159
|
function MacrostratColumnProvider(props) {
|
|
149
|
-
const { axisType } = useMacrostratColumnData();
|
|
160
|
+
const { axisType, isTransitioning, hideLabelsWhileTransitioning } = useMacrostratColumnData();
|
|
150
161
|
const { units, domain, pixelScale, scale, children } = props;
|
|
151
162
|
return h__default.default(
|
|
152
163
|
columnComponents.ColumnProvider,
|
|
@@ -155,7 +166,9 @@ function MacrostratColumnProvider(props) {
|
|
|
155
166
|
divisions: units,
|
|
156
167
|
range: domain,
|
|
157
168
|
pixelsPerMeter: pixelScale,
|
|
158
|
-
scale
|
|
169
|
+
scale,
|
|
170
|
+
isTransitioning,
|
|
171
|
+
hideLabelsWhileTransitioning
|
|
159
172
|
},
|
|
160
173
|
children
|
|
161
174
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.cjs","sources":["../../src/data-provider/store.ts"],"sourcesContent":["import {\n createContext,\n ReactNode,\n RefObject,\n useContext,\n useMemo,\n} from \"react\";\nimport h from \"@macrostrat/hyper\";\nimport {\n CompositeColumnScale,\n createCompositeScale,\n} from \"../prepare-units/composite-scale\";\nimport { ColumnAxisType, ColumnProvider } from \"@macrostrat/column-components\";\nimport type { ExtUnit, PackageLayoutData } from \"../prepare-units\";\nimport {\n allowUnitSelectionAtom,\n selectedUnitIDAtom,\n UnitSelectionCallbacks,\n UnitSelectionCallbackManager,\n selectedUnitElementAtom,\n} from \"./unit-selection\";\nimport type { BaseUnit } from \"@macrostrat/api-types\";\nimport {\n type AtomMap,\n createScopedStore,\n StateIsolation,\n} from \"@macrostrat/scoped-store\";\nimport { atom } from \"jotai\";\nimport { useEffect } from \"react\";\n\nexport const scope: StateIsolation = createScopedStore();\n\nexport const columnUnitsAtom = atom<BaseUnit[]>();\n\nexport const columnUnitsMapAtom = atom<Map<number, BaseUnit> | null>((get) => {\n const units = get(columnUnitsAtom);\n if (!units) return null;\n const unitMap = new Map<number, BaseUnit>();\n units.forEach((unit) => {\n unitMap.set(unit.unit_id, unit);\n });\n return unitMap;\n});\n\nexport interface ColumnStateProviderProps<\n T extends BaseUnit,\n> extends Partial<UnitSelectionCallbacks> {\n children: ReactNode;\n units: T[];\n selectedUnit: number | null;\n allowUnitSelection?: boolean;\n}\n\nexport function MacrostratColumnStateProvider<T extends BaseUnit>({\n children,\n units,\n allowUnitSelection = false,\n onUnitSelected,\n selectedUnit,\n}: ColumnStateProviderProps<T>) {\n /** Top-level provider for Macrostrat column data.\n * It is either provided by the Column component itself, or\n * can be hoisted higher in the tree to provide a common data context\n */\n\n /* By default, unit selection is disabled. However, if any related props are passed,\n we enable it.\n */\n const _allowSelection = useMemo(() => {\n if (allowUnitSelection) {\n return true;\n }\n return selectedUnit != null || onUnitSelected != null;\n }, []);\n\n // Check if we're already in a columnStateProvider, and render a no-op if so\n const existingUnits = scope.useAtomValueIfExists(columnUnitsAtom);\n if (existingUnits != null) {\n if (allowUnitSelection || onUnitSelected || selectedUnit != null) {\n console.warn(\n \"MacrostratColumnStateProvider: unit selection props are ignored because a provider already exists in the tree\",\n );\n }\n return children;\n }\n\n const atomMap: AtomMap = [\n [columnUnitsAtom, units],\n [allowUnitSelectionAtom, _allowSelection],\n [selectedUnitIDAtom, selectedUnit],\n ];\n\n let selectionHandlers: ReactNode = null;\n if (_allowSelection) {\n selectionHandlers = h(UnitSelectionCallbackManager, { onUnitSelected });\n }\n\n return h(\n scope.Provider,\n {\n atoms: atomMap,\n keepUpdated: true,\n },\n [selectionHandlers, children],\n );\n}\n\n/** Interface for imperative handlers that can\n * be invoked outside of the column's react context\n */\nexport interface ColumnRef {\n scrollSelectedUnitIntoView(): void;\n}\n\nexport interface MacrostratColumnDataContext<T extends BaseUnit> {\n units: T[];\n sections: PackageLayoutData[];\n totalHeight?: number;\n axisType?: ColumnAxisType;\n allowUnitSelection?: boolean;\n}\n\nexport interface ColumnDataProviderProps<T extends BaseUnit>\n extends MacrostratColumnDataContext<T>, ColumnStateProviderProps<T> {\n children: ReactNode;\n ref: RefObject<ColumnRef>;\n}\n\nconst MacrostratColumnDataContext =\n createContext<MacrostratColumnDataContext<any>>(null);\n\nexport function MacrostratColumnDataProvider<T extends BaseUnit>({\n children,\n units,\n sections,\n totalHeight,\n axisType,\n allowUnitSelection,\n onUnitSelected,\n selectedUnit,\n ref,\n}: ColumnDataProviderProps<T>) {\n /** Internal provider for Macrostrat column data.\n * As a general rule, we want to provide data and column-axis\n * height calculations through the context, since these need to\n * be accessed by any component that lays out information on the\n * column.\n *\n * Cross-axis layout and view configuration (e.g., showing and hiding\n * of different components or labels) should be handled through passing\n * props to the components themselves.\n * */\n\n const value = useMemo(() => {\n // For now, change ordinal axis types to age axis types\n return {\n units,\n sections,\n totalHeight,\n axisType,\n };\n }, [units, sections, totalHeight, axisType]);\n\n return h(\n MacrostratColumnStateProvider,\n {\n units,\n allowUnitSelection,\n onUnitSelected,\n selectedUnit,\n ref,\n },\n [\n h(ColumnRefManager, { ref }),\n h(MacrostratColumnDataContext.Provider, { value }, children),\n ],\n );\n}\n\nfunction ColumnRefManager({ ref }: { ref?: RefObject<ColumnRef> }) {\n const selectedUnitElement = scope.useAtomValue(selectedUnitElementAtom);\n useEffect(() => {\n if (ref == null) return;\n ref.current = {\n scrollSelectedUnitIntoView(opts?: ScrollIntoViewOptions) {\n selectedUnitElement?.scrollIntoView(\n opts ?? {\n behavior: \"smooth\",\n block: \"center\",\n inline: \"nearest\",\n },\n );\n },\n };\n }, [ref, selectedUnitElement]);\n\n return null;\n}\n\nexport function UnitSelectionProvider(props: ColumnStateProviderProps<any>) {\n /* A basic unit selection provider without column data context.\n Mostly for use with the CorrelationChart component.\n */\n return h(MacrostratColumnStateProvider, {\n ...props,\n allowUnitSelection: true,\n });\n}\n\nexport function useMacrostratColumnData() {\n const ctx = useContext(MacrostratColumnDataContext);\n if (!ctx) {\n throw new Error(\n \"useMacrostratColumnData must be used within a MacrostratColumnDataProvider\",\n );\n }\n return ctx;\n}\n\nexport function useMacrostratUnits() {\n return scope.useAtomValue(columnUnitsAtom);\n}\n\nexport function useColumnUnitsMap(): Map<number, ExtUnit> | null {\n try {\n return scope.useAtomValue(columnUnitsMapAtom) as Map<number, ExtUnit>;\n } catch {\n return null;\n }\n}\n\nexport function useCompositeScale(): CompositeColumnScale {\n const ctx = useMacrostratColumnData();\n return useMemo(\n () => createCompositeScale(ctx.sections, true),\n [ctx.sections],\n );\n}\n\nexport function MacrostratColumnProvider(props) {\n /** A column provider specialized the Macrostrat API. Maps more\n * generic concepts to Macrostrat-specific ones.\n */\n\n const { axisType } = useMacrostratColumnData();\n const { units, domain, pixelScale, scale, children } = props;\n return h(\n ColumnProvider,\n {\n axisType,\n divisions: units,\n range: domain,\n pixelsPerMeter: pixelScale,\n scale,\n },\n children,\n );\n}\n\n/** This is now a legacy provider */\nexport function LithologiesProvider({ children }) {\n useEffect(() => {\n console.warn(\n \"LithologiesProvider is deprecated. Replace with MacrostratDataProvider\",\n );\n }, []);\n return children;\n}\n"],"names":["createScopedStore","atom","useMemo","allowUnitSelectionAtom","selectedUnitIDAtom","h","UnitSelectionCallbackManager","createContext","selectedUnitElementAtom","useEffect","useContext","createCompositeScale","ColumnProvider"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"store.cjs","sources":["../../src/data-provider/store.ts"],"sourcesContent":["import {\n createContext,\n ReactNode,\n RefObject,\n useContext,\n useMemo,\n} from \"react\";\nimport h from \"@macrostrat/hyper\";\nimport {\n CompositeColumnScale,\n createCompositeScale,\n} from \"../prepare-units/composite-scale\";\nimport { ColumnAxisType, ColumnProvider } from \"@macrostrat/column-components\";\nimport type { ExtUnit, PackageLayoutData } from \"../prepare-units\";\nimport {\n allowUnitSelectionAtom,\n selectedUnitIDAtom,\n UnitSelectionCallbacks,\n UnitSelectionCallbackManager,\n selectedUnitElementAtom,\n} from \"./unit-selection\";\nimport type { BaseUnit } from \"@macrostrat/api-types\";\nimport {\n type AtomMap,\n createScopedStore,\n StateIsolation,\n} from \"@macrostrat/scoped-store\";\nimport { atom } from \"jotai\";\nimport { useEffect } from \"react\";\n\nexport const scope: StateIsolation = createScopedStore();\n\nexport const columnUnitsAtom = atom<BaseUnit[]>();\n\nexport const columnUnitsMapAtom = atom<Map<number, BaseUnit> | null>((get) => {\n const units = get(columnUnitsAtom);\n if (!units) return null;\n const unitMap = new Map<number, BaseUnit>();\n units.forEach((unit) => {\n unitMap.set(unit.unit_id, unit);\n });\n return unitMap;\n});\n\nexport interface ColumnStateProviderProps<\n T extends BaseUnit,\n> extends Partial<UnitSelectionCallbacks> {\n children: ReactNode;\n units: T[];\n selectedUnit: number | null;\n allowUnitSelection?: boolean;\n}\n\nexport function MacrostratColumnStateProvider<T extends BaseUnit>({\n children,\n units,\n allowUnitSelection = false,\n onUnitSelected,\n selectedUnit,\n}: ColumnStateProviderProps<T>) {\n /** Top-level provider for Macrostrat column data.\n * It is either provided by the Column component itself, or\n * can be hoisted higher in the tree to provide a common data context\n */\n\n /* By default, unit selection is disabled. However, if any related props are passed,\n we enable it.\n */\n const _allowSelection = useMemo(() => {\n if (allowUnitSelection) {\n return true;\n }\n return selectedUnit != null || onUnitSelected != null;\n }, []);\n\n // Check if we're already in a columnStateProvider, and render a no-op if so\n const existingUnits = scope.useAtomValueIfExists(columnUnitsAtom);\n if (existingUnits != null) {\n if (allowUnitSelection || onUnitSelected || selectedUnit != null) {\n console.warn(\n \"MacrostratColumnStateProvider: unit selection props are ignored because a provider already exists in the tree\",\n );\n }\n return children;\n }\n\n const atomMap: AtomMap = [\n [columnUnitsAtom, units],\n [allowUnitSelectionAtom, _allowSelection],\n [selectedUnitIDAtom, selectedUnit],\n ];\n\n let selectionHandlers: ReactNode = null;\n if (_allowSelection) {\n selectionHandlers = h(UnitSelectionCallbackManager, { onUnitSelected });\n }\n\n return h(\n scope.Provider,\n {\n atoms: atomMap,\n keepUpdated: true,\n },\n [selectionHandlers, children],\n );\n}\n\n/** Interface for imperative handlers that can\n * be invoked outside of the column's react context\n */\nexport interface ColumnRef {\n scrollSelectedUnitIntoView(): void;\n}\n\nexport interface MacrostratColumnDataContext<T extends BaseUnit> {\n units: T[];\n sections: PackageLayoutData[];\n totalHeight?: number;\n axisType?: ColumnAxisType;\n allowUnitSelection?: boolean;\n /** True while the age window is animating; propagated to each section's\n * `ColumnProvider` so per-frame label/pattern work can be skipped. */\n isTransitioning?: boolean;\n /** Hide unit labels while transitioning (perf escape hatch; default false). */\n hideLabelsWhileTransitioning?: boolean;\n}\n\nexport interface ColumnDataProviderProps<T extends BaseUnit>\n extends MacrostratColumnDataContext<T>, ColumnStateProviderProps<T> {\n children: ReactNode;\n ref: RefObject<ColumnRef>;\n}\n\nconst MacrostratColumnDataContext =\n createContext<MacrostratColumnDataContext<any>>(null);\n\nexport function MacrostratColumnDataProvider<T extends BaseUnit>({\n children,\n units,\n sections,\n totalHeight,\n axisType,\n allowUnitSelection,\n onUnitSelected,\n selectedUnit,\n isTransitioning,\n hideLabelsWhileTransitioning,\n ref,\n}: ColumnDataProviderProps<T>) {\n /** Internal provider for Macrostrat column data.\n * As a general rule, we want to provide data and column-axis\n * height calculations through the context, since these need to\n * be accessed by any component that lays out information on the\n * column.\n *\n * Cross-axis layout and view configuration (e.g., showing and hiding\n * of different components or labels) should be handled through passing\n * props to the components themselves.\n * */\n\n const value = useMemo(() => {\n // For now, change ordinal axis types to age axis types\n return {\n units,\n sections,\n totalHeight,\n axisType,\n isTransitioning,\n hideLabelsWhileTransitioning,\n };\n }, [\n units,\n sections,\n totalHeight,\n axisType,\n isTransitioning,\n hideLabelsWhileTransitioning,\n ]);\n\n return h(\n MacrostratColumnStateProvider,\n {\n units,\n allowUnitSelection,\n onUnitSelected,\n selectedUnit,\n ref,\n },\n [\n h(ColumnRefManager, { ref }),\n h(MacrostratColumnDataContext.Provider, { value }, children),\n ],\n );\n}\n\nfunction ColumnRefManager({ ref }: { ref?: RefObject<ColumnRef> }) {\n const selectedUnitElement = scope.useAtomValue(selectedUnitElementAtom);\n useEffect(() => {\n if (ref == null) return;\n ref.current = {\n scrollSelectedUnitIntoView(opts?: ScrollIntoViewOptions) {\n selectedUnitElement?.scrollIntoView(\n opts ?? {\n behavior: \"smooth\",\n block: \"center\",\n inline: \"nearest\",\n },\n );\n },\n };\n }, [ref, selectedUnitElement]);\n\n return null;\n}\n\nexport function UnitSelectionProvider(props: ColumnStateProviderProps<any>) {\n /* A basic unit selection provider without column data context.\n Mostly for use with the CorrelationChart component.\n */\n return h(MacrostratColumnStateProvider, {\n ...props,\n allowUnitSelection: true,\n });\n}\n\nexport function useMacrostratColumnData() {\n const ctx = useContext(MacrostratColumnDataContext);\n if (!ctx) {\n throw new Error(\n \"useMacrostratColumnData must be used within a MacrostratColumnDataProvider\",\n );\n }\n return ctx;\n}\n\nexport function useMacrostratUnits() {\n return scope.useAtomValue(columnUnitsAtom);\n}\n\nexport function useColumnUnitsMap(): Map<number, ExtUnit> | null {\n try {\n return scope.useAtomValue(columnUnitsMapAtom) as Map<number, ExtUnit>;\n } catch {\n return null;\n }\n}\n\nexport function useCompositeScale(): CompositeColumnScale {\n const ctx = useMacrostratColumnData();\n return useMemo(\n () => createCompositeScale(ctx.sections, true),\n [ctx.sections],\n );\n}\n\nexport function MacrostratColumnProvider(props) {\n /** A column provider specialized the Macrostrat API. Maps more\n * generic concepts to Macrostrat-specific ones.\n */\n\n const { axisType, isTransitioning, hideLabelsWhileTransitioning } =\n useMacrostratColumnData();\n const { units, domain, pixelScale, scale, children } = props;\n return h(\n ColumnProvider,\n {\n axisType,\n divisions: units,\n range: domain,\n pixelsPerMeter: pixelScale,\n scale,\n isTransitioning,\n hideLabelsWhileTransitioning,\n },\n children,\n );\n}\n\n/** This is now a legacy provider */\nexport function LithologiesProvider({ children }) {\n useEffect(() => {\n console.warn(\n \"LithologiesProvider is deprecated. Replace with MacrostratDataProvider\",\n );\n }, []);\n return children;\n}\n"],"names":["createScopedStore","atom","useMemo","allowUnitSelectionAtom","selectedUnitIDAtom","h","UnitSelectionCallbackManager","createContext","selectedUnitElementAtom","useEffect","useContext","createCompositeScale","ColumnProvider"],"mappings":"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"}
|
|
@@ -34,12 +34,17 @@ export interface MacrostratColumnDataContext<T extends BaseUnit> {
|
|
|
34
34
|
totalHeight?: number;
|
|
35
35
|
axisType?: ColumnAxisType;
|
|
36
36
|
allowUnitSelection?: boolean;
|
|
37
|
+
/** True while the age window is animating; propagated to each section's
|
|
38
|
+
* `ColumnProvider` so per-frame label/pattern work can be skipped. */
|
|
39
|
+
isTransitioning?: boolean;
|
|
40
|
+
/** Hide unit labels while transitioning (perf escape hatch; default false). */
|
|
41
|
+
hideLabelsWhileTransitioning?: boolean;
|
|
37
42
|
}
|
|
38
43
|
export interface ColumnDataProviderProps<T extends BaseUnit> extends MacrostratColumnDataContext<T>, ColumnStateProviderProps<T> {
|
|
39
44
|
children: ReactNode;
|
|
40
45
|
ref: RefObject<ColumnRef>;
|
|
41
46
|
}
|
|
42
|
-
export declare function MacrostratColumnDataProvider<T extends BaseUnit>({ children, units, sections, totalHeight, axisType, allowUnitSelection, onUnitSelected, selectedUnit, ref, }: ColumnDataProviderProps<T>): import('react').FunctionComponentElement<ColumnStateProviderProps<BaseUnit>>;
|
|
47
|
+
export declare function MacrostratColumnDataProvider<T extends BaseUnit>({ children, units, sections, totalHeight, axisType, allowUnitSelection, onUnitSelected, selectedUnit, isTransitioning, hideLabelsWhileTransitioning, ref, }: ColumnDataProviderProps<T>): import('react').FunctionComponentElement<ColumnStateProviderProps<BaseUnit>>;
|
|
43
48
|
export declare function UnitSelectionProvider(props: ColumnStateProviderProps<any>): import('react').FunctionComponentElement<ColumnStateProviderProps<BaseUnit>>;
|
|
44
49
|
export declare function useMacrostratColumnData(): MacrostratColumnDataContext<any>;
|
|
45
50
|
export declare function useMacrostratUnits(): any;
|
|
@@ -66,6 +66,8 @@ function MacrostratColumnDataProvider({
|
|
|
66
66
|
allowUnitSelection,
|
|
67
67
|
onUnitSelected,
|
|
68
68
|
selectedUnit,
|
|
69
|
+
isTransitioning,
|
|
70
|
+
hideLabelsWhileTransitioning,
|
|
69
71
|
ref
|
|
70
72
|
}) {
|
|
71
73
|
const value = useMemo(() => {
|
|
@@ -73,9 +75,18 @@ function MacrostratColumnDataProvider({
|
|
|
73
75
|
units,
|
|
74
76
|
sections,
|
|
75
77
|
totalHeight,
|
|
76
|
-
axisType
|
|
78
|
+
axisType,
|
|
79
|
+
isTransitioning,
|
|
80
|
+
hideLabelsWhileTransitioning
|
|
77
81
|
};
|
|
78
|
-
}, [
|
|
82
|
+
}, [
|
|
83
|
+
units,
|
|
84
|
+
sections,
|
|
85
|
+
totalHeight,
|
|
86
|
+
axisType,
|
|
87
|
+
isTransitioning,
|
|
88
|
+
hideLabelsWhileTransitioning
|
|
89
|
+
]);
|
|
79
90
|
return h(
|
|
80
91
|
MacrostratColumnStateProvider,
|
|
81
92
|
{
|
|
@@ -142,7 +153,7 @@ function useCompositeScale() {
|
|
|
142
153
|
);
|
|
143
154
|
}
|
|
144
155
|
function MacrostratColumnProvider(props) {
|
|
145
|
-
const { axisType } = useMacrostratColumnData();
|
|
156
|
+
const { axisType, isTransitioning, hideLabelsWhileTransitioning } = useMacrostratColumnData();
|
|
146
157
|
const { units, domain, pixelScale, scale, children } = props;
|
|
147
158
|
return h(
|
|
148
159
|
ColumnProvider,
|
|
@@ -151,7 +162,9 @@ function MacrostratColumnProvider(props) {
|
|
|
151
162
|
divisions: units,
|
|
152
163
|
range: domain,
|
|
153
164
|
pixelsPerMeter: pixelScale,
|
|
154
|
-
scale
|
|
165
|
+
scale,
|
|
166
|
+
isTransitioning,
|
|
167
|
+
hideLabelsWhileTransitioning
|
|
155
168
|
},
|
|
156
169
|
children
|
|
157
170
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sources":["../../src/data-provider/store.ts"],"sourcesContent":["import {\n createContext,\n ReactNode,\n RefObject,\n useContext,\n useMemo,\n} from \"react\";\nimport h from \"@macrostrat/hyper\";\nimport {\n CompositeColumnScale,\n createCompositeScale,\n} from \"../prepare-units/composite-scale\";\nimport { ColumnAxisType, ColumnProvider } from \"@macrostrat/column-components\";\nimport type { ExtUnit, PackageLayoutData } from \"../prepare-units\";\nimport {\n allowUnitSelectionAtom,\n selectedUnitIDAtom,\n UnitSelectionCallbacks,\n UnitSelectionCallbackManager,\n selectedUnitElementAtom,\n} from \"./unit-selection\";\nimport type { BaseUnit } from \"@macrostrat/api-types\";\nimport {\n type AtomMap,\n createScopedStore,\n StateIsolation,\n} from \"@macrostrat/scoped-store\";\nimport { atom } from \"jotai\";\nimport { useEffect } from \"react\";\n\nexport const scope: StateIsolation = createScopedStore();\n\nexport const columnUnitsAtom = atom<BaseUnit[]>();\n\nexport const columnUnitsMapAtom = atom<Map<number, BaseUnit> | null>((get) => {\n const units = get(columnUnitsAtom);\n if (!units) return null;\n const unitMap = new Map<number, BaseUnit>();\n units.forEach((unit) => {\n unitMap.set(unit.unit_id, unit);\n });\n return unitMap;\n});\n\nexport interface ColumnStateProviderProps<\n T extends BaseUnit,\n> extends Partial<UnitSelectionCallbacks> {\n children: ReactNode;\n units: T[];\n selectedUnit: number | null;\n allowUnitSelection?: boolean;\n}\n\nexport function MacrostratColumnStateProvider<T extends BaseUnit>({\n children,\n units,\n allowUnitSelection = false,\n onUnitSelected,\n selectedUnit,\n}: ColumnStateProviderProps<T>) {\n /** Top-level provider for Macrostrat column data.\n * It is either provided by the Column component itself, or\n * can be hoisted higher in the tree to provide a common data context\n */\n\n /* By default, unit selection is disabled. However, if any related props are passed,\n we enable it.\n */\n const _allowSelection = useMemo(() => {\n if (allowUnitSelection) {\n return true;\n }\n return selectedUnit != null || onUnitSelected != null;\n }, []);\n\n // Check if we're already in a columnStateProvider, and render a no-op if so\n const existingUnits = scope.useAtomValueIfExists(columnUnitsAtom);\n if (existingUnits != null) {\n if (allowUnitSelection || onUnitSelected || selectedUnit != null) {\n console.warn(\n \"MacrostratColumnStateProvider: unit selection props are ignored because a provider already exists in the tree\",\n );\n }\n return children;\n }\n\n const atomMap: AtomMap = [\n [columnUnitsAtom, units],\n [allowUnitSelectionAtom, _allowSelection],\n [selectedUnitIDAtom, selectedUnit],\n ];\n\n let selectionHandlers: ReactNode = null;\n if (_allowSelection) {\n selectionHandlers = h(UnitSelectionCallbackManager, { onUnitSelected });\n }\n\n return h(\n scope.Provider,\n {\n atoms: atomMap,\n keepUpdated: true,\n },\n [selectionHandlers, children],\n );\n}\n\n/** Interface for imperative handlers that can\n * be invoked outside of the column's react context\n */\nexport interface ColumnRef {\n scrollSelectedUnitIntoView(): void;\n}\n\nexport interface MacrostratColumnDataContext<T extends BaseUnit> {\n units: T[];\n sections: PackageLayoutData[];\n totalHeight?: number;\n axisType?: ColumnAxisType;\n allowUnitSelection?: boolean;\n}\n\nexport interface ColumnDataProviderProps<T extends BaseUnit>\n extends MacrostratColumnDataContext<T>, ColumnStateProviderProps<T> {\n children: ReactNode;\n ref: RefObject<ColumnRef>;\n}\n\nconst MacrostratColumnDataContext =\n createContext<MacrostratColumnDataContext<any>>(null);\n\nexport function MacrostratColumnDataProvider<T extends BaseUnit>({\n children,\n units,\n sections,\n totalHeight,\n axisType,\n allowUnitSelection,\n onUnitSelected,\n selectedUnit,\n ref,\n}: ColumnDataProviderProps<T>) {\n /** Internal provider for Macrostrat column data.\n * As a general rule, we want to provide data and column-axis\n * height calculations through the context, since these need to\n * be accessed by any component that lays out information on the\n * column.\n *\n * Cross-axis layout and view configuration (e.g., showing and hiding\n * of different components or labels) should be handled through passing\n * props to the components themselves.\n * */\n\n const value = useMemo(() => {\n // For now, change ordinal axis types to age axis types\n return {\n units,\n sections,\n totalHeight,\n axisType,\n };\n }, [units, sections, totalHeight, axisType]);\n\n return h(\n MacrostratColumnStateProvider,\n {\n units,\n allowUnitSelection,\n onUnitSelected,\n selectedUnit,\n ref,\n },\n [\n h(ColumnRefManager, { ref }),\n h(MacrostratColumnDataContext.Provider, { value }, children),\n ],\n );\n}\n\nfunction ColumnRefManager({ ref }: { ref?: RefObject<ColumnRef> }) {\n const selectedUnitElement = scope.useAtomValue(selectedUnitElementAtom);\n useEffect(() => {\n if (ref == null) return;\n ref.current = {\n scrollSelectedUnitIntoView(opts?: ScrollIntoViewOptions) {\n selectedUnitElement?.scrollIntoView(\n opts ?? {\n behavior: \"smooth\",\n block: \"center\",\n inline: \"nearest\",\n },\n );\n },\n };\n }, [ref, selectedUnitElement]);\n\n return null;\n}\n\nexport function UnitSelectionProvider(props: ColumnStateProviderProps<any>) {\n /* A basic unit selection provider without column data context.\n Mostly for use with the CorrelationChart component.\n */\n return h(MacrostratColumnStateProvider, {\n ...props,\n allowUnitSelection: true,\n });\n}\n\nexport function useMacrostratColumnData() {\n const ctx = useContext(MacrostratColumnDataContext);\n if (!ctx) {\n throw new Error(\n \"useMacrostratColumnData must be used within a MacrostratColumnDataProvider\",\n );\n }\n return ctx;\n}\n\nexport function useMacrostratUnits() {\n return scope.useAtomValue(columnUnitsAtom);\n}\n\nexport function useColumnUnitsMap(): Map<number, ExtUnit> | null {\n try {\n return scope.useAtomValue(columnUnitsMapAtom) as Map<number, ExtUnit>;\n } catch {\n return null;\n }\n}\n\nexport function useCompositeScale(): CompositeColumnScale {\n const ctx = useMacrostratColumnData();\n return useMemo(\n () => createCompositeScale(ctx.sections, true),\n [ctx.sections],\n );\n}\n\nexport function MacrostratColumnProvider(props) {\n /** A column provider specialized the Macrostrat API. Maps more\n * generic concepts to Macrostrat-specific ones.\n */\n\n const { axisType } = useMacrostratColumnData();\n const { units, domain, pixelScale, scale, children } = props;\n return h(\n ColumnProvider,\n {\n axisType,\n divisions: units,\n range: domain,\n pixelsPerMeter: pixelScale,\n scale,\n },\n children,\n );\n}\n\n/** This is now a legacy provider */\nexport function LithologiesProvider({ children }) {\n useEffect(() => {\n console.warn(\n \"LithologiesProvider is deprecated. Replace with MacrostratDataProvider\",\n );\n }, []);\n return children;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"store.js","sources":["../../src/data-provider/store.ts"],"sourcesContent":["import {\n createContext,\n ReactNode,\n RefObject,\n useContext,\n useMemo,\n} from \"react\";\nimport h from \"@macrostrat/hyper\";\nimport {\n CompositeColumnScale,\n createCompositeScale,\n} from \"../prepare-units/composite-scale\";\nimport { ColumnAxisType, ColumnProvider } from \"@macrostrat/column-components\";\nimport type { ExtUnit, PackageLayoutData } from \"../prepare-units\";\nimport {\n allowUnitSelectionAtom,\n selectedUnitIDAtom,\n UnitSelectionCallbacks,\n UnitSelectionCallbackManager,\n selectedUnitElementAtom,\n} from \"./unit-selection\";\nimport type { BaseUnit } from \"@macrostrat/api-types\";\nimport {\n type AtomMap,\n createScopedStore,\n StateIsolation,\n} from \"@macrostrat/scoped-store\";\nimport { atom } from \"jotai\";\nimport { useEffect } from \"react\";\n\nexport const scope: StateIsolation = createScopedStore();\n\nexport const columnUnitsAtom = atom<BaseUnit[]>();\n\nexport const columnUnitsMapAtom = atom<Map<number, BaseUnit> | null>((get) => {\n const units = get(columnUnitsAtom);\n if (!units) return null;\n const unitMap = new Map<number, BaseUnit>();\n units.forEach((unit) => {\n unitMap.set(unit.unit_id, unit);\n });\n return unitMap;\n});\n\nexport interface ColumnStateProviderProps<\n T extends BaseUnit,\n> extends Partial<UnitSelectionCallbacks> {\n children: ReactNode;\n units: T[];\n selectedUnit: number | null;\n allowUnitSelection?: boolean;\n}\n\nexport function MacrostratColumnStateProvider<T extends BaseUnit>({\n children,\n units,\n allowUnitSelection = false,\n onUnitSelected,\n selectedUnit,\n}: ColumnStateProviderProps<T>) {\n /** Top-level provider for Macrostrat column data.\n * It is either provided by the Column component itself, or\n * can be hoisted higher in the tree to provide a common data context\n */\n\n /* By default, unit selection is disabled. However, if any related props are passed,\n we enable it.\n */\n const _allowSelection = useMemo(() => {\n if (allowUnitSelection) {\n return true;\n }\n return selectedUnit != null || onUnitSelected != null;\n }, []);\n\n // Check if we're already in a columnStateProvider, and render a no-op if so\n const existingUnits = scope.useAtomValueIfExists(columnUnitsAtom);\n if (existingUnits != null) {\n if (allowUnitSelection || onUnitSelected || selectedUnit != null) {\n console.warn(\n \"MacrostratColumnStateProvider: unit selection props are ignored because a provider already exists in the tree\",\n );\n }\n return children;\n }\n\n const atomMap: AtomMap = [\n [columnUnitsAtom, units],\n [allowUnitSelectionAtom, _allowSelection],\n [selectedUnitIDAtom, selectedUnit],\n ];\n\n let selectionHandlers: ReactNode = null;\n if (_allowSelection) {\n selectionHandlers = h(UnitSelectionCallbackManager, { onUnitSelected });\n }\n\n return h(\n scope.Provider,\n {\n atoms: atomMap,\n keepUpdated: true,\n },\n [selectionHandlers, children],\n );\n}\n\n/** Interface for imperative handlers that can\n * be invoked outside of the column's react context\n */\nexport interface ColumnRef {\n scrollSelectedUnitIntoView(): void;\n}\n\nexport interface MacrostratColumnDataContext<T extends BaseUnit> {\n units: T[];\n sections: PackageLayoutData[];\n totalHeight?: number;\n axisType?: ColumnAxisType;\n allowUnitSelection?: boolean;\n /** True while the age window is animating; propagated to each section's\n * `ColumnProvider` so per-frame label/pattern work can be skipped. */\n isTransitioning?: boolean;\n /** Hide unit labels while transitioning (perf escape hatch; default false). */\n hideLabelsWhileTransitioning?: boolean;\n}\n\nexport interface ColumnDataProviderProps<T extends BaseUnit>\n extends MacrostratColumnDataContext<T>, ColumnStateProviderProps<T> {\n children: ReactNode;\n ref: RefObject<ColumnRef>;\n}\n\nconst MacrostratColumnDataContext =\n createContext<MacrostratColumnDataContext<any>>(null);\n\nexport function MacrostratColumnDataProvider<T extends BaseUnit>({\n children,\n units,\n sections,\n totalHeight,\n axisType,\n allowUnitSelection,\n onUnitSelected,\n selectedUnit,\n isTransitioning,\n hideLabelsWhileTransitioning,\n ref,\n}: ColumnDataProviderProps<T>) {\n /** Internal provider for Macrostrat column data.\n * As a general rule, we want to provide data and column-axis\n * height calculations through the context, since these need to\n * be accessed by any component that lays out information on the\n * column.\n *\n * Cross-axis layout and view configuration (e.g., showing and hiding\n * of different components or labels) should be handled through passing\n * props to the components themselves.\n * */\n\n const value = useMemo(() => {\n // For now, change ordinal axis types to age axis types\n return {\n units,\n sections,\n totalHeight,\n axisType,\n isTransitioning,\n hideLabelsWhileTransitioning,\n };\n }, [\n units,\n sections,\n totalHeight,\n axisType,\n isTransitioning,\n hideLabelsWhileTransitioning,\n ]);\n\n return h(\n MacrostratColumnStateProvider,\n {\n units,\n allowUnitSelection,\n onUnitSelected,\n selectedUnit,\n ref,\n },\n [\n h(ColumnRefManager, { ref }),\n h(MacrostratColumnDataContext.Provider, { value }, children),\n ],\n );\n}\n\nfunction ColumnRefManager({ ref }: { ref?: RefObject<ColumnRef> }) {\n const selectedUnitElement = scope.useAtomValue(selectedUnitElementAtom);\n useEffect(() => {\n if (ref == null) return;\n ref.current = {\n scrollSelectedUnitIntoView(opts?: ScrollIntoViewOptions) {\n selectedUnitElement?.scrollIntoView(\n opts ?? {\n behavior: \"smooth\",\n block: \"center\",\n inline: \"nearest\",\n },\n );\n },\n };\n }, [ref, selectedUnitElement]);\n\n return null;\n}\n\nexport function UnitSelectionProvider(props: ColumnStateProviderProps<any>) {\n /* A basic unit selection provider without column data context.\n Mostly for use with the CorrelationChart component.\n */\n return h(MacrostratColumnStateProvider, {\n ...props,\n allowUnitSelection: true,\n });\n}\n\nexport function useMacrostratColumnData() {\n const ctx = useContext(MacrostratColumnDataContext);\n if (!ctx) {\n throw new Error(\n \"useMacrostratColumnData must be used within a MacrostratColumnDataProvider\",\n );\n }\n return ctx;\n}\n\nexport function useMacrostratUnits() {\n return scope.useAtomValue(columnUnitsAtom);\n}\n\nexport function useColumnUnitsMap(): Map<number, ExtUnit> | null {\n try {\n return scope.useAtomValue(columnUnitsMapAtom) as Map<number, ExtUnit>;\n } catch {\n return null;\n }\n}\n\nexport function useCompositeScale(): CompositeColumnScale {\n const ctx = useMacrostratColumnData();\n return useMemo(\n () => createCompositeScale(ctx.sections, true),\n [ctx.sections],\n );\n}\n\nexport function MacrostratColumnProvider(props) {\n /** A column provider specialized the Macrostrat API. Maps more\n * generic concepts to Macrostrat-specific ones.\n */\n\n const { axisType, isTransitioning, hideLabelsWhileTransitioning } =\n useMacrostratColumnData();\n const { units, domain, pixelScale, scale, children } = props;\n return h(\n ColumnProvider,\n {\n axisType,\n divisions: units,\n range: domain,\n pixelsPerMeter: pixelScale,\n scale,\n isTransitioning,\n hideLabelsWhileTransitioning,\n },\n children,\n );\n}\n\n/** This is now a legacy provider */\nexport function LithologiesProvider({ children }) {\n useEffect(() => {\n console.warn(\n \"LithologiesProvider is deprecated. Replace with MacrostratDataProvider\",\n );\n }, []);\n return children;\n}\n"],"names":[],"mappings":";;;;;;;AA8BO,MAAM,QAAwB,kBAAA;AAE9B,MAAM,kBAAkB,KAAA;AAExB,MAAM,qBAAqB,KAAmC,CAAC,QAAQ;AAC5E,QAAM,QAAQ,IAAI,eAAe;AACjC,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,8BAAc,IAAA;AACpB,QAAM,QAAQ,CAAC,SAAS;AACtB,YAAQ,IAAI,KAAK,SAAS,IAAI;AAAA,EAChC,CAAC;AACD,SAAO;AACT,CAAC;AAWM,SAAS,8BAAkD;AAAA,EAChE;AAAA,EACA;AAAA,EACA,qBAAqB;AAAA,EACrB;AAAA,EACA;AACF,GAAgC;AAS9B,QAAM,kBAAkB,QAAQ,MAAM;AACpC,QAAI,oBAAoB;AACtB,aAAO;AAAA,IACT;AACA,WAAO,gBAAgB,QAAQ,kBAAkB;AAAA,EACnD,GAAG,CAAA,CAAE;AAGL,QAAM,gBAAgB,MAAM,qBAAqB,eAAe;AAChE,MAAI,iBAAiB,MAAM;AACzB,QAAI,sBAAsB,kBAAkB,gBAAgB,MAAM;AAChE,cAAQ;AAAA,QACN;AAAA,MAAA;AAAA,IAEJ;AACA,WAAO;AAAA,EACT;AAEA,QAAM,UAAmB;AAAA,IACvB,CAAC,iBAAiB,KAAK;AAAA,IACvB,CAAC,wBAAwB,eAAe;AAAA,IACxC,CAAC,oBAAoB,YAAY;AAAA,EAAA;AAGnC,MAAI,oBAA+B;AACnC,MAAI,iBAAiB;AACnB,wBAAoB,EAAE,8BAA8B,EAAE,eAAA,CAAgB;AAAA,EACxE;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,MACE,OAAO;AAAA,MACP,aAAa;AAAA,IAAA;AAAA,IAEf,CAAC,mBAAmB,QAAQ;AAAA,EAAA;AAEhC;AA4BA,MAAM,8BACJ,cAAgD,IAAI;AAE/C,SAAS,6BAAiD;AAAA,EAC/D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA+B;AAY7B,QAAM,QAAQ,QAAQ,MAAM;AAE1B,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACD;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,IAEF;AAAA,MACE,EAAE,kBAAkB,EAAE,KAAK;AAAA,MAC3B,EAAE,4BAA4B,UAAU,EAAE,MAAA,GAAS,QAAQ;AAAA,IAAA;AAAA,EAC7D;AAEJ;AAEA,SAAS,iBAAiB,EAAE,OAAuC;AACjE,QAAM,sBAAsB,MAAM,aAAa,uBAAuB;AACtE,YAAU,MAAM;AACd,QAAI,OAAO,KAAM;AACjB,QAAI,UAAU;AAAA,MACZ,2BAA2B,MAA8B;AACvD,6BAAqB;AAAA,UACnB,QAAQ;AAAA,YACN,UAAU;AAAA,YACV,OAAO;AAAA,YACP,QAAQ;AAAA,UAAA;AAAA,QACV;AAAA,MAEJ;AAAA,IAAA;AAAA,EAEJ,GAAG,CAAC,KAAK,mBAAmB,CAAC;AAE7B,SAAO;AACT;AAEO,SAAS,sBAAsB,OAAsC;AAI1E,SAAO,EAAE,+BAA+B;AAAA,IACtC,GAAG;AAAA,IACH,oBAAoB;AAAA,EAAA,CACrB;AACH;AAEO,SAAS,0BAA0B;AACxC,QAAM,MAAM,WAAW,2BAA2B;AAClD,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AACA,SAAO;AACT;AAEO,SAAS,qBAAqB;AACnC,SAAO,MAAM,aAAa,eAAe;AAC3C;AAEO,SAAS,oBAAiD;AAC/D,MAAI;AACF,WAAO,MAAM,aAAa,kBAAkB;AAAA,EAC9C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,oBAA0C;AACxD,QAAM,MAAM,wBAAA;AACZ,SAAO;AAAA,IACL,MAAM,qBAAqB,IAAI,UAAU,IAAI;AAAA,IAC7C,CAAC,IAAI,QAAQ;AAAA,EAAA;AAEjB;AAEO,SAAS,yBAAyB,OAAO;AAK9C,QAAM,EAAE,UAAU,iBAAiB,6BAAA,IACjC,wBAAA;AACF,QAAM,EAAE,OAAO,QAAQ,YAAY,OAAO,aAAa;AACvD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,MACE;AAAA,MACA,WAAW;AAAA,MACX,OAAO;AAAA,MACP,gBAAgB;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,IAEF;AAAA,EAAA;AAEJ;AAGO,SAAS,oBAAoB,EAAE,YAAY;AAChD,YAAU,MAAM;AACd,YAAQ;AAAA,MACN;AAAA,IAAA;AAAA,EAEJ,GAAG,CAAA,CAAE;AACL,SAAO;AACT;"}
|