@macrostrat/column-views 1.0.3 → 2.0.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 (242) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/esm/_shared.f7eec55a.js +9 -0
  3. package/dist/esm/_shared.f7eec55a.js.map +1 -0
  4. package/dist/esm/age-axis.4a8cf5e6.js +98 -0
  5. package/dist/esm/age-axis.4a8cf5e6.js.map +1 -0
  6. package/dist/esm/age-axis.module.03773a80.css +33 -0
  7. package/dist/esm/age-axis.module.03773a80.css.map +1 -0
  8. package/dist/esm/age-axis.module.3cc91335.js +22 -0
  9. package/dist/esm/age-axis.module.3cc91335.js.map +1 -0
  10. package/dist/esm/age-model-overlay.c7226855.js +57 -0
  11. package/dist/esm/age-model-overlay.c7226855.js.map +1 -0
  12. package/dist/esm/age-model-overlay.module.5d9e78fb.css +14 -0
  13. package/dist/esm/age-model-overlay.module.5d9e78fb.css.map +1 -0
  14. package/dist/esm/age-model-overlay.module.cd985dcb.js +16 -0
  15. package/dist/esm/age-model-overlay.module.cd985dcb.js.map +1 -0
  16. package/dist/esm/base.910b80b4.js +288 -0
  17. package/dist/esm/base.910b80b4.js.map +1 -0
  18. package/dist/esm/boxes.8292cff2.js +258 -0
  19. package/dist/esm/boxes.8292cff2.js.map +1 -0
  20. package/dist/esm/boxes.module.2b5fb18e.css +26 -0
  21. package/dist/esm/boxes.module.2b5fb18e.css.map +1 -0
  22. package/dist/esm/boxes.module.4ebc7796.js +19 -0
  23. package/dist/esm/boxes.module.4ebc7796.js.map +1 -0
  24. package/dist/esm/{carbon-isotopes.3b502a9e.js → carbon-isotopes.10db8285.js} +2 -2
  25. package/dist/esm/{carbon-isotopes.3b502a9e.js.map → carbon-isotopes.10db8285.js.map} +1 -1
  26. package/dist/esm/colors.395c6db5.js +40 -0
  27. package/dist/esm/colors.395c6db5.js.map +1 -0
  28. package/dist/esm/column-correlation.c8dcfe98.js +9 -0
  29. package/dist/esm/column-correlation.c8dcfe98.js.map +1 -0
  30. package/dist/esm/column-nav.5414677c.js +55 -0
  31. package/dist/esm/column-nav.5414677c.js.map +1 -0
  32. package/dist/esm/column-navigation.37cd3245.js +9 -0
  33. package/dist/esm/column-navigation.37cd3245.js.map +1 -0
  34. package/dist/esm/column.01d68dd8.js +127 -0
  35. package/dist/esm/column.01d68dd8.js.map +1 -0
  36. package/dist/esm/{column.db058031.js → column.a25f8ebd.js} +4 -4
  37. package/dist/esm/column.a25f8ebd.js.map +1 -0
  38. package/dist/esm/column.module.1b776e15.js +46 -0
  39. package/dist/esm/column.module.1b776e15.js.map +1 -0
  40. package/dist/esm/column.module.a67a6b4c.css +159 -0
  41. package/dist/esm/column.module.a67a6b4c.css.map +1 -0
  42. package/dist/esm/composite-scale.577bf64a.js +222 -0
  43. package/dist/esm/composite-scale.577bf64a.js.map +1 -0
  44. package/dist/esm/composite.039e4798.js +163 -0
  45. package/dist/esm/composite.039e4798.js.map +1 -0
  46. package/dist/esm/{core.4db8e452.js → core.843310d3.js} +11 -12
  47. package/dist/esm/core.843310d3.js.map +1 -0
  48. package/dist/esm/core.91ede078.js +206 -0
  49. package/dist/esm/core.91ede078.js.map +1 -0
  50. package/dist/esm/correlation-chart.abd8b346.js +9 -0
  51. package/dist/esm/correlation-chart.abd8b346.js.map +1 -0
  52. package/dist/esm/data-provider.1506eb64.js.map +1 -1
  53. package/dist/esm/data-provider.f10c6d0b.js +13 -0
  54. package/dist/esm/data-provider.f10c6d0b.js.map +1 -0
  55. package/dist/esm/fetch.99aec438.js +152 -0
  56. package/dist/esm/fetch.99aec438.js.map +1 -0
  57. package/dist/esm/hash-string.285b37fb.js +39 -0
  58. package/dist/esm/hash-string.285b37fb.js.map +1 -0
  59. package/dist/esm/helpers.2f0a0cb7.js +141 -0
  60. package/dist/esm/helpers.2f0a0cb7.js.map +1 -0
  61. package/dist/esm/index.d.ts +797 -130
  62. package/dist/esm/index.d.ts.map +1 -1
  63. package/dist/esm/index.js +13 -9
  64. package/dist/esm/index.js.map +1 -1
  65. package/dist/esm/inset-map.3c18106d.js +66 -0
  66. package/dist/esm/inset-map.3c18106d.js.map +1 -0
  67. package/dist/esm/keyboard-navigation.6713401b.js +48 -0
  68. package/dist/esm/keyboard-navigation.6713401b.js.map +1 -0
  69. package/dist/esm/keyboard-navigation.a9fc80dd.js +112 -0
  70. package/dist/esm/keyboard-navigation.a9fc80dd.js.map +1 -0
  71. package/dist/esm/layers.033d3fb0.js +170 -0
  72. package/dist/esm/layers.033d3fb0.js.map +1 -0
  73. package/dist/esm/main.2e0375a5.js +221 -0
  74. package/dist/esm/main.2e0375a5.js.map +1 -0
  75. package/dist/esm/main.module.3dd9500b.css +134 -0
  76. package/dist/esm/main.module.3dd9500b.css.map +1 -0
  77. package/dist/esm/main.module.c09154b1.js +70 -0
  78. package/dist/esm/main.module.c09154b1.js.map +1 -0
  79. package/dist/esm/mapbox.cac42eed.js +167 -0
  80. package/dist/esm/mapbox.cac42eed.js.map +1 -0
  81. package/dist/esm/maps.bcdea9c1.js +11 -0
  82. package/dist/esm/maps.bcdea9c1.js.map +1 -0
  83. package/dist/esm/{names.f6a4e9a4.js → names.a8f2b452.js} +5 -5
  84. package/dist/esm/names.a8f2b452.js.map +1 -0
  85. package/dist/esm/panel.598f76a5.js +420 -0
  86. package/dist/esm/panel.598f76a5.js.map +1 -0
  87. package/dist/esm/panel.module.386166cc.js +58 -0
  88. package/dist/esm/panel.module.386166cc.js.map +1 -0
  89. package/dist/esm/panel.module.3d2ea3c6.css +111 -0
  90. package/dist/esm/panel.module.3d2ea3c6.css.map +1 -0
  91. package/dist/esm/popover.a810b7bc.js +66 -0
  92. package/dist/esm/popover.a810b7bc.js.map +1 -0
  93. package/dist/esm/popover.module.c4ba4189.js +22 -0
  94. package/dist/esm/popover.module.c4ba4189.js.map +1 -0
  95. package/dist/esm/{selection-popover.module.0a701258.css → popover.module.c4d6bfb0.css} +11 -8
  96. package/dist/esm/popover.module.c4d6bfb0.css.map +1 -0
  97. package/dist/esm/prepare-data.d4284b4a.js +125 -0
  98. package/dist/esm/prepare-data.d4284b4a.js.map +1 -0
  99. package/dist/esm/prepare-units.6c890a96.js +104 -0
  100. package/dist/esm/prepare-units.6c890a96.js.map +1 -0
  101. package/dist/esm/{resolvers.b5c82b78.js → resolvers.36013b49.js} +13 -2
  102. package/dist/esm/resolvers.36013b49.js.map +1 -0
  103. package/dist/esm/section.a34d379a.js +215 -0
  104. package/dist/esm/section.a34d379a.js.map +1 -0
  105. package/dist/esm/selection.f5b0297e.js +143 -0
  106. package/dist/esm/selection.f5b0297e.js.map +1 -0
  107. package/dist/esm/state.178ef364.js +75 -0
  108. package/dist/esm/state.178ef364.js.map +1 -0
  109. package/dist/esm/state.2952cbca.js +118 -0
  110. package/dist/esm/state.2952cbca.js.map +1 -0
  111. package/dist/esm/store.c4d7a8a4.js +52 -0
  112. package/dist/esm/store.c4d7a8a4.js.map +1 -0
  113. package/dist/esm/styles.7bc776d1.js +95 -0
  114. package/dist/esm/styles.7bc776d1.js.map +1 -0
  115. package/dist/esm/svg.4b9a96c1.js +89 -0
  116. package/dist/esm/svg.4b9a96c1.js.map +1 -0
  117. package/dist/esm/types.0f0b57c9.js +3 -0
  118. package/dist/esm/types.0f0b57c9.js.map +1 -0
  119. package/dist/esm/unit-details.071cefed.js +9 -0
  120. package/dist/esm/unit-details.071cefed.js.map +1 -0
  121. package/dist/esm/units.5a4fc058.js +98 -0
  122. package/dist/esm/units.5a4fc058.js.map +1 -0
  123. package/dist/esm/utils.d7a43a2a.js +55 -0
  124. package/dist/esm/utils.d7a43a2a.js.map +1 -0
  125. package/dist/node/index.js.map +1 -1
  126. package/package.json +24 -7
  127. package/src/age-axis.module.sass +27 -0
  128. package/src/age-axis.ts +82 -19
  129. package/src/age-model-overlay.module.sass +11 -0
  130. package/src/age-model-overlay.ts +73 -0
  131. package/src/carbon-isotopes/column.ts +4 -2
  132. package/src/carbon-isotopes/core.ts +9 -6
  133. package/src/carbon-isotopes/data-provider.ts +3 -3
  134. package/src/column.module.sass +58 -49
  135. package/src/column.ts +149 -135
  136. package/src/correlation-chart/hash-string.ts +57 -0
  137. package/src/correlation-chart/index.ts +2 -0
  138. package/src/correlation-chart/main.module.sass +122 -0
  139. package/src/correlation-chart/main.ts +305 -0
  140. package/src/correlation-chart/prepare-data.ts +217 -0
  141. package/src/correlation-chart/stories/correlation-chart.stories.ts +192 -0
  142. package/src/correlation-chart/stories/stories.module.sass +18 -0
  143. package/src/correlation-chart/unconformity-line.module.sass +8 -0
  144. package/src/correlation-chart/unconformity-line.ts +25 -0
  145. package/src/data-provider/base.ts +388 -0
  146. package/src/data-provider/column-nav.ts +53 -0
  147. package/src/data-provider/fetch.ts +231 -0
  148. package/src/data-provider/index.ts +4 -0
  149. package/src/data-provider/store.ts +72 -0
  150. package/src/index.ts +5 -3
  151. package/src/maps/_shared/index.ts +2 -0
  152. package/src/maps/_shared/inset-map.stories.ts +20 -0
  153. package/src/maps/_shared/inset-map.ts +87 -0
  154. package/src/maps/_shared/styles.ts +57 -0
  155. package/src/maps/column-correlation/column-correlation-map.stories.ts +96 -0
  156. package/src/maps/column-correlation/core.ts +225 -0
  157. package/src/maps/column-correlation/index.ts +2 -0
  158. package/src/maps/column-correlation/state.ts +192 -0
  159. package/src/maps/column-navigation/index.ts +2 -0
  160. package/src/maps/column-navigation/mapbox/column-navigation-map.stories.ts +102 -0
  161. package/src/maps/column-navigation/mapbox/index.ts +219 -0
  162. package/src/maps/column-navigation/mapbox/keyboard-navigation.ts +119 -0
  163. package/src/maps/column-navigation/mapbox/state.ts +109 -0
  164. package/src/maps/column-navigation/svg/column-navigation-svg-map.stories.ts +46 -0
  165. package/src/{map → maps/column-navigation/svg}/index.ts +18 -6
  166. package/src/{map → maps/column-navigation/svg}/layers.ts +28 -109
  167. package/src/maps/column-navigation/utils/keyboard-navigation.ts +58 -0
  168. package/src/maps/index.ts +3 -0
  169. package/src/prepare-units/composite-scale.ts +353 -0
  170. package/src/prepare-units/helpers.ts +226 -0
  171. package/src/prepare-units/index.ts +177 -0
  172. package/src/prepare-units/utils.ts +98 -0
  173. package/src/section.ts +264 -84
  174. package/src/unit-details/index.ts +2 -215
  175. package/src/unit-details/{index.module.sass → panel.module.sass} +39 -8
  176. package/src/unit-details/panel.ts +523 -0
  177. package/src/{selection-popover.module.sass → unit-details/popover.module.sass} +4 -2
  178. package/src/unit-details/popover.ts +82 -0
  179. package/src/units/boxes.module.sass +16 -0
  180. package/src/units/boxes.ts +243 -90
  181. package/src/units/colors.ts +64 -0
  182. package/src/units/composite.ts +157 -152
  183. package/src/units/index.ts +76 -9
  184. package/src/units/names.ts +8 -4
  185. package/src/units/resolvers.ts +11 -0
  186. package/src/units/selection.ts +115 -101
  187. package/src/units/types.ts +5 -16
  188. package/dist/esm/age-axis.64c509ee.js +0 -41
  189. package/dist/esm/age-axis.64c509ee.js.map +0 -1
  190. package/dist/esm/boxes.13968b76.js +0 -164
  191. package/dist/esm/boxes.13968b76.js.map +0 -1
  192. package/dist/esm/boxes.module.28873d08.css +0 -4
  193. package/dist/esm/boxes.module.28873d08.css.map +0 -1
  194. package/dist/esm/boxes.module.605bdcd6.js +0 -13
  195. package/dist/esm/boxes.module.605bdcd6.js.map +0 -1
  196. package/dist/esm/column.8dd26e1a.js +0 -149
  197. package/dist/esm/column.8dd26e1a.js.map +0 -1
  198. package/dist/esm/column.db058031.js.map +0 -1
  199. package/dist/esm/column.module.039d872c.css +0 -151
  200. package/dist/esm/column.module.039d872c.css.map +0 -1
  201. package/dist/esm/column.module.e632868a.js +0 -19
  202. package/dist/esm/column.module.e632868a.js.map +0 -1
  203. package/dist/esm/composite.608a4ca2.js +0 -153
  204. package/dist/esm/composite.608a4ca2.js.map +0 -1
  205. package/dist/esm/core.4db8e452.js.map +0 -1
  206. package/dist/esm/helpers.8a03cfc7.js +0 -94
  207. package/dist/esm/helpers.8a03cfc7.js.map +0 -1
  208. package/dist/esm/index.module.0844afd8.css +0 -65
  209. package/dist/esm/index.module.0844afd8.css.map +0 -1
  210. package/dist/esm/index.module.24fe3a2e.js +0 -37
  211. package/dist/esm/index.module.24fe3a2e.js.map +0 -1
  212. package/dist/esm/layers.ad5fd25d.js +0 -231
  213. package/dist/esm/layers.ad5fd25d.js.map +0 -1
  214. package/dist/esm/map.7aa26f17.js +0 -82
  215. package/dist/esm/map.7aa26f17.js.map +0 -1
  216. package/dist/esm/names.f6a4e9a4.js.map +0 -1
  217. package/dist/esm/providers.cd1e652f.js +0 -25
  218. package/dist/esm/providers.cd1e652f.js.map +0 -1
  219. package/dist/esm/resolvers.b5c82b78.js.map +0 -1
  220. package/dist/esm/section.cc1b1100.js +0 -118
  221. package/dist/esm/section.cc1b1100.js.map +0 -1
  222. package/dist/esm/selection-popover.17d1bd55.js +0 -60
  223. package/dist/esm/selection-popover.17d1bd55.js.map +0 -1
  224. package/dist/esm/selection-popover.module.0a701258.css.map +0 -1
  225. package/dist/esm/selection-popover.module.e22f5183.js +0 -22
  226. package/dist/esm/selection-popover.module.e22f5183.js.map +0 -1
  227. package/dist/esm/selection.bbf26d0e.js +0 -117
  228. package/dist/esm/selection.bbf26d0e.js.map +0 -1
  229. package/dist/esm/store.25eaa168.js +0 -18
  230. package/dist/esm/store.25eaa168.js.map +0 -1
  231. package/dist/esm/types.f016e032.js +0 -18
  232. package/dist/esm/types.f016e032.js.map +0 -1
  233. package/dist/esm/unit-details.56ff8b70.js +0 -209
  234. package/dist/esm/unit-details.56ff8b70.js.map +0 -1
  235. package/dist/esm/units.361088d4.js +0 -42
  236. package/dist/esm/units.361088d4.js.map +0 -1
  237. package/src/helpers.ts +0 -133
  238. package/src/providers.ts +0 -34
  239. package/src/selection-popover.ts +0 -71
  240. package/src/store.ts +0 -12
  241. package/src/units/units.scss +0 -16
  242. /package/src/{map → maps/column-navigation/svg}/animated.ts +0 -0
