@macrostrat/column-views 3.4.2 → 3.5.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 (51) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/column-views.css +7 -7
  3. package/dist/column.cjs +21 -21
  4. package/dist/column.cjs.map +1 -1
  5. package/dist/column.d.ts +3 -1
  6. package/dist/column.js +4 -4
  7. package/dist/column.js.map +1 -1
  8. package/dist/data-provider/store.cjs +26 -3
  9. package/dist/data-provider/store.cjs.map +1 -1
  10. package/dist/data-provider/store.d.ts +52 -0
  11. package/dist/data-provider/store.js +27 -4
  12. package/dist/data-provider/store.js.map +1 -1
  13. package/dist/data-provider/unit-selection.cjs +10 -4
  14. package/dist/data-provider/unit-selection.cjs.map +1 -1
  15. package/dist/data-provider/unit-selection.d.ts +3 -0
  16. package/dist/data-provider/unit-selection.js +10 -4
  17. package/dist/data-provider/unit-selection.js.map +1 -1
  18. package/dist/index.cjs +1 -0
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.js +2 -1
  21. package/dist/prepare-units/helpers.cjs +58 -36
  22. package/dist/prepare-units/helpers.cjs.map +1 -1
  23. package/dist/prepare-units/helpers.d.ts +13 -5
  24. package/dist/prepare-units/helpers.js +59 -37
  25. package/dist/prepare-units/helpers.js.map +1 -1
  26. package/dist/prepare-units/index.cjs +1 -0
  27. package/dist/prepare-units/index.cjs.map +1 -1
  28. package/dist/prepare-units/index.d.ts +2 -2
  29. package/dist/prepare-units/index.js +1 -0
  30. package/dist/prepare-units/index.js.map +1 -1
  31. package/dist/unit-details/panel.cjs +1 -1
  32. package/dist/unit-details/panel.cjs.map +1 -1
  33. package/dist/unit-details/panel.js +1 -1
  34. package/dist/unit-details/panel.js.map +1 -1
  35. package/dist/units/boxes.module.sass.cjs +3 -3
  36. package/dist/units/boxes.module.sass.js +3 -3
  37. package/dist/units/index.cjs +5 -5
  38. package/dist/units/index.cjs.map +1 -1
  39. package/dist/units/index.d.ts +2 -2
  40. package/dist/units/index.js +5 -5
  41. package/dist/units/index.js.map +1 -1
  42. package/package.json +4 -4
  43. package/src/column.ts +6 -4
  44. package/src/correlation-chart/stories/namibia-correlation.stories.ts +151 -0
  45. package/src/data-provider/store.ts +48 -4
  46. package/src/data-provider/unit-selection.ts +10 -5
  47. package/src/prepare-units/helpers.ts +98 -50
  48. package/src/prepare-units/index.ts +4 -1
  49. package/src/unit-details/panel.ts +1 -1
  50. package/src/units/boxes.module.sass +2 -2
  51. package/src/units/index.ts +7 -7
