@macrostrat/column-views 3.10.0 → 3.11.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 +19 -0
- package/dist/column-views.css +10 -0
- package/dist/correlation-chart/main.cjs +11 -3
- package/dist/correlation-chart/main.cjs.map +1 -1
- package/dist/correlation-chart/main.d.ts +1 -1
- package/dist/correlation-chart/main.js +11 -3
- package/dist/correlation-chart/main.js.map +1 -1
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/unit-details/age-window-tag.cjs +68 -0
- package/dist/unit-details/age-window-tag.cjs.map +1 -0
- package/dist/unit-details/age-window-tag.d.ts +26 -0
- package/dist/unit-details/age-window-tag.js +66 -0
- package/dist/unit-details/age-window-tag.js.map +1 -0
- package/dist/unit-details/age-window-tag.module.sass.cjs +12 -0
- package/dist/unit-details/age-window-tag.module.sass.cjs.map +1 -0
- package/dist/unit-details/age-window-tag.module.sass.js +11 -0
- package/dist/unit-details/age-window-tag.module.sass.js.map +1 -0
- package/dist/unit-details/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/correlation-chart/main.ts +14 -2
- package/src/unit-details/age-window-tag.module.sass +10 -0
- package/src/unit-details/age-window-tag.ts +102 -0
- package/src/unit-details/index.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.11.0] - 2026-09-04 [_changes_](https://github.com/UW-Macrostrat/web-components/compare/@macrostrat/column-views-v3.10.0...@macrostrat/column-views-v3.11.0)
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Add `AgeWindowTag`, a compact, clearable indicator of the age window a column
|
|
8
|
+
or
|
|
9
|
+
[0dfa4399](https://github.com/UW-Macrostrat/web-components/commit/0dfa4399e47298a2cb37aafa5785149a5f5b994d)
|
|
10
|
+
correlation chart is focused on — an interval tag with its range (or the
|
|
11
|
+
refined range when the window is narrower than the interval), or a bare age
|
|
12
|
+
range — for use in a chart's `axisTopContent` or page chrome.
|
|
13
|
+
|
|
14
|
+
Add `intervalShortFromTimescale`, adapting the `Interval` delivered by a
|
|
15
|
+
`Timescale` click (`eag`/`lag`/`nam`/`col`) to the `IntervalShort` shape the
|
|
16
|
+
`@macrostrat/data-components` tags take.
|
|
17
|
+
|
|
18
|
+
Add `timescaleIntervalStyle` to `CorrelationChart`, forwarding a per-interval
|
|
19
|
+
style to its timescale so the selected interval can be highlighted, matching
|
|
20
|
+
the existing `Column` prop.
|
|
21
|
+
|
|
3
22
|
## [3.10.0] - 2026-09-01 [_changes_](https://github.com/UW-Macrostrat/web-components/compare/@macrostrat/column-views-v3.9.0...@macrostrat/column-views-v3.10.0)
|
|
4
23
|
|
|
5
24
|
### Minor Changes
|
package/dist/column-views.css
CHANGED
|
@@ -441,6 +441,16 @@ body.dark-mode ._column-container_1j8hh_1 svg pattern image {
|
|
|
441
441
|
right: 0;
|
|
442
442
|
position: absolute;
|
|
443
443
|
border-top: 1px solid lightgreen;
|
|
444
|
+
}._age-window-tag_1tskh_1 {
|
|
445
|
+
display: inline-flex;
|
|
446
|
+
align-items: center;
|
|
447
|
+
gap: 0.15em;
|
|
448
|
+
white-space: nowrap;
|
|
449
|
+
vertical-align: middle;
|
|
450
|
+
}
|
|
451
|
+
._age-window-tag_1tskh_1 ._clear-button_1tskh_8 {
|
|
452
|
+
min-width: 0;
|
|
453
|
+
min-height: 0;
|
|
444
454
|
}._truncated-list_120po_1 {
|
|
445
455
|
padding-left: 0.2em;
|
|
446
456
|
font-size: 0.9em;
|
|
@@ -47,6 +47,7 @@ function CorrelationChart({
|
|
|
47
47
|
columnHeaderComponent,
|
|
48
48
|
axisTopContent,
|
|
49
49
|
onClickTimescaleInterval,
|
|
50
|
+
timescaleIntervalStyle,
|
|
50
51
|
onColumnMouseOver,
|
|
51
52
|
onColumnClick,
|
|
52
53
|
isTransitioning = false,
|
|
@@ -82,7 +83,8 @@ function CorrelationChart({
|
|
|
82
83
|
main_module.default(TimescaleColumn, {
|
|
83
84
|
scaleInfo,
|
|
84
85
|
unconformityLabels,
|
|
85
|
-
onClickInterval: onClickTimescaleInterval
|
|
86
|
+
onClickInterval: onClickTimescaleInterval,
|
|
87
|
+
intervalStyle: timescaleIntervalStyle
|
|
86
88
|
}),
|
|
87
89
|
main_module.default(MainChartArea, [
|
|
88
90
|
main_module.default(
|
|
@@ -305,13 +307,19 @@ function ColumnHeaderCell({
|
|
|
305
307
|
);
|
|
306
308
|
}
|
|
307
309
|
function TimescaleColumn(props) {
|
|
308
|
-
const {
|
|
310
|
+
const {
|
|
311
|
+
scaleInfo,
|
|
312
|
+
unconformityLabels = true,
|
|
313
|
+
onClickInterval,
|
|
314
|
+
intervalStyle
|
|
315
|
+
} = props;
|
|
309
316
|
return main_module.default("div.column-container.age-axis-container", [
|
|
310
317
|
main_module.default(ageAxis.CompositeAgeAxisCore, { ...scaleInfo }),
|
|
311
318
|
main_module.default(section.CompositeTimescaleCore, {
|
|
312
319
|
...scaleInfo,
|
|
313
320
|
unconformityLabels,
|
|
314
|
-
onClickInterval
|
|
321
|
+
onClickInterval,
|
|
322
|
+
intervalStyle
|
|
315
323
|
})
|
|
316
324
|
]);
|
|
317
325
|
}
|
|
@@ -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 /** 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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"}
|
|
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 {\n IntervalStyleBuilder,\n TimescaleClickHandler,\n} 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 timescaleIntervalStyle,\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 intervalStyle: timescaleIntervalStyle,\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 intervalStyle?: IntervalStyleBuilder;\n}\n\nfunction TimescaleColumn(props: TimescaleColumnProps) {\n const {\n scaleInfo,\n unconformityLabels = true,\n onClickInterval,\n intervalStyle,\n } = props;\n return h(\"div.column-container.age-axis-container\", [\n h(CompositeAgeAxisCore, { ...scaleInfo }),\n h(CompositeTimescaleCore, {\n ...scaleInfo,\n unconformityLabels,\n onClickInterval,\n intervalStyle,\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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"}
|
|
@@ -50,4 +50,4 @@ export interface CorrelationChartProps extends CorrelationChartSettings {
|
|
|
50
50
|
/** Called when a column header is clicked (e.g. to frame it on a map) */
|
|
51
51
|
onColumnClick?: (columnID: number) => void;
|
|
52
52
|
}
|
|
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;
|
|
53
|
+
export declare function CorrelationChart({ data, columnSpacing, columnWidth, unconformityLabels, showUnitPopover, selectedUnit, onUnitSelected, unitComponent, columnHeaderComponent, axisTopContent, onClickTimescaleInterval, timescaleIntervalStyle, onColumnMouseOver, onColumnClick, isTransitioning, hideLabelsWhileTransitioning, ...scaleProps }: CorrelationChartProps): import('react').FunctionComponentElement<import('..').ColumnContainerProps> | null;
|
|
@@ -43,6 +43,7 @@ function CorrelationChart({
|
|
|
43
43
|
columnHeaderComponent,
|
|
44
44
|
axisTopContent,
|
|
45
45
|
onClickTimescaleInterval,
|
|
46
|
+
timescaleIntervalStyle,
|
|
46
47
|
onColumnMouseOver,
|
|
47
48
|
onColumnClick,
|
|
48
49
|
isTransitioning = false,
|
|
@@ -78,7 +79,8 @@ function CorrelationChart({
|
|
|
78
79
|
h(TimescaleColumn, {
|
|
79
80
|
scaleInfo,
|
|
80
81
|
unconformityLabels,
|
|
81
|
-
onClickInterval: onClickTimescaleInterval
|
|
82
|
+
onClickInterval: onClickTimescaleInterval,
|
|
83
|
+
intervalStyle: timescaleIntervalStyle
|
|
82
84
|
}),
|
|
83
85
|
h(MainChartArea, [
|
|
84
86
|
h(
|
|
@@ -301,13 +303,19 @@ function ColumnHeaderCell({
|
|
|
301
303
|
);
|
|
302
304
|
}
|
|
303
305
|
function TimescaleColumn(props) {
|
|
304
|
-
const {
|
|
306
|
+
const {
|
|
307
|
+
scaleInfo,
|
|
308
|
+
unconformityLabels = true,
|
|
309
|
+
onClickInterval,
|
|
310
|
+
intervalStyle
|
|
311
|
+
} = props;
|
|
305
312
|
return h("div.column-container.age-axis-container", [
|
|
306
313
|
h(CompositeAgeAxisCore, { ...scaleInfo }),
|
|
307
314
|
h(CompositeTimescaleCore, {
|
|
308
315
|
...scaleInfo,
|
|
309
316
|
unconformityLabels,
|
|
310
|
-
onClickInterval
|
|
317
|
+
onClickInterval,
|
|
318
|
+
intervalStyle
|
|
311
319
|
})
|
|
312
320
|
]);
|
|
313
321
|
}
|
|
@@ -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 /** 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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"}
|
|
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 {\n IntervalStyleBuilder,\n TimescaleClickHandler,\n} 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 timescaleIntervalStyle,\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 intervalStyle: timescaleIntervalStyle,\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 intervalStyle?: IntervalStyleBuilder;\n}\n\nfunction TimescaleColumn(props: TimescaleColumnProps) {\n const {\n scaleInfo,\n unconformityLabels = true,\n onClickInterval,\n intervalStyle,\n } = props;\n return h(\"div.column-container.age-axis-container\", [\n h(CompositeAgeAxisCore, { ...scaleInfo }),\n h(CompositeTimescaleCore, {\n ...scaleInfo,\n unconformityLabels,\n onClickInterval,\n intervalStyle,\n }),\n ]);\n}\n"],"names":[],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -9,6 +9,7 @@ const ageModelOverlay = require("./age-model-overlay.cjs");
|
|
|
9
9
|
const notes = require("./notes.cjs");
|
|
10
10
|
const mapViews = require("@macrostrat/map-views");
|
|
11
11
|
const ageRange = require("./unit-details/age-range.cjs");
|
|
12
|
+
const ageWindowTag = require("./unit-details/age-window-tag.cjs");
|
|
12
13
|
const composite = require("./units/composite.cjs");
|
|
13
14
|
const base = require("./facets/measurements/base.cjs");
|
|
14
15
|
const dataComponents = require("@macrostrat/data-components");
|
|
@@ -60,6 +61,8 @@ exports.Duration = ageRange.Duration;
|
|
|
60
61
|
exports.IntervalProportions = ageRange.IntervalProportions;
|
|
61
62
|
exports.getAge = ageRange.getAge;
|
|
62
63
|
exports.getAgeRange = ageRange.getAgeRange;
|
|
64
|
+
exports.AgeWindowTag = ageWindowTag.AgeWindowTag;
|
|
65
|
+
exports.intervalShortFromTimescale = ageWindowTag.intervalShortFromTimescale;
|
|
63
66
|
exports.AnnotatedUnitsColumn = composite.AnnotatedUnitsColumn;
|
|
64
67
|
exports.ColumnNotesProvider = composite.ColumnNotesProvider;
|
|
65
68
|
exports.CompositeUnitComponent = composite.CompositeUnitComponent;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { BoundaryAgeModelOverlay, ComputedSurfacesOverlay } from "./age-model-ov
|
|
|
7
7
|
import { ColumnNotes } from "./notes.js";
|
|
8
8
|
export * from "@macrostrat/map-views";
|
|
9
9
|
import { AgeField, AgeLabel, AgeRange, Duration, IntervalProportions, getAge, getAgeRange } from "./unit-details/age-range.js";
|
|
10
|
+
import { AgeWindowTag, intervalShortFromTimescale } from "./unit-details/age-window-tag.js";
|
|
10
11
|
import { AnnotatedUnitsColumn, ColumnNotesProvider, CompositeUnitComponent, CompositeUnitsColumn, LabelTrackerProvider, SectionLabelsColumn, TrackedLabeledUnit } from "./units/composite.js";
|
|
11
12
|
import { BaseMeasurementsColumn, TruncatedList, groupNotesByPixelDistance, mergeHeightRanges, standardizeMeasurementHeight } from "./facets/measurements/base.js";
|
|
12
13
|
import { ClickableText, Identifier, UnitIdentifier } from "@macrostrat/data-components";
|
|
@@ -34,6 +35,7 @@ export {
|
|
|
34
35
|
AgeField,
|
|
35
36
|
AgeLabel,
|
|
36
37
|
AgeRange,
|
|
38
|
+
AgeWindowTag,
|
|
37
39
|
AnnotatedUnitsColumn,
|
|
38
40
|
ApproximateHeightAxis,
|
|
39
41
|
BaseMeasurementsColumn,
|
|
@@ -107,6 +109,7 @@ export {
|
|
|
107
109
|
getPositionWithinUnit,
|
|
108
110
|
getUnitHeightRange,
|
|
109
111
|
groupNotesByPixelDistance,
|
|
112
|
+
intervalShortFromTimescale,
|
|
110
113
|
mergeHeightRanges,
|
|
111
114
|
parseLineFromString,
|
|
112
115
|
prepareColumnUnits,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const core = require("@blueprintjs/core");
|
|
4
|
+
const dataComponents = require("@macrostrat/data-components");
|
|
5
|
+
const classNames = require("classnames");
|
|
6
|
+
const ageWindowTag_module = require("./age-window-tag.module.sass.cjs");
|
|
7
|
+
const ageRange = require("./age-range.cjs");
|
|
8
|
+
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
9
|
+
const classNames__default = /* @__PURE__ */ _interopDefault(classNames);
|
|
10
|
+
function intervalShortFromTimescale(interval) {
|
|
11
|
+
return {
|
|
12
|
+
id: interval.int_id ?? interval.oid,
|
|
13
|
+
name: interval.nam,
|
|
14
|
+
color: interval.col,
|
|
15
|
+
b_age: interval.eag,
|
|
16
|
+
t_age: interval.lag,
|
|
17
|
+
rank: interval.lvl
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function AgeWindowTag(props) {
|
|
21
|
+
const {
|
|
22
|
+
interval = null,
|
|
23
|
+
window = null,
|
|
24
|
+
onClear,
|
|
25
|
+
size = dataComponents.TagSize.Small,
|
|
26
|
+
className
|
|
27
|
+
} = props;
|
|
28
|
+
if (interval == null && window == null) return null;
|
|
29
|
+
let tag = null;
|
|
30
|
+
if (interval == null) {
|
|
31
|
+
tag = ageWindowTag_module(dataComponents.Tag, { size, name: ageWindowTag_module(ageRange.AgeRange, { data: window }) });
|
|
32
|
+
} else if (window == null || windowMatchesInterval(window, interval)) {
|
|
33
|
+
tag = ageWindowTag_module(dataComponents.IntervalTag, { interval, showAgeRange: true, size });
|
|
34
|
+
} else {
|
|
35
|
+
tag = ageWindowTag_module(RefinedIntervalTag, { interval, window, size });
|
|
36
|
+
}
|
|
37
|
+
return ageWindowTag_module("span.age-window-tag", { className: classNames__default.default(className) }, [
|
|
38
|
+
tag,
|
|
39
|
+
ageWindowTag_module.if(onClear != null)(core.Button, {
|
|
40
|
+
className: "clear-button",
|
|
41
|
+
icon: "cross",
|
|
42
|
+
minimal: true,
|
|
43
|
+
small: true,
|
|
44
|
+
title: "Clear",
|
|
45
|
+
onClick: onClear
|
|
46
|
+
})
|
|
47
|
+
]);
|
|
48
|
+
}
|
|
49
|
+
function RefinedIntervalTag({
|
|
50
|
+
interval,
|
|
51
|
+
window,
|
|
52
|
+
size
|
|
53
|
+
}) {
|
|
54
|
+
const interaction = dataComponents.useInteractionProps({ int_id: interval.id });
|
|
55
|
+
return ageWindowTag_module(dataComponents.Tag, {
|
|
56
|
+
...interaction,
|
|
57
|
+
size,
|
|
58
|
+
name: interval.name,
|
|
59
|
+
color: interval.color,
|
|
60
|
+
details: ageWindowTag_module(ageRange.AgeRange, { data: window })
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function windowMatchesInterval(window, interval) {
|
|
64
|
+
return window.t_age === interval.t_age && window.b_age === interval.b_age;
|
|
65
|
+
}
|
|
66
|
+
exports.AgeWindowTag = AgeWindowTag;
|
|
67
|
+
exports.intervalShortFromTimescale = intervalShortFromTimescale;
|
|
68
|
+
//# sourceMappingURL=age-window-tag.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"age-window-tag.cjs","sources":["../../src/unit-details/age-window-tag.ts"],"sourcesContent":["import { Button } from \"@blueprintjs/core\";\nimport {\n IntervalShort,\n IntervalTag,\n Tag,\n TagSize,\n useInteractionProps,\n} from \"@macrostrat/data-components\";\nimport type { Interval } from \"@macrostrat/timescale\";\nimport classNames from \"classnames\";\nimport h from \"./age-window-tag.module.sass\";\nimport { AgeRange } from \"./age-range\";\nimport type { AgeWindow } from \"../animated-age-window\";\n\n/** Adapt a timescale `Interval` (as delivered by a `Timescale` click, with\n * `eag`/`lag`/`nam`/`col`) to the `IntervalShort` shape the tag components\n * take. The id prefers the Macrostrat `int_id` when the interval tree was built\n * from the API, falling back to the interval's own `oid`. */\nexport function intervalShortFromTimescale(interval: Interval): IntervalShort {\n return {\n id: interval.int_id ?? interval.oid,\n name: interval.nam,\n color: interval.col,\n b_age: interval.eag,\n t_age: interval.lag,\n rank: interval.lvl,\n };\n}\n\nexport interface AgeWindowTagProps {\n /** The interval the window was set from, if any. */\n interval?: IntervalShort | null;\n /** The rendered window. When it differs from the interval's own span (a\n * refined window) it is shown in place of the interval's range. */\n window?: AgeWindow | null;\n /** Renders a clear button when given. */\n onClear?: () => void;\n size?: TagSize;\n className?: string;\n}\n\n/** A compact, clearable indicator of the age window a column or correlation\n * chart is focused on — an interval tag (linking to the interval, with its\n * range) or a bare age range. Renders nothing without an interval or window,\n * so it can live permanently in a chart's `axisTopContent`. */\nexport function AgeWindowTag(props: AgeWindowTagProps) {\n const {\n interval = null,\n window = null,\n onClear,\n size = TagSize.Small,\n className,\n } = props;\n if (interval == null && window == null) return null;\n\n let tag = null;\n if (interval == null) {\n tag = h(Tag, { size, name: h(AgeRange, { data: window }) });\n } else if (window == null || windowMatchesInterval(window, interval)) {\n tag = h(IntervalTag, { interval, showAgeRange: true, size });\n } else {\n tag = h(RefinedIntervalTag, { interval, window, size });\n }\n\n return h(\"span.age-window-tag\", { className: classNames(className) }, [\n tag,\n h.if(onClear != null)(Button, {\n className: \"clear-button\",\n icon: \"cross\",\n minimal: true,\n small: true,\n title: \"Clear\",\n onClick: onClear,\n }),\n ]);\n}\n\nfunction RefinedIntervalTag({\n interval,\n window,\n size,\n}: {\n interval: IntervalShort;\n window: AgeWindow;\n size: TagSize;\n}) {\n const interaction = useInteractionProps({ int_id: interval.id });\n return h(Tag, {\n ...interaction,\n size,\n name: interval.name,\n color: interval.color,\n details: h(AgeRange, { data: window }),\n });\n}\n\nfunction windowMatchesInterval(\n window: AgeWindow,\n interval: IntervalShort,\n): boolean {\n return window.t_age === interval.t_age && window.b_age === interval.b_age;\n}\n"],"names":["TagSize","h","Tag","AgeRange","IntervalTag","classNames","Button","useInteractionProps"],"mappings":";;;;;;;;;AAkBO,SAAS,2BAA2B,UAAmC;AAC5E,SAAO;AAAA,IACL,IAAI,SAAS,UAAU,SAAS;AAAA,IAChC,MAAM,SAAS;AAAA,IACf,OAAO,SAAS;AAAA,IAChB,OAAO,SAAS;AAAA,IAChB,OAAO,SAAS;AAAA,IAChB,MAAM,SAAS;AAAA,EAAA;AAEnB;AAkBO,SAAS,aAAa,OAA0B;AACrD,QAAM;AAAA,IACJ,WAAW;AAAA,IACX,SAAS;AAAA,IACT;AAAA,IACA,OAAOA,eAAAA,QAAQ;AAAA,IACf;AAAA,EAAA,IACE;AACJ,MAAI,YAAY,QAAQ,UAAU,KAAM,QAAO;AAE/C,MAAI,MAAM;AACV,MAAI,YAAY,MAAM;AACpB,UAAMC,oBAAEC,oBAAK,EAAE,MAAM,MAAMD,oBAAEE,SAAAA,UAAU,EAAE,MAAM,OAAA,CAAQ,EAAA,CAAG;AAAA,EAC5D,WAAW,UAAU,QAAQ,sBAAsB,QAAQ,QAAQ,GAAG;AACpE,UAAMF,oBAAEG,4BAAa,EAAE,UAAU,cAAc,MAAM,MAAM;AAAA,EAC7D,OAAO;AACL,UAAMH,oBAAE,oBAAoB,EAAE,UAAU,QAAQ,MAAM;AAAA,EACxD;AAEA,SAAOA,oBAAE,uBAAuB,EAAE,WAAWI,oBAAAA,QAAW,SAAS,KAAK;AAAA,IACpE;AAAA,IACAJ,oBAAE,GAAG,WAAW,IAAI,EAAEK,KAAAA,QAAQ;AAAA,MAC5B,WAAW;AAAA,MACX,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,IAAA,CACV;AAAA,EAAA,CACF;AACH;AAEA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,cAAcC,eAAAA,oBAAoB,EAAE,QAAQ,SAAS,IAAI;AAC/D,SAAON,oBAAEC,eAAAA,KAAK;AAAA,IACZ,GAAG;AAAA,IACH;AAAA,IACA,MAAM,SAAS;AAAA,IACf,OAAO,SAAS;AAAA,IAChB,SAASD,oBAAEE,SAAAA,UAAU,EAAE,MAAM,QAAQ;AAAA,EAAA,CACtC;AACH;AAEA,SAAS,sBACP,QACA,UACS;AACT,SAAO,OAAO,UAAU,SAAS,SAAS,OAAO,UAAU,SAAS;AACtE;;;"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { IntervalShort, TagSize } from '@macrostrat/data-components';
|
|
2
|
+
import { Interval } from '@macrostrat/timescale';
|
|
3
|
+
import { AgeWindow } from '../animated-age-window';
|
|
4
|
+
/** Adapt a timescale `Interval` (as delivered by a `Timescale` click, with
|
|
5
|
+
* `eag`/`lag`/`nam`/`col`) to the `IntervalShort` shape the tag components
|
|
6
|
+
* take. The id prefers the Macrostrat `int_id` when the interval tree was built
|
|
7
|
+
* from the API, falling back to the interval's own `oid`. */
|
|
8
|
+
export declare function intervalShortFromTimescale(interval: Interval): IntervalShort;
|
|
9
|
+
export interface AgeWindowTagProps {
|
|
10
|
+
/** The interval the window was set from, if any. */
|
|
11
|
+
interval?: IntervalShort | null;
|
|
12
|
+
/** The rendered window. When it differs from the interval's own span (a
|
|
13
|
+
* refined window) it is shown in place of the interval's range. */
|
|
14
|
+
window?: AgeWindow | null;
|
|
15
|
+
/** Renders a clear button when given. */
|
|
16
|
+
onClear?: () => void;
|
|
17
|
+
size?: TagSize;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
/** A compact, clearable indicator of the age window a column or correlation
|
|
21
|
+
* chart is focused on — an interval tag (linking to the interval, with its
|
|
22
|
+
* range) or a bare age range. Renders nothing without an interval or window,
|
|
23
|
+
* so it can live permanently in a chart's `axisTopContent`. */
|
|
24
|
+
export declare function AgeWindowTag(props: AgeWindowTagProps): import('react').ReactElement<{
|
|
25
|
+
className: string;
|
|
26
|
+
}, string | import('react').JSXElementConstructor<any>> | null;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Button } from "@blueprintjs/core";
|
|
2
|
+
import { TagSize, Tag, IntervalTag, useInteractionProps } from "@macrostrat/data-components";
|
|
3
|
+
import classNames from "classnames";
|
|
4
|
+
import h from "./age-window-tag.module.sass.js";
|
|
5
|
+
import { AgeRange } from "./age-range.js";
|
|
6
|
+
function intervalShortFromTimescale(interval) {
|
|
7
|
+
return {
|
|
8
|
+
id: interval.int_id ?? interval.oid,
|
|
9
|
+
name: interval.nam,
|
|
10
|
+
color: interval.col,
|
|
11
|
+
b_age: interval.eag,
|
|
12
|
+
t_age: interval.lag,
|
|
13
|
+
rank: interval.lvl
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function AgeWindowTag(props) {
|
|
17
|
+
const {
|
|
18
|
+
interval = null,
|
|
19
|
+
window = null,
|
|
20
|
+
onClear,
|
|
21
|
+
size = TagSize.Small,
|
|
22
|
+
className
|
|
23
|
+
} = props;
|
|
24
|
+
if (interval == null && window == null) return null;
|
|
25
|
+
let tag = null;
|
|
26
|
+
if (interval == null) {
|
|
27
|
+
tag = h(Tag, { size, name: h(AgeRange, { data: window }) });
|
|
28
|
+
} else if (window == null || windowMatchesInterval(window, interval)) {
|
|
29
|
+
tag = h(IntervalTag, { interval, showAgeRange: true, size });
|
|
30
|
+
} else {
|
|
31
|
+
tag = h(RefinedIntervalTag, { interval, window, size });
|
|
32
|
+
}
|
|
33
|
+
return h("span.age-window-tag", { className: classNames(className) }, [
|
|
34
|
+
tag,
|
|
35
|
+
h.if(onClear != null)(Button, {
|
|
36
|
+
className: "clear-button",
|
|
37
|
+
icon: "cross",
|
|
38
|
+
minimal: true,
|
|
39
|
+
small: true,
|
|
40
|
+
title: "Clear",
|
|
41
|
+
onClick: onClear
|
|
42
|
+
})
|
|
43
|
+
]);
|
|
44
|
+
}
|
|
45
|
+
function RefinedIntervalTag({
|
|
46
|
+
interval,
|
|
47
|
+
window,
|
|
48
|
+
size
|
|
49
|
+
}) {
|
|
50
|
+
const interaction = useInteractionProps({ int_id: interval.id });
|
|
51
|
+
return h(Tag, {
|
|
52
|
+
...interaction,
|
|
53
|
+
size,
|
|
54
|
+
name: interval.name,
|
|
55
|
+
color: interval.color,
|
|
56
|
+
details: h(AgeRange, { data: window })
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function windowMatchesInterval(window, interval) {
|
|
60
|
+
return window.t_age === interval.t_age && window.b_age === interval.b_age;
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
AgeWindowTag,
|
|
64
|
+
intervalShortFromTimescale
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=age-window-tag.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"age-window-tag.js","sources":["../../src/unit-details/age-window-tag.ts"],"sourcesContent":["import { Button } from \"@blueprintjs/core\";\nimport {\n IntervalShort,\n IntervalTag,\n Tag,\n TagSize,\n useInteractionProps,\n} from \"@macrostrat/data-components\";\nimport type { Interval } from \"@macrostrat/timescale\";\nimport classNames from \"classnames\";\nimport h from \"./age-window-tag.module.sass\";\nimport { AgeRange } from \"./age-range\";\nimport type { AgeWindow } from \"../animated-age-window\";\n\n/** Adapt a timescale `Interval` (as delivered by a `Timescale` click, with\n * `eag`/`lag`/`nam`/`col`) to the `IntervalShort` shape the tag components\n * take. The id prefers the Macrostrat `int_id` when the interval tree was built\n * from the API, falling back to the interval's own `oid`. */\nexport function intervalShortFromTimescale(interval: Interval): IntervalShort {\n return {\n id: interval.int_id ?? interval.oid,\n name: interval.nam,\n color: interval.col,\n b_age: interval.eag,\n t_age: interval.lag,\n rank: interval.lvl,\n };\n}\n\nexport interface AgeWindowTagProps {\n /** The interval the window was set from, if any. */\n interval?: IntervalShort | null;\n /** The rendered window. When it differs from the interval's own span (a\n * refined window) it is shown in place of the interval's range. */\n window?: AgeWindow | null;\n /** Renders a clear button when given. */\n onClear?: () => void;\n size?: TagSize;\n className?: string;\n}\n\n/** A compact, clearable indicator of the age window a column or correlation\n * chart is focused on — an interval tag (linking to the interval, with its\n * range) or a bare age range. Renders nothing without an interval or window,\n * so it can live permanently in a chart's `axisTopContent`. */\nexport function AgeWindowTag(props: AgeWindowTagProps) {\n const {\n interval = null,\n window = null,\n onClear,\n size = TagSize.Small,\n className,\n } = props;\n if (interval == null && window == null) return null;\n\n let tag = null;\n if (interval == null) {\n tag = h(Tag, { size, name: h(AgeRange, { data: window }) });\n } else if (window == null || windowMatchesInterval(window, interval)) {\n tag = h(IntervalTag, { interval, showAgeRange: true, size });\n } else {\n tag = h(RefinedIntervalTag, { interval, window, size });\n }\n\n return h(\"span.age-window-tag\", { className: classNames(className) }, [\n tag,\n h.if(onClear != null)(Button, {\n className: \"clear-button\",\n icon: \"cross\",\n minimal: true,\n small: true,\n title: \"Clear\",\n onClick: onClear,\n }),\n ]);\n}\n\nfunction RefinedIntervalTag({\n interval,\n window,\n size,\n}: {\n interval: IntervalShort;\n window: AgeWindow;\n size: TagSize;\n}) {\n const interaction = useInteractionProps({ int_id: interval.id });\n return h(Tag, {\n ...interaction,\n size,\n name: interval.name,\n color: interval.color,\n details: h(AgeRange, { data: window }),\n });\n}\n\nfunction windowMatchesInterval(\n window: AgeWindow,\n interval: IntervalShort,\n): boolean {\n return window.t_age === interval.t_age && window.b_age === interval.b_age;\n}\n"],"names":[],"mappings":";;;;;AAkBO,SAAS,2BAA2B,UAAmC;AAC5E,SAAO;AAAA,IACL,IAAI,SAAS,UAAU,SAAS;AAAA,IAChC,MAAM,SAAS;AAAA,IACf,OAAO,SAAS;AAAA,IAChB,OAAO,SAAS;AAAA,IAChB,OAAO,SAAS;AAAA,IAChB,MAAM,SAAS;AAAA,EAAA;AAEnB;AAkBO,SAAS,aAAa,OAA0B;AACrD,QAAM;AAAA,IACJ,WAAW;AAAA,IACX,SAAS;AAAA,IACT;AAAA,IACA,OAAO,QAAQ;AAAA,IACf;AAAA,EAAA,IACE;AACJ,MAAI,YAAY,QAAQ,UAAU,KAAM,QAAO;AAE/C,MAAI,MAAM;AACV,MAAI,YAAY,MAAM;AACpB,UAAM,EAAE,KAAK,EAAE,MAAM,MAAM,EAAE,UAAU,EAAE,MAAM,OAAA,CAAQ,EAAA,CAAG;AAAA,EAC5D,WAAW,UAAU,QAAQ,sBAAsB,QAAQ,QAAQ,GAAG;AACpE,UAAM,EAAE,aAAa,EAAE,UAAU,cAAc,MAAM,MAAM;AAAA,EAC7D,OAAO;AACL,UAAM,EAAE,oBAAoB,EAAE,UAAU,QAAQ,MAAM;AAAA,EACxD;AAEA,SAAO,EAAE,uBAAuB,EAAE,WAAW,WAAW,SAAS,KAAK;AAAA,IACpE;AAAA,IACA,EAAE,GAAG,WAAW,IAAI,EAAE,QAAQ;AAAA,MAC5B,WAAW;AAAA,MACX,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,IAAA,CACV;AAAA,EAAA,CACF;AACH;AAEA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,cAAc,oBAAoB,EAAE,QAAQ,SAAS,IAAI;AAC/D,SAAO,EAAE,KAAK;AAAA,IACZ,GAAG;AAAA,IACH;AAAA,IACA,MAAM,SAAS;AAAA,IACf,OAAO,SAAS;AAAA,IAChB,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ;AAAA,EAAA,CACtC;AACH;AAEA,SAAS,sBACP,QACA,UACS;AACT,SAAO,OAAO,UAAU,SAAS,SAAS,OAAO,UAAU,SAAS;AACtE;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const h$1 = require("@macrostrat/hyper");
|
|
3
|
+
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
4
|
+
const h__default = /* @__PURE__ */ _interopDefault(h$1);
|
|
5
|
+
const styles = {
|
|
6
|
+
"age-window-tag": "_age-window-tag_1tskh_1",
|
|
7
|
+
"clear-button": "_clear-button_1tskh_8"
|
|
8
|
+
};
|
|
9
|
+
let h = h__default.default.styled(styles);
|
|
10
|
+
Object.assign(h, styles);
|
|
11
|
+
module.exports = h;
|
|
12
|
+
//# sourceMappingURL=age-window-tag.module.sass.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"age-window-tag.module.sass.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import h$1 from "@macrostrat/hyper";
|
|
2
|
+
const styles = {
|
|
3
|
+
"age-window-tag": "_age-window-tag_1tskh_1",
|
|
4
|
+
"clear-button": "_clear-button_1tskh_8"
|
|
5
|
+
};
|
|
6
|
+
let h = h$1.styled(styles);
|
|
7
|
+
Object.assign(h, styles);
|
|
8
|
+
export {
|
|
9
|
+
h as default
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=age-window-tag.module.sass.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"age-window-tag.module.sass.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;"}
|
|
@@ -2,5 +2,6 @@ export * from './panel';
|
|
|
2
2
|
export * from './popover';
|
|
3
3
|
export * from './modal-panel';
|
|
4
4
|
export * from './age-range';
|
|
5
|
+
export * from './age-window-tag';
|
|
5
6
|
export * from './strat-names';
|
|
6
7
|
export { ClickableText, Identifier, UnitIdentifier, } from '@macrostrat/data-components';
|
package/package.json
CHANGED
|
@@ -34,7 +34,10 @@ import type { ColumnData } from "@macrostrat/data-provider";
|
|
|
34
34
|
import { BaseUnit } from "@macrostrat/api-types";
|
|
35
35
|
import { ScaleContinuousNumeric } from "d3-scale";
|
|
36
36
|
import { ExtUnit } from "../prepare-units/types";
|
|
37
|
-
import type {
|
|
37
|
+
import type {
|
|
38
|
+
IntervalStyleBuilder,
|
|
39
|
+
TimescaleClickHandler,
|
|
40
|
+
} from "@macrostrat/timescale";
|
|
38
41
|
import { useMacrostratColumnInfo } from "@macrostrat/data-provider";
|
|
39
42
|
|
|
40
43
|
/** Standard props passed to a `columnHeaderComponent`. Everything a header
|
|
@@ -122,6 +125,7 @@ export function CorrelationChart({
|
|
|
122
125
|
columnHeaderComponent,
|
|
123
126
|
axisTopContent,
|
|
124
127
|
onClickTimescaleInterval,
|
|
128
|
+
timescaleIntervalStyle,
|
|
125
129
|
onColumnMouseOver,
|
|
126
130
|
onColumnClick,
|
|
127
131
|
isTransitioning = false,
|
|
@@ -166,6 +170,7 @@ export function CorrelationChart({
|
|
|
166
170
|
scaleInfo,
|
|
167
171
|
unconformityLabels,
|
|
168
172
|
onClickInterval: onClickTimescaleInterval,
|
|
173
|
+
intervalStyle: timescaleIntervalStyle,
|
|
169
174
|
}),
|
|
170
175
|
h(MainChartArea, [
|
|
171
176
|
h(
|
|
@@ -515,16 +520,23 @@ interface TimescaleColumnProps {
|
|
|
515
520
|
showLabels?: boolean;
|
|
516
521
|
unconformityLabels?: boolean;
|
|
517
522
|
onClickInterval?: TimescaleClickHandler;
|
|
523
|
+
intervalStyle?: IntervalStyleBuilder;
|
|
518
524
|
}
|
|
519
525
|
|
|
520
526
|
function TimescaleColumn(props: TimescaleColumnProps) {
|
|
521
|
-
const {
|
|
527
|
+
const {
|
|
528
|
+
scaleInfo,
|
|
529
|
+
unconformityLabels = true,
|
|
530
|
+
onClickInterval,
|
|
531
|
+
intervalStyle,
|
|
532
|
+
} = props;
|
|
522
533
|
return h("div.column-container.age-axis-container", [
|
|
523
534
|
h(CompositeAgeAxisCore, { ...scaleInfo }),
|
|
524
535
|
h(CompositeTimescaleCore, {
|
|
525
536
|
...scaleInfo,
|
|
526
537
|
unconformityLabels,
|
|
527
538
|
onClickInterval,
|
|
539
|
+
intervalStyle,
|
|
528
540
|
}),
|
|
529
541
|
]);
|
|
530
542
|
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Button } from "@blueprintjs/core";
|
|
2
|
+
import {
|
|
3
|
+
IntervalShort,
|
|
4
|
+
IntervalTag,
|
|
5
|
+
Tag,
|
|
6
|
+
TagSize,
|
|
7
|
+
useInteractionProps,
|
|
8
|
+
} from "@macrostrat/data-components";
|
|
9
|
+
import type { Interval } from "@macrostrat/timescale";
|
|
10
|
+
import classNames from "classnames";
|
|
11
|
+
import h from "./age-window-tag.module.sass";
|
|
12
|
+
import { AgeRange } from "./age-range";
|
|
13
|
+
import type { AgeWindow } from "../animated-age-window";
|
|
14
|
+
|
|
15
|
+
/** Adapt a timescale `Interval` (as delivered by a `Timescale` click, with
|
|
16
|
+
* `eag`/`lag`/`nam`/`col`) to the `IntervalShort` shape the tag components
|
|
17
|
+
* take. The id prefers the Macrostrat `int_id` when the interval tree was built
|
|
18
|
+
* from the API, falling back to the interval's own `oid`. */
|
|
19
|
+
export function intervalShortFromTimescale(interval: Interval): IntervalShort {
|
|
20
|
+
return {
|
|
21
|
+
id: interval.int_id ?? interval.oid,
|
|
22
|
+
name: interval.nam,
|
|
23
|
+
color: interval.col,
|
|
24
|
+
b_age: interval.eag,
|
|
25
|
+
t_age: interval.lag,
|
|
26
|
+
rank: interval.lvl,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface AgeWindowTagProps {
|
|
31
|
+
/** The interval the window was set from, if any. */
|
|
32
|
+
interval?: IntervalShort | null;
|
|
33
|
+
/** The rendered window. When it differs from the interval's own span (a
|
|
34
|
+
* refined window) it is shown in place of the interval's range. */
|
|
35
|
+
window?: AgeWindow | null;
|
|
36
|
+
/** Renders a clear button when given. */
|
|
37
|
+
onClear?: () => void;
|
|
38
|
+
size?: TagSize;
|
|
39
|
+
className?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** A compact, clearable indicator of the age window a column or correlation
|
|
43
|
+
* chart is focused on — an interval tag (linking to the interval, with its
|
|
44
|
+
* range) or a bare age range. Renders nothing without an interval or window,
|
|
45
|
+
* so it can live permanently in a chart's `axisTopContent`. */
|
|
46
|
+
export function AgeWindowTag(props: AgeWindowTagProps) {
|
|
47
|
+
const {
|
|
48
|
+
interval = null,
|
|
49
|
+
window = null,
|
|
50
|
+
onClear,
|
|
51
|
+
size = TagSize.Small,
|
|
52
|
+
className,
|
|
53
|
+
} = props;
|
|
54
|
+
if (interval == null && window == null) return null;
|
|
55
|
+
|
|
56
|
+
let tag = null;
|
|
57
|
+
if (interval == null) {
|
|
58
|
+
tag = h(Tag, { size, name: h(AgeRange, { data: window }) });
|
|
59
|
+
} else if (window == null || windowMatchesInterval(window, interval)) {
|
|
60
|
+
tag = h(IntervalTag, { interval, showAgeRange: true, size });
|
|
61
|
+
} else {
|
|
62
|
+
tag = h(RefinedIntervalTag, { interval, window, size });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return h("span.age-window-tag", { className: classNames(className) }, [
|
|
66
|
+
tag,
|
|
67
|
+
h.if(onClear != null)(Button, {
|
|
68
|
+
className: "clear-button",
|
|
69
|
+
icon: "cross",
|
|
70
|
+
minimal: true,
|
|
71
|
+
small: true,
|
|
72
|
+
title: "Clear",
|
|
73
|
+
onClick: onClear,
|
|
74
|
+
}),
|
|
75
|
+
]);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function RefinedIntervalTag({
|
|
79
|
+
interval,
|
|
80
|
+
window,
|
|
81
|
+
size,
|
|
82
|
+
}: {
|
|
83
|
+
interval: IntervalShort;
|
|
84
|
+
window: AgeWindow;
|
|
85
|
+
size: TagSize;
|
|
86
|
+
}) {
|
|
87
|
+
const interaction = useInteractionProps({ int_id: interval.id });
|
|
88
|
+
return h(Tag, {
|
|
89
|
+
...interaction,
|
|
90
|
+
size,
|
|
91
|
+
name: interval.name,
|
|
92
|
+
color: interval.color,
|
|
93
|
+
details: h(AgeRange, { data: window }),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function windowMatchesInterval(
|
|
98
|
+
window: AgeWindow,
|
|
99
|
+
interval: IntervalShort,
|
|
100
|
+
): boolean {
|
|
101
|
+
return window.t_age === interval.t_age && window.b_age === interval.b_age;
|
|
102
|
+
}
|