@macrostrat/column-views 1.0.2 → 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 +21 -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 -120
  62. package/dist/esm/index.d.ts.map +1 -1
  63. package/dist/esm/index.js +14 -8
  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 +6 -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
@@ -6,11 +6,14 @@ import {
6
6
  } from "@macrostrat/svg-map-components";
7
7
  import { useAPIResult, useKeyHandler } from "@macrostrat/ui-components";
8
8
  import chroma from "chroma-js";
9
- import { ExtendedFeature, geoCentroid } from "d3-geo";
10
- import { geoVoronoi } from "d3-geo-voronoi";
11
- import { FeatureCollection, GeometryCollection, Polygon } from "geojson";
12
- import { useContext, useEffect, useMemo } from "react";
13
- import { feature } from "topojson-client";
9
+ import { ExtendedFeature } from "d3-geo";
10
+ import { Polygon } from "geojson";
11
+ import { useContext, useMemo } from "react";
12
+ import { useColumnFeatures } from "../../../data-provider";
13
+ import {
14
+ buildKeyMapping,
15
+ buildTriangulation,
16
+ } from "../utils/keyboard-navigation";
14
17
 
15
18
  const defaultStyle = {
16
19
  fill: "rgb(239, 180, 249)",
@@ -37,16 +40,6 @@ type ColumnProps = { col_id: number };
37
40
 
38
41
  type ColumnFeature = ExtendedFeature<Polygon, ColumnProps>;
39
42
 
40
- function processTopoJSON(res) {
41
- try {
42
- const { data } = res.success;
43
- const { features: f } = feature(data, data.objects.output) as any;
44
- return f;
45
- } catch (err) {
46
- console.error(err);
47
- return [];
48
- }
49
- }
50
43
  function ColumnFeatures(props) {
51
44
  const {
52
45
  features,
@@ -55,6 +48,8 @@ function ColumnFeatures(props) {
55
48
  singleFeature = true,
56
49
  } = props;
57
50
 
51
+ console.log(features);
52
+
58
53
  const c = chroma(color);
59
54
 
60
55
  return h(
@@ -93,58 +88,6 @@ interface KeyboardNavProps extends ColumnNavProps {
93
88
  showLayers: boolean;
94
89
  }
95
90
 
96
- function normalize(angle) {
97
- if (angle > Math.PI) {
98
- angle -= 2 * Math.PI;
99
- } else if (angle <= -Math.PI) {
100
- angle += 2 * Math.PI;
101
- }
102
- return angle;
103
- }
104
-
105
- function buildTriangulation(features) {
106
- console.log("Computing triangulation");
107
- const centroids = features.map(geoCentroid);
108
- const tri = geoVoronoi(centroids);
109
- return { centroids, tri };
110
- }
111
-
112
- function buildKeyMapping(neighbors, centroids, currentIndex, projection) {
113
- if (neighbors == null) return;
114
-
115
- const currentCentroid = projection(centroids[currentIndex]);
116
-
117
- let edgeAngles = neighbors.map((index) => {
118
- const centroid = projection(centroids[index]);
119
- const dx = centroid[0] - currentCentroid[0];
120
- const dy = centroid[1] - currentCentroid[1];
121
- return { col_index: index, angle: Math.atan2(dy, dx) };
122
- });
123
-
124
- edgeAngles.sort((d) => d.angle);
125
-
126
- function closestAngle(num) {
127
- // Find closest angle in array of neighbors
128
- let curr = edgeAngles[0];
129
- for (let next of edgeAngles) {
130
- if (
131
- Math.abs(normalize(num - next.angle)) <
132
- Math.abs(normalize(num - curr.angle))
133
- ) {
134
- curr = next;
135
- }
136
- }
137
- return curr.col_index;
138
- }
139
-
140
- return {
141
- 37: closestAngle(Math.PI), // left
142
- 38: closestAngle((3 * Math.PI) / 2), // up
143
- 39: closestAngle(0), // right
144
- 40: closestAngle(Math.PI / 2), // down
145
- };
146
- }
147
-
148
91
  function ColumnKeyboardNavigation(props: KeyboardNavProps) {
149
92
  /** Keyboard navigation of columns using a Delaunay triangulation */
150
93
  const {
@@ -174,10 +117,8 @@ function ColumnKeyboardNavigation(props: KeyboardNavProps) {
174
117
  (event) => {
175
118
  const nextColumnIx = keyMapping[event.keyCode];
176
119
  if (nextColumnIx == null) return;
177
- const { col_id } = features[nextColumnIx].properties;
178
-
179
120
  // @ts-ignore
180
- onChange({ col_id, ...projectArgs });
121
+ onChange(features[nextColumnIx]);
181
122
  },
182
123
  [keyMapping]
183
124
  );
@@ -203,45 +144,25 @@ function ColumnKeyboardNavigation(props: KeyboardNavProps) {
203
144
  fill: "rgba(93, 101, 212, 0.5)",
204
145
  },
205
146
  }),
206
-
207
- //h(FeatureLayer, {features: tri.centers, useCanvas: false})
147
+ h(FeatureLayer, {
148
+ features: [
149
+ {
150
+ type: "Feature",
151
+ geometry: {
152
+ type: "MultiPoint",
153
+ coordinates: centroids,
154
+ },
155
+ },
156
+ ],
157
+ useCanvas: false,
158
+ style: {
159
+ r: 1,
160
+ fill: "purple",
161
+ },
162
+ }),
208
163
  ]);
209
164
  }
210
165
 
211
- function processGeoJSON(res) {
212
- return processGeoJSONBare(res?.success?.data);
213
- }
214
-
215
- function processGeoJSONBare(res) {
216
- return res?.features;
217
- }
218
-
219
- const processors = {
220
- topojson: processTopoJSON,
221
- geojson: processGeoJSON,
222
- geojson_bare: processGeoJSONBare,
223
- };
224
-
225
- function useColumnData({
226
- apiRoute = "/columns",
227
- status_code,
228
- project_id,
229
- format = "topojson",
230
- }) {
231
- let all: boolean = undefined;
232
- if (status_code == null && project_id == null) {
233
- all = true;
234
- }
235
-
236
- const processor = processors[format];
237
-
238
- return useAPIResult(
239
- apiRoute,
240
- { format, all, status_code, project_id },
241
- processor
242
- );
243
- }
244
-
245
166
  interface ColumnExtraInfo {
246
167
  apiRoute?: string;
247
168
  color?: string;
@@ -263,7 +184,7 @@ const Columns = (props: ColumnNavProps & ColumnExtraInfo) => {
263
184
  format = "topojson",
264
185
  } = props;
265
186
 
266
- let features: any[] = useColumnData({
187
+ let features: any[] = useColumnFeatures({
267
188
  apiRoute,
268
189
  status_code,
269
190
  project_id,
@@ -308,9 +229,7 @@ const CurrentColumn = (props) => {
308
229
  export {
309
230
  Columns,
310
231
  CurrentColumn,
311
- processTopoJSON,
312
232
  ColumnCenters,
313
233
  ColumnFeatures,
314
234
  ColumnKeyboardNavigation,
315
- useColumnData,
316
235
  };
@@ -0,0 +1,58 @@
1
+ import { geoCentroid } from "d3-geo";
2
+ import { geoVoronoi } from "d3-geo-voronoi";
3
+
4
+ export function buildKeyMapping(
5
+ neighbors,
6
+ centroids,
7
+ currentIndex,
8
+ projection
9
+ ) {
10
+ if (neighbors == null) return;
11
+
12
+ const currentCentroid = projection(centroids[currentIndex]);
13
+
14
+ let edgeAngles = neighbors.map((index) => {
15
+ const centroid = projection(centroids[index]);
16
+ const dx = centroid[0] - currentCentroid[0];
17
+ const dy = centroid[1] - currentCentroid[1];
18
+ return { col_index: index, angle: Math.atan2(dy, dx) };
19
+ });
20
+
21
+ edgeAngles.sort((d) => d.angle);
22
+
23
+ function closestAngle(num) {
24
+ // Find closest angle in array of neighbors
25
+ let curr = edgeAngles[0];
26
+ for (let next of edgeAngles) {
27
+ if (
28
+ Math.abs(normalize(num - next.angle)) <
29
+ Math.abs(normalize(num - curr.angle))
30
+ ) {
31
+ curr = next;
32
+ }
33
+ }
34
+ return curr.col_index;
35
+ }
36
+
37
+ return {
38
+ 37: closestAngle(Math.PI), // left
39
+ 38: closestAngle((3 * Math.PI) / 2), // up
40
+ 39: closestAngle(0), // right
41
+ 40: closestAngle(Math.PI / 2), // down
42
+ };
43
+ }
44
+
45
+ function normalize(angle) {
46
+ if (angle > Math.PI) {
47
+ angle -= 2 * Math.PI;
48
+ } else if (angle <= -Math.PI) {
49
+ angle += 2 * Math.PI;
50
+ }
51
+ return angle;
52
+ }
53
+
54
+ export function buildTriangulation(features) {
55
+ const centroids = features.map(geoCentroid);
56
+ const tri = geoVoronoi(centroids);
57
+ return { centroids, tri };
58
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./column-navigation";
2
+ export * from "./column-correlation";
3
+ export * from "./_shared";
@@ -0,0 +1,353 @@
1
+ import type { ExtUnit, SectionInfo } from "./helpers";
2
+ import { ColumnAxisType } from "@macrostrat/column-components";
3
+ import { ensureArray, getUnitHeightRange } from "./utils";
4
+ import { ScaleLinear, scaleLinear } from "d3-scale";
5
+ import { UnitLong } from "@macrostrat/api-types";
6
+
7
+ export interface ColumnHeightScaleOptions {
8
+ /** A fixed pixel scale to use for the section (pixels per Myr) */
9
+ pixelScale?: number;
10
+ /** The target height of a constituent unit in pixels, for dynamic
11
+ * scale generation */
12
+ targetUnitHeight?: number;
13
+ /** Min height of a section in pixels. Will override minPixelScale in some cases. */
14
+ minSectionHeight?: number;
15
+ /** The minimum pixel scale to use for the section (pixels per Myr). This is mostly
16
+ * needed because small sections (<1-2 units) don't necessarily have space to comfortably
17
+ * render two axis labels */
18
+ minPixelScale?: number;
19
+ // Axis scale type
20
+ axisType?: ColumnAxisType;
21
+ // Unconformity height in pixels
22
+ unconformityHeight?: number;
23
+ // Whether to collapse unconformities that are less than a height threshold
24
+ collapseSmallUnconformities?: boolean | number;
25
+ }
26
+
27
+ export interface SectionScaleOptions extends ColumnHeightScaleOptions {
28
+ axisType: ColumnAxisType;
29
+ domain: [number, number];
30
+ }
31
+
32
+ export interface LinearScaleDef {
33
+ domain: [number, number];
34
+ pixelScale: number;
35
+ }
36
+
37
+ /** Output of a section scale. For now, this assumes that the
38
+ * mapping is linear, but it could be extended to support arbitrary
39
+ * scale functions.
40
+ */
41
+ export interface PackageScaleInfo extends LinearScaleDef {
42
+ pixelHeight: number;
43
+ // TODO: add a function
44
+ scale: ScaleLinear<number, number>;
45
+ }
46
+
47
+ export type PackageScaleLayoutData = PackageScaleInfo & {
48
+ // A unique key for the section to use in React
49
+ key: string;
50
+ offset: number;
51
+ // How much to
52
+ paddingTop: number;
53
+ };
54
+
55
+ export type PackageLayoutData<T extends UnitLong = ExtUnit> = SectionInfo<T> & {
56
+ scaleInfo: PackageScaleLayoutData;
57
+ // A unique key for the section to use in React
58
+ key: string;
59
+ };
60
+
61
+ export interface CompositeScaleData {
62
+ totalHeight: number;
63
+ sections: PackageScaleLayoutData[];
64
+ }
65
+
66
+ export interface ColumnScaleOptions extends ColumnHeightScaleOptions {
67
+ axisType: ColumnAxisType;
68
+ unconformityHeight: number;
69
+ }
70
+
71
+ // Composite scale information augmented with units in each package
72
+
73
+ export interface CompositeColumnData<T extends UnitLong = ExtUnit>
74
+ extends Omit<CompositeScaleData, "sections"> {
75
+ sections: PackageLayoutData<T>[];
76
+ }
77
+
78
+ export function buildCompositeScaleInfo(
79
+ inputScales: LinearScaleDef[],
80
+ unconformityHeight: number
81
+ ): CompositeScaleData {
82
+ /** Finalize the heights of sections, including the heights of unconformities
83
+ * between them.
84
+ */
85
+
86
+ let totalHeight = unconformityHeight / 2;
87
+ let lastSectionTopHeight = 0;
88
+
89
+ const packages2: PackageScaleLayoutData[] = [];
90
+ for (const group of inputScales) {
91
+ const { domain, pixelScale } = group;
92
+ const [b_age, t_age] = domain;
93
+ const key = `package-${b_age}-${t_age}`;
94
+
95
+ packages2.push({
96
+ ...createPackageScale(group, totalHeight),
97
+ key,
98
+ offset: totalHeight,
99
+ // Unconformity height above this particular section
100
+ paddingTop: totalHeight - lastSectionTopHeight,
101
+ });
102
+ const pixelHeight = pixelScale * Math.abs(b_age - t_age);
103
+ lastSectionTopHeight = totalHeight + pixelHeight;
104
+ totalHeight = lastSectionTopHeight + unconformityHeight;
105
+ }
106
+ totalHeight += unconformityHeight / 2;
107
+ return {
108
+ totalHeight,
109
+ sections: packages2,
110
+ };
111
+ }
112
+
113
+ export function finalizeSectionHeights<T extends UnitLong>(
114
+ sections: SectionInfoWithScale<T>[],
115
+ unconformityHeight: number
116
+ ): CompositeColumnData<T> {
117
+ /** Finalize the heights of sections, including the heights of unconformities
118
+ * between them.
119
+ */
120
+
121
+ const sectionScales = sections.map((d) => d.scaleInfo);
122
+ const { totalHeight, sections: packages } = buildCompositeScaleInfo(
123
+ sectionScales,
124
+ unconformityHeight
125
+ );
126
+
127
+ // This could perhaps be simplified.
128
+ const sections1: PackageLayoutData<T>[] = [];
129
+ for (const i in sections) {
130
+ const group = sections[i];
131
+ const scaleInfo = packages[i];
132
+ sections1.push({
133
+ ...group,
134
+ key: scaleInfo.key,
135
+ scaleInfo,
136
+ });
137
+ }
138
+ return {
139
+ totalHeight,
140
+ sections: sections1,
141
+ };
142
+ }
143
+
144
+ interface SectionInfoWithScale<T extends UnitLong = ExtUnit>
145
+ extends SectionInfo<T> {
146
+ scaleInfo: PackageScaleInfo;
147
+ }
148
+
149
+ export function computeSectionHeights<T extends UnitLong>(
150
+ sections: SectionInfo<T>[],
151
+ opts: ColumnScaleOptions
152
+ ): SectionInfoWithScale<T>[] {
153
+ return sections.map((group) => {
154
+ return addScaleToSection<T>(group, opts);
155
+ });
156
+ }
157
+
158
+ function addScaleToSection<T extends UnitLong = ExtUnit>(
159
+ group: SectionInfo<T>,
160
+ opts: ColumnScaleOptions
161
+ ): SectionInfoWithScale<T> {
162
+ const { t_age, b_age, units } = group;
163
+ let _range = null;
164
+ // if t_age and b_age are set for a group, use them to define the range...
165
+ if (t_age != null && b_age != null && opts.axisType == ColumnAxisType.AGE) {
166
+ _range = [b_age, t_age];
167
+ }
168
+
169
+ const scaleInfo = buildSectionScale<T>(units, {
170
+ ...opts,
171
+ domain: _range,
172
+ });
173
+
174
+ return {
175
+ ...group,
176
+ scaleInfo,
177
+ };
178
+ }
179
+
180
+ function buildSectionScale<T extends UnitLong>(
181
+ data: T[],
182
+ opts: SectionScaleOptions
183
+ ): PackageScaleInfo {
184
+ const {
185
+ targetUnitHeight = 20,
186
+ minPixelScale = 0.2,
187
+ axisType,
188
+ minSectionHeight,
189
+ } = opts;
190
+ const domain = opts.domain ?? findSectionHeightRange(data, axisType);
191
+
192
+ const dAge = Math.abs(domain[0] - domain[1]);
193
+
194
+ let _pixelScale = opts.pixelScale;
195
+ if (_pixelScale == null) {
196
+ const avgAgeRange = findAverageUnitHeight(data, axisType);
197
+ // Get pixel height necessary to render average unit at target height
198
+ _pixelScale = Math.max(targetUnitHeight / avgAgeRange, minPixelScale);
199
+
200
+ // OLD METHOD that cares about overall section height vs. individual unit height
201
+ // 0.2 pixel per myr is the floor scale
202
+ //const targetHeight = targetUnitHeight * data.length;
203
+ // 1 pixel per myr is the floor scale
204
+ //_pixelScale = Math.max(targetHeight / dAge, minPixelScale);
205
+ }
206
+
207
+ let height = dAge * _pixelScale;
208
+
209
+ // If height is less than minSectionHeight, set it to minSectionHeight
210
+ const _minSectionHeight = minSectionHeight ?? targetUnitHeight ?? 0;
211
+ height = Math.max(height, _minSectionHeight);
212
+ _pixelScale = height / dAge;
213
+
214
+ return createPackageScale({ domain, pixelScale: _pixelScale }, 0);
215
+ }
216
+
217
+ export function createPackageScale(
218
+ def: LinearScaleDef,
219
+ offset: number = 0
220
+ ): PackageScaleInfo {
221
+ /** Build a section scale */
222
+ // Domain should be oriented from bottom to top, but scale is oriented from top to bottom
223
+ const { domain, pixelScale } = def;
224
+ const pixelHeight = pixelScale * Math.abs(domain[0] - domain[1]);
225
+ return {
226
+ domain,
227
+ pixelScale,
228
+ pixelHeight,
229
+ scale: scaleLinear()
230
+ .domain([domain[1], domain[0]])
231
+ .range([offset, pixelHeight + offset]),
232
+ };
233
+ }
234
+
235
+ function findSectionHeightRange(
236
+ data: UnitLong[],
237
+ axisType: ColumnAxisType
238
+ ): [number, number] {
239
+ if (axisType == null) {
240
+ throw new Error("Axis type is not set");
241
+ }
242
+ if (axisType === ColumnAxisType.AGE) {
243
+ const t_age = Math.min(...data.map((d) => d.t_age));
244
+ const b_age = Math.max(...data.map((d) => d.b_age));
245
+ return [b_age, t_age];
246
+ } else if (
247
+ axisType == ColumnAxisType.DEPTH ||
248
+ axisType == ColumnAxisType.ORDINAL
249
+ ) {
250
+ const t_pos = Math.min(...data.map((d) => d.t_pos));
251
+ const b_pos = Math.max(...data.map((d) => d.b_pos));
252
+ return [b_pos, t_pos];
253
+ } else if (axisType == ColumnAxisType.HEIGHT) {
254
+ const t_pos = Math.max(...data.map((d) => d.t_pos));
255
+ const b_pos = Math.min(...data.map((d) => d.b_pos));
256
+ return [b_pos, t_pos];
257
+ }
258
+ }
259
+
260
+ function findAverageUnitHeight(
261
+ data: UnitLong[],
262
+ axisType: ColumnAxisType
263
+ ): number {
264
+ const unitHeights = data.map((d) => {
265
+ const [b_pos, t_pos] = getUnitHeightRange(d, axisType);
266
+ return Math.abs(b_pos - t_pos);
267
+ });
268
+ return unitHeights.reduce((a, b) => a + b, 0) / unitHeights.length;
269
+ }
270
+
271
+ export function createCompositeScale(
272
+ sections: PackageLayoutData[],
273
+ interpolateUnconformities: boolean = false
274
+ ): (age: number) => number | null {
275
+ /** Create a scale that works across multiple packages */
276
+ // Get surfaces at which scale breaks
277
+ let scaleBreaks: [number, number][] = [];
278
+ for (const section of sections) {
279
+ const { pixelHeight, pixelScale, offset, domain } = section.scaleInfo;
280
+
281
+ scaleBreaks.push([domain[1], offset]);
282
+ scaleBreaks.push([domain[0], offset + pixelHeight]);
283
+ }
284
+ // Sort the scale breaks by age
285
+ scaleBreaks.sort((a, b) => a[0] - b[0]);
286
+
287
+ return (age) => {
288
+ /** Given an age, find the corresponding pixel position */
289
+ // Iterate through the sections to find the correct one
290
+
291
+ // Accumulate scale breaks and pixel height
292
+ let pixelHeight = 0;
293
+ let pixelScale = 0;
294
+ let lastAge = null;
295
+ for (const [age1, height] of scaleBreaks) {
296
+ if (age <= age1) {
297
+ if (lastAge != null) {
298
+ pixelHeight += (age - lastAge) * pixelScale;
299
+ return pixelHeight;
300
+ }
301
+ lastAge = age;
302
+ pixelHeight = height;
303
+ }
304
+ }
305
+ };
306
+ }
307
+
308
+ /** Collapse sections separated by unconformities that are smaller than a given pixel height. */
309
+ export function collapseUnconformitiesByPixelHeight<T extends UnitLong>(
310
+ sections: SectionInfoWithScale<T>[],
311
+ threshold: number,
312
+ opts: ColumnScaleOptions
313
+ ): SectionInfoWithScale<T>[] {
314
+ const newSections = [];
315
+ let currentSection: SectionInfoWithScale<T> | null = null;
316
+ for (const nextSection of sections) {
317
+ if (currentSection == null) {
318
+ currentSection = nextSection;
319
+ continue;
320
+ }
321
+ const dAge = Math.abs(nextSection.t_age - currentSection.b_age);
322
+ const pxHeight =
323
+ dAge *
324
+ Math.max(
325
+ currentSection.scaleInfo.pixelScale,
326
+ nextSection.scaleInfo.pixelScale
327
+ );
328
+ if (pxHeight < threshold) {
329
+ // We need to merge the sections
330
+ const compositeSection0: SectionInfo<T> = {
331
+ units: [...currentSection.units, ...nextSection.units],
332
+ section_id: [
333
+ ...ensureArray(currentSection.section_id),
334
+ ...ensureArray(nextSection.section_id),
335
+ ],
336
+ t_age: Math.min(currentSection.t_age, nextSection.t_age),
337
+ b_age: Math.max(currentSection.b_age, nextSection.b_age),
338
+ };
339
+
340
+ const compositeSection = addScaleToSection(compositeSection0, opts);
341
+ currentSection = compositeSection;
342
+ } else {
343
+ // We need to keep the section
344
+ newSections.push(currentSection);
345
+ currentSection = nextSection;
346
+ }
347
+ }
348
+ if (currentSection != null) {
349
+ newSections.push(currentSection);
350
+ }
351
+
352
+ return newSections;
353
+ }