@@ -11,26 +11,40 @@ import {
11
11
  import {
12
12
  AgeRangeRelationship,
13
13
  compareAgeRanges,
14
+ mergeAgeRanges,
15
+ MergeMode,
14
16
  } from "@macrostrat/stratigraphy-utils";
15
17
  import type { ExtUnit, SectionInfo, StratigraphicPackage } from "./types";
16
18
 
17
19
  const dt = 0.001;
18
20
 
19
- export type UnitWithDefinedOverlap<T extends BaseUnit> = T & {
20
- overlap: UnitOverlapInfo<T>;
21
+ export type UnitWithLayoutParameters<T extends BaseUnit> = T & {
22
+ layout: UnitLayoutData<T>;
21
23
  };
22
24
 
23
- type UnitOverlapInfo<T extends BaseUnit> = {
25
+ export type UnitWithLayoutHints<T extends BaseUnit> = T & {
26
+ layoutHints?: UnitLayoutHints;
27
+ };
28
+
29
+ interface UnitLayoutInfo {
24
30
  column: number;
25
31
  nColumns: number;
32
+ }
33
+
34
+ type UnitLayoutHints = Partial<UnitLayoutInfo>;
35
+
36
+ type UnitLayoutData<T extends BaseUnit> = UnitLayoutInfo & {
37
+ totalColumns: number;
26
38
  unitGroup: UnitGroup<T>;
27
39
  };
28
40
 
29
41
  class UnitGroup<T extends BaseUnit> implements StratigraphicPackage {
30
42
  units: T[];
43
+ axisType: ColumnAxisType;
31
44
 
32
- constructor(units: T[]) {
45
+ constructor(units: T[], axisType: ColumnAxisType = ColumnAxisType.AGE) {
33
46
  this.units = units;
47
+ this.axisType = axisType;
34
48
  }
35
49
 
36
50
  get t_age(): number {
@@ -41,7 +55,7 @@ class UnitGroup<T extends BaseUnit> implements StratigraphicPackage {
41
55
  return Math.max(...this.units.map((d) => d.b_age));
42
56
  }
43
57
 
44
- getUnits(): UnitWithDefinedOverlap<T>[] {
58
+ getUnits(): UnitWithLayoutParameters<T>[] {
45
59
  return assignColumnsToUnitsWithinOverlappingGroup(this);
46
60
  }
47
61
  }
@@ -49,39 +63,51 @@ class UnitGroup<T extends BaseUnit> implements StratigraphicPackage {
49
63
  function groupUnitsByMutualOverlap<T extends BaseUnit>(
50
64
  units: T[],
51
65
  tolerance: number = dt,
66
+ axisType: ColumnAxisType = ColumnAxisType.AGE,
52
67
  ): UnitGroup<T>[] {
53
68
  /** Group units within a section that have mutual overlap. */
54
- const sections = groupUnitsIntoSectionsByOverlap(
55
- units,
56
- ColumnAxisType.AGE,
57
- tolerance,
58
- );
69
+
70
+ const sections = groupUnitsIntoSectionsByOverlap(units, axisType, tolerance);
71
+
72
+ console.log("Grouped sections", sections);
73
+
59
74
  return sections.map((d) => {
60
- return new UnitGroup(d.units);
75
+ return new UnitGroup(d.units, axisType);
61
76
  });
62
77
  }
63
78
 
64
79
  const sortByAge = createUnitSorter(ColumnAxisType.AGE);
65
80
 
66
81
  function assignColumnsToUnitsWithinOverlappingGroup<T extends BaseUnit>(
67
- group: UnitGroup<T>,
68
- ): UnitWithDefinedOverlap<T>[] {
82
+ group: UnitGroup<UnitWithLayoutHints<T>>,
83
+ ): UnitWithLayoutParameters<T>[] {
69
84
  /** A relatively naïve function to assign columns to units within a mutually overlapping group.
70
85
  * This gets the number of columns that would be needed to accommodate the units in the group.
71
86
  * It then assigns columns to units in the group based on the number of columns needed, with
72
87
  * lower units further to the left.
73
88
  */
74
89
 
75
- const sortedUnits = [...group.units].sort((a, b) => b.b_age - a.b_age);
90
+ const sortedUnits = [...group.units].sort(createUnitSorter(group.axisType));
76
91
 
77
92
  const columns: T[][] = [];
78
93
 
94
+ let nColumns = 1;
95
+
79
96
  for (const unit of sortedUnits) {
97
+ let startIndex = 0;
98
+ let endIndex = 0;
80
99
  // Find a column that is not already occupied by an overlapping unit
100
+ const colHint = unit.layoutHints?.column;
101
+ if (colHint != null) {
102
+ columns[colHint] ??= [];
103
+ columns[colHint].push(unit);
104
+ continue;
105
+ }
81
106
  let didAddToExistingColumn = false;
107
+
82
108
  for (const column of columns) {
83
109
  const lastUnit = column[column.length - 1];
84
- if (!unitsOverlap(unit, lastUnit, ColumnAxisType.AGE, dt)) {
110
+ if (!unitsOverlap(unit, lastUnit, group.axisType, dt)) {
85
111
  column.push(unit);
86
112
  didAddToExistingColumn = true;
87
113
  break;
@@ -92,14 +118,17 @@ function assignColumnsToUnitsWithinOverlappingGroup<T extends BaseUnit>(
92
118
  }
93
119
  }
94
120
 
95
- const units: UnitWithDefinedOverlap<T>[] = columns.flatMap(
121
+ console.log(columns);
122
+
123
+ const units: UnitWithLayoutParameters<T>[] = columns.flatMap(
96
124
  (column, columnIndex) =>
97
125
  column.map((unit) => {
98
126
  return {
99
127
  ...unit,
100
- overlap: {
128
+ layout: {
101
129
  column: columnIndex,
102
- nColumns: columns.length,
130
+ nColumns: 1,
131
+ totalColumns: columns.length,
103
132
  unitGroup: group,
104
133
  },
105
134
  };
@@ -121,7 +150,7 @@ export function preprocessUnits<T extends UnitLong = UnitLong>(
121
150
  tolerance = 0.01; // 1cm tolerance for height/depth columns
122
151
  }
123
152
 
124
- const unitGroups = groupUnitsByMutualOverlap(units, tolerance);
153
+ const unitGroups = groupUnitsByMutualOverlap(units, tolerance, axisType);
125
154
 
126
155
  const divisions: any[] = [];
127
156
  // Serialize all groups' units to a single array
@@ -186,7 +215,7 @@ export function groupUnitsIntoSectionsBySectionID<T extends UnitLong>(
186
215
  interface WorkingSection {
187
216
  units: UnitLong[];
188
217
  // Position or age
189
- heightRange?: [number, number];
218
+ heightRange: [number, number];
190
219
  }
191
220
 
192
221
  export function groupUnitsIntoSectionsByOverlap<T extends BaseUnit>(
@@ -201,41 +230,60 @@ export function groupUnitsIntoSectionsByOverlap<T extends BaseUnit>(
201
230
  * */
202
231
  // Start with each unit as its own "section", and progressively merge...
203
232
  const sectionList: WorkingSection[] = [];
204
- for (const unit of units) {
205
- // Check if the unit overlaps with any existing section
206
- const heightRange = getUnitHeightRange(unit, axisType);
207
- let section: WorkingSection | undefined = sectionList.find(
208
- (s) =>
209
- compareAgeRanges(heightRange, s.heightRange, tolerance) !==
210
- AgeRangeRelationship.Disjoint,
211
- );
212
- if (section == null) {
213
- // No overlap, create a new section
214
- sectionList.push({
215
- heightRange,
216
- units: [unit],
217
- });
218
- } else {
219
- // Overlap, merge the unit into the section
220
- section.units.push(unit);
221
- // Update the height range
222
- if (axisType == ColumnAxisType.DEPTH || axisType == ColumnAxisType.AGE) {
223
- section.heightRange = [
224
- Math.max(section.heightRange[0], heightRange[0]),
225
- Math.min(section.heightRange[1], heightRange[1]),
226
- ];
233
+
234
+ const initialSections: WorkingSection[] = units.map((unit) => {
235
+ return {
236
+ units: [unit],
237
+ heightRange: getUnitHeightRange(unit, axisType),
238
+ };
239
+ });
240
+
241
+ const isOverlapping = (a: WorkingSection, b: WorkingSection) => {
242
+ const res = compareAgeRanges(a.heightRange, b.heightRange, tolerance);
243
+ return res !== AgeRangeRelationship.Disjoint;
244
+ };
245
+
246
+ const mergeSections = (a: WorkingSection, b: WorkingSection) => {
247
+ return {
248
+ units: [...a.units, ...b.units],
249
+ heightRange: mergeAgeRanges(
250
+ [a.heightRange, b.heightRange],
251
+ MergeMode.Outer,
252
+ ),
253
+ };
254
+ };
255
+
256
+ // Merge overlapping sections progressively until no more merges are possible
257
+ let finalSectionList = initialSections;
258
+
259
+ while (true) {
260
+ let merged = false;
261
+ const nextSections: WorkingSection[] = [];
262
+
263
+ for (const section of finalSectionList) {
264
+ if (nextSections.length === 0) {
265
+ nextSections.push(section);
227
266
  } else {
228
- section.heightRange = [
229
- Math.min(section.heightRange[0], heightRange[0]),
230
- Math.max(section.heightRange[1], heightRange[1]),
231
- ];
267
+ const lastSection = nextSections[nextSections.length - 1];
268
+ if (isOverlapping(section, lastSection)) {
269
+ // Merge with the last section
270
+ nextSections[nextSections.length - 1] = mergeSections(lastSection, section);
271
+ merged = true;
272
+ } else {
273
+ nextSections.push(section);
274
+ }
232
275
  }
233
276
  }
277
+
278
+ finalSectionList = nextSections;
279
+
280
+ // Stop when no more merges occurred in this pass
281
+ if (!merged) {
282
+ break;
283
+ }
234
284
  }
235
- // We should have a section for each unit, now we can convert to SectionInfo
236
- // Ages have to be really actually ages, not heights
237
285
 
238
- return sectionList.map((section, i) => {
286
+ return finalSectionList.map((section, i) => {
239
287
  const [b_age, t_age] = getSectionAgeRange(section.units);
240
288
  const [b_pos, t_pos] = getSectionPosRange(section.units, axisType);
241
289
  return {
@@ -6,6 +6,7 @@ import {
6
6
  mergeOverlappingSections,
7
7
  preprocessSectionUnit,
8
8
  preprocessUnits,
9
+ UnitWithLayoutHints,
9
10
  } from "./helpers";
10
11
  import { ColumnAxisType } from "@macrostrat/column-components";
11
12
  import { useMemo } from "react";
@@ -43,7 +44,7 @@ export function usePreparedColumnUnits(
43
44
  }
44
45
 
45
46
  export function prepareColumnUnits(
46
- units: UnitLong[],
47
+ units: UnitWithLayoutHints<UnitLong>[],
47
48
  options: PrepareColumnOptions,
48
49
  ): PreparedColumnData {
49
50
  /** Prepare units for rendering into Macrostrat columns */
@@ -184,6 +185,8 @@ export function prepareColumnUnits(
184
185
  * We do this after merging sections so that we can
185
186
  * handle cases where there are overlapping units across sections
186
187
  * */
188
+ console.log(sections2, "sections");
189
+
187
190
  const sectionsOut = sections2.map((section) => {
188
191
  return {
189
192
  ...section,
@@ -93,7 +93,7 @@ export function UnitDetailsPanel({
93
93
  key: "json-view-toggle",
94
94
  className: classNames("json-view-toggle", { enabled: setShowJSON }),
95
95
  onClick(evt) {
96
- setShowJSON(!showJSON);
96
+ setShowJSON(!_showJSON);
97
97
  evt.stopPropagation();
98
98
  },
99
99
  }),
@@ -4,8 +4,8 @@
4
4
  .labeled-unit
5
5
  --column-unit-background-internal: var(--column-unit-background-color, var(--column-background-color))
6
6
  :global(.unit-overlay)
7
- font-size: 10px
8
- font-style: italic
7
+ font-size: var(--column-unit-font-size, 10px)
8
+ font-style: var(--column-unit-font-style, italic)
9
9
  display: flex
10
10
  align-items: center
11
11
  justify-content: center
@@ -14,7 +14,7 @@ import { useEnvironments, useLithologies } from "@macrostrat/data-provider";
14
14
  import { useMemo } from "react";
15
15
  import { resolveID } from "./resolvers";
16
16
  import { BaseUnit, Lithology } from "@macrostrat/api-types";
17
- import { UnitWithDefinedOverlap } from "../prepare-units/helpers.ts";
17
+ import { UnitWithLayoutParameters } from "../prepare-units/helpers.ts";
18
18
 
19
19
  export * from "./composite";
20
20
  export * from "./types";
@@ -58,7 +58,7 @@ export function BasicUnitComponent({ division, ...rest }) {
58
58
  }
59
59
 
60
60
  interface UnitComponentProps<T extends BaseUnit> {
61
- division: UnitWithDefinedOverlap<T> | T;
61
+ division: UnitWithLayoutParameters<T> | T;
62
62
  nColumns: number;
63
63
  width?: number;
64
64
  }
@@ -78,11 +78,11 @@ export function UnitComponent<T extends BaseUnit>({
78
78
  let x = 0;
79
79
 
80
80
  let reducedWidth = _nColumns;
81
- if ("overlap" in division) {
82
- const overlap = division.overlap;
83
- _nColumns = Math.min(_nColumns, overlap.nColumns);
84
- columnIx = overlap.column;
85
- reducedWidth = width / _nColumns;
81
+ if ("layout" in division) {
82
+ const layout = division.layout;
83
+ _nColumns = Math.min(_nColumns, layout.totalColumns);
84
+ columnIx = layout.column;
85
+ reducedWidth = width / layout.totalColumns / layout.nColumns;
86
86
  x = (columnIx * width) / _nColumns;
87
87
  }
88
88
  return h(TrackedLabeledUnit, {