@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
@@ -0,0 +1,225 @@
1
+ import { MapViewProps } from "@macrostrat/map-interface";
2
+ import {
3
+ useMapClickHandler,
4
+ useMapEaseTo,
5
+ useMapStyleOperator,
6
+ } from "@macrostrat/mapbox-react";
7
+ import { LngLatBounds } from "mapbox-gl";
8
+ import h from "@macrostrat/hyper";
9
+ import { Feature, FeatureCollection } from "geojson";
10
+ import { ReactNode, useMemo } from "react";
11
+ import { setGeoJSON } from "@macrostrat/mapbox-utils";
12
+
13
+ import { useCorrelationMapStore } from "./state";
14
+ import { buildColumnsStyle, InsetMap, InsetMapProps } from "../_shared";
15
+ import { buildCrossSectionLayers } from "@macrostrat/map-styles";
16
+
17
+ export interface CorrelationMapProps extends InsetMapProps {
18
+ padding?: number;
19
+ children?: ReactNode;
20
+ accessToken?: string;
21
+ columnColor?: string;
22
+ }
23
+
24
+ export function ColumnCorrelationMap(props: CorrelationMapProps) {
25
+ const { padding = 50, children, columnColor, ...rest } = props;
26
+
27
+ const overlayStyles = useMemo(() => {
28
+ return [
29
+ buildColumnsStyle(columnColor),
30
+ selectedColumnsStyle,
31
+ lineOfSectionStyle,
32
+ ];
33
+ }, [columnColor]);
34
+
35
+ return h(
36
+ InsetMap,
37
+ {
38
+ ...rest,
39
+ boxZoom: false,
40
+ dragRotate: false,
41
+ overlayStyles,
42
+ },
43
+ [
44
+ h(ColumnsLayer),
45
+ h(SelectedColumnsLayer),
46
+ h(MapClickHandler),
47
+ h(SectionLine, { padding }),
48
+ children,
49
+ ]
50
+ );
51
+ }
52
+
53
+ function MapClickHandler() {
54
+ const onClickMap = useCorrelationMapStore((state) => state.onClickMap);
55
+
56
+ useMapClickHandler(
57
+ (e) => {
58
+ onClickMap(e, { type: "Point", coordinates: e.lngLat.toArray() });
59
+ },
60
+ [onClickMap]
61
+ );
62
+
63
+ return null;
64
+ }
65
+
66
+ function SelectedColumnsLayer() {
67
+ const focusedColumns = useCorrelationMapStore(
68
+ (state) => state.focusedColumns
69
+ );
70
+
71
+ useMapStyleOperator(
72
+ (map) => {
73
+ let features = focusedColumns;
74
+
75
+ const data: FeatureCollection = {
76
+ type: "FeatureCollection",
77
+ features,
78
+ };
79
+
80
+ const columnCentroidLine: Feature = {
81
+ type: "Feature",
82
+ geometry: {
83
+ type: "LineString",
84
+ coordinates: features.map(
85
+ (col) => col.properties.centroid.geometry.coordinates
86
+ ),
87
+ },
88
+ properties: {},
89
+ };
90
+
91
+ setGeoJSON(map, "selected-columns", data);
92
+ setGeoJSON(map, "selected-column-centroids", {
93
+ type: "FeatureCollection",
94
+ features: [columnCentroidLine],
95
+ });
96
+ },
97
+ [focusedColumns]
98
+ );
99
+ return null;
100
+ }
101
+
102
+ function ColumnsLayer({ enabled = true }) {
103
+ const columns = useCorrelationMapStore((state) => state.columns);
104
+
105
+ useMapStyleOperator(
106
+ (map) => {
107
+ if (columns == null) {
108
+ return;
109
+ }
110
+ const data: FeatureCollection = {
111
+ type: "FeatureCollection",
112
+ features: columns,
113
+ };
114
+
115
+ console.log(" columns", data);
116
+ setGeoJSON(map, "columns", data);
117
+ },
118
+ [columns, enabled]
119
+ );
120
+ return null;
121
+ }
122
+
123
+ const selectedColumnsStyle = {
124
+ sources: {
125
+ "selected-columns": buildGeoJSONSource(),
126
+ "selected-column-centroids": buildGeoJSONSource(),
127
+ },
128
+ layers: [
129
+ {
130
+ id: "selected-columns-fill",
131
+ type: "fill",
132
+ source: "selected-columns",
133
+ paint: {
134
+ "fill-color": "rgba(255, 0, 0, 0.1)",
135
+ },
136
+ },
137
+ {
138
+ id: "selected-column-centroids-line",
139
+ type: "line",
140
+ source: "selected-column-centroids",
141
+ paint: {
142
+ "line-color": "rgba(255, 0, 0, 0.8)",
143
+ "line-width": 2,
144
+ "line-dasharray": [2, 2],
145
+ },
146
+ },
147
+ {
148
+ id: "selected-column-centroids-points",
149
+ type: "circle",
150
+ source: "selected-column-centroids",
151
+ paint: {
152
+ "circle-radius": 4,
153
+ "circle-color": "rgba(255, 0, 0, 0.8)",
154
+ },
155
+ },
156
+ ],
157
+ };
158
+
159
+ const lineOfSectionStyle = {
160
+ sources: {
161
+ elevationMarker: buildGeoJSONSource(),
162
+ crossSectionLine: buildGeoJSONSource(),
163
+ crossSectionEndpoints: buildGeoJSONSource(),
164
+ },
165
+ layers: buildCrossSectionLayers(),
166
+ };
167
+
168
+ function buildGeoJSONSource(data: FeatureCollection | null = null) {
169
+ return {
170
+ type: "geojson",
171
+ data: data ?? {
172
+ type: "FeatureCollection",
173
+ features: [],
174
+ },
175
+ };
176
+ }
177
+
178
+ function SectionLine({ padding }: { padding: number }) {
179
+ const focusedLine = useCorrelationMapStore((state) => state.focusedLine);
180
+
181
+ // Setup focused line
182
+ useMapStyleOperator(
183
+ (map) => {
184
+ if (focusedLine == null) {
185
+ return;
186
+ }
187
+ const data: FeatureCollection = {
188
+ type: "FeatureCollection",
189
+ features: [
190
+ {
191
+ type: "Feature",
192
+ geometry: focusedLine,
193
+ properties: { id: "focusedLine" },
194
+ },
195
+ ],
196
+ };
197
+
198
+ setGeoJSON(map, "crossSectionLine", data);
199
+ setGeoJSON(map, "crossSectionEndpoints", {
200
+ type: "FeatureCollection",
201
+ features: focusedLine.coordinates.map((coord) => ({
202
+ type: "Feature",
203
+ geometry: { type: "Point", coordinates: coord },
204
+ properties: {},
205
+ })),
206
+ });
207
+ },
208
+ [focusedLine]
209
+ );
210
+
211
+ const bounds = useMemo(() => {
212
+ if (focusedLine == null || focusedLine?.coordinates.length < 2) {
213
+ return null;
214
+ }
215
+ let bounds = new LngLatBounds();
216
+ for (let coord of focusedLine.coordinates) {
217
+ bounds.extend(coord);
218
+ }
219
+ return bounds;
220
+ }, [focusedLine]);
221
+
222
+ useMapEaseTo({ bounds, padding, trackResize: true });
223
+
224
+ return null;
225
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./core";
2
+ export * from "./state";
@@ -0,0 +1,192 @@
1
+ import { LineString, Point } from "geojson";
2
+ import { create, StoreApi, useStore } from "zustand";
3
+ import type { ColumnGeoJSONRecord } from "@macrostrat/api-types";
4
+ // Turf intersection
5
+ import { lineIntersect } from "@turf/line-intersect";
6
+ import distance from "@turf/distance";
7
+ import { nearestPointOnLine } from "@turf/nearest-point-on-line";
8
+ import { centroid } from "@turf/centroid";
9
+ import mapboxgl from "mapbox-gl";
10
+ import {
11
+ createContext,
12
+ useState,
13
+ useContext,
14
+ ReactNode,
15
+ useEffect,
16
+ } from "react";
17
+ import h from "@macrostrat/hyper";
18
+ import { createComputed } from "zustand-computed";
19
+ import { useMacrostratColumns } from "../../data-provider/base";
20
+
21
+ export interface CorrelationMapInput {
22
+ columns: ColumnGeoJSONRecord[];
23
+ focusedLine: LineString | null;
24
+ }
25
+
26
+ export interface CorrelationMapStore extends CorrelationMapInput {
27
+ onClickMap: (event: mapboxgl.MapMouseEvent, point: Point) => void;
28
+ }
29
+
30
+ export interface CorrelationProviderProps extends CorrelationMapInput {
31
+ projectID?: number;
32
+ inProcess?: boolean;
33
+ columns: ColumnGeoJSONRecord[] | null;
34
+ children: ReactNode;
35
+ onSelectColumns?: (
36
+ columns: FocusedColumnGeoJSONRecord[],
37
+ line: LineString | null
38
+ ) => void;
39
+ }
40
+
41
+ const CorrelationStoreContext =
42
+ createContext<StoreApi<CorrelationMapStore> | null>(null);
43
+
44
+ type ComputedStore = {
45
+ focusedColumns: FocusedColumnGeoJSONRecord[];
46
+ };
47
+
48
+ /** A computed store that will automatically update when the state changes */
49
+ const computed = createComputed((state: CorrelationMapStore): ComputedStore => {
50
+ return {
51
+ // We compute the focused columns based on columns and focusedLine
52
+ focusedColumns: buildCorrelationColumns(state.columns, state.focusedLine),
53
+ };
54
+ }) as any;
55
+
56
+ export function ColumnCorrelationProvider({
57
+ children,
58
+ columns,
59
+ projectID,
60
+ inProcess,
61
+ focusedLine,
62
+ onSelectColumns,
63
+ }: CorrelationProviderProps) {
64
+ const [store] = useState(() => {
65
+ return create<CorrelationMapStore & ComputedStore>(
66
+ computed((set, get): CorrelationMapStore => {
67
+ return {
68
+ focusedLine,
69
+ columns: null,
70
+ onClickMap(event: mapboxgl.MapMouseEvent, point: Point) {
71
+ const state = get();
72
+ // Check if shift key is pressed
73
+ const shiftKeyPressed = event.originalEvent.shiftKey;
74
+ let existingCoords = state.focusedLine?.coordinates ?? [];
75
+
76
+ if (existingCoords.length >= 2 && !shiftKeyPressed) {
77
+ // Reset the line to zero length
78
+ existingCoords = [];
79
+ }
80
+ set({
81
+ focusedLine: {
82
+ type: "LineString",
83
+ coordinates: [...existingCoords, point.coordinates],
84
+ },
85
+ });
86
+ },
87
+ };
88
+ })
89
+ );
90
+ });
91
+
92
+ // Set up the store
93
+ /** TODO: move the fetching of all columns to within the map */
94
+ const _columns = useMacrostratColumns(projectID, inProcess);
95
+ useEffect(() => {
96
+ if (_columns != null) {
97
+ store.setState({ columns: _columns });
98
+ }
99
+ }, [_columns]);
100
+
101
+ // Kind of an awkward way to do this but we need to allow the selector to run
102
+ const focusedColumns = useStore(store, (state) => state.focusedColumns);
103
+ const _focusedLine = useStore(store, (state) => state.focusedLine);
104
+
105
+ useEffect(() => {
106
+ onSelectColumns?.(focusedColumns, _focusedLine);
107
+ }, [focusedColumns, _focusedLine]);
108
+
109
+ return h(CorrelationStoreContext.Provider, { value: store }, children);
110
+ }
111
+
112
+ export function useCorrelationMapStore(
113
+ selector: (state: CorrelationMapStore & ComputedStore) => any
114
+ ) {
115
+ const storeApi = useContext(CorrelationStoreContext);
116
+ if (storeApi == null) {
117
+ throw new Error("Missing CorrelationMapProvider");
118
+ }
119
+ return useStore(storeApi, selector);
120
+ }
121
+
122
+ function buildCorrelationColumns(
123
+ columns: ColumnGeoJSONRecord[],
124
+ line: LineString
125
+ ): FocusedColumnGeoJSONRecord[] {
126
+ if (columns == null || line == null || line.coordinates.length < 2) {
127
+ return [];
128
+ }
129
+ return orderColumnsByDistance(
130
+ computeIntersectingColumns(columns, line),
131
+ line
132
+ );
133
+ }
134
+
135
+ function computeIntersectingColumns(
136
+ columns: ColumnGeoJSONRecord[],
137
+ line: LineString
138
+ ): ColumnGeoJSONRecord[] {
139
+ if (columns == null || line == null) {
140
+ return [];
141
+ }
142
+
143
+ return columns.filter((col) => {
144
+ const poly = col.geometry;
145
+
146
+ // Some in-process datasets seem to have null geometries
147
+ if (poly == null) return false;
148
+ if (poly.type != "Polygon" && poly.type != "MultiPolygon") return false;
149
+
150
+ const intersection = lineIntersect(line, poly);
151
+ return intersection.features.length > 0;
152
+ });
153
+ }
154
+
155
+ interface FocusedColumnGeoJSONRecord extends ColumnGeoJSONRecord {
156
+ properties: {
157
+ centroid: Point;
158
+ nearestPointOnLine: Point;
159
+ distanceAlongLine: number;
160
+ } & ColumnGeoJSONRecord["properties"];
161
+ }
162
+
163
+ function orderColumnsByDistance(
164
+ columns: ColumnGeoJSONRecord[],
165
+ line: LineString
166
+ ): FocusedColumnGeoJSONRecord[] {
167
+ const centroids = columns.map((col) => centroid(col.geometry));
168
+ const projectedPoints = centroids.map((point) =>
169
+ nearestPointOnLine(line, point)
170
+ );
171
+ const distances = projectedPoints.map((point) =>
172
+ distance(point.geometry.coordinates, line.coordinates[0])
173
+ );
174
+
175
+ let newColumns = columns.map((col, i) => {
176
+ return {
177
+ ...col,
178
+ properties: {
179
+ ...col.properties,
180
+ centroid: centroids[i],
181
+ nearestPointOnLine: projectedPoints[i],
182
+ distanceAlongLine: distances[i],
183
+ },
184
+ };
185
+ });
186
+
187
+ return sorted(newColumns, (d) => d.properties.distanceAlongLine);
188
+ }
189
+
190
+ function sorted(data, accessor: (d) => number) {
191
+ return data.sort((a, b) => accessor(a) - accessor(b));
192
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./mapbox";
2
+ export * from "./svg";
@@ -0,0 +1,102 @@
1
+ import h from "@macrostrat/hyper";
2
+
3
+ const mapboxToken = import.meta.env.VITE_MAPBOX_API_TOKEN;
4
+
5
+ import { Meta } from "@storybook/react";
6
+ import { ColumnNavigationMap } from ".";
7
+ import { useState } from "react";
8
+
9
+ function ColumnNavigationMapExt(props) {
10
+ return h(ColumnNavigationMap, {
11
+ style: { width: "800px", height: "600px" },
12
+ padding: 100,
13
+ accessToken: mapboxToken,
14
+ ...props,
15
+ });
16
+ }
17
+
18
+ // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
19
+ export default {
20
+ title: "Column views/Maps/Column navigation",
21
+ component: ColumnNavigationMapExt,
22
+ description: "Cross section creation map",
23
+ } as Meta<typeof ColumnNavigationMap>;
24
+
25
+ export const ColumnNavigation = {
26
+ args: {
27
+ showTriangulation: false,
28
+ },
29
+ };
30
+
31
+ export const nonStandardProjectInProcess = {
32
+ args: {
33
+ padding: 100,
34
+ projectID: 10,
35
+ inProcess: true,
36
+ showTriangulation: false,
37
+ mapPosition: {
38
+ camera: {
39
+ lng: -72,
40
+ lat: 44,
41
+ altitude: 600000,
42
+ },
43
+ },
44
+ },
45
+ };
46
+
47
+ export const DeepSea = {
48
+ args: {
49
+ padding: 100,
50
+ projectID: 4,
51
+ inProcess: true,
52
+ showTriangulation: false,
53
+ center: [0, 0],
54
+ zoom: 2,
55
+ mapPosition: null,
56
+ },
57
+ };
58
+
59
+ export const eODP = {
60
+ args: {
61
+ projectID: 3,
62
+ inProcess: true,
63
+ },
64
+ };
65
+
66
+ export const showTriangulation = {
67
+ description: "Show the triangulation used for keyboard navigation",
68
+ args: {
69
+ showTriangulation: true,
70
+ columnColor: "#1fff53",
71
+ triangulationColor: "#9a33bb",
72
+ },
73
+ };
74
+
75
+ export const onlyPhysicalBasemap = {
76
+ args: {
77
+ mapStyle: "mapbox://styles/mapbox/outdoors-v11",
78
+ showLabels: true,
79
+ showAdmin: false,
80
+ showRoads: false,
81
+ },
82
+ };
83
+
84
+ export function ControlledColumnNavigation() {
85
+ const [selectedColumn, setSelectedColumn] = useState(157);
86
+ const [hoveredColumn, setHoveredColumn] = useState(null);
87
+
88
+ return h("div.controlled-navigation", [
89
+ h(ColumnNavigationMapExt, {
90
+ selectedColumn,
91
+ hoveredColumn,
92
+ onSelectColumn: setSelectedColumn,
93
+ onHoverColumn: setHoveredColumn,
94
+ }),
95
+ h("div.column-info", [
96
+ h("h3", "Selected column"),
97
+ h("p", selectedColumn),
98
+ h("h3", "Hovered column"),
99
+ h("p", hoveredColumn),
100
+ ]),
101
+ ]);
102
+ }