@macrostrat/column-views 3.11.0 → 3.12.1

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.
Files changed (138) hide show
  1. package/CHANGELOG.md +184 -0
  2. package/dist/age-axis.cjs +1 -2
  3. package/dist/age-axis.cjs.map +1 -1
  4. package/dist/age-axis.js +1 -2
  5. package/dist/age-axis.js.map +1 -1
  6. package/dist/age-model/data.cjs +57 -0
  7. package/dist/age-model/data.cjs.map +1 -0
  8. package/dist/age-model/data.d.ts +29 -0
  9. package/dist/age-model/data.js +57 -0
  10. package/dist/age-model/data.js.map +1 -0
  11. package/dist/age-model/details.cjs +260 -0
  12. package/dist/age-model/details.cjs.map +1 -0
  13. package/dist/age-model/details.d.ts +39 -0
  14. package/dist/age-model/details.js +257 -0
  15. package/dist/age-model/details.js.map +1 -0
  16. package/dist/age-model/details.module.sass.cjs +42 -0
  17. package/dist/age-model/details.module.sass.cjs.map +1 -0
  18. package/dist/age-model/details.module.sass.js +40 -0
  19. package/dist/age-model/details.module.sass.js.map +1 -0
  20. package/dist/age-model/index.d.ts +5 -0
  21. package/dist/age-model/legacy.cjs +28 -0
  22. package/dist/age-model/legacy.cjs.map +1 -0
  23. package/dist/age-model/legacy.d.ts +6 -0
  24. package/dist/age-model/legacy.js +26 -0
  25. package/dist/age-model/legacy.js.map +1 -0
  26. package/dist/age-model/surfaces.cjs +354 -0
  27. package/dist/age-model/surfaces.cjs.map +1 -0
  28. package/dist/age-model/surfaces.d.ts +68 -0
  29. package/dist/age-model/surfaces.js +351 -0
  30. package/dist/age-model/surfaces.js.map +1 -0
  31. package/dist/age-model/surfaces.module.sass.cjs +45 -0
  32. package/dist/age-model/surfaces.module.sass.cjs.map +1 -0
  33. package/dist/age-model/surfaces.module.sass.js +43 -0
  34. package/dist/age-model/surfaces.module.sass.js.map +1 -0
  35. package/dist/age-model/types.cjs +229 -0
  36. package/dist/age-model/types.cjs.map +1 -0
  37. package/dist/age-model/types.d.ts +112 -0
  38. package/dist/age-model/types.js +229 -0
  39. package/dist/age-model/types.js.map +1 -0
  40. package/dist/column-views.css +406 -74
  41. package/dist/column.cjs +20 -13
  42. package/dist/column.cjs.map +1 -1
  43. package/dist/column.d.ts +21 -6
  44. package/dist/column.js +21 -14
  45. package/dist/column.js.map +1 -1
  46. package/dist/column.module.sass.cjs +19 -15
  47. package/dist/column.module.sass.cjs.map +1 -1
  48. package/dist/column.module.sass.js +19 -15
  49. package/dist/column.module.sass.js.map +1 -1
  50. package/dist/data-provider/store.cjs +34 -1
  51. package/dist/data-provider/store.cjs.map +1 -1
  52. package/dist/data-provider/store.d.ts +5 -0
  53. package/dist/data-provider/store.js +35 -2
  54. package/dist/data-provider/store.js.map +1 -1
  55. package/dist/index.cjs +78 -18
  56. package/dist/index.cjs.map +1 -1
  57. package/dist/index.d.ts +3 -1
  58. package/dist/index.js +55 -4
  59. package/dist/index.js.map +1 -1
  60. package/dist/notes.cjs +11 -2
  61. package/dist/notes.cjs.map +1 -1
  62. package/dist/notes.d.ts +11 -1
  63. package/dist/notes.js +11 -2
  64. package/dist/notes.js.map +1 -1
  65. package/dist/prepare-units/composite-scale.cjs +18 -16
  66. package/dist/prepare-units/composite-scale.cjs.map +1 -1
  67. package/dist/prepare-units/composite-scale.js +18 -16
  68. package/dist/prepare-units/composite-scale.js.map +1 -1
  69. package/dist/prepare-units/density.cjs +83 -0
  70. package/dist/prepare-units/density.cjs.map +1 -0
  71. package/dist/prepare-units/density.d.ts +92 -0
  72. package/dist/prepare-units/density.js +83 -0
  73. package/dist/prepare-units/density.js.map +1 -0
  74. package/dist/prepare-units/index.cjs +15 -7
  75. package/dist/prepare-units/index.cjs.map +1 -1
  76. package/dist/prepare-units/index.d.ts +1 -0
  77. package/dist/prepare-units/index.js +15 -7
  78. package/dist/prepare-units/index.js.map +1 -1
  79. package/dist/prepare-units/types.cjs.map +1 -1
  80. package/dist/prepare-units/types.d.ts +34 -13
  81. package/dist/prepare-units/types.js.map +1 -1
  82. package/dist/section.cjs +108 -24
  83. package/dist/section.cjs.map +1 -1
  84. package/dist/section.d.ts +66 -6
  85. package/dist/section.js +109 -25
  86. package/dist/section.js.map +1 -1
  87. package/dist/timescale-zoom.cjs +191 -0
  88. package/dist/timescale-zoom.cjs.map +1 -0
  89. package/dist/timescale-zoom.d.ts +74 -0
  90. package/dist/timescale-zoom.js +191 -0
  91. package/dist/timescale-zoom.js.map +1 -0
  92. package/dist/unit-details/age-range.cjs +14 -43
  93. package/dist/unit-details/age-range.cjs.map +1 -1
  94. package/dist/unit-details/age-range.d.ts +1 -13
  95. package/dist/unit-details/age-range.js +6 -43
  96. package/dist/unit-details/age-range.js.map +1 -1
  97. package/dist/unit-details/utils.cjs +0 -5
  98. package/dist/unit-details/utils.cjs.map +1 -1
  99. package/dist/unit-details/utils.js +0 -5
  100. package/dist/unit-details/utils.js.map +1 -1
  101. package/dist/units/composite.cjs +4 -1
  102. package/dist/units/composite.cjs.map +1 -1
  103. package/dist/units/composite.d.ts +2 -0
  104. package/dist/units/composite.js +4 -1
  105. package/dist/units/composite.js.map +1 -1
  106. package/package.json +8 -8
  107. package/src/age-model/data.ts +98 -0
  108. package/src/age-model/details.module.sass +108 -0
  109. package/src/age-model/details.ts +333 -0
  110. package/src/age-model/index.ts +5 -0
  111. package/src/age-model/legacy.ts +30 -0
  112. package/src/age-model/surfaces.module.sass +168 -0
  113. package/src/age-model/surfaces.ts +568 -0
  114. package/src/age-model/types.ts +392 -0
  115. package/src/column.module.sass +59 -8
  116. package/src/column.ts +49 -23
  117. package/src/data-provider/store.ts +50 -1
  118. package/src/index.ts +5 -1
  119. package/src/notes.ts +20 -2
  120. package/src/prepare-units/composite-scale.ts +34 -31
  121. package/src/prepare-units/density.ts +197 -0
  122. package/src/prepare-units/index.ts +25 -6
  123. package/src/prepare-units/types.ts +34 -13
  124. package/src/section.ts +219 -33
  125. package/src/timescale-zoom.ts +341 -0
  126. package/src/unit-details/age-range.ts +12 -58
  127. package/src/units/composite.ts +11 -0
  128. package/dist/age-model-overlay.cjs +0 -50
  129. package/dist/age-model-overlay.cjs.map +0 -1
  130. package/dist/age-model-overlay.d.ts +0 -24
  131. package/dist/age-model-overlay.js +0 -48
  132. package/dist/age-model-overlay.js.map +0 -1
  133. package/dist/age-model-overlay.module.sass.cjs +0 -12
  134. package/dist/age-model-overlay.module.sass.cjs.map +0 -1
  135. package/dist/age-model-overlay.module.sass.js +0 -11
  136. package/dist/age-model-overlay.module.sass.js.map +0 -1
  137. package/src/age-model-overlay.module.sass +0 -11
  138. package/src/age-model-overlay.ts +0 -96
