@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.
- package/CHANGELOG.md +21 -0
- package/dist/esm/_shared.f7eec55a.js +9 -0
- package/dist/esm/_shared.f7eec55a.js.map +1 -0
- package/dist/esm/age-axis.4a8cf5e6.js +98 -0
- package/dist/esm/age-axis.4a8cf5e6.js.map +1 -0
- package/dist/esm/age-axis.module.03773a80.css +33 -0
- package/dist/esm/age-axis.module.03773a80.css.map +1 -0
- package/dist/esm/age-axis.module.3cc91335.js +22 -0
- package/dist/esm/age-axis.module.3cc91335.js.map +1 -0
- package/dist/esm/age-model-overlay.c7226855.js +57 -0
- package/dist/esm/age-model-overlay.c7226855.js.map +1 -0
- package/dist/esm/age-model-overlay.module.5d9e78fb.css +14 -0
- package/dist/esm/age-model-overlay.module.5d9e78fb.css.map +1 -0
- package/dist/esm/age-model-overlay.module.cd985dcb.js +16 -0
- package/dist/esm/age-model-overlay.module.cd985dcb.js.map +1 -0
- package/dist/esm/base.910b80b4.js +288 -0
- package/dist/esm/base.910b80b4.js.map +1 -0
- package/dist/esm/boxes.8292cff2.js +258 -0
- package/dist/esm/boxes.8292cff2.js.map +1 -0
- package/dist/esm/boxes.module.2b5fb18e.css +26 -0
- package/dist/esm/boxes.module.2b5fb18e.css.map +1 -0
- package/dist/esm/boxes.module.4ebc7796.js +19 -0
- package/dist/esm/boxes.module.4ebc7796.js.map +1 -0
- package/dist/esm/{carbon-isotopes.3b502a9e.js → carbon-isotopes.10db8285.js} +2 -2
- package/dist/esm/{carbon-isotopes.3b502a9e.js.map → carbon-isotopes.10db8285.js.map} +1 -1
- package/dist/esm/colors.395c6db5.js +40 -0
- package/dist/esm/colors.395c6db5.js.map +1 -0
- package/dist/esm/column-correlation.c8dcfe98.js +9 -0
- package/dist/esm/column-correlation.c8dcfe98.js.map +1 -0
- package/dist/esm/column-nav.5414677c.js +55 -0
- package/dist/esm/column-nav.5414677c.js.map +1 -0
- package/dist/esm/column-navigation.37cd3245.js +9 -0
- package/dist/esm/column-navigation.37cd3245.js.map +1 -0
- package/dist/esm/column.01d68dd8.js +127 -0
- package/dist/esm/column.01d68dd8.js.map +1 -0
- package/dist/esm/{column.db058031.js → column.a25f8ebd.js} +4 -4
- package/dist/esm/column.a25f8ebd.js.map +1 -0
- package/dist/esm/column.module.1b776e15.js +46 -0
- package/dist/esm/column.module.1b776e15.js.map +1 -0
- package/dist/esm/column.module.a67a6b4c.css +159 -0
- package/dist/esm/column.module.a67a6b4c.css.map +1 -0
- package/dist/esm/composite-scale.577bf64a.js +222 -0
- package/dist/esm/composite-scale.577bf64a.js.map +1 -0
- package/dist/esm/composite.039e4798.js +163 -0
- package/dist/esm/composite.039e4798.js.map +1 -0
- package/dist/esm/{core.4db8e452.js → core.843310d3.js} +11 -12
- package/dist/esm/core.843310d3.js.map +1 -0
- package/dist/esm/core.91ede078.js +206 -0
- package/dist/esm/core.91ede078.js.map +1 -0
- package/dist/esm/correlation-chart.abd8b346.js +9 -0
- package/dist/esm/correlation-chart.abd8b346.js.map +1 -0
- package/dist/esm/data-provider.1506eb64.js.map +1 -1
- package/dist/esm/data-provider.f10c6d0b.js +13 -0
- package/dist/esm/data-provider.f10c6d0b.js.map +1 -0
- package/dist/esm/fetch.99aec438.js +152 -0
- package/dist/esm/fetch.99aec438.js.map +1 -0
- package/dist/esm/hash-string.285b37fb.js +39 -0
- package/dist/esm/hash-string.285b37fb.js.map +1 -0
- package/dist/esm/helpers.2f0a0cb7.js +141 -0
- package/dist/esm/helpers.2f0a0cb7.js.map +1 -0
- package/dist/esm/index.d.ts +797 -120
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +14 -8
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/inset-map.3c18106d.js +66 -0
- package/dist/esm/inset-map.3c18106d.js.map +1 -0
- package/dist/esm/keyboard-navigation.6713401b.js +48 -0
- package/dist/esm/keyboard-navigation.6713401b.js.map +1 -0
- package/dist/esm/keyboard-navigation.a9fc80dd.js +112 -0
- package/dist/esm/keyboard-navigation.a9fc80dd.js.map +1 -0
- package/dist/esm/layers.033d3fb0.js +170 -0
- package/dist/esm/layers.033d3fb0.js.map +1 -0
- package/dist/esm/main.2e0375a5.js +221 -0
- package/dist/esm/main.2e0375a5.js.map +1 -0
- package/dist/esm/main.module.3dd9500b.css +134 -0
- package/dist/esm/main.module.3dd9500b.css.map +1 -0
- package/dist/esm/main.module.c09154b1.js +70 -0
- package/dist/esm/main.module.c09154b1.js.map +1 -0
- package/dist/esm/mapbox.cac42eed.js +167 -0
- package/dist/esm/mapbox.cac42eed.js.map +1 -0
- package/dist/esm/maps.bcdea9c1.js +11 -0
- package/dist/esm/maps.bcdea9c1.js.map +1 -0
- package/dist/esm/{names.f6a4e9a4.js → names.a8f2b452.js} +5 -5
- package/dist/esm/names.a8f2b452.js.map +1 -0
- package/dist/esm/panel.598f76a5.js +420 -0
- package/dist/esm/panel.598f76a5.js.map +1 -0
- package/dist/esm/panel.module.386166cc.js +58 -0
- package/dist/esm/panel.module.386166cc.js.map +1 -0
- package/dist/esm/panel.module.3d2ea3c6.css +111 -0
- package/dist/esm/panel.module.3d2ea3c6.css.map +1 -0
- package/dist/esm/popover.a810b7bc.js +66 -0
- package/dist/esm/popover.a810b7bc.js.map +1 -0
- package/dist/esm/popover.module.c4ba4189.js +22 -0
- package/dist/esm/popover.module.c4ba4189.js.map +1 -0
- package/dist/esm/{selection-popover.module.0a701258.css → popover.module.c4d6bfb0.css} +11 -8
- package/dist/esm/popover.module.c4d6bfb0.css.map +1 -0
- package/dist/esm/prepare-data.d4284b4a.js +125 -0
- package/dist/esm/prepare-data.d4284b4a.js.map +1 -0
- package/dist/esm/prepare-units.6c890a96.js +104 -0
- package/dist/esm/prepare-units.6c890a96.js.map +1 -0
- package/dist/esm/{resolvers.b5c82b78.js → resolvers.36013b49.js} +13 -2
- package/dist/esm/resolvers.36013b49.js.map +1 -0
- package/dist/esm/section.a34d379a.js +215 -0
- package/dist/esm/section.a34d379a.js.map +1 -0
- package/dist/esm/selection.f5b0297e.js +143 -0
- package/dist/esm/selection.f5b0297e.js.map +1 -0
- package/dist/esm/state.178ef364.js +75 -0
- package/dist/esm/state.178ef364.js.map +1 -0
- package/dist/esm/state.2952cbca.js +118 -0
- package/dist/esm/state.2952cbca.js.map +1 -0
- package/dist/esm/store.c4d7a8a4.js +52 -0
- package/dist/esm/store.c4d7a8a4.js.map +1 -0
- package/dist/esm/styles.7bc776d1.js +95 -0
- package/dist/esm/styles.7bc776d1.js.map +1 -0
- package/dist/esm/svg.4b9a96c1.js +89 -0
- package/dist/esm/svg.4b9a96c1.js.map +1 -0
- package/dist/esm/types.0f0b57c9.js +3 -0
- package/dist/esm/types.0f0b57c9.js.map +1 -0
- package/dist/esm/unit-details.071cefed.js +9 -0
- package/dist/esm/unit-details.071cefed.js.map +1 -0
- package/dist/esm/units.5a4fc058.js +98 -0
- package/dist/esm/units.5a4fc058.js.map +1 -0
- package/dist/esm/utils.d7a43a2a.js +55 -0
- package/dist/esm/utils.d7a43a2a.js.map +1 -0
- package/dist/node/index.js.map +1 -1
- package/package.json +24 -7
- package/src/age-axis.module.sass +27 -0
- package/src/age-axis.ts +82 -19
- package/src/age-model-overlay.module.sass +11 -0
- package/src/age-model-overlay.ts +73 -0
- package/src/carbon-isotopes/column.ts +4 -2
- package/src/carbon-isotopes/core.ts +9 -6
- package/src/carbon-isotopes/data-provider.ts +3 -3
- package/src/column.module.sass +58 -49
- package/src/column.ts +149 -135
- package/src/correlation-chart/hash-string.ts +57 -0
- package/src/correlation-chart/index.ts +2 -0
- package/src/correlation-chart/main.module.sass +122 -0
- package/src/correlation-chart/main.ts +305 -0
- package/src/correlation-chart/prepare-data.ts +217 -0
- package/src/correlation-chart/stories/correlation-chart.stories.ts +192 -0
- package/src/correlation-chart/stories/stories.module.sass +18 -0
- package/src/correlation-chart/unconformity-line.module.sass +8 -0
- package/src/correlation-chart/unconformity-line.ts +25 -0
- package/src/data-provider/base.ts +388 -0
- package/src/data-provider/column-nav.ts +53 -0
- package/src/data-provider/fetch.ts +231 -0
- package/src/data-provider/index.ts +4 -0
- package/src/data-provider/store.ts +72 -0
- package/src/index.ts +6 -3
- package/src/maps/_shared/index.ts +2 -0
- package/src/maps/_shared/inset-map.stories.ts +20 -0
- package/src/maps/_shared/inset-map.ts +87 -0
- package/src/maps/_shared/styles.ts +57 -0
- package/src/maps/column-correlation/column-correlation-map.stories.ts +96 -0
- package/src/maps/column-correlation/core.ts +225 -0
- package/src/maps/column-correlation/index.ts +2 -0
- package/src/maps/column-correlation/state.ts +192 -0
- package/src/maps/column-navigation/index.ts +2 -0
- package/src/maps/column-navigation/mapbox/column-navigation-map.stories.ts +102 -0
- package/src/maps/column-navigation/mapbox/index.ts +219 -0
- package/src/maps/column-navigation/mapbox/keyboard-navigation.ts +119 -0
- package/src/maps/column-navigation/mapbox/state.ts +109 -0
- package/src/maps/column-navigation/svg/column-navigation-svg-map.stories.ts +46 -0
- package/src/{map → maps/column-navigation/svg}/index.ts +18 -6
- package/src/{map → maps/column-navigation/svg}/layers.ts +28 -109
- package/src/maps/column-navigation/utils/keyboard-navigation.ts +58 -0
- package/src/maps/index.ts +3 -0
- package/src/prepare-units/composite-scale.ts +353 -0
- package/src/prepare-units/helpers.ts +226 -0
- package/src/prepare-units/index.ts +177 -0
- package/src/prepare-units/utils.ts +98 -0
- package/src/section.ts +264 -84
- package/src/unit-details/index.ts +2 -215
- package/src/unit-details/{index.module.sass → panel.module.sass} +39 -8
- package/src/unit-details/panel.ts +523 -0
- package/src/{selection-popover.module.sass → unit-details/popover.module.sass} +4 -2
- package/src/unit-details/popover.ts +82 -0
- package/src/units/boxes.module.sass +16 -0
- package/src/units/boxes.ts +243 -90
- package/src/units/colors.ts +64 -0
- package/src/units/composite.ts +157 -152
- package/src/units/index.ts +76 -9
- package/src/units/names.ts +8 -4
- package/src/units/resolvers.ts +11 -0
- package/src/units/selection.ts +115 -101
- package/src/units/types.ts +5 -16
- package/dist/esm/age-axis.64c509ee.js +0 -41
- package/dist/esm/age-axis.64c509ee.js.map +0 -1
- package/dist/esm/boxes.13968b76.js +0 -164
- package/dist/esm/boxes.13968b76.js.map +0 -1
- package/dist/esm/boxes.module.28873d08.css +0 -4
- package/dist/esm/boxes.module.28873d08.css.map +0 -1
- package/dist/esm/boxes.module.605bdcd6.js +0 -13
- package/dist/esm/boxes.module.605bdcd6.js.map +0 -1
- package/dist/esm/column.8dd26e1a.js +0 -149
- package/dist/esm/column.8dd26e1a.js.map +0 -1
- package/dist/esm/column.db058031.js.map +0 -1
- package/dist/esm/column.module.039d872c.css +0 -151
- package/dist/esm/column.module.039d872c.css.map +0 -1
- package/dist/esm/column.module.e632868a.js +0 -19
- package/dist/esm/column.module.e632868a.js.map +0 -1
- package/dist/esm/composite.608a4ca2.js +0 -153
- package/dist/esm/composite.608a4ca2.js.map +0 -1
- package/dist/esm/core.4db8e452.js.map +0 -1
- package/dist/esm/helpers.8a03cfc7.js +0 -94
- package/dist/esm/helpers.8a03cfc7.js.map +0 -1
- package/dist/esm/index.module.0844afd8.css +0 -65
- package/dist/esm/index.module.0844afd8.css.map +0 -1
- package/dist/esm/index.module.24fe3a2e.js +0 -37
- package/dist/esm/index.module.24fe3a2e.js.map +0 -1
- package/dist/esm/layers.ad5fd25d.js +0 -231
- package/dist/esm/layers.ad5fd25d.js.map +0 -1
- package/dist/esm/map.7aa26f17.js +0 -82
- package/dist/esm/map.7aa26f17.js.map +0 -1
- package/dist/esm/names.f6a4e9a4.js.map +0 -1
- package/dist/esm/providers.cd1e652f.js +0 -25
- package/dist/esm/providers.cd1e652f.js.map +0 -1
- package/dist/esm/resolvers.b5c82b78.js.map +0 -1
- package/dist/esm/section.cc1b1100.js +0 -118
- package/dist/esm/section.cc1b1100.js.map +0 -1
- package/dist/esm/selection-popover.17d1bd55.js +0 -60
- package/dist/esm/selection-popover.17d1bd55.js.map +0 -1
- package/dist/esm/selection-popover.module.0a701258.css.map +0 -1
- package/dist/esm/selection-popover.module.e22f5183.js +0 -22
- package/dist/esm/selection-popover.module.e22f5183.js.map +0 -1
- package/dist/esm/selection.bbf26d0e.js +0 -117
- package/dist/esm/selection.bbf26d0e.js.map +0 -1
- package/dist/esm/store.25eaa168.js +0 -18
- package/dist/esm/store.25eaa168.js.map +0 -1
- package/dist/esm/types.f016e032.js +0 -18
- package/dist/esm/types.f016e032.js.map +0 -1
- package/dist/esm/unit-details.56ff8b70.js +0 -209
- package/dist/esm/unit-details.56ff8b70.js.map +0 -1
- package/dist/esm/units.361088d4.js +0 -42
- package/dist/esm/units.361088d4.js.map +0 -1
- package/src/helpers.ts +0 -133
- package/src/providers.ts +0 -34
- package/src/selection-popover.ts +0 -71
- package/src/store.ts +0 -12
- package/src/units/units.scss +0 -16
- /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
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
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(
|
|
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
|
-
|
|
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[] =
|
|
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,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
|
+
}
|