@@ -0,0 +1,305 @@
1
+ /** Correlation chart */
2
+ import {
3
+ UnitSelectionProvider,
4
+ UnitKeyboardNavigation,
5
+ useUnitSelectionStore,
6
+ } from "../units";
7
+ import { UnitSelectionPopover } from "../unit-details";
8
+ import hyper from "@macrostrat/hyper";
9
+ import styles from "./main.module.sass";
10
+ import { useMemo, useRef } from "react";
11
+ import { useInDarkMode } from "@macrostrat/ui-components";
12
+ import { CompositeTimescaleCore } from "../section";
13
+ import classNames from "classnames";
14
+ import {
15
+ findLaterallyExtensiveUnits,
16
+ splitStratIntoBoxes,
17
+ UnitGroupBox,
18
+ CorrelationChartSettings,
19
+ buildCorrelationChartData,
20
+ } from "./prepare-data";
21
+ import {
22
+ CompositeAgeAxisCore,
23
+ CompositeStratigraphicScaleInfo,
24
+ } from "../age-axis";
25
+ import {
26
+ ColumnAxisType,
27
+ ColumnProvider,
28
+ SVG,
29
+ } from "@macrostrat/column-components";
30
+ import { ColoredUnitComponent } from "../units";
31
+ import { UnitBoxes } from "../units/boxes";
32
+ import { ExtUnit } from "../prepare-units/helpers";
33
+ import { ColumnContainer } from "../column";
34
+ import { ColumnData } from "../data-provider";
35
+ import { BaseUnit } from "@macrostrat/api-types";
36
+
37
+ const h = hyper.styled(styles);
38
+
39
+ export interface CorrelationChartProps extends CorrelationChartSettings {
40
+ data: ColumnData[];
41
+ columnWidth?: number;
42
+ columnSpacing?: number;
43
+ targetUnitHeight?: number;
44
+ unconformityLabels?: boolean;
45
+ selectedUnit?: number | null;
46
+ showUnitPopover?: boolean;
47
+ onUnitSelected?: (unitID: number | null, unit: BaseUnit | null) => void;
48
+ }
49
+
50
+ export function CorrelationChart({
51
+ data,
52
+ columnSpacing = 0,
53
+ columnWidth = 130,
54
+ unconformityLabels = true,
55
+ showUnitPopover = true,
56
+ selectedUnit,
57
+ onUnitSelected,
58
+ ...scaleProps
59
+ }: CorrelationChartProps) {
60
+ const defaultScaleProps = {
61
+ targetUnitHeight: 10,
62
+ unconformityHeight: 60,
63
+ minSectionHeight: 60,
64
+ collapseSmallUnconformities: true,
65
+ };
66
+
67
+ const chartData = useMemo(() => {
68
+ if (!data) return null;
69
+ return buildCorrelationChartData(data, {
70
+ ...defaultScaleProps,
71
+ ...scaleProps,
72
+ });
73
+ }, [data, ...Object.values(scaleProps)]);
74
+
75
+ const columnRef = useRef(null);
76
+
77
+ // A flattened units array is used to support keyboard navigation
78
+ const units = useMemo(() => {
79
+ return data?.map((d0) => d0.units).flat() ?? [];
80
+ }, [data]);
81
+
82
+ const inDarkMode = useInDarkMode();
83
+
84
+ const className = classNames({
85
+ "dark-mode": inDarkMode,
86
+ });
87
+
88
+ if (chartData == null) {
89
+ return null;
90
+ }
91
+
92
+ const { packages, scaleInfo, nColumns } = chartData;
93
+
94
+ const mainWidth = (columnWidth + columnSpacing) * nColumns;
95
+
96
+ return h(
97
+ ColumnContainer,
98
+ { className: "correlation-diagram" },
99
+ h(
100
+ UnitSelectionProvider,
101
+ { columnRef, selectedUnit, onUnitSelected, units },
102
+ h(ChartArea, [
103
+ h(TimescaleColumn, {
104
+ key: "timescale",
105
+ scaleInfo,
106
+ unconformityLabels,
107
+ }),
108
+ h("div.main-chart", { ref: columnRef }, [
109
+ h(
110
+ SVG,
111
+ {
112
+ className,
113
+ innerWidth: mainWidth,
114
+ height: scaleInfo.totalHeight,
115
+ paddingH: 4,
116
+ },
117
+ packages.map((pkg, i) => {
118
+ const { offset, domain, pixelScale, key } = scaleInfo.packages[i];
119
+ return h(Package, {
120
+ columnData: pkg.columnData,
121
+ key,
122
+ columnWidth,
123
+ columnSpacing,
124
+ offset,
125
+ domain,
126
+ pixelScale,
127
+ });
128
+ })
129
+ ),
130
+ h.if(showUnitPopover)(UnitSelectionPopover),
131
+ // Navigation only works within a column for now...
132
+ h(UnitKeyboardNavigation, { units }),
133
+ ]),
134
+ ])
135
+ )
136
+ );
137
+ }
138
+
139
+ function Package({
140
+ columnData,
141
+ columnSpacing,
142
+ columnWidth,
143
+ offset,
144
+ domain,
145
+ pixelScale,
146
+ }) {
147
+ return h("g.package", { transform: `translate(0 ${offset})` }, [
148
+ // Disable the SVG overlay for now
149
+ //h(PackageSVGOverlay, { data, columnSpacing }),
150
+ h("g.column-units", [
151
+ columnData.map((data, i) => {
152
+ return h(Column, {
153
+ units: data.units,
154
+ width: columnWidth,
155
+ key: i,
156
+ domain,
157
+ pixelScale,
158
+ offsetLeft: i * (columnWidth + columnSpacing),
159
+ });
160
+ }),
161
+ ]),
162
+ ]);
163
+ }
164
+
165
+ interface ColumnProps {
166
+ units: ExtUnit[];
167
+ unitComponent?: React.FunctionComponent<any>;
168
+ unitComponentProps?: any;
169
+ showLabels?: boolean;
170
+ width?: number;
171
+ columnWidth?: number;
172
+ columnSpacing?: number;
173
+ targetUnitHeight?: number;
174
+ offsetLeft?: number;
175
+ domain: [number, number];
176
+ pixelScale: number;
177
+ }
178
+
179
+ function Column(props: ColumnProps) {
180
+ const { units, width = 150, offsetLeft, domain, pixelScale } = props;
181
+
182
+ const columnWidth = width;
183
+
184
+ if (units.length == 0) {
185
+ return null;
186
+ }
187
+
188
+ return h(
189
+ "g.section",
190
+ {
191
+ transform: `translate(${offsetLeft} 0)`,
192
+ },
193
+ h(
194
+ ColumnProvider,
195
+ {
196
+ // Need to tighten up types here...
197
+ divisions: units as any[],
198
+ range: domain,
199
+ pixelsPerMeter: pixelScale, // Actually pixels per myr
200
+ axisType: ColumnAxisType.AGE,
201
+ },
202
+ h(UnitBoxes, {
203
+ unitComponent: ColoredUnitComponent,
204
+ unitComponentProps: {
205
+ nColumns: 2,
206
+ width: columnWidth,
207
+ },
208
+ })
209
+ )
210
+ );
211
+ }
212
+
213
+ function PackageSVGOverlay({ data, columnWidth = 100, columnSpacing = 0 }) {
214
+ const { b_age, t_age, bestPixelScale, columnData } = data;
215
+
216
+ const width = (columnWidth + columnSpacing) * columnData.length;
217
+ const height = Math.ceil((b_age - t_age) * bestPixelScale) + 2;
218
+
219
+ const extensiveUnits = findLaterallyExtensiveUnits(data);
220
+
221
+ const scale = (val: number) => {
222
+ return (val - t_age) * bestPixelScale;
223
+ };
224
+
225
+ return h(
226
+ "div.package-overlay",
227
+ { style: { width, height } },
228
+ extensiveUnits.map((d) => {
229
+ return h(LaterallyExtensiveUnit, {
230
+ data: d,
231
+ scale,
232
+ pixelScale: bestPixelScale,
233
+ columnSpacing,
234
+ });
235
+ })
236
+ );
237
+ }
238
+
239
+ function LaterallyExtensiveUnit({ data, scale, pixelScale, columnSpacing }) {
240
+ const { b_age, t_age, strat_name_long, units } = data;
241
+ // Build boxes by column groups
242
+ const boxes: UnitGroupBox[] = splitStratIntoBoxes(data);
243
+
244
+ return h(
245
+ "div.laterally-extensive-unit",
246
+ boxes.map((d, i) => {
247
+ return h(StratColSpan, {
248
+ scale,
249
+ data: d,
250
+ pixelScale,
251
+ key: i,
252
+ columnSpacing,
253
+ });
254
+ })
255
+ );
256
+ }
257
+
258
+ function StratColSpan({
259
+ data,
260
+ scale,
261
+ columnWidth = 100,
262
+ columnSpacing = 0,
263
+ pixelScale = 1,
264
+ }) {
265
+ const { startCol, endCol, strat_name_long, t_age, b_age } = data;
266
+ const top = scale(t_age);
267
+ const left = startCol * (columnWidth + columnSpacing);
268
+ const width = (endCol - startCol + 1) * (columnWidth + columnSpacing);
269
+ const height = (b_age - t_age) * pixelScale;
270
+ return h(
271
+ "div.strat-col-span",
272
+ { style: { top, height, width, left } },
273
+ strat_name_long
274
+ );
275
+ }
276
+
277
+ function ChartArea({ children }) {
278
+ const setSelectedUnit = useUnitSelectionStore(
279
+ (state) => state.setSelectedUnit
280
+ );
281
+
282
+ return h(
283
+ "div.correlation-chart-inner",
284
+ {
285
+ onClick() {
286
+ setSelectedUnit(null);
287
+ },
288
+ },
289
+ children
290
+ );
291
+ }
292
+
293
+ interface TimescaleColumnProps {
294
+ scaleInfo: CompositeStratigraphicScaleInfo;
295
+ showLabels?: boolean;
296
+ unconformityLabels?: boolean;
297
+ }
298
+
299
+ function TimescaleColumn(props: TimescaleColumnProps) {
300
+ const { scaleInfo, unconformityLabels = true } = props;
301
+ return h("div.column-container.age-axis-container", [
302
+ h(CompositeAgeAxisCore, { ...scaleInfo }),
303
+ h(CompositeTimescaleCore, { ...scaleInfo, unconformityLabels }),
304
+ ]);
305
+ }
@@ -0,0 +1,217 @@
1
+ import { CompositeStratigraphicScaleInfo } from "../age-axis";
2
+ import { PackageLayoutData } from "../prepare-units/composite-scale";
3
+ import { ColumnAxisType } from "@macrostrat/column-components";
4
+ import { type ColumnGeoJSONRecord, UnitLong } from "@macrostrat/api-types";
5
+ import {
6
+ MergeSectionsMode,
7
+ PrepareColumnOptions,
8
+ prepareColumnUnits,
9
+ preprocessUnits,
10
+ } from "../prepare-units";
11
+ import { mergeAgeRanges } from "@macrostrat/stratigraphy-utils";
12
+
13
+ export interface ColumnIdentifier {
14
+ col_id: number;
15
+ col_name: string;
16
+ project_id: number;
17
+ }
18
+
19
+ interface ColumnData {
20
+ columnID: number;
21
+ units: UnitLong[];
22
+ }
23
+
24
+ export interface CorrelationChartSettings
25
+ extends Omit<PrepareColumnOptions, "axisType"> {
26
+ targetUnitHeight?: number;
27
+ }
28
+
29
+ export interface CorrelationChartData {
30
+ packages: MultiColumnPackageData[];
31
+ scaleInfo: CompositeStratigraphicScaleInfo;
32
+ nColumns: number;
33
+ }
34
+
35
+ export interface ColumnIdentifier {
36
+ col_id: number;
37
+ col_name: string;
38
+ project_id: number;
39
+ }
40
+
41
+ export function buildCorrelationChartData(
42
+ columns: ColumnData[],
43
+ settings: CorrelationChartSettings
44
+ ): CorrelationChartData {
45
+ console.log(settings);
46
+ const {
47
+ mergeSections = MergeSectionsMode.OVERLAPPING,
48
+ targetUnitHeight,
49
+ ...rest
50
+ } = settings;
51
+
52
+ const opts: PrepareColumnOptions = {
53
+ axisType: ColumnAxisType.AGE,
54
+ targetUnitHeight,
55
+ ...rest,
56
+ };
57
+
58
+ if (columns.length == 0) {
59
+ return null;
60
+ }
61
+
62
+ // Flatten the units array to pretend that all units are in the same column
63
+ const _units = columns.map((d) => d.units).flat();
64
+
65
+ const columnIDs = columns.map((d) => d.columnID);
66
+
67
+ const preparedUnits = prepareColumnUnits(_units, opts);
68
+
69
+ const { sections, totalHeight } = preparedUnits;
70
+
71
+ const scaleInfo: CompositeStratigraphicScaleInfo = {
72
+ axisType: ColumnAxisType.AGE,
73
+ totalHeight,
74
+ packages: sections.map((d) => d.scaleInfo),
75
+ };
76
+
77
+ const packages = sections.map((d) => {
78
+ return separateColumns(d, columnIDs);
79
+ });
80
+
81
+ return { scaleInfo, packages, nColumns: columnIDs.length };
82
+ }
83
+
84
+ interface UnitGroup {
85
+ b_age: number;
86
+ t_age: number;
87
+ strat_name_id: number;
88
+ strat_name_long: string;
89
+ units: (UnitLong | null)[];
90
+ }
91
+
92
+ export interface UnitGroupBox extends UnitGroup {
93
+ units: UnitLong[];
94
+ startCol: number;
95
+ endCol: number;
96
+ }
97
+
98
+ interface ColumnExt {
99
+ columnID: number;
100
+ units: UnitLong[];
101
+ }
102
+
103
+ interface MultiColumnPackageData {
104
+ columnData: ColumnExt[];
105
+ bestPixelScale: number;
106
+ b_age: number;
107
+ t_age: number;
108
+ }
109
+
110
+ export function findLaterallyExtensiveUnits(
111
+ pkg: MultiColumnPackageData
112
+ ): UnitGroup[] {
113
+ const { columnData, b_age, t_age } = pkg;
114
+ // Group units by strat_name_id
115
+ const unitIndex = new Map<number, Map<number, UnitLong>>();
116
+ for (const column of columnData) {
117
+ const { units } = column;
118
+ for (const unit of units) {
119
+ if (unit.strat_name_id == null) continue;
120
+ if (!unitIndex.has(unit.strat_name_id)) {
121
+ unitIndex.set(unit.strat_name_id, new Map());
122
+ }
123
+ unitIndex.get(unit.strat_name_id).set(column.columnID, unit);
124
+ }
125
+ }
126
+
127
+ // Prepare grouped units for rendering
128
+ const unitGroups: UnitGroup[] = [];
129
+ for (const [strat_name_id, unitIndex0] of unitIndex) {
130
+ const units = columnData.map((d) => unitIndex0.get(d.columnID) ?? null);
131
+ const filteredUnits = units.filter((d) => d != null);
132
+ const [t_age, b_age] = mergeAgeRanges(
133
+ filteredUnits.map((d) => [d.t_age, d.b_age])
134
+ );
135
+ if (filteredUnits.length <= 1) continue;
136
+
137
+ unitGroups.push({
138
+ b_age,
139
+ t_age,
140
+ strat_name_id,
141
+ strat_name_long: filteredUnits[0].strat_name_long,
142
+ units,
143
+ });
144
+ }
145
+
146
+ return unitGroups;
147
+ }
148
+
149
+ export function splitStratIntoBoxes(pkg: UnitGroup): UnitGroupBox[] {
150
+ const { strat_name_long, strat_name_id, units } = pkg;
151
+ const boxes: UnitGroupBox[] = [];
152
+ let currentBox: UnitGroupBox = null;
153
+ for (let i = 0; i < units.length; i++) {
154
+ const unit = units[i];
155
+ if (unit == null) {
156
+ if (currentBox != null) {
157
+ boxes.push(currentBox);
158
+ currentBox = null;
159
+ }
160
+ continue;
161
+ }
162
+ if (currentBox == null) {
163
+ currentBox = {
164
+ startCol: i,
165
+ endCol: i,
166
+ strat_name_id,
167
+ strat_name_long,
168
+ t_age: unit.t_age,
169
+ b_age: unit.b_age,
170
+ units: [],
171
+ };
172
+ } else {
173
+ currentBox.endCol = i;
174
+ }
175
+ currentBox.units.push(unit);
176
+ }
177
+ return boxes;
178
+ }
179
+
180
+ function separateColumns(
181
+ pkg: PackageLayoutData,
182
+ columnIDs: number[]
183
+ ): MultiColumnPackageData {
184
+ /** Separate columns by col_id */
185
+ const { units, t_age, b_age } = pkg;
186
+
187
+ return {
188
+ columnData: columnIDs.map((d) => {
189
+ const u1 = units.filter((unit) => unit.col_id == d);
190
+ u1.sort((a, b) => a.t_age - b.t_age);
191
+ return {
192
+ columnID: d,
193
+ // Ensure that the units correctly show overlap
194
+ units: preprocessUnits(
195
+ {
196
+ ...pkg,
197
+ units: u1,
198
+ },
199
+ ColumnAxisType.AGE
200
+ ),
201
+ };
202
+ }),
203
+ bestPixelScale: pkg.scaleInfo.pixelScale,
204
+ t_age,
205
+ b_age,
206
+ };
207
+ }
208
+
209
+ export function columnGeoJSONRecordToColumnIdentifier(
210
+ col: ColumnGeoJSONRecord
211
+ ): ColumnIdentifier {
212
+ return {
213
+ col_id: col.properties.col_id,
214
+ col_name: col.properties.col_name,
215
+ project_id: col.properties.project_id,
216
+ };
217
+ }
@@ -0,0 +1,192 @@
1
+ import { Meta } from "@storybook/react";
2
+ import "@macrostrat/style-system";
3
+ import { useArgs } from "@storybook/preview-api";
4
+ import { useCallback } from "react";
5
+ import {
6
+ ColumnCorrelationMap,
7
+ ColumnCorrelationProvider,
8
+ fetchUnits,
9
+ useCorrelationMapStore,
10
+ } from "@macrostrat/column-views";
11
+ import { hyperStyled } from "@macrostrat/hyper";
12
+
13
+ import styles from "./stories.module.sass";
14
+ import { CorrelationChart, CorrelationChartProps } from "../main";
15
+ import { ErrorBoundary, useAsyncMemo } from "@macrostrat/ui-components";
16
+ import { OverlaysProvider } from "@blueprintjs/core";
17
+ import { parseLineFromString, stringifyLine } from "../hash-string";
18
+
19
+ const mapboxToken = import.meta.env.VITE_MAPBOX_API_TOKEN;
20
+
21
+ const h = hyperStyled(styles);
22
+
23
+ function CorrelationStoryUI({
24
+ focusedLine,
25
+ setFocusedLine,
26
+ columnID,
27
+ setColumn,
28
+ selectedUnit,
29
+ setSelectedUnit,
30
+ inProcess,
31
+ projectID,
32
+ ...rest
33
+ }: any) {
34
+ return h(
35
+ ColumnCorrelationProvider,
36
+ {
37
+ focusedLine,
38
+ columns: null,
39
+ onSelectColumns(cols, line) {
40
+ setFocusedLine(line);
41
+ },
42
+ },
43
+ h("div.correlation-ui", [
44
+ h("div.correlation-container", h(CorrelationDiagramWrapper, rest)),
45
+ h("div.right-column", [
46
+ h(ColumnCorrelationMap, {
47
+ accessToken: mapboxToken,
48
+ className: "correlation-map",
49
+ //showLogo: false,
50
+ }),
51
+ ]),
52
+ ])
53
+ );
54
+ }
55
+
56
+ function CorrelationDiagramWrapper(props: Omit<CorrelationChartProps, "data">) {
57
+ /** This state management is a bit too complicated, but it does kinda sorta work */
58
+
59
+ // Sync focused columns with map
60
+ const focusedColumns = useCorrelationMapStore(
61
+ (state) => state.focusedColumns
62
+ );
63
+
64
+ const columnUnits = useAsyncMemo(async () => {
65
+ const col_ids = focusedColumns.map((col) => col.properties.col_id);
66
+ return await fetchUnits(col_ids);
67
+ }, [focusedColumns]);
68
+
69
+ return h("div.correlation-diagram", [
70
+ h(
71
+ ErrorBoundary,
72
+ h(OverlaysProvider, [
73
+ h(CorrelationChart, { data: columnUnits, ...props }),
74
+ ])
75
+ ),
76
+ ]);
77
+ }
78
+
79
+ export default {
80
+ title: "Column views/Correlation chart",
81
+ component: CorrelationStoryUI,
82
+ parameters: {
83
+ layout: "fullscreen",
84
+ docs: {
85
+ description: {
86
+ component: "Correlation chart for Macrostrat columns",
87
+ },
88
+ story: {
89
+ inline: false,
90
+ iframeHeight: 500,
91
+ },
92
+ },
93
+ },
94
+ args: {
95
+ focusedLine: "-100,45 -90,50",
96
+ columnSpacing: 0,
97
+ columnWidth: 100,
98
+ collapseSmallUnconformities: false,
99
+ targetUnitHeight: 20,
100
+ },
101
+ argTypes: {
102
+ selectedUnit: {
103
+ control: {
104
+ type: "number",
105
+ },
106
+ },
107
+ t_age: {
108
+ control: {
109
+ type: "number",
110
+ },
111
+ },
112
+ b_age: {
113
+ control: {
114
+ type: "number",
115
+ },
116
+ },
117
+ columnSpacing: {
118
+ control: {
119
+ type: "number",
120
+ },
121
+ },
122
+ columnWidth: {
123
+ control: {
124
+ type: "number",
125
+ },
126
+ },
127
+ mergeSections: {
128
+ options: ["all", "overlapping", null],
129
+ control: { type: "radio" },
130
+ },
131
+ pixelScale: {
132
+ control: {
133
+ type: "number",
134
+ },
135
+ },
136
+ collapseSmallUnconformities: {
137
+ control: {
138
+ type: "boolean",
139
+ },
140
+ },
141
+ minSectionHeight: {
142
+ control: {
143
+ type: "number",
144
+ },
145
+ },
146
+ targetUnitHeight: {
147
+ control: {
148
+ type: "number",
149
+ },
150
+ },
151
+ showLabelColumn: {
152
+ control: {
153
+ type: "boolean",
154
+ },
155
+ },
156
+ maxInternalColumns: {
157
+ control: {
158
+ type: "number",
159
+ },
160
+ },
161
+ },
162
+ } as Meta<typeof CorrelationStoryUI>;
163
+
164
+ function useCorrelationLine() {
165
+ const [{ focusedLine, selectedUnit }, updateArgs] = useArgs();
166
+ const setFocusedLine = (line) => {
167
+ updateArgs({ focusedLine: stringifyLine(line) });
168
+ };
169
+
170
+ const setSelectedUnit = useCallback(
171
+ (selectedUnit) => {
172
+ updateArgs({ selectedUnit });
173
+ },
174
+ [updateArgs]
175
+ );
176
+
177
+ return {
178
+ focusedLine: parseLineFromString(focusedLine),
179
+ setFocusedLine,
180
+ selectedUnit,
181
+ setSelectedUnit,
182
+ };
183
+ }
184
+
185
+ function Template(args) {
186
+ return h(CorrelationStoryUI, {
187
+ ...args,
188
+ ...useCorrelationLine(),
189
+ });
190
+ }
191
+
192
+ export const Primary = Template.bind({});