package/dist/section.cjs CHANGED
@@ -5,13 +5,13 @@ const timescale = require("@macrostrat/timescale");
5
5
  const columnComponents = require("@macrostrat/column-components");
6
6
  const h$1 = require("@macrostrat/hyper");
7
7
  const column_module = require("./column.module.sass.cjs");
8
- const dataProvider = require("@macrostrat/data-provider");
9
8
  const dataComponents = require("@macrostrat/data-components");
10
9
  const store = require("./data-provider/store.cjs");
11
10
  const composite = require("./units/composite.cjs");
12
11
  const ageRange = require("./unit-details/age-range.cjs");
13
12
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
14
13
  const h__default = /* @__PURE__ */ _interopDefault(h$1);
14
+ const INTERNATIONAL_TIMESCALE_ID = 11;
15
15
  const h = h__default.default.styled(column_module.default);
16
16
  function SectionsColumn(props) {
17
17
  const {
@@ -23,7 +23,8 @@ function SectionsColumn(props) {
23
23
  columnWidth = 150,
24
24
  showLabelColumn = true,
25
25
  clipUnits = true,
26
- maxInternalColumns
26
+ maxInternalColumns,
27
+ labelSuppressHeight
27
28
  } = props;
28
29
  const units = store.useMacrostratUnits();
29
30
  const key = units[0]?.col_id;
@@ -38,7 +39,8 @@ function SectionsColumn(props) {
38
39
  unconformityLabels
39
40
  }),
40
41
  h.if(showLabelColumn)(composite.SectionLabelsColumn, {
41
- width: width - columnWidth
42
+ width: width - columnWidth,
43
+ labelSuppressHeight
42
44
  })
43
45
  ]);
44
46
  }
@@ -53,7 +55,7 @@ function SectionUnitsColumn(props) {
53
55
  axisType,
54
56
  unconformityLabels = true
55
57
  } = props;
56
- const { sections, totalHeight } = store.useMacrostratColumnData();
58
+ const { sections, totalHeight, axisType: columnAxisType } = store.useMacrostratColumnData();
57
59
  const scaleData = sections.map((section) => {
58
60
  return section.scaleInfo;
59
61
  });
@@ -90,6 +92,9 @@ function SectionUnitsColumn(props) {
90
92
  h.if(unconformityLabels)(UnconformityLabels, {
91
93
  width,
92
94
  sections: scaleData,
95
+ // A gap between sections is measured in whatever the axis is: metres
96
+ // down a core, Myr across a time column
97
+ axisType: axisType ?? columnAxisType,
93
98
  verbose: false
94
99
  })
95
100
  ]);
@@ -153,44 +158,71 @@ function CompositeTimescale(props) {
153
158
  ...props
154
159
  });
155
160
  }
