@macrostrat/column-views 3.2.2 → 3.3.1
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 +10 -0
- package/dist/index.cjs +15 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +11 -5
- package/dist/maps/column-correlation/core.cjs +10 -30
- package/dist/maps/column-correlation/core.cjs.map +1 -1
- package/dist/maps/column-correlation/core.d.ts +1 -1
- package/dist/maps/column-correlation/core.js +10 -30
- package/dist/maps/column-correlation/core.js.map +1 -1
- package/dist/maps/column-navigation/mapbox/index.cjs +156 -118
- package/dist/maps/column-navigation/mapbox/index.cjs.map +1 -1
- package/dist/maps/column-navigation/mapbox/index.d.ts +23 -2
- package/dist/maps/column-navigation/mapbox/index.js +158 -120
- package/dist/maps/column-navigation/mapbox/index.js.map +1 -1
- package/dist/maps/column-navigation/mapbox/keyboard-navigation.cjs +7 -1
- package/dist/maps/column-navigation/mapbox/keyboard-navigation.cjs.map +1 -1
- package/dist/maps/column-navigation/mapbox/keyboard-navigation.d.ts +3 -26
- package/dist/maps/column-navigation/mapbox/keyboard-navigation.js +9 -3
- package/dist/maps/column-navigation/mapbox/keyboard-navigation.js.map +1 -1
- package/dist/maps/index.d.ts +2 -2
- package/dist/maps/{_shared/inset-map.cjs → inset-map/index.cjs} +1 -1
- package/dist/maps/inset-map/index.cjs.map +1 -0
- package/dist/maps/{_shared/inset-map.js → inset-map/index.js} +1 -1
- package/dist/maps/inset-map/index.js.map +1 -0
- package/dist/maps/layers/columns.cjs +161 -0
- package/dist/maps/layers/columns.cjs.map +1 -0
- package/dist/maps/layers/columns.d.ts +28 -0
- package/dist/maps/layers/columns.js +161 -0
- package/dist/maps/layers/columns.js.map +1 -0
- package/dist/maps/layers/index.d.ts +2 -0
- package/dist/maps/{units-overlay/index.cjs → layers/units.cjs} +41 -88
- package/dist/maps/layers/units.cjs.map +1 -0
- package/dist/maps/{units-overlay/index.d.ts → layers/units.d.ts} +1 -1
- package/dist/maps/{units-overlay/index.js → layers/units.js} +34 -82
- package/dist/maps/layers/units.js.map +1 -0
- package/dist/unit-details/age-range.cjs +86 -44
- package/dist/unit-details/age-range.cjs.map +1 -1
- package/dist/unit-details/age-range.d.ts +32 -5
- package/dist/unit-details/age-range.js +84 -44
- package/dist/unit-details/age-range.js.map +1 -1
- package/package.json +4 -4
- package/src/maps/column-correlation/core.ts +9 -29
- package/src/maps/column-navigation/mapbox/index.ts +191 -138
- package/src/maps/column-navigation/mapbox/keyboard-navigation.ts +17 -3
- package/src/maps/index.ts +2 -2
- package/src/maps/layers/columns.ts +210 -0
- package/src/maps/layers/index.ts +2 -0
- package/src/maps/{units-overlay/index.ts → layers/units.ts} +34 -84
- package/src/maps/unit-map.stories.ts +27 -12
- package/src/unit-details/age-range.ts +124 -47
- package/dist/maps/_shared/index.d.ts +0 -2
- package/dist/maps/_shared/inset-map.cjs.map +0 -1
- package/dist/maps/_shared/inset-map.js.map +0 -1
- package/dist/maps/_shared/styles.cjs +0 -73
- package/dist/maps/_shared/styles.cjs.map +0 -1
- package/dist/maps/_shared/styles.d.ts +0 -2
- package/dist/maps/_shared/styles.js +0 -73
- package/dist/maps/_shared/styles.js.map +0 -1
- package/dist/maps/units-overlay/index.cjs.map +0 -1
- package/dist/maps/units-overlay/index.js.map +0 -1
- package/src/maps/_shared/index.ts +0 -2
- package/src/maps/_shared/styles.ts +0 -76
- /package/dist/maps/{_shared/inset-map.d.ts → inset-map/index.d.ts} +0 -0
- /package/src/maps/{_shared/inset-map.ts → inset-map/index.ts} +0 -0
- /package/src/maps/{_shared → inset-map}/inset-map.stories.ts +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"age-range.js","sources":["../../src/unit-details/age-range.ts"],"sourcesContent":["import {\n DataField,\n IntervalShort,\n IntervalTag,\n ItemList,\n Value,\n} from \"@macrostrat/data-components\";\nimport { useMacrostratDefs } from \"@macrostrat/data-provider\";\nimport h from \"./age-range.module.sass\";\nimport { formatProportion, formatRange } from \"./utils\";\n\nexport function AgeField({ unit, children }) {\n const [
|
|
1
|
+
{"version":3,"file":"age-range.js","sources":["../../src/unit-details/age-range.ts"],"sourcesContent":["import {\n DataField,\n IntervalShort,\n IntervalTag,\n type IntervalTagProps,\n ItemList,\n Value,\n} from \"@macrostrat/data-components\";\nimport { useMacrostratDefs } from \"@macrostrat/data-provider\";\nimport h from \"./age-range.module.sass\";\nimport { formatProportion, formatRange } from \"./utils\";\nimport classNames from \"classnames\";\nimport { useMemo } from \"react\";\n\nexport function AgeField({ unit, children, ...rest }) {\n const [_b_age, _t_age, _unit] = getAgeRange(unit);\n\n return h(\n DataField,\n {\n label: \"Age\",\n value: formatRange(_b_age, _t_age),\n unit: _unit,\n ...rest,\n },\n children,\n );\n}\n\nexport function AgeRange({\n data,\n className,\n}: {\n data: {\n t_age: number;\n b_age: number;\n };\n className?: string;\n}) {\n const [_b_age, _t_age, _unit] = getAgeRange(data);\n\n return h(Value, {\n value: formatRange(_b_age, _t_age),\n unit: _unit,\n className,\n });\n}\n\nexport function AgeLabel({\n age,\n maximumFractionDigits = 2,\n minimumFractionDigits = 0,\n className,\n}: {\n age: number;\n className?: string;\n maximumFractionDigits?: number;\n minimumFractionDigits?: number;\n}) {\n /** Component to display a single age value with unit conversion from\n * Ma to ka or Ga as appropriate.\n */\n const [value, unit] = getAge(age);\n\n const _value = value.toLocaleString(\"en-US\", {\n maximumFractionDigits,\n minimumFractionDigits,\n });\n\n return h(Value, { value: _value, unit, className });\n}\n\nexport function Duration({\n value,\n maximumFractionDigits = 2,\n minimumFractionDigits = 0,\n}) {\n let unit = \"Myr\";\n if (value < 0.8) {\n unit = \"kyr\";\n value *= 1000;\n if (value < 5) {\n unit = \"yr\";\n value *= 1000;\n }\n } else if (value > 1000) {\n unit = \"Gyr\";\n value /= 1000;\n }\n\n let _value = value.toLocaleString(\"en-US\", {\n maximumFractionDigits,\n minimumFractionDigits,\n });\n\n return h(Value, { value: _value, unit });\n}\n\ninterface UnitIntervalConstraints {\n b_int_id?: number;\n t_int_id?: number;\n b_prop?: number;\n t_prop?: number;\n b_int_name?: string;\n t_int_name?: string;\n b_age?: number;\n t_age?: number;\n}\n\nexport interface IntervalProportionsProps extends Omit<\n IntervalTagProps,\n \"interval\"\n> {\n unit: UnitIntervalConstraints;\n showProportions?: boolean;\n calculateProportionsFromAges?: boolean;\n}\n\nexport function IntervalProportions({\n unit,\n className,\n showProportions,\n calculateProportionsFromAges = true,\n ...rest\n}: IntervalProportionsProps) {\n /** Display the proportions of the unit that belong to the base and top intervals, if they are different */\n if (unit.b_int_id == null && unit.t_int_id == null) return null;\n\n let _showProps = showProportions;\n\n const i0 = unit.b_int_id;\n const i1 = unit.t_int_id;\n\n /** Get interval information */\n const intervalMap = useMacrostratDefs(\"intervals\");\n const [int0, int1] = useMemo(() => {\n const int0 = intervalMap?.get(i0) ?? {};\n if (i0 === i1) {\n return [int0, int0];\n }\n const int1 = intervalMap?.get(i1) ?? {};\n return [int0, int1];\n }, [intervalMap, i0, i1]);\n\n const interval0: IntervalShort = {\n id: i0,\n name: unit.b_int_name,\n ...int0,\n };\n\n let b_prop = unit.b_prop;\n let t_prop = unit.t_prop;\n\n // If we have b_age and t_age, then we can calculate proportions if they are not given\n if (b_prop == null && unit.b_age != null && calculateProportionsFromAges) {\n b_prop = getProportion(unit.b_age, int0);\n }\n if (t_prop == null && unit.t_age != null && calculateProportionsFromAges) {\n t_prop = getProportion(unit.t_age, int1);\n }\n\n // If there are no proportions given and we are not explicitly directed to show them,\n // then we set them to hidden.\n if (b_prop == null && t_prop == null) {\n _showProps ??= false;\n }\n\n /*\n Set default proportions to 0 and 1 if they are not given,\n so that we can display \"base\" and \"top\" labels\n */\n b_prop ??= 0;\n t_prop ??= 1;\n\n let p0: any = null;\n let p1: any = null;\n\n if (_showProps !== false) {\n p1 = h(Proportion, { value: t_prop });\n\n if (i0 !== i1 || b_prop !== 0 || t_prop !== 1) {\n // We have a single interval with undefined proportions\n p0 = h(Proportion, { value: b_prop });\n }\n\n if (i0 === i1 && (b_prop !== 0 || t_prop !== 1)) {\n p0 = h(\"span.joint-proportion\", [p0, \" \", h(\"span.sep\", \"to\"), \" \", p1]);\n }\n }\n\n return h(\n ItemList,\n { className: classNames(\"interval-proportions\", className) },\n [\n h(IntervalTag, {\n interval: interval0,\n prefix: p0,\n ...rest,\n }),\n h.if(i0 != i1)(\"span.discourage-break\", [\n h(\"span.sep\", \" to \"),\n h(IntervalTag, {\n interval: {\n id: i1,\n name: unit.t_int_name,\n ...int1,\n },\n prefix: p1,\n ...rest,\n }),\n ]),\n ],\n );\n}\n\nfunction getProportion(age: number, interval: IntervalShort): number | null {\n /** Get proportion with the age */\n return (interval.b_age - age) / (interval.b_age - interval.t_age);\n}\n\nfunction Proportion({ value }) {\n let content = null;\n if (value == 0) {\n content = \"base\";\n } else if (value == 1) {\n content = \"top\";\n } else {\n content = formatProportion(value * 100) + \"%\";\n }\n\n return h(\"span.proportion\", content);\n}\n\nexport function getAgeRange(_unit) {\n let b_age = _unit.b_age;\n let t_age = _unit.t_age;\n let unit = \"Ma\";\n\n if (b_age < 0.8 && t_age < 1.2) {\n b_age *= 1000;\n t_age *= 1000;\n unit = \"ka\";\n } else if (b_age > 800 && t_age > 1200) {\n b_age /= 1000;\n t_age /= 1000;\n unit = \"Ga\";\n }\n\n return [b_age, t_age, unit];\n}\n\nexport function getAge(value) {\n /** Get the age value in Ma, ka, or Ga as appropriate */\n let unit = \"Ma\";\n if (value < 0.8) {\n unit = \"ka\";\n value *= 1000;\n if (value < 5) {\n unit = \"yr\";\n value *= 1000;\n }\n } else if (value > 1000) {\n unit = \"Ga\";\n value /= 1000;\n }\n\n return [value, unit];\n}\n"],"names":["int0","int1"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@macrostrat/column-views",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.1",
|
|
4
4
|
"description": "Data views for Macrostrat stratigraphic columns",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
"@macrostrat/api-types": "^1.1.5",
|
|
50
50
|
"@macrostrat/color-utils": "^1.2.1",
|
|
51
51
|
"@macrostrat/column-components": "^2.0.4",
|
|
52
|
-
"@macrostrat/data-components": "^1.1.
|
|
52
|
+
"@macrostrat/data-components": "^1.1.3",
|
|
53
53
|
"@macrostrat/data-provider": "^1.0.1",
|
|
54
54
|
"@macrostrat/hyper": "^3.0.6",
|
|
55
|
-
"@macrostrat/map-interface": "^2.
|
|
55
|
+
"@macrostrat/map-interface": "^2.2.0",
|
|
56
56
|
"@macrostrat/map-styles": "^2.1.0",
|
|
57
|
-
"@macrostrat/mapbox-react": "^3.0
|
|
57
|
+
"@macrostrat/mapbox-react": "^3.1.0",
|
|
58
58
|
"@macrostrat/mapbox-utils": "^1.7.2",
|
|
59
59
|
"@macrostrat/stratigraphy-utils": "^1.2.1",
|
|
60
60
|
"@macrostrat/svg-map-components": "^2.0.1",
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
useMapClickHandler,
|
|
3
3
|
useMapEaseTo,
|
|
4
4
|
useMapStyleOperator,
|
|
5
|
+
useOverlayStyle,
|
|
5
6
|
} from "@macrostrat/mapbox-react";
|
|
6
7
|
import { LngLatBounds, Style } from "mapbox-gl";
|
|
7
8
|
import h from "@macrostrat/hyper";
|
|
@@ -10,7 +11,8 @@ import { ReactNode, useMemo } from "react";
|
|
|
10
11
|
import { setGeoJSON, buildGeoJSONSource } from "@macrostrat/mapbox-utils";
|
|
11
12
|
|
|
12
13
|
import { useCorrelationMapStore } from "./state";
|
|
13
|
-
import {
|
|
14
|
+
import { InsetMap, type InsetMapProps } from "../inset-map";
|
|
15
|
+
import { BaseColumnsLayer } from "../layers";
|
|
14
16
|
import { buildCrossSectionLayers } from "@macrostrat/map-styles";
|
|
15
17
|
|
|
16
18
|
export interface CorrelationMapProps extends InsetMapProps {
|
|
@@ -23,24 +25,15 @@ export interface CorrelationMapProps extends InsetMapProps {
|
|
|
23
25
|
export function ColumnCorrelationMap(props: CorrelationMapProps) {
|
|
24
26
|
const { padding = 50, children, columnColor, projectID, ...rest } = props;
|
|
25
27
|
|
|
26
|
-
const overlayStyles: Partial<Style>[] = useMemo(() => {
|
|
27
|
-
return [
|
|
28
|
-
buildColumnsStyle(columnColor) as Style,
|
|
29
|
-
selectedColumnsStyle as Style,
|
|
30
|
-
lineOfSectionStyle as Style,
|
|
31
|
-
];
|
|
32
|
-
}, [columnColor]);
|
|
33
|
-
|
|
34
28
|
return h(
|
|
35
29
|
InsetMap,
|
|
36
30
|
{
|
|
37
31
|
...rest,
|
|
38
32
|
boxZoom: false,
|
|
39
33
|
dragRotate: false,
|
|
40
|
-
overlayStyles,
|
|
41
34
|
},
|
|
42
35
|
[
|
|
43
|
-
h(ColumnsLayer),
|
|
36
|
+
h(ColumnsLayer, { color: columnColor }),
|
|
44
37
|
h(SelectedColumnsLayer),
|
|
45
38
|
h(MapClickHandler),
|
|
46
39
|
h(SectionLine, { padding }),
|
|
@@ -63,6 +56,8 @@ function MapClickHandler() {
|
|
|
63
56
|
}
|
|
64
57
|
|
|
65
58
|
function SelectedColumnsLayer() {
|
|
59
|
+
useOverlayStyle(() => selectedColumnsStyle, []);
|
|
60
|
+
|
|
66
61
|
const focusedColumns = useCorrelationMapStore(
|
|
67
62
|
(state) => state.focusedColumns,
|
|
68
63
|
);
|
|
@@ -98,25 +93,9 @@ function SelectedColumnsLayer() {
|
|
|
98
93
|
return null;
|
|
99
94
|
}
|
|
100
95
|
|
|
101
|
-
function ColumnsLayer({ enabled = true }) {
|
|
96
|
+
function ColumnsLayer({ enabled = true, color }) {
|
|
102
97
|
const columns = useCorrelationMapStore((state) => state.columns);
|
|
103
|
-
|
|
104
|
-
useMapStyleOperator(
|
|
105
|
-
(map) => {
|
|
106
|
-
if (columns == null) {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
const data: FeatureCollection = {
|
|
110
|
-
type: "FeatureCollection",
|
|
111
|
-
features: columns,
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
console.log(" columns", data);
|
|
115
|
-
setGeoJSON(map, "columns", data);
|
|
116
|
-
},
|
|
117
|
-
[columns, enabled],
|
|
118
|
-
);
|
|
119
|
-
return null;
|
|
98
|
+
return h(BaseColumnsLayer, { enabled, color, columns });
|
|
120
99
|
}
|
|
121
100
|
|
|
122
101
|
const selectedColumnsStyle: Style = {
|
|
@@ -167,6 +146,7 @@ const lineOfSectionStyle: Style = {
|
|
|
167
146
|
};
|
|
168
147
|
|
|
169
148
|
function SectionLine({ padding }: { padding: number }) {
|
|
149
|
+
useOverlayStyle(() => lineOfSectionStyle, []);
|
|
170
150
|
const focusedLine = useCorrelationMapStore((state) => state.focusedLine);
|
|
171
151
|
|
|
172
152
|
// Setup focused line
|
|
@@ -1,21 +1,17 @@
|
|
|
1
|
-
import { useMapStyleOperator } from "@macrostrat/mapbox-react";
|
|
1
|
+
import { useMapRef, useMapStyleOperator } from "@macrostrat/mapbox-react";
|
|
2
2
|
import h from "@macrostrat/hyper";
|
|
3
|
-
import {
|
|
4
|
-
import { ReactNode, useMemo, useRef } from "react";
|
|
5
|
-
import { buildColumnsStyle, InsetMapProps } from "../../_shared";
|
|
6
|
-
import { setGeoJSON } from "@macrostrat/mapbox-utils";
|
|
3
|
+
import { ReactNode, useCallback, useEffect, useMemo, useRef } from "react";
|
|
7
4
|
|
|
8
5
|
import {
|
|
9
6
|
ColumnNavigationProvider,
|
|
10
7
|
NavigationProviderProps,
|
|
11
8
|
useColumnNavigationStore,
|
|
12
9
|
} from "./state";
|
|
13
|
-
import { InsetMap } from "../../
|
|
10
|
+
import { InsetMap, type InsetMapProps } from "../../inset-map";
|
|
14
11
|
import { geoCentroid } from "d3-geo";
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} from "./keyboard-navigation";
|
|
12
|
+
import { BaseColumnsLayer, SelectedColumnOverlay } from "../../layers";
|
|
13
|
+
import { ColumnKeyboardNavigation } from "./keyboard-navigation";
|
|
14
|
+
import type { ColumnFeature } from "../../layers";
|
|
19
15
|
|
|
20
16
|
export interface ColumnNavigationMapProps extends InsetMapProps {
|
|
21
17
|
padding?: number;
|
|
@@ -27,14 +23,18 @@ export interface ColumnNavigationMapProps extends InsetMapProps {
|
|
|
27
23
|
onHoverColumn?: (colID: number | null) => void;
|
|
28
24
|
showTriangulation?: boolean;
|
|
29
25
|
columnColor?: string;
|
|
30
|
-
triangulationColor?: string;
|
|
31
|
-
keyboardNavigation?: boolean;
|
|
32
26
|
}
|
|
33
27
|
|
|
34
28
|
export function ColumnNavigationMap(
|
|
35
29
|
props: ColumnNavigationMapProps & NavigationProviderProps,
|
|
36
30
|
) {
|
|
37
31
|
const {
|
|
32
|
+
padding = 50,
|
|
33
|
+
children,
|
|
34
|
+
columnColor,
|
|
35
|
+
showTriangulation,
|
|
36
|
+
triangulationColor,
|
|
37
|
+
keyboardNavigation = true,
|
|
38
38
|
columns,
|
|
39
39
|
columnIDs,
|
|
40
40
|
onSelectColumn,
|
|
@@ -42,182 +42,235 @@ export function ColumnNavigationMap(
|
|
|
42
42
|
selectedColumn,
|
|
43
43
|
hoveredColumn,
|
|
44
44
|
projectID,
|
|
45
|
-
children,
|
|
46
45
|
inProcess,
|
|
47
46
|
...rest
|
|
48
47
|
} = props;
|
|
49
48
|
|
|
50
|
-
return h(
|
|
51
|
-
ColumnNavigationProvider,
|
|
52
|
-
{
|
|
53
|
-
columns,
|
|
54
|
-
columnIDs,
|
|
55
|
-
onSelectColumn,
|
|
56
|
-
onHoverColumn,
|
|
57
|
-
selectedColumn,
|
|
58
|
-
hoveredColumn,
|
|
59
|
-
projectID,
|
|
60
|
-
inProcess,
|
|
61
|
-
},
|
|
62
|
-
h(_ColumnNavigationMap, props),
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function _ColumnNavigationMap(props: ColumnNavigationMapProps) {
|
|
67
|
-
const {
|
|
68
|
-
padding = 50,
|
|
69
|
-
children,
|
|
70
|
-
columnColor,
|
|
71
|
-
showTriangulation,
|
|
72
|
-
triangulationColor,
|
|
73
|
-
keyboardNavigation = true,
|
|
74
|
-
...rest
|
|
75
|
-
} = props;
|
|
76
|
-
|
|
77
|
-
const overlayStyles = useMemo(() => {
|
|
78
|
-
let styles: any[] = [buildColumnsStyle(columnColor)];
|
|
79
|
-
if (showTriangulation) {
|
|
80
|
-
styles.push(buildKeyboardNavigationStyle(triangulationColor));
|
|
81
|
-
}
|
|
82
|
-
return styles;
|
|
83
|
-
}, [columnColor, showTriangulation, triangulationColor]);
|
|
84
|
-
|
|
85
49
|
return h(
|
|
86
50
|
InsetMap,
|
|
87
51
|
{
|
|
88
52
|
...rest,
|
|
89
53
|
boxZoom: false,
|
|
90
54
|
dragRotate: false,
|
|
91
|
-
overlayStyles,
|
|
92
55
|
},
|
|
93
56
|
[
|
|
94
|
-
h(
|
|
57
|
+
h(ColumnsNavigationLayer, {
|
|
58
|
+
color: columnColor,
|
|
59
|
+
columns,
|
|
60
|
+
columnIDs,
|
|
61
|
+
onSelectColumn,
|
|
62
|
+
onHoverColumn,
|
|
63
|
+
selectedColumn,
|
|
64
|
+
hoveredColumn,
|
|
65
|
+
projectID,
|
|
66
|
+
inProcess,
|
|
67
|
+
keyboardNavigation,
|
|
68
|
+
showTriangulation,
|
|
69
|
+
triangulationColor,
|
|
70
|
+
}),
|
|
95
71
|
children,
|
|
96
|
-
h.if(keyboardNavigation)(ColumnKeyboardNavigation, { showTriangulation }),
|
|
97
72
|
],
|
|
98
73
|
);
|
|
99
74
|
}
|
|
100
75
|
|
|
101
|
-
|
|
76
|
+
interface ColumnLayerProps {
|
|
77
|
+
enabled?: boolean;
|
|
78
|
+
color?: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface ColumnKeyboardNavigationProps {
|
|
82
|
+
triangulationColor?: string;
|
|
83
|
+
keyboardNavigation?: boolean;
|
|
84
|
+
showTriangulation?: boolean;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function ColumnsNavigationLayer(
|
|
88
|
+
props: NavigationProviderProps &
|
|
89
|
+
ColumnLayerProps &
|
|
90
|
+
ColumnKeyboardNavigationProps,
|
|
91
|
+
) {
|
|
92
|
+
const {
|
|
93
|
+
enabled,
|
|
94
|
+
color,
|
|
95
|
+
keyboardNavigation,
|
|
96
|
+
showTriangulation,
|
|
97
|
+
triangulationColor,
|
|
98
|
+
...providerProps
|
|
99
|
+
} = props;
|
|
100
|
+
|
|
101
|
+
return h(ColumnNavigationProvider, providerProps, [
|
|
102
|
+
h(_ColumnsNavigationLayer, { enabled, color }),
|
|
103
|
+
h.if(keyboardNavigation)(ColumnKeyboardNavigation, {
|
|
104
|
+
showTriangulation,
|
|
105
|
+
triangulationColor,
|
|
106
|
+
}),
|
|
107
|
+
]);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const columnLayers = ["columns-points", "columns-fill"];
|
|
111
|
+
|
|
112
|
+
function _ColumnsNavigationLayer({ enabled = true, color }) {
|
|
102
113
|
const columns = useColumnNavigationStore((state) => state.columns);
|
|
103
|
-
const
|
|
114
|
+
const selectedColumnID = useColumnNavigationStore(
|
|
104
115
|
(state) => state.selectedColumn,
|
|
105
116
|
);
|
|
106
|
-
const hoveredColumn = useColumnNavigationStore(
|
|
107
|
-
(state) => state.hoveredColumn,
|
|
108
|
-
);
|
|
109
117
|
const selectColumn = useColumnNavigationStore((state) => state.selectColumn);
|
|
110
118
|
const setHoveredColumn = useColumnNavigationStore(
|
|
111
119
|
(state) => state.setHoveredColumn,
|
|
112
120
|
);
|
|
113
121
|
|
|
122
|
+
const onHover = useCallback(
|
|
123
|
+
(event) => setHoveredColumn(event.features?.[0]?.id),
|
|
124
|
+
[setHoveredColumn],
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
/** Convert features into column IDs to pass to the selection manager */
|
|
128
|
+
const onSelectColumn = useCallback(
|
|
129
|
+
(column) => selectColumn(column.id),
|
|
130
|
+
[selectColumn],
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const selectedColumnFeature = useMemo(() => {
|
|
134
|
+
if (columns == null || selectedColumnID == null) return null;
|
|
135
|
+
return columns.find((d) => d.id == selectedColumnID);
|
|
136
|
+
}, [selectedColumnID, columns]);
|
|
137
|
+
|
|
138
|
+
return h([
|
|
139
|
+
h(BaseColumnsLayer, { enabled, color, columns }),
|
|
140
|
+
h(ColumnSelectionManager, {
|
|
141
|
+
selectedColumn: selectedColumnFeature,
|
|
142
|
+
onSelectColumn,
|
|
143
|
+
}),
|
|
144
|
+
h(ColumnHoverInteraction, { onHover }),
|
|
145
|
+
]);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function ColumnSelectionManager({
|
|
149
|
+
selectedColumn,
|
|
150
|
+
onSelectColumn,
|
|
151
|
+
centerOnSelect = true,
|
|
152
|
+
}: {
|
|
153
|
+
selectedColumn: ColumnFeature;
|
|
154
|
+
onSelectColumn: (column: ColumnFeature) => void;
|
|
155
|
+
centerOnSelect?: boolean;
|
|
156
|
+
}) {
|
|
157
|
+
const onClick = useCallback(
|
|
158
|
+
(event) => {
|
|
159
|
+
if (event.features.length == 0) return;
|
|
160
|
+
const selectedColumn = event.features[0];
|
|
161
|
+
onSelectColumn(selectedColumn);
|
|
162
|
+
},
|
|
163
|
+
[onSelectColumn],
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
return h([
|
|
167
|
+
h.if(centerOnSelect)(SelectedColumnCenterer, {
|
|
168
|
+
selectedColumn,
|
|
169
|
+
}),
|
|
170
|
+
h(SelectedColumnOverlay, { selectedColumn }),
|
|
171
|
+
h(ClickInteraction, {
|
|
172
|
+
onClick,
|
|
173
|
+
layers: columnLayers,
|
|
174
|
+
}),
|
|
175
|
+
]);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function ColumnHoverInteraction({ onHover }) {
|
|
179
|
+
return h(HoverInteraction, { onHover, layers: columnLayers });
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function ClickInteraction({ onClick, layers }) {
|
|
114
183
|
useMapStyleOperator(
|
|
115
184
|
(map) => {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
type: "FeatureCollection",
|
|
121
|
-
features: columns,
|
|
185
|
+
// Setup hover styles on map
|
|
186
|
+
map.on("click", layers, onClick);
|
|
187
|
+
return () => {
|
|
188
|
+
map.off("click", layers, onClick);
|
|
122
189
|
};
|
|
190
|
+
},
|
|
191
|
+
[layers, onClick],
|
|
192
|
+
);
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
123
195
|
|
|
124
|
-
|
|
196
|
+
function HoverInteraction({ onHover, layers }) {
|
|
197
|
+
const hoveredFeaturesRef = useRef([]);
|
|
198
|
+
const updateFeatureState = useCallback((map, features) => {
|
|
199
|
+
// Reset hover state for previously hovered features
|
|
200
|
+
for (const f of hoveredFeaturesRef.current) {
|
|
201
|
+
map.setFeatureState(
|
|
202
|
+
{ source: f.source, id: f.id, sourceLayer: f.sourceLayer },
|
|
203
|
+
{ hover: false },
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
// Set hover state for new features
|
|
207
|
+
for (const f of features) {
|
|
208
|
+
map.setFeatureState(
|
|
209
|
+
{ source: f.source, id: f.id, sourceLayer: f.sourceLayer },
|
|
210
|
+
{ hover: true },
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
hoveredFeaturesRef.current = features;
|
|
214
|
+
}, []);
|
|
125
215
|
|
|
216
|
+
useMapStyleOperator(
|
|
217
|
+
(map) => {
|
|
126
218
|
const mouseMove = (event) => {
|
|
127
219
|
if (event.features.length == 0) return;
|
|
128
|
-
|
|
129
|
-
|
|
220
|
+
onHover?.(event);
|
|
221
|
+
updateFeatureState(map, event.features);
|
|
130
222
|
map.getCanvas().style.cursor = "pointer";
|
|
131
223
|
};
|
|
132
|
-
const mouseLeave = () => {
|
|
133
|
-
|
|
224
|
+
const mouseLeave = (event) => {
|
|
225
|
+
onHover?.(event);
|
|
226
|
+
updateFeatureState(map, event.features ?? []);
|
|
134
227
|
map.getCanvas().style.cursor = "";
|
|
135
228
|
};
|
|
136
229
|
|
|
137
|
-
const clickHandler = (event) => {
|
|
138
|
-
if (event.features.length == 0) return;
|
|
139
|
-
const selectedColumn = event.features[0];
|
|
140
|
-
const id = selectedColumn.id;
|
|
141
|
-
selectColumn(id);
|
|
142
|
-
};
|
|
143
|
-
|
|
144
230
|
// Setup hover styles on map
|
|
145
|
-
const layers = ["columns-points", "columns-fill"];
|
|
146
231
|
map.on("mousemove", layers, mouseMove);
|
|
147
232
|
map.on("mouseleave", layers, mouseLeave);
|
|
148
|
-
map.on("click", layers, clickHandler);
|
|
149
233
|
|
|
150
234
|
return () => {
|
|
151
235
|
map.off("mouseenter", layers, mouseMove);
|
|
152
236
|
map.off("mouseleave", layers, mouseLeave);
|
|
153
|
-
map.off("click", layers, clickHandler);
|
|
154
237
|
};
|
|
155
238
|
},
|
|
156
|
-
[
|
|
239
|
+
[layers, onHover],
|
|
157
240
|
);
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
158
243
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
hoveredColumnRef.current = hoveredColumn;
|
|
172
|
-
// Select the current column
|
|
173
|
-
map.setFeatureState(
|
|
174
|
-
{ source: "columns", id: hoveredColumn },
|
|
175
|
-
{ hover: true },
|
|
176
|
-
);
|
|
177
|
-
},
|
|
178
|
-
[hoveredColumn, columns],
|
|
179
|
-
);
|
|
244
|
+
function SelectedColumnCenterer({
|
|
245
|
+
selectedColumn,
|
|
246
|
+
easeDuration = 500,
|
|
247
|
+
}: {
|
|
248
|
+
selectedColumn: ColumnFeature;
|
|
249
|
+
easeDuration?: number;
|
|
250
|
+
}) {
|
|
251
|
+
const columnCenter = useMemo(() => {
|
|
252
|
+
const columnGeometry = selectedColumn?.geometry;
|
|
253
|
+
if (columnGeometry == null) return null;
|
|
254
|
+
return geoCentroid(columnGeometry);
|
|
255
|
+
}, [selectedColumn]);
|
|
180
256
|
|
|
181
|
-
|
|
182
|
-
const
|
|
257
|
+
const mapRef = useMapRef();
|
|
258
|
+
const map = mapRef.current;
|
|
183
259
|
const initialRenderRef = useRef(true);
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
// Select the current column
|
|
200
|
-
map.setFeatureState(
|
|
201
|
-
{ source: "columns", id: selectedColumn },
|
|
202
|
-
{ selected: true },
|
|
203
|
-
);
|
|
204
|
-
|
|
205
|
-
// Center the selected column
|
|
206
|
-
const columnGeometry = columns.find(
|
|
207
|
-
(d) => d.id == selectedColumn,
|
|
208
|
-
)?.geometry;
|
|
209
|
-
if (columnGeometry == null) return;
|
|
210
|
-
const center = geoCentroid(columnGeometry);
|
|
211
|
-
|
|
212
|
-
const isInitialRender = initialRenderRef.current;
|
|
213
|
-
|
|
214
|
-
map.easeTo({ center }, { duration: isInitialRender ? 0 : 500 });
|
|
215
|
-
if (isInitialRender) {
|
|
216
|
-
initialRenderRef.current = false;
|
|
217
|
-
}
|
|
218
|
-
},
|
|
219
|
-
[selectedColumn, columns],
|
|
220
|
-
);
|
|
260
|
+
// Center the map on the selected column when it changes
|
|
261
|
+
useEffect(() => {
|
|
262
|
+
if (map == null) return;
|
|
263
|
+
const isInitialRender = initialRenderRef.current;
|
|
264
|
+
if (isInitialRender) initialRenderRef.current = false;
|
|
265
|
+
// If this is the first render of the map, jump to the location. Otherwise, ease to it.
|
|
266
|
+
if (columnCenter == null) return;
|
|
267
|
+
if (isInitialRender) {
|
|
268
|
+
map.setCenter(columnCenter);
|
|
269
|
+
initialRenderRef.current = false;
|
|
270
|
+
} else {
|
|
271
|
+
map.easeTo({ center: columnCenter }, { duration: easeDuration });
|
|
272
|
+
}
|
|
273
|
+
}, [mapRef.current, columnCenter]);
|
|
221
274
|
|
|
222
275
|
return null;
|
|
223
276
|
}
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo } from "react";
|
|
2
2
|
import { buildGeoJSONSource, setGeoJSON } from "@macrostrat/mapbox-utils";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
useMapRef,
|
|
5
|
+
useMapStyleOperator,
|
|
6
|
+
useOverlayStyle,
|
|
7
|
+
} from "@macrostrat/mapbox-react";
|
|
4
8
|
import { useColumnNavigationStore } from "./state";
|
|
5
9
|
import {
|
|
6
10
|
buildTriangulation,
|
|
7
11
|
buildKeyMapping,
|
|
8
12
|
} from "../utils/keyboard-navigation";
|
|
13
|
+
import { StyleSpecification } from "mapbox-gl";
|
|
9
14
|
|
|
10
15
|
interface KeyboardNavProps {
|
|
11
16
|
showTriangulation: boolean;
|
|
17
|
+
triangulationColor?: string;
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
export function ColumnKeyboardNavigation(props: KeyboardNavProps) {
|
|
15
21
|
/** Keyboard navigation of columns using a Delaunay triangulation */
|
|
16
|
-
const { showTriangulation = false } = props;
|
|
22
|
+
const { showTriangulation = false, triangulationColor } = props;
|
|
17
23
|
const columns = useColumnNavigationStore((state) => state.columns);
|
|
18
24
|
const col_id = useColumnNavigationStore((state) => state.selectedColumn);
|
|
19
25
|
const selectColumn = useColumnNavigationStore((state) => state.selectColumn);
|
|
@@ -26,6 +32,14 @@ export function ColumnKeyboardNavigation(props: KeyboardNavProps) {
|
|
|
26
32
|
const mapRef = useMapRef();
|
|
27
33
|
const map = mapRef.current;
|
|
28
34
|
|
|
35
|
+
// Set up overlay style for triangulation
|
|
36
|
+
useOverlayStyle(() => {
|
|
37
|
+
if (!showTriangulation) return null;
|
|
38
|
+
return buildKeyboardNavigationStyle(
|
|
39
|
+
triangulationColor,
|
|
40
|
+
) as Partial<StyleSpecification>;
|
|
41
|
+
}, [triangulationColor, showTriangulation]);
|
|
42
|
+
|
|
29
43
|
const keyMapping = useMemo(() => {
|
|
30
44
|
if (columns == null || voronoi == null || map == null) return null;
|
|
31
45
|
|
|
@@ -115,5 +129,5 @@ export function buildKeyboardNavigationStyle(color: string = "purple") {
|
|
|
115
129
|
},
|
|
116
130
|
},
|
|
117
131
|
],
|
|
118
|
-
}
|
|
132
|
+
} as Partial<StyleSpecification>;
|
|
119
133
|
}
|
package/src/maps/index.ts
CHANGED