@macrostrat/column-views 3.5.0 → 3.6.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.
Files changed (36) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/column-views.css +7 -7
  3. package/dist/data-provider/store.cjs +2 -2
  4. package/dist/data-provider/store.cjs.map +1 -1
  5. package/dist/data-provider/store.d.ts +1 -1
  6. package/dist/data-provider/store.js +1 -1
  7. package/dist/data-provider/store.js.map +1 -1
  8. package/dist/prepare-units/helpers.cjs +58 -36
  9. package/dist/prepare-units/helpers.cjs.map +1 -1
  10. package/dist/prepare-units/helpers.d.ts +13 -5
  11. package/dist/prepare-units/helpers.js +59 -37
  12. package/dist/prepare-units/helpers.js.map +1 -1
  13. package/dist/prepare-units/index.cjs +1 -0
  14. package/dist/prepare-units/index.cjs.map +1 -1
  15. package/dist/prepare-units/index.d.ts +2 -2
  16. package/dist/prepare-units/index.js +1 -0
  17. package/dist/prepare-units/index.js.map +1 -1
  18. package/dist/unit-details/panel.cjs +1 -1
  19. package/dist/unit-details/panel.cjs.map +1 -1
  20. package/dist/unit-details/panel.js +1 -1
  21. package/dist/unit-details/panel.js.map +1 -1
  22. package/dist/units/boxes.module.sass.cjs +3 -3
  23. package/dist/units/boxes.module.sass.js +3 -3
  24. package/dist/units/index.cjs +5 -5
  25. package/dist/units/index.cjs.map +1 -1
  26. package/dist/units/index.d.ts +2 -2
  27. package/dist/units/index.js +5 -5
  28. package/dist/units/index.js.map +1 -1
  29. package/package.json +10 -9
  30. package/src/correlation-chart/stories/namibia-correlation.stories.ts +151 -0
  31. package/src/data-provider/store.ts +1 -1
  32. package/src/prepare-units/helpers.ts +98 -50
  33. package/src/prepare-units/index.ts +4 -1
  34. package/src/unit-details/panel.ts +1 -1
  35. package/src/units/boxes.module.sass +2 -2
  36. package/src/units/index.ts +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/units/index.ts"],"sourcesContent":["import h from \"@macrostrat/hyper\";\nimport {\n LithologyColumn,\n useGeologicPattern,\n} from \"@macrostrat/column-components\";\nimport { UnitNamesColumn } from \"./names\";\nimport { ICompositeUnitProps } from \"./composite\";\nimport { UnitBoxes, UnitProps } from \"./boxes\";\nimport { useColumnLayout } from \"@macrostrat/column-components\";\nimport { useInDarkMode } from \"@macrostrat/ui-components\";\nimport { getMixedUnitColor } from \"./colors\";\nimport { TrackedLabeledUnit } from \"./composite\";\nimport { useEnvironments, useLithologies } from \"@macrostrat/data-provider\";\nimport { useMemo } from \"react\";\nimport { resolveID } from \"./resolvers\";\nimport { BaseUnit, Lithology } from \"@macrostrat/api-types\";\nimport { UnitWithDefinedOverlap } from \"../prepare-units/helpers.ts\";\n\nexport * from \"./composite\";\nexport * from \"./types\";\nexport * from \"./colors\";\n\nexport function UnitsColumn({ width = 100 }) {\n /*\n A column showing units with USGS color fill\n */\n return h(LithologyColumn, { width }, h(UnitBoxes));\n}\n\nexport function SimpleUnitsColumn(props: ICompositeUnitProps) {\n /*\n A column with units and names either\n overlapping or offset to the right\n */\n const { columnWidth, width, gutterWidth = 0, labelOffset = 30 } = props;\n\n return h([\n h(UnitsColumn, {\n width: columnWidth,\n }),\n h(UnitNamesColumn, {\n transform: `translate(${columnWidth + gutterWidth})`,\n paddingLeft: labelOffset,\n width: width - columnWidth - gutterWidth,\n }),\n ]);\n}\n\nexport function BasicUnitComponent({ division, ...rest }) {\n /** A unit that allows directly setting colors and patterns. */\n\n return h(UnitComponent, {\n division,\n ...rest,\n backgroundColor: division.color,\n patternID: division.patternID,\n });\n}\n\ninterface UnitComponentProps<T extends BaseUnit> {\n division: UnitWithDefinedOverlap<T> | T;\n nColumns: number;\n width?: number;\n}\n\nexport function UnitComponent<T extends BaseUnit>({\n division,\n nColumns = 2,\n ...rest\n}: UnitComponentProps<T>) {\n const width = rest.width ?? useColumnLayout()?.width;\n\n let _nColumns = nColumns;\n if (isNaN(_nColumns)) {\n _nColumns = 2;\n }\n let columnIx = 0;\n let x = 0;\n\n let reducedWidth = _nColumns;\n if (\"overlap\" in division) {\n const overlap = division.overlap;\n _nColumns = Math.min(_nColumns, overlap.nColumns);\n columnIx = overlap.column;\n reducedWidth = width / _nColumns;\n x = (columnIx * width) / _nColumns;\n }\n return h(TrackedLabeledUnit, {\n division,\n ...rest,\n width: reducedWidth,\n x,\n });\n}\n\ninterface UnitColorOptions {\n asBackground?: boolean;\n}\n\nexport function useUnitColor(unit, opts: UnitColorOptions = {}): string | null {\n /** Get the color for a unit based on its lithology */\n const lithMap = useLithologies();\n const inDarkMode = useInDarkMode();\n const { asBackground = true } = opts;\n\n return useMemo(() => {\n if (unit == null || lithMap == null) return null;\n return getMixedUnitColor(unit, lithMap, inDarkMode, asBackground);\n }, [unit?.unit_id, lithMap, inDarkMode, asBackground]);\n}\n\nexport function ColoredUnitComponent(props) {\n /** A unit component that is colored using a mixture of lithologies.\n * This is a separate component because it depends on more providers/contexts to determine coloring. */\n const backgroundColor = useUnitColor(props.division);\n\n const patternID = useMemo(() => {\n return resolveID(props.division); // ?? getPatternID(props.division.lith, lithMap);\n }, [props.division?.unit_id]);\n\n const fill = useGeologicPattern(patternID);\n\n return h(UnitComponent, {\n fill,\n backgroundColor,\n ...props,\n });\n}\n\nexport function useUnitColorByEnvironment(\n unit,\n opts: UnitColorOptions = {},\n): string | null {\n /** Get the color for a unit based on its lithology */\n const environmentMap = useEnvironments();\n const lithMap = useLithologies();\n const inDarkMode = useInDarkMode();\n const { asBackground = true } = opts;\n\n return useMemo(() => {\n if (unit == null || environmentMap == null) return null;\n let c = getMixedUnitColor(unit, environmentMap, inDarkMode, asBackground, {\n key: \"environ\",\n id_key: \"environ_id\",\n });\n if (c != null) {\n return c;\n }\n // Fallback to lithology color if no environment color is found\n return getMixedUnitColor(unit, lithMap, inDarkMode, asBackground);\n }, [unit?.unit_id, environmentMap, lithMap, inDarkMode, asBackground]);\n}\n\nexport function EnvironmentColoredUnitComponent(props) {\n /** A unit component that is colored using a mixture of lithologies.\n * This is a separate component because it depends on more providers/contexts to determine coloring. */\n const backgroundColor = useUnitColorByEnvironment(props.division);\n\n const patternID = useMemo(() => {\n return resolveID(props.division); // ?? getPatternID(props.division.lith, lithMap);\n }, [props.division?.unit_id]);\n\n const fill = useGeologicPattern(patternID);\n\n return h(UnitComponent, {\n fill,\n backgroundColor,\n ...props,\n });\n}\n\nfunction getPatternID(\n liths: Array<Lithology>,\n lithMap: Map<number, Lithology>,\n): string | null {\n if (lithMap == null || liths == null || liths.length == 0) {\n return null;\n }\n const patternIDs = new Set<string>();\n for (const lith of liths) {\n const lithData = lithMap.get(lith.lith_id);\n if (lithData) {\n patternIDs.add(`${lithData.fill}`);\n }\n }\n let id = patternIDs.values()[0];\n if (id == \"0\") return null;\n return id;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/units/index.ts"],"sourcesContent":["import h from \"@macrostrat/hyper\";\nimport {\n LithologyColumn,\n useGeologicPattern,\n} from \"@macrostrat/column-components\";\nimport { UnitNamesColumn } from \"./names\";\nimport { ICompositeUnitProps } from \"./composite\";\nimport { UnitBoxes, UnitProps } from \"./boxes\";\nimport { useColumnLayout } from \"@macrostrat/column-components\";\nimport { useInDarkMode } from \"@macrostrat/ui-components\";\nimport { getMixedUnitColor } from \"./colors\";\nimport { TrackedLabeledUnit } from \"./composite\";\nimport { useEnvironments, useLithologies } from \"@macrostrat/data-provider\";\nimport { useMemo } from \"react\";\nimport { resolveID } from \"./resolvers\";\nimport { BaseUnit, Lithology } from \"@macrostrat/api-types\";\nimport { UnitWithLayoutParameters } from \"../prepare-units/helpers.ts\";\n\nexport * from \"./composite\";\nexport * from \"./types\";\nexport * from \"./colors\";\n\nexport function UnitsColumn({ width = 100 }) {\n /*\n A column showing units with USGS color fill\n */\n return h(LithologyColumn, { width }, h(UnitBoxes));\n}\n\nexport function SimpleUnitsColumn(props: ICompositeUnitProps) {\n /*\n A column with units and names either\n overlapping or offset to the right\n */\n const { columnWidth, width, gutterWidth = 0, labelOffset = 30 } = props;\n\n return h([\n h(UnitsColumn, {\n width: columnWidth,\n }),\n h(UnitNamesColumn, {\n transform: `translate(${columnWidth + gutterWidth})`,\n paddingLeft: labelOffset,\n width: width - columnWidth - gutterWidth,\n }),\n ]);\n}\n\nexport function BasicUnitComponent({ division, ...rest }) {\n /** A unit that allows directly setting colors and patterns. */\n\n return h(UnitComponent, {\n division,\n ...rest,\n backgroundColor: division.color,\n patternID: division.patternID,\n });\n}\n\ninterface UnitComponentProps<T extends BaseUnit> {\n division: UnitWithLayoutParameters<T> | T;\n nColumns: number;\n width?: number;\n}\n\nexport function UnitComponent<T extends BaseUnit>({\n division,\n nColumns = 2,\n ...rest\n}: UnitComponentProps<T>) {\n const width = rest.width ?? useColumnLayout()?.width;\n\n let _nColumns = nColumns;\n if (isNaN(_nColumns)) {\n _nColumns = 2;\n }\n let columnIx = 0;\n let x = 0;\n\n let reducedWidth = _nColumns;\n if (\"layout\" in division) {\n const layout = division.layout;\n _nColumns = Math.min(_nColumns, layout.totalColumns);\n columnIx = layout.column;\n reducedWidth = width / layout.totalColumns / layout.nColumns;\n x = (columnIx * width) / _nColumns;\n }\n return h(TrackedLabeledUnit, {\n division,\n ...rest,\n width: reducedWidth,\n x,\n });\n}\n\ninterface UnitColorOptions {\n asBackground?: boolean;\n}\n\nexport function useUnitColor(unit, opts: UnitColorOptions = {}): string | null {\n /** Get the color for a unit based on its lithology */\n const lithMap = useLithologies();\n const inDarkMode = useInDarkMode();\n const { asBackground = true } = opts;\n\n return useMemo(() => {\n if (unit == null || lithMap == null) return null;\n return getMixedUnitColor(unit, lithMap, inDarkMode, asBackground);\n }, [unit?.unit_id, lithMap, inDarkMode, asBackground]);\n}\n\nexport function ColoredUnitComponent(props) {\n /** A unit component that is colored using a mixture of lithologies.\n * This is a separate component because it depends on more providers/contexts to determine coloring. */\n const backgroundColor = useUnitColor(props.division);\n\n const patternID = useMemo(() => {\n return resolveID(props.division); // ?? getPatternID(props.division.lith, lithMap);\n }, [props.division?.unit_id]);\n\n const fill = useGeologicPattern(patternID);\n\n return h(UnitComponent, {\n fill,\n backgroundColor,\n ...props,\n });\n}\n\nexport function useUnitColorByEnvironment(\n unit,\n opts: UnitColorOptions = {},\n): string | null {\n /** Get the color for a unit based on its lithology */\n const environmentMap = useEnvironments();\n const lithMap = useLithologies();\n const inDarkMode = useInDarkMode();\n const { asBackground = true } = opts;\n\n return useMemo(() => {\n if (unit == null || environmentMap == null) return null;\n let c = getMixedUnitColor(unit, environmentMap, inDarkMode, asBackground, {\n key: \"environ\",\n id_key: \"environ_id\",\n });\n if (c != null) {\n return c;\n }\n // Fallback to lithology color if no environment color is found\n return getMixedUnitColor(unit, lithMap, inDarkMode, asBackground);\n }, [unit?.unit_id, environmentMap, lithMap, inDarkMode, asBackground]);\n}\n\nexport function EnvironmentColoredUnitComponent(props) {\n /** A unit component that is colored using a mixture of lithologies.\n * This is a separate component because it depends on more providers/contexts to determine coloring. */\n const backgroundColor = useUnitColorByEnvironment(props.division);\n\n const patternID = useMemo(() => {\n return resolveID(props.division); // ?? getPatternID(props.division.lith, lithMap);\n }, [props.division?.unit_id]);\n\n const fill = useGeologicPattern(patternID);\n\n return h(UnitComponent, {\n fill,\n backgroundColor,\n ...props,\n });\n}\n\nfunction getPatternID(\n liths: Array<Lithology>,\n lithMap: Map<number, Lithology>,\n): string | null {\n if (lithMap == null || liths == null || liths.length == 0) {\n return null;\n }\n const patternIDs = new Set<string>();\n for (const lith of liths) {\n const lithData = lithMap.get(lith.lith_id);\n if (lithData) {\n patternIDs.add(`${lithData.fill}`);\n }\n }\n let id = patternIDs.values()[0];\n if (id == \"0\") return null;\n return id;\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@macrostrat/column-views",
3
- "version": "3.5.0",
3
+ "version": "3.6.0",
4
4
  "description": "Data views for Macrostrat stratigraphic columns",
5
5
  "repository": {
6
6
  "type": "git",
@@ -48,18 +48,19 @@
48
48
  "@blueprintjs/core": "^6.14.0",
49
49
  "@macrostrat/api-types": "^1.2.0",
50
50
  "@macrostrat/color-utils": "^1.2.2",
51
- "@macrostrat/column-components": "^2.0.8",
52
- "@macrostrat/data-components": "^1.1.12",
51
+ "@macrostrat/column-components": "^2.0.9",
52
+ "@macrostrat/data-components": "^1.4.0",
53
53
  "@macrostrat/data-provider": "^1.1.0",
54
54
  "@macrostrat/hyper": "^3.1.1",
55
- "@macrostrat/map-interface": "^2.2.6",
56
- "@macrostrat/map-styles": "^2.2.4",
57
- "@macrostrat/mapbox-react": "^3.2.2",
58
- "@macrostrat/mapbox-utils": "^1.7.4",
55
+ "@macrostrat/map-interface": "^2.3.0",
56
+ "@macrostrat/map-styles": "^2.2.6",
57
+ "@macrostrat/mapbox-react": "^3.3.0",
58
+ "@macrostrat/mapbox-utils": "^1.8.0",
59
+ "@macrostrat/scoped-store": "^1.0.1",
59
60
  "@macrostrat/stratigraphy-utils": "^1.3.0",
60
61
  "@macrostrat/svg-map-components": "^2.0.3",
61
- "@macrostrat/timescale": "^3.1.4",
62
- "@macrostrat/ui-components": "^5.0.10",
62
+ "@macrostrat/timescale": "^3.1.5",
63
+ "@macrostrat/ui-components": "^5.1.0",
63
64
  "@turf/boolean-point-in-polygon": "^7.3.2",
64
65
  "@turf/buffer": "^7.3.2",
65
66
  "@turf/centroid": "^7.3.2",
@@ -0,0 +1,151 @@
1
+ import "@macrostrat/style-system";
2
+ import { MergeSectionsMode, UnitComponent } from "../..";
3
+ import { Meta } from "@storybook/react-vite";
4
+
5
+ import h from "./stories.module.sass";
6
+ import { CorrelationChart } from "../main";
7
+ import { BaseUnit } from "@macrostrat/api-types";
8
+ import { useGeologicPattern } from "@macrostrat/column-components";
9
+
10
+ export default {
11
+ title: "Column views/Correlation chart",
12
+ component: CorrelationChart,
13
+ parameters: {
14
+ layout: "fullscreen",
15
+ docs: {
16
+ description: {
17
+ component: "Correlation chart for Macrostrat columns",
18
+ },
19
+ story: {
20
+ inline: false,
21
+ iframeHeight: 500,
22
+ },
23
+ },
24
+ },
25
+ args: {},
26
+ } as Meta<typeof CorrelationChart>;
27
+
28
+ const nosib = {
29
+ b_age: 900,
30
+ t_age: 800,
31
+ name: "Nosib",
32
+ color: "#ffd4ba",
33
+ };
34
+
35
+ const namUnits: (BaseUnit | BaseUnit[])[] = [
36
+ [
37
+ nosib,
38
+ { b_age: 746, t_age: 720, name: "Chuos", color: "#d0b4ff" },
39
+ {
40
+ b_age: 720,
41
+ t_age: 600,
42
+ name: "Otavi",
43
+ color: "dodgerblue",
44
+ },
45
+ ],
46
+ [
47
+ nosib,
48
+ {
49
+ b_age: 740,
50
+ t_age: 600,
51
+ name: "Swakop",
52
+ color: "#aaa",
53
+ },
54
+ ],
55
+ [
56
+ nosib,
57
+ {
58
+ b_age: 670,
59
+ t_age: 580,
60
+ name: "Witvlei",
61
+ color: "#fffc4e",
62
+ },
63
+ ],
64
+ [
65
+ {
66
+ b_age: 610,
67
+ t_age: 575,
68
+ name: "Zebra Series",
69
+ color: "#fdbcf0",
70
+ },
71
+ {
72
+ b_age: 660,
73
+ t_age: 610,
74
+ name: "Naukluft complex",
75
+ color: "#fdbcbc",
76
+ },
77
+ ],
78
+ {
79
+ b_age: 550,
80
+ t_age: 520,
81
+ name: "Nama",
82
+ color: "#baf1a7",
83
+ },
84
+ // {
85
+ // unit_id: 0,
86
+ // b_age: 900,
87
+ // t_age: 0,
88
+ // unit_name: "",
89
+ // column: 8,
90
+ // },
91
+ ];
92
+
93
+ export function NamibiaCorrelationChart() {
94
+ return h(
95
+ "div",
96
+ {
97
+ style: {
98
+ "--column-unit-font-size": "14px",
99
+ "--column-unit-font-style": "bold",
100
+ "--column-text-color": "white",
101
+ },
102
+ },
103
+ [
104
+ h(CorrelationChart, {
105
+ id: 432,
106
+ data: namUnits.map((u, i) => {
107
+ let units: any = null;
108
+ if (Array.isArray(u)) {
109
+ units = u.map((u) => buildUnit(u, i));
110
+ } else {
111
+ units = [buildUnit(u, i)];
112
+ }
113
+ return {
114
+ columnID: i,
115
+ units,
116
+ };
117
+ }),
118
+ columnSpacing: 10,
119
+ t_age: 450,
120
+ b_age: 850,
121
+ //width: 400,
122
+ //columnWidth: 400,
123
+ pixelScale: 2,
124
+ //showLabelColumn: false,
125
+ mergeSections: MergeSectionsMode.ALL,
126
+ unitComponent: ProvidedColorUnitComponent,
127
+ }),
128
+ ],
129
+ );
130
+ }
131
+
132
+ function buildUnit(unit, i) {
133
+ return {
134
+ unit_id: i,
135
+ col_id: i,
136
+ ...unit,
137
+ unit_name: unit.name,
138
+ };
139
+ }
140
+
141
+ function ProvidedColorUnitComponent(props) {
142
+ /** A unit component that is colored by its own properties. */
143
+
144
+ const fill = useGeologicPattern(props.division.patternID);
145
+
146
+ return h(UnitComponent, {
147
+ fill,
148
+ backgroundColor: props.division.color ?? null,
149
+ ...props,
150
+ });
151
+ }
@@ -24,7 +24,7 @@ import {
24
24
  type AtomMap,
25
25
  createScopedStore,
26
26
  StateIsolation,
27
- } from "@macrostrat/data-components";
27
+ } from "@macrostrat/scoped-store";
28
28
  import { atom } from "jotai";
29
29
  import { useEffect } from "react";
30
30
 
@@ -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, {