161
+ function TimescaleLabel({ timescale: timescale2 }) {
162
+ const { label, name } = timescale2;
163
+ const style = levelCountStyle(levelCount(timescale2));
164
+ let content = label;
165
+ if (label == null && name != null) {
166
+ content = h("span.timescale-label-text", name);
167
+ }
168
+ if (content == null) return h("div.timescale-label", { style });
169
+ return h("div.timescale-label", { style }, content);
170
+ }
171
+ function levelCountStyle(levelCount2) {
172
+ return { "--timescale-level-count": levelCount2 };
173
+ }
156
174
  function CompositeTimescaleCore(props) {
157
175
  const {
158
- levels = 3,
159
176
  packages,
160
177
  unconformityLabels = false,
161
178
  onClickInterval,
162
- intervalStyle
179
+ intervalStyle,
180
+ showLabels = false,
181
+ className
163
182
  } = props;
164
- const baseURL = dataProvider.useMacrostratBaseURL();
165
- const intervals = timescale.useMacrostratIntervals({ baseURL });
166
- let _levels;
167
- if (typeof levels === "number") {
168
- _levels = [2, Math.max(2 + Math.min(levels, 5) - 1, 1)];
169
- } else {
170
- _levels = levels;
183
+ const timescales = useColumnTimescales(props);
184
+ function forTimescale(id) {
185
+ let onClick = null;
186
+ if (onClickInterval != null) {
187
+ onClick = (event, data) => {
188
+ onClickInterval(event, { ...data, timescaleID: id });
189
+ };
190
+ }
191
+ let style = intervalStyle;
192
+ if (typeof intervalStyle === "function") {
193
+ style = (interval) => intervalStyle(interval, id);
194
+ }
195
+ return { onClick, intervalStyle: style };
171
196
  }
172
- const nCols = _levels[1] - _levels[0] + 1;
173
- return h("div.timescale-column", [
197
+ return h("div.timescale-column", { className }, [
198
+ h.if(showLabels)(
199
+ "div.timescale-labels",
200
+ timescales.map(
201
+ (timescale2) => h(TimescaleLabel, { key: timescale2.id, timescale: timescale2 })
202
+ )
203
+ ),
174
204
  h(
175
205
  "div.timescales",
176
206
  packages.map((group) => {
177
207
  const { pixelHeight, paddingTop, key, scale } = group;
178
208
  return h(
179
- "div.timescale-container",
180
- { style: { paddingTop, "--timescale-level-count": nCols }, key },
181
- [
182
- h(timescale.Timescale, {
209
+ "div.section-timescales",
210
+ { style: { paddingTop }, key },
211
+ timescales.map(
212
+ (timescale$1) => h(timescale.Timescale, {
213
+ key: timescale$1.id,
183
214
  orientation: timescale.TimescaleOrientation.VERTICAL,
184
215
  length: pixelHeight,
185
- levels: _levels,
216
+ levels: timescale$1.levels,
217
+ rootInterval: timescale$1.rootInterval,
186
218
  absoluteAgeScale: true,
187
219
  showAgeAxis: false,
188
220
  scale,
189
- intervals,
190
- onClick: onClickInterval,
191
- intervalStyle
221
+ intervals: timescale$1.intervals,
222
+ style: levelCountStyle(levelCount(timescale$1)),
223
+ ...forTimescale(timescale$1.id)
192
224
  })
193
- ]
225
+ )
194
226
  );
195
227
  })
196
228
  ),
@@ -202,6 +234,58 @@ function CompositeTimescaleCore(props) {
202
234
  })
203
235
  ]);
204
236
  }
237
+ function useColumnTimescales(props) {
238
+ const { timescales, levels = 3, timescaleID, additionalTimescales } = props;
239
+ const specs = React.useMemo(
240
+ () => timescaleSpecs({ timescales, levels, timescaleID, additionalTimescales }),
241
+ [
242
+ timescales,
243
+ levels,
244
+ timescaleID,
245
+ additionalTimescales?.join(",")
246
+ ]
247
+ );
248
+ const fetchIDs = React.useMemo(
249
+ () => specs.filter((d) => d.intervals == null).map((d) => d.id),
250
+ [specs]
251
+ );
252
+ const intervalSets = timescale.useMacrostratTimescales(fetchIDs);
253
+ return React.useMemo(
254
+ () => specs.map((spec) => ({
255
+ ...spec,
256
+ intervals: spec.intervals ?? intervalSets.get(spec.id) ?? []
257
+ })),
258
+ [specs, intervalSets]
259
+ );
260
+ }
261
+ function timescaleSpecs(props) {
262
+ const { timescales, levels = 3, timescaleID, additionalTimescales = [] } = props;
263
+ if (timescales != null) {
264
+ return timescales.map(normalizeTimescale);
265
+ }
266
+ return [
267
+ {
268
+ id: timescaleID ?? INTERNATIONAL_TIMESCALE_ID,
269
+ levels: levelRange(levels)
270
+ },
271
+ ...additionalTimescales.map(normalizeTimescale)
272
+ ];
273
+ }
274
+ function normalizeTimescale(timescale2) {
275
+ if (typeof timescale2 === "number") {
276
+ return { id: timescale2, levels: FLAT_TIMESCALE_LEVELS };
277
+ }
278
+ return { levels: FLAT_TIMESCALE_LEVELS, ...timescale2 };
279
+ }
280
+ const FLAT_TIMESCALE_LEVELS = [1, 1];
281
+ function levelRange(levels) {
282
+ if (typeof levels !== "number") return levels;
283
+ return [2, Math.max(2 + Math.min(levels, 5) - 1, 1)];
284
+ }
285
+ function levelCount(timescale2) {
286
+ const [min, max] = timescale2.levels ?? FLAT_TIMESCALE_LEVELS;
287
+ return Math.max(max - min + 1, 1);
288
+ }
205
289
  function UnconformityLabels(props) {
206
290
  const { width, sections, className, axisType, verbose } = props;
207
291
  return h(
@@ -1 +1 @@
1
- {"version":3,"file":"section.cjs","sources":["../src/section.ts"],"sourcesContent":["import {\n CompositeUnitsColumn,\n LabelTrackerProvider,\n SectionLabelsColumn,\n} from \"./units\";\nimport { ReactNode, FunctionComponent, useMemo } from \"react\";\nimport {\n Timescale,\n TimescaleOrientation,\n TimescaleClickHandler,\n useMacrostratIntervals,\n type IntervalStyleBuilder,\n} from \"@macrostrat/timescale\";\nimport { ColumnAxisType, SVG } from \"@macrostrat/column-components\";\nimport hyper from \"@macrostrat/hyper\";\nimport styles from \"./column.module.sass\";\nimport {\n useMacrostratColumnData,\n useMacrostratUnits,\n MacrostratColumnProvider,\n} from \"./data-provider\";\nimport {\n useMacrostratBaseURL,\n useMacrostratData,\n} from \"@macrostrat/data-provider\";\nimport { Duration } from \"./unit-details\";\nimport { Value } from \"@macrostrat/data-components\";\nimport type { ExtUnit, PackageScaleLayoutData } from \"./prepare-units/types\";\n\nconst h = hyper.styled(styles);\n\nexport interface SectionSharedProps {\n unitComponent?: FunctionComponent<any>;\n unitComponentProps?: any;\n showLabels?: boolean;\n width?: number;\n columnWidth?: number;\n children?: ReactNode;\n showLabelColumn?: boolean;\n axisType?: ColumnAxisType;\n className?: string;\n clipUnits?: boolean;\n maxInternalColumns?: number;\n // Space between sections\n verticalSpacing?: number;\n // Whether to render unconformity labels\n unconformityLabels?: boolean;\n}\n\nexport interface SectionProps extends SectionSharedProps {\n units: ExtUnit[];\n scaleInfo: PackageScaleLayoutData;\n}\n\nexport function SectionsColumn(props: SectionSharedProps) {\n const {\n unconformityLabels = true,\n unitComponent,\n unitComponentProps,\n showLabels = true,\n width = 300,\n columnWidth = 150,\n showLabelColumn = true,\n clipUnits = true,\n maxInternalColumns,\n } = props;\n\n const units = useMacrostratUnits();\n\n // Get a unique key for the column\n const key = units[0]?.col_id;\n\n return h(LabelTrackerProvider, { units, key }, [\n h(SectionUnitsColumn, {\n width: columnWidth,\n unitComponent,\n unitComponentProps,\n showLabels,\n clipUnits,\n maxInternalColumns,\n unconformityLabels,\n }),\n h.if(showLabelColumn)(SectionLabelsColumn, {\n width: width - columnWidth,\n }),\n ]);\n}\n\nfunction SectionUnitsColumn(props: SectionSharedProps) {\n const {\n width,\n showLabels,\n unitComponent,\n unitComponentProps,\n clipUnits,\n maxInternalColumns,\n axisType,\n unconformityLabels = true,\n } = props;\n\n const { sections, totalHeight } = useMacrostratColumnData();\n\n const scaleData: PackageScaleLayoutData[] = sections.map((section) => {\n return section.scaleInfo;\n });\n\n const innerWidth = width - 2;\n\n return h(\"div.section-units-container\", { style: { width } }, [\n h(\n SVG,\n {\n className: \"sections\",\n height: totalHeight,\n innerWidth,\n paddingH: 1,\n },\n sections.map((group) => {\n const { units, scaleInfo, section_id } = group;\n\n const key = `section-${section_id}`;\n return h(\n SectionUnits,\n {\n units,\n scaleInfo,\n key,\n unitComponent,\n unitComponentProps,\n showLabels,\n width: innerWidth,\n clipUnits,\n maxInternalColumns,\n }, // This unconformity is with the section _above_\n );\n }),\n ),\n h.if(unconformityLabels)(UnconformityLabels, {\n width,\n sections: scaleData,\n verbose: false,\n }),\n ]);\n}\n\nfunction SectionUnits(props: SectionProps) {\n // Section with \"squishy\" timescale\n const {\n units,\n scaleInfo,\n unitComponent,\n showLabels = true,\n width = 300,\n unitComponentProps,\n className,\n clipUnits = true,\n maxInternalColumns,\n } = props;\n\n const { domain, pixelScale, pixelHeight, scale } = scaleInfo;\n\n /** Ensure that we can arrange units into the maximum number\n * of columns defined by unitComponentProps, but that we don't\n * use more than necessary.\n */\n const _unitComponentProps = useMemo(() => {\n return {\n ...unitComponentProps,\n nColumns: Math.min(\n maxInternalColumns ?? Math.floor(width / 10),\n unitComponentProps?.nColumns ?? Infinity,\n ),\n //axisType,\n };\n }, [units, unitComponentProps, maxInternalColumns, width]);\n\n const style = {\n \"--section-height\": `${pixelHeight}px`,\n \"--section-width\": `${width}px`,\n };\n\n return h(\n \"g.section\",\n { className, style, transform: `translate(0 ${scaleInfo.offset})` },\n h(\n MacrostratColumnProvider,\n {\n units,\n domain,\n pixelScale, // Actually pixels per myr,\n scale,\n },\n h(CompositeUnitsColumn, {\n width,\n showLabels,\n unitComponent,\n unitComponentProps: _unitComponentProps,\n clipToFrame: clipUnits,\n }),\n ),\n );\n}\n\ninterface CompositeTimescaleProps {\n levels?: [number, number] | number;\n unconformityLabels?: boolean;\n onClickInterval?: TimescaleClickHandler;\n /** Per-interval style (e.g. to highlight the currently selected interval). */\n intervalStyle?: IntervalStyleBuilder;\n}\n\nexport function CompositeTimescale(props: CompositeTimescaleProps) {\n const { sections } = useMacrostratColumnData();\n const sectionScales = sections.map((section) => {\n return section.scaleInfo;\n });\n\n return h(CompositeTimescaleCore, {\n packages: sectionScales,\n ...props,\n });\n}\n\ntype CompositeTimescaleCoreProps = CompositeTimescaleProps & {\n packages: PackageScaleLayoutData[];\n onClickInterval?: TimescaleClickHandler;\n};\n\nexport function CompositeTimescaleCore(props: CompositeTimescaleCoreProps) {\n const {\n levels = 3,\n packages,\n unconformityLabels = false,\n onClickInterval,\n intervalStyle,\n } = props;\n\n // Use intervals from Macrostrat API\n const baseURL = useMacrostratBaseURL();\n const intervals = useMacrostratIntervals({ baseURL });\n\n let _levels: [number, number];\n if (typeof levels === \"number\") {\n // If levels is a number, use the most common starting level\n _levels = [2, Math.max(2 + Math.min(levels, 5) - 1, 1)];\n } else {\n _levels = levels;\n }\n\n const nCols = _levels[1] - _levels[0] + 1;\n\n return h(\"div.timescale-column\", [\n h(\n \"div.timescales\",\n packages.map((group) => {\n const { pixelHeight, paddingTop, key, scale } = group;\n return h(\n \"div.timescale-container\",\n { style: { paddingTop, \"--timescale-level-count\": nCols }, key },\n [\n h(Timescale, {\n orientation: TimescaleOrientation.VERTICAL,\n length: pixelHeight,\n levels: _levels,\n absoluteAgeScale: true,\n showAgeAxis: false,\n scale,\n intervals,\n onClick: onClickInterval,\n intervalStyle,\n }),\n ],\n );\n }),\n ),\n h.if(unconformityLabels)(UnconformityLabels, {\n width: \"100%\",\n sections: packages,\n className: \"unconformity-labels\",\n axisType: ColumnAxisType.AGE,\n }),\n ]);\n}\n\nexport function UnconformityLabels(props: {\n width: string | number;\n sections: PackageScaleLayoutData[];\n axisType?: ColumnAxisType;\n className?: string;\n verbose?: boolean;\n}) {\n const { width, sections, className, axisType, verbose } = props;\n\n return h(\n \"div.unconformity-labels\",\n {\n style: {\n width,\n },\n className,\n },\n sections.map((scaleInfo, i) => {\n const lastGroup = sections[i - 1];\n const top = scaleInfo.offset - scaleInfo.paddingTop;\n const upperAge = lastGroup?.domain[0];\n const lowerAge = scaleInfo.domain[1];\n return h(Unconformity, {\n axisType,\n upperAge,\n lowerAge,\n style: {\n width,\n height: scaleInfo.paddingTop,\n top,\n },\n verbose,\n });\n }),\n );\n}\n\nfunction Unconformity({\n upperAge,\n lowerAge,\n style,\n axisType,\n verbose = false,\n}) {\n if (upperAge == null || lowerAge == null) {\n return null;\n }\n\n const ageGap = Math.abs(upperAge - lowerAge);\n\n let maximumFractionDigits = 0;\n\n let className: string = null;\n if (ageGap > 1000) {\n className = \"giga\";\n } else if (ageGap > 100) {\n className = \"mega\";\n } else if (ageGap > 10) {\n className = \"large\";\n } else if (ageGap < 1) {\n className = \"small\";\n maximumFractionDigits = 2;\n } else {\n maximumFractionDigits = 1;\n }\n\n let val: ReactNode;\n if (axisType === ColumnAxisType.DEPTH || axisType === ColumnAxisType.HEIGHT) {\n const _txt = ageGap.toLocaleString(\"en-US\", { maximumFractionDigits });\n val = h(Value, { value: _txt, unit: \"m\" });\n } else {\n val = h(Duration, { value: ageGap, maximumFractionDigits });\n }\n\n let prefix: ReactNode = null;\n if (verbose) {\n prefix = h([\" \", h(\"span.prefix\", \" gap\")]);\n }\n\n return h(\"div.unconformity\", { style, className }, [\n h(\"div.unconformity-inner\", h(\"div.unconformity-text\", [val, prefix])),\n ]);\n}\n"],"names":["hyper","styles","useMacrostratUnits","LabelTrackerProvider","SectionLabelsColumn","useMacrostratColumnData","SVG","useMemo","MacrostratColumnProvider","CompositeUnitsColumn","useMacrostratBaseURL","useMacrostratIntervals","Timescale","TimescaleOrientation","ColumnAxisType","Value","Duration"],"mappings":"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"}
1
+ {"version":3,"file":"section.cjs","sources":["../src/section.ts"],"sourcesContent":["import {\n CompositeUnitsColumn,\n LabelTrackerProvider,\n SectionLabelsColumn,\n} from \"./units\";\nimport {\n type CSSProperties,\n ReactNode,\n FunctionComponent,\n useMemo,\n} from \"react\";\nimport {\n Timescale,\n TimescaleOrientation,\n useMacrostratTimescales,\n type Interval,\n type IntervalStyleBuilder,\n type TimescaleClickData,\n} from \"@macrostrat/timescale\";\n\n/** Macrostrat's international timescale, the default for a column */\nconst INTERNATIONAL_TIMESCALE_ID = 11;\nimport { ColumnAxisType, SVG } from \"@macrostrat/column-components\";\nimport hyper from \"@macrostrat/hyper\";\nimport styles from \"./column.module.sass\";\nimport {\n useMacrostratColumnData,\n useMacrostratUnits,\n MacrostratColumnProvider,\n} from \"./data-provider\";\nimport { Duration } from \"./unit-details\";\nimport { Value } from \"@macrostrat/data-components\";\nimport type { ExtUnit, PackageScaleLayoutData } from \"./prepare-units/types\";\n\nconst h = hyper.styled(styles);\n\nexport interface SectionSharedProps {\n unitComponent?: FunctionComponent<any>;\n unitComponentProps?: any;\n showLabels?: boolean;\n width?: number;\n columnWidth?: number;\n children?: ReactNode;\n showLabelColumn?: boolean;\n /** Suppress the label for a unit drawn thinner than this many pixels */\n labelSuppressHeight?: number;\n axisType?: ColumnAxisType;\n className?: string;\n clipUnits?: boolean;\n maxInternalColumns?: number;\n // Space between sections\n verticalSpacing?: number;\n // Whether to render unconformity labels\n unconformityLabels?: boolean;\n}\n\nexport interface SectionProps extends SectionSharedProps {\n units: ExtUnit[];\n scaleInfo: PackageScaleLayoutData;\n}\n\nexport function SectionsColumn(props: SectionSharedProps) {\n const {\n unconformityLabels = true,\n unitComponent,\n unitComponentProps,\n showLabels = true,\n width = 300,\n columnWidth = 150,\n showLabelColumn = true,\n clipUnits = true,\n maxInternalColumns,\n labelSuppressHeight,\n } = props;\n\n const units = useMacrostratUnits();\n\n // Get a unique key for the column\n const key = units[0]?.col_id;\n\n return h(LabelTrackerProvider, { units, key }, [\n h(SectionUnitsColumn, {\n width: columnWidth,\n unitComponent,\n unitComponentProps,\n showLabels,\n clipUnits,\n maxInternalColumns,\n unconformityLabels,\n }),\n h.if(showLabelColumn)(SectionLabelsColumn, {\n width: width - columnWidth,\n labelSuppressHeight,\n }),\n ]);\n}\n\nfunction SectionUnitsColumn(props: SectionSharedProps) {\n const {\n width,\n showLabels,\n unitComponent,\n unitComponentProps,\n clipUnits,\n maxInternalColumns,\n axisType,\n unconformityLabels = true,\n } = props;\n\n const { sections, totalHeight, axisType: columnAxisType } =\n useMacrostratColumnData();\n\n const scaleData: PackageScaleLayoutData[] = sections.map((section) => {\n return section.scaleInfo;\n });\n\n const innerWidth = width - 2;\n\n return h(\"div.section-units-container\", { style: { width } }, [\n h(\n SVG,\n {\n className: \"sections\",\n height: totalHeight,\n innerWidth,\n paddingH: 1,\n },\n sections.map((group) => {\n const { units, scaleInfo, section_id } = group;\n\n const key = `section-${section_id}`;\n return h(\n SectionUnits,\n {\n units,\n scaleInfo,\n key,\n unitComponent,\n unitComponentProps,\n showLabels,\n width: innerWidth,\n clipUnits,\n maxInternalColumns,\n }, // This unconformity is with the section _above_\n );\n }),\n ),\n h.if(unconformityLabels)(UnconformityLabels, {\n width,\n sections: scaleData,\n // A gap between sections is measured in whatever the axis is: metres\n // down a core, Myr across a time column\n axisType: axisType ?? columnAxisType,\n verbose: false,\n }),\n ]);\n}\n\nfunction SectionUnits(props: SectionProps) {\n // Section with \"squishy\" timescale\n const {\n units,\n scaleInfo,\n unitComponent,\n showLabels = true,\n width = 300,\n unitComponentProps,\n className,\n clipUnits = true,\n maxInternalColumns,\n } = props;\n\n const { domain, pixelScale, pixelHeight, scale } = scaleInfo;\n\n /** Ensure that we can arrange units into the maximum number\n * of columns defined by unitComponentProps, but that we don't\n * use more than necessary.\n */\n const _unitComponentProps = useMemo(() => {\n return {\n ...unitComponentProps,\n nColumns: Math.min(\n maxInternalColumns ?? Math.floor(width / 10),\n unitComponentProps?.nColumns ?? Infinity,\n ),\n //axisType,\n };\n }, [units, unitComponentProps, maxInternalColumns, width]);\n\n const style = {\n \"--section-height\": `${pixelHeight}px`,\n \"--section-width\": `${width}px`,\n };\n\n return h(\n \"g.section\",\n { className, style, transform: `translate(0 ${scaleInfo.offset})` },\n h(\n MacrostratColumnProvider,\n {\n units,\n domain,\n pixelScale, // Actually pixels per myr,\n scale,\n },\n h(CompositeUnitsColumn, {\n width,\n showLabels,\n unitComponent,\n unitComponentProps: _unitComponentProps,\n clipToFrame: clipUnits,\n }),\n ),\n );\n}\n\n/** A per-interval style that also knows which timescale the interval was\n * drawn from. The same interval often appears in several of the timescales\n * beside each other, and they aren't interchangeable — only one of them is\n * the one a selection was made in. */\nexport type ColumnIntervalStyleBuilder =\n | CSSProperties\n | ((interval: Interval, timescaleID: number) => CSSProperties)\n | null;\n\n/** A timescale click, reporting which timescale was clicked in */\nexport type ColumnTimescaleClickHandler = (\n event: Event,\n data: TimescaleClickData & { timescaleID: number },\n) => void;\n\n/** A timescale to draw beside a column.\n *\n * The international timescale is one of these, not a special case: it is the\n * one that happens to be nested several levels deep. Anything with the same\n * shape can take its place or sit beside it — a regional set from the API, a\n * zonation assembled locally, or a hierarchy that isn't a timescale at all,\n * so long as its \"intervals\" carry ages.\n */\nexport interface ColumnTimescale {\n /** Integer identifier. Clicks and per-interval styles report it, so a\n * consumer can tell one column's copy of an interval from another's. For a\n * Macrostrat timescale it is the `timescale_id`. */\n id: number;\n /** Shown above the column, unless `label` says otherwise */\n name?: string;\n /** The intervals themselves, flat or already nested by `pid`. Left out,\n * the timescale `id` is fetched from the Macrostrat API. */\n intervals?: Interval[];\n /** Levels to draw, and so how many slots wide the column is (default\n * `[1, 1]`: one level, which is what a flat timescale has) */\n levels?: [number, number];\n /** `oid` of the interval the tree hangs from (default 0) */\n rootInterval?: number;\n /** Drawn above the column in place of the name — any node, so a consumer\n * can put a control or a legend there instead of text */\n label?: ReactNode;\n}\n\nexport type ColumnTimescaleLike = number | ColumnTimescale;\n\ninterface CompositeTimescaleProps {\n /** Every timescale to draw, in order. A bare number is a Macrostrat\n * timescale to fetch and draw as a single level.\n *\n * Given this, `levels`, `timescaleID` and `additionalTimescales` are\n * ignored: it says what they say and more. */\n timescales?: ColumnTimescaleLike[];\n /** Levels of the ICS hierarchy to show. If a number, the finest level is\n * `levels[0]`, the second-finest is `levels[1]`, etc. If an array, the\n * first element is the starting level, the second is the ending level. */\n levels?: [number, number] | number;\n unconformityLabels?: boolean;\n onClickInterval?: ColumnTimescaleClickHandler;\n /** Per-interval style (e.g. to highlight the currently selected interval). */\n intervalStyle?: ColumnIntervalStyleBuilder;\n /** The timescale to draw. Defaults to the international one; any other\n * Macrostrat timescale (a regional or project-specific set of intervals)\n * can be drawn in its place. */\n timescaleID?: number;\n /** Further timescales drawn as extra level columns beside the main one,\n * against the same scale. Shorthand for listing them in `timescales`. */\n additionalTimescales?: number[];\n /** Draw the names above the columns. They sit above the column proper, so\n * leave top padding for them. */\n showLabels?: boolean;\n className?: string;\n}\n\nexport function CompositeTimescale(props: CompositeTimescaleProps) {\n const { sections } = useMacrostratColumnData();\n const sectionScales = sections.map((section) => {\n return section.scaleInfo;\n });\n\n return h(CompositeTimescaleCore, {\n packages: sectionScales,\n ...props,\n });\n}\n\ntype CompositeTimescaleCoreProps = CompositeTimescaleProps & {\n packages: PackageScaleLayoutData[];\n};\n\n/** What is drawn above a timescale: its name, reading up the page, or\n * whatever node the consumer gave instead. */\nfunction TimescaleLabel({ timescale }: { timescale: ColumnTimescale }) {\n const { label, name } = timescale;\n const style = levelCountStyle(levelCount(timescale));\n\n let content: ReactNode = label;\n if (label == null && name != null) {\n content = h(\"span.timescale-label-text\", name);\n }\n if (content == null) return h(\"div.timescale-label\", { style });\n\n return h(\"div.timescale-label\", { style }, content);\n}\n\n/** How wide a timescale draws: one slot per level it shows. */\nfunction levelCountStyle(levelCount: number): CSSProperties {\n return { \"--timescale-level-count\": levelCount } as CSSProperties;\n}\n\nexport function CompositeTimescaleCore(props: CompositeTimescaleCoreProps) {\n const {\n packages,\n unconformityLabels = false,\n onClickInterval,\n intervalStyle,\n showLabels = false,\n className,\n } = props;\n\n const timescales = useColumnTimescales(props);\n\n /** Clicks and styles carry the timescale they came from, so a consumer can\n * tell one column's copy of an interval from another's. */\n function forTimescale(id: number) {\n let onClick = null;\n if (onClickInterval != null) {\n onClick = (event: Event, data: TimescaleClickData) => {\n onClickInterval(event, { ...data, timescaleID: id });\n };\n }\n let style = intervalStyle as IntervalStyleBuilder;\n if (typeof intervalStyle === \"function\") {\n style = (interval: Interval) => intervalStyle(interval, id);\n }\n return { onClick, intervalStyle: style };\n }\n\n return h(\"div.timescale-column\", { className }, [\n h.if(showLabels)(\n \"div.timescale-labels\",\n timescales.map((timescale) =>\n h(TimescaleLabel, { key: timescale.id, timescale }),\n ),\n ),\n h(\n \"div.timescales\",\n packages.map((group) => {\n const { pixelHeight, paddingTop, key, scale } = group;\n return h(\n \"div.section-timescales\",\n { style: { paddingTop }, key },\n timescales.map((timescale) =>\n h(Timescale, {\n key: timescale.id,\n orientation: TimescaleOrientation.VERTICAL,\n length: pixelHeight,\n levels: timescale.levels,\n rootInterval: timescale.rootInterval,\n absoluteAgeScale: true,\n showAgeAxis: false,\n scale,\n intervals: timescale.intervals,\n style: levelCountStyle(levelCount(timescale)),\n ...forTimescale(timescale.id),\n }),\n ),\n );\n }),\n ),\n h.if(unconformityLabels)(UnconformityLabels, {\n width: \"100%\",\n sections: packages,\n className: \"unconformity-labels\",\n axisType: ColumnAxisType.AGE,\n }),\n ]);\n}\n\n/** The timescales to draw, with their intervals.\n *\n * Every timescale a column draws is fetched in one place: a column is split\n * into sections, and fetching per section would ask for the same timescale\n * once per section per timescale.\n */\nfunction useColumnTimescales(props: CompositeTimescaleProps): ColumnTimescale[] {\n const { timescales, levels = 3, timescaleID, additionalTimescales } = props;\n\n const specs = useMemo(\n () => timescaleSpecs({ timescales, levels, timescaleID, additionalTimescales }),\n [\n timescales,\n levels,\n timescaleID,\n additionalTimescales?.join(\",\"),\n ],\n );\n\n // Only the ones that didn't come with their own intervals need fetching\n const fetchIDs = useMemo(\n () => specs.filter((d) => d.intervals == null).map((d) => d.id),\n [specs],\n );\n const intervalSets = useMacrostratTimescales(fetchIDs);\n\n return useMemo(\n () =>\n specs.map((spec) => ({\n ...spec,\n intervals: spec.intervals ?? intervalSets.get(spec.id) ?? [],\n })),\n [specs, intervalSets],\n );\n}\n\n/** The `timescales` list, or one built from the older props that name the\n * leveled timescale and the flat ones beside it. */\nfunction timescaleSpecs(props: CompositeTimescaleProps): ColumnTimescale[] {\n const { timescales, levels = 3, timescaleID, additionalTimescales = [] } = props;\n\n if (timescales != null) {\n return timescales.map(normalizeTimescale);\n }\n\n return [\n {\n id: timescaleID ?? INTERNATIONAL_TIMESCALE_ID,\n levels: levelRange(levels),\n },\n ...additionalTimescales.map(normalizeTimescale),\n ];\n}\n\nfunction normalizeTimescale(timescale: ColumnTimescaleLike): ColumnTimescale {\n if (typeof timescale === \"number\") {\n return { id: timescale, levels: FLAT_TIMESCALE_LEVELS };\n }\n return { levels: FLAT_TIMESCALE_LEVELS, ...timescale };\n}\n\n/** Regional and project timescales come back flat: one level of intervals. */\nconst FLAT_TIMESCALE_LEVELS: [number, number] = [1, 1];\n\nfunction levelRange(levels: [number, number] | number): [number, number] {\n if (typeof levels !== \"number\") return levels;\n // A count, rather than a range: start at the level most columns start at\n return [2, Math.max(2 + Math.min(levels, 5) - 1, 1)];\n}\n\n/** How many slots wide a timescale draws: one per level it shows. */\nfunction levelCount(timescale: ColumnTimescale): number {\n const [min, max] = timescale.levels ?? FLAT_TIMESCALE_LEVELS;\n return Math.max(max - min + 1, 1);\n}\n\nexport function UnconformityLabels(props: {\n width: string | number;\n sections: PackageScaleLayoutData[];\n axisType?: ColumnAxisType;\n className?: string;\n verbose?: boolean;\n}) {\n const { width, sections, className, axisType, verbose } = props;\n\n return h(\n \"div.unconformity-labels\",\n {\n style: {\n width,\n },\n className,\n },\n sections.map((scaleInfo, i) => {\n const lastGroup = sections[i - 1];\n const top = scaleInfo.offset - scaleInfo.paddingTop;\n const upperAge = lastGroup?.domain[0];\n const lowerAge = scaleInfo.domain[1];\n return h(Unconformity, {\n axisType,\n upperAge,\n lowerAge,\n style: {\n width,\n height: scaleInfo.paddingTop,\n top,\n },\n verbose,\n });\n }),\n );\n}\n\nfunction Unconformity({\n upperAge,\n lowerAge,\n style,\n axisType,\n verbose = false,\n}) {\n if (upperAge == null || lowerAge == null) {\n return null;\n }\n\n const ageGap = Math.abs(upperAge - lowerAge);\n\n let maximumFractionDigits = 0;\n\n let className: string = null;\n if (ageGap > 1000) {\n className = \"giga\";\n } else if (ageGap > 100) {\n className = \"mega\";\n } else if (ageGap > 10) {\n className = \"large\";\n } else if (ageGap < 1) {\n className = \"small\";\n maximumFractionDigits = 2;\n } else {\n maximumFractionDigits = 1;\n }\n\n let val: ReactNode;\n if (axisType === ColumnAxisType.DEPTH || axisType === ColumnAxisType.HEIGHT) {\n const _txt = ageGap.toLocaleString(\"en-US\", { maximumFractionDigits });\n val = h(Value, { value: _txt, unit: \"m\" });\n } else {\n val = h(Duration, { value: ageGap, maximumFractionDigits });\n }\n\n let prefix: ReactNode = null;\n if (verbose) {\n prefix = h([\" \", h(\"span.prefix\", \" gap\")]);\n }\n\n return h(\"div.unconformity\", { style, className }, [\n h(\"div.unconformity-inner\", h(\"div.unconformity-text\", [val, prefix])),\n ]);\n}\n"],"names":["hyper","styles","useMacrostratUnits","LabelTrackerProvider","SectionLabelsColumn","useMacrostratColumnData","SVG","useMemo","MacrostratColumnProvider","CompositeUnitsColumn","timescale","levelCount","Timescale","TimescaleOrientation","ColumnAxisType","useMacrostratTimescales","Value","Duration"],"mappings":"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"}
package/dist/section.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { ReactNode, FunctionComponent } from 'react';
2
- import { TimescaleClickHandler, IntervalStyleBuilder } from '@macrostrat/timescale';
1
+ import { CSSProperties, ReactNode, FunctionComponent } from 'react';
2
+ import { Interval, TimescaleClickData } from '@macrostrat/timescale';
3
3
  import { ColumnAxisType } from '@macrostrat/column-components';
4
4
  import { ExtUnit, PackageScaleLayoutData } from './prepare-units/types';
5
5
  export interface SectionSharedProps {
@@ -10,6 +10,8 @@ export interface SectionSharedProps {
10
10
  columnWidth?: number;
11
11
  children?: ReactNode;
12
12
  showLabelColumn?: boolean;
13
+ /** Suppress the label for a unit drawn thinner than this many pixels */
14
+ labelSuppressHeight?: number;
13
15
  axisType?: ColumnAxisType;
14
16
  className?: string;
15
17
  clipUnits?: boolean;
@@ -22,19 +24,77 @@ export interface SectionProps extends SectionSharedProps {
22
24
  scaleInfo: PackageScaleLayoutData;
23
25
  }
24
26
  export declare function SectionsColumn(props: SectionSharedProps): import('react').FunctionComponentElement<any>;
27
+ /** A per-interval style that also knows which timescale the interval was
28
+ * drawn from. The same interval often appears in several of the timescales
29
+ * beside each other, and they aren't interchangeable — only one of them is
30
+ * the one a selection was made in. */
31
+ export type ColumnIntervalStyleBuilder = CSSProperties | ((interval: Interval, timescaleID: number) => CSSProperties) | null;
32
+ /** A timescale click, reporting which timescale was clicked in */
33
+ export type ColumnTimescaleClickHandler = (event: Event, data: TimescaleClickData & {
34
+ timescaleID: number;
35
+ }) => void;
36
+ /** A timescale to draw beside a column.
37
+ *
38
+ * The international timescale is one of these, not a special case: it is the
39
+ * one that happens to be nested several levels deep. Anything with the same
40
+ * shape can take its place or sit beside it — a regional set from the API, a
41
+ * zonation assembled locally, or a hierarchy that isn't a timescale at all,
42
+ * so long as its "intervals" carry ages.
43
+ */
44
+ export interface ColumnTimescale {
45
+ /** Integer identifier. Clicks and per-interval styles report it, so a
46
+ * consumer can tell one column's copy of an interval from another's. For a
47
+ * Macrostrat timescale it is the `timescale_id`. */
48
+ id: number;
49
+ /** Shown above the column, unless `label` says otherwise */
50
+ name?: string;
51
+ /** The intervals themselves, flat or already nested by `pid`. Left out,
52
+ * the timescale `id` is fetched from the Macrostrat API. */
53
+ intervals?: Interval[];
54
+ /** Levels to draw, and so how many slots wide the column is (default
55
+ * `[1, 1]`: one level, which is what a flat timescale has) */
56
+ levels?: [number, number];
57
+ /** `oid` of the interval the tree hangs from (default 0) */
58
+ rootInterval?: number;
59
+ /** Drawn above the column in place of the name — any node, so a consumer
60
+ * can put a control or a legend there instead of text */
61
+ label?: ReactNode;
62
+ }
63
+ export type ColumnTimescaleLike = number | ColumnTimescale;
25
64
  interface CompositeTimescaleProps {
65
+ /** Every timescale to draw, in order. A bare number is a Macrostrat
66
+ * timescale to fetch and draw as a single level.
67
+ *
68
+ * Given this, `levels`, `timescaleID` and `additionalTimescales` are
69
+ * ignored: it says what they say and more. */
70
+ timescales?: ColumnTimescaleLike[];
71
+ /** Levels of the ICS hierarchy to show. If a number, the finest level is
72
+ * `levels[0]`, the second-finest is `levels[1]`, etc. If an array, the
73
+ * first element is the starting level, the second is the ending level. */
26
74
  levels?: [number, number] | number;
27
75
  unconformityLabels?: boolean;
28
- onClickInterval?: TimescaleClickHandler;
76
+ onClickInterval?: ColumnTimescaleClickHandler;
29
77
  /** Per-interval style (e.g. to highlight the currently selected interval). */
30
- intervalStyle?: IntervalStyleBuilder;
78
+ intervalStyle?: ColumnIntervalStyleBuilder;
79
+ /** The timescale to draw. Defaults to the international one; any other
80
+ * Macrostrat timescale (a regional or project-specific set of intervals)
81
+ * can be drawn in its place. */
82
+ timescaleID?: number;
83
+ /** Further timescales drawn as extra level columns beside the main one,
84
+ * against the same scale. Shorthand for listing them in `timescales`. */
85
+ additionalTimescales?: number[];
86
+ /** Draw the names above the columns. They sit above the column proper, so
87
+ * leave top padding for them. */
88
+ showLabels?: boolean;
89
+ className?: string;
31
90
  }
32
91
  export declare function CompositeTimescale(props: CompositeTimescaleProps): import('react').FunctionComponentElement<CompositeTimescaleCoreProps>;
33
92
  type CompositeTimescaleCoreProps = CompositeTimescaleProps & {
34
93
  packages: PackageScaleLayoutData[];
35
- onClickInterval?: TimescaleClickHandler;
36
94
  };
37
- export declare function CompositeTimescaleCore(props: CompositeTimescaleCoreProps): import('react').DOMElement<import('react').DOMAttributes<Element>, Element>;
95
+ export declare function CompositeTimescaleCore(props: CompositeTimescaleCoreProps): import('react').ReactElement<{
96
+ className: string | undefined;
97
+ }, string | import('react').JSXElementConstructor<any>>;
38
98
  export declare function UnconformityLabels(props: {
39
99
  width: string | number;
40
100
  sections: PackageScaleLayoutData[];
package/dist/section.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { useMemo } from "react";
2
- import { useMacrostratIntervals, Timescale, TimescaleOrientation } from "@macrostrat/timescale";
2
+ import { Timescale, TimescaleOrientation, useMacrostratTimescales } from "@macrostrat/timescale";
3
3
  import { ColumnAxisType, SVG } from "@macrostrat/column-components";
4
4
  import h$1 from "@macrostrat/hyper";
5
5
  import h$2 from "./column.module.sass.js";
6
- import { useMacrostratBaseURL } from "@macrostrat/data-provider";
7
6
  import { Value } from "@macrostrat/data-components";
8
7
  import { useMacrostratColumnData, useMacrostratUnits, MacrostratColumnProvider } from "./data-provider/store.js";
9
8
  import { LabelTrackerProvider, SectionLabelsColumn, CompositeUnitsColumn } from "./units/composite.js";
10
9
  import { Duration } from "./unit-details/age-range.js";
10
+ const INTERNATIONAL_TIMESCALE_ID = 11;
11
11
  const h = h$1.styled(h$2);
12
12
  function SectionsColumn(props) {
13
13
  const {
@@ -19,7 +19,8 @@ function SectionsColumn(props) {
19
19
  columnWidth = 150,
20
20
  showLabelColumn = true,
21
21
  clipUnits = true,
22
- maxInternalColumns
22
+ maxInternalColumns,
23
+ labelSuppressHeight
23
24
  } = props;
24
25
  const units = useMacrostratUnits();
25
26
  const key = units[0]?.col_id;
@@ -34,7 +35,8 @@ function SectionsColumn(props) {
34
35
  unconformityLabels
35
36
  }),
36
37
  h.if(showLabelColumn)(SectionLabelsColumn, {
37
- width: width - columnWidth
38
+ width: width - columnWidth,
39
+ labelSuppressHeight
38
40
  })
39
41
  ]);
40
42
  }
@@ -49,7 +51,7 @@ function SectionUnitsColumn(props) {
49
51
  axisType,
50
52
  unconformityLabels = true
51
53
  } = props;
52
- const { sections, totalHeight } = useMacrostratColumnData();
54
+ const { sections, totalHeight, axisType: columnAxisType } = useMacrostratColumnData();
53
55
  const scaleData = sections.map((section) => {
54
56
  return section.scaleInfo;
55
57
  });
@@ -86,6 +88,9 @@ function SectionUnitsColumn(props) {
86
88
  h.if(unconformityLabels)(UnconformityLabels, {
87
89
  width,
88
90
  sections: scaleData,
91
+ // A gap between sections is measured in whatever the axis is: metres
92
+ // down a core, Myr across a time column
93
+ axisType: axisType ?? columnAxisType,
89
94
  verbose: false
90
95
  })
91
96
  ]);
@@ -149,44 +154,71 @@ function CompositeTimescale(props) {
149
154
  ...props
150
155
  });
151
156
  }
157
+ function TimescaleLabel({ timescale }) {
158
+ const { label, name } = timescale;
159
+ const style = levelCountStyle(levelCount(timescale));
160
+ let content = label;
161
+ if (label == null && name != null) {
162
+ content = h("span.timescale-label-text", name);
163
+ }
164
+ if (content == null) return h("div.timescale-label", { style });
165
+ return h("div.timescale-label", { style }, content);
166
+ }
167
+ function levelCountStyle(levelCount2) {
168
+ return { "--timescale-level-count": levelCount2 };
169
+ }
152
170
  function CompositeTimescaleCore(props) {
153
171
  const {
154
- levels = 3,
155
172
  packages,
156
173
  unconformityLabels = false,
157
174
  onClickInterval,
158
- intervalStyle
175
+ intervalStyle,
176
+ showLabels = false,
177
+ className
159
178
  } = props;
160
- const baseURL = useMacrostratBaseURL();
161
- const intervals = useMacrostratIntervals({ baseURL });
162
- let _levels;
163
- if (typeof levels === "number") {
164
- _levels = [2, Math.max(2 + Math.min(levels, 5) - 1, 1)];
165
- } else {
166
- _levels = levels;
179
+ const timescales = useColumnTimescales(props);
180
+ function forTimescale(id) {
181
+ let onClick = null;
182
+ if (onClickInterval != null) {
183
+ onClick = (event, data) => {
184
+ onClickInterval(event, { ...data, timescaleID: id });
185
+ };
186
+ }
187
+ let style = intervalStyle;
188
+ if (typeof intervalStyle === "function") {
189
+ style = (interval) => intervalStyle(interval, id);
190
+ }
191
+ return { onClick, intervalStyle: style };
167
192
  }
168
- const nCols = _levels[1] - _levels[0] + 1;
169
- return h("div.timescale-column", [
193
+ return h("div.timescale-column", { className }, [
194
+ h.if(showLabels)(
195
+ "div.timescale-labels",
196
+ timescales.map(
197
+ (timescale) => h(TimescaleLabel, { key: timescale.id, timescale })
198
+ )
199
+ ),
170
200
  h(
171
201
  "div.timescales",
172
202
  packages.map((group) => {
173
203
  const { pixelHeight, paddingTop, key, scale } = group;
174
204
  return h(
175
- "div.timescale-container",
176
- { style: { paddingTop, "--timescale-level-count": nCols }, key },
177
- [
178
- h(Timescale, {
205
+ "div.section-timescales",
206
+ { style: { paddingTop }, key },
207
+ timescales.map(
208
+ (timescale) => h(Timescale, {
209
+ key: timescale.id,
179
210
  orientation: TimescaleOrientation.VERTICAL,
180
211
  length: pixelHeight,
181
- levels: _levels,
212
+ levels: timescale.levels,
213
+ rootInterval: timescale.rootInterval,
182
214
  absoluteAgeScale: true,
183
215
  showAgeAxis: false,
184
216
  scale,
185
- intervals,
186
- onClick: onClickInterval,
187
- intervalStyle
217
+ intervals: timescale.intervals,
218
+ style: levelCountStyle(levelCount(timescale)),
219
+ ...forTimescale(timescale.id)
188
220
  })
189
- ]
221
+ )
190
222
  );
191
223
  })
192
224
  ),
@@ -198,6 +230,58 @@ function CompositeTimescaleCore(props) {
198
230
  })
199
231
  ]);
200
232
  }
233
+ function useColumnTimescales(props) {
234
+ const { timescales, levels = 3, timescaleID, additionalTimescales } = props;
235
+ const specs = useMemo(
236
+ () => timescaleSpecs({ timescales, levels, timescaleID, additionalTimescales }),
237
+ [
238
+ timescales,
239
+ levels,
240
+ timescaleID,
241
+ additionalTimescales?.join(",")
242
+ ]
243
+ );
244
+ const fetchIDs = useMemo(
245
+ () => specs.filter((d) => d.intervals == null).map((d) => d.id),
246
+ [specs]
247
+ );
248
+ const intervalSets = useMacrostratTimescales(fetchIDs);
249
+ return useMemo(
250
+ () => specs.map((spec) => ({
251
+ ...spec,
252
+ intervals: spec.intervals ?? intervalSets.get(spec.id) ?? []
253
+ })),
254
+ [specs, intervalSets]
255
+ );
256
+ }
257
+ function timescaleSpecs(props) {
258
+ const { timescales, levels = 3, timescaleID, additionalTimescales = [] } = props;
259
+ if (timescales != null) {
260
+ return timescales.map(normalizeTimescale);
261
+ }
262
+ return [
263
+ {
264
+ id: timescaleID ?? INTERNATIONAL_TIMESCALE_ID,
265
+ levels: levelRange(levels)
266
+ },
267
+ ...additionalTimescales.map(normalizeTimescale)
268
+ ];
269
+ }
270
+ function normalizeTimescale(timescale) {
271
+ if (typeof timescale === "number") {
272
+ return { id: timescale, levels: FLAT_TIMESCALE_LEVELS };
273
+ }
274
+ return { levels: FLAT_TIMESCALE_LEVELS, ...timescale };
275
+ }
276
+ const FLAT_TIMESCALE_LEVELS = [1, 1];
277
+ function levelRange(levels) {
278
+ if (typeof levels !== "number") return levels;
279
+ return [2, Math.max(2 + Math.min(levels, 5) - 1, 1)];
280
+ }
281
+ function levelCount(timescale) {
282
+ const [min, max] = timescale.levels ?? FLAT_TIMESCALE_LEVELS;
283
+ return Math.max(max - min + 1, 1);
284
+ }
201
285
  function UnconformityLabels(props) {
202
286
  const { width, sections, className, axisType, verbose } = props;
203
287
  return h(