@macrostrat/column-views 3.2.2 → 3.3.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 (65) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/index.cjs +15 -9
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.js +11 -5
  5. package/dist/maps/column-correlation/core.cjs +10 -30
  6. package/dist/maps/column-correlation/core.cjs.map +1 -1
  7. package/dist/maps/column-correlation/core.d.ts +1 -1
  8. package/dist/maps/column-correlation/core.js +10 -30
  9. package/dist/maps/column-correlation/core.js.map +1 -1
  10. package/dist/maps/column-navigation/mapbox/index.cjs +156 -118
  11. package/dist/maps/column-navigation/mapbox/index.cjs.map +1 -1
  12. package/dist/maps/column-navigation/mapbox/index.d.ts +23 -2
  13. package/dist/maps/column-navigation/mapbox/index.js +158 -120
  14. package/dist/maps/column-navigation/mapbox/index.js.map +1 -1
  15. package/dist/maps/column-navigation/mapbox/keyboard-navigation.cjs +7 -1
  16. package/dist/maps/column-navigation/mapbox/keyboard-navigation.cjs.map +1 -1
  17. package/dist/maps/column-navigation/mapbox/keyboard-navigation.d.ts +3 -26
  18. package/dist/maps/column-navigation/mapbox/keyboard-navigation.js +9 -3
  19. package/dist/maps/column-navigation/mapbox/keyboard-navigation.js.map +1 -1
  20. package/dist/maps/index.d.ts +2 -2
  21. package/dist/maps/{_shared/inset-map.cjs → inset-map/index.cjs} +1 -1
  22. package/dist/maps/inset-map/index.cjs.map +1 -0
  23. package/dist/maps/{_shared/inset-map.js → inset-map/index.js} +1 -1
  24. package/dist/maps/inset-map/index.js.map +1 -0
  25. package/dist/maps/layers/columns.cjs +161 -0
  26. package/dist/maps/layers/columns.cjs.map +1 -0
  27. package/dist/maps/layers/columns.d.ts +28 -0
  28. package/dist/maps/layers/columns.js +161 -0
  29. package/dist/maps/layers/columns.js.map +1 -0
  30. package/dist/maps/layers/index.d.ts +2 -0
  31. package/dist/maps/{units-overlay/index.cjs → layers/units.cjs} +41 -88
  32. package/dist/maps/layers/units.cjs.map +1 -0
  33. package/dist/maps/{units-overlay/index.d.ts → layers/units.d.ts} +1 -1
  34. package/dist/maps/{units-overlay/index.js → layers/units.js} +34 -82
  35. package/dist/maps/layers/units.js.map +1 -0
  36. package/dist/unit-details/age-range.cjs +87 -44
  37. package/dist/unit-details/age-range.cjs.map +1 -1
  38. package/dist/unit-details/age-range.d.ts +32 -5
  39. package/dist/unit-details/age-range.js +85 -44
  40. package/dist/unit-details/age-range.js.map +1 -1
  41. package/package.json +4 -4
  42. package/src/maps/column-correlation/core.ts +9 -29
  43. package/src/maps/column-navigation/mapbox/index.ts +191 -138
  44. package/src/maps/column-navigation/mapbox/keyboard-navigation.ts +17 -3
  45. package/src/maps/index.ts +2 -2
  46. package/src/maps/layers/columns.ts +210 -0
  47. package/src/maps/layers/index.ts +2 -0
  48. package/src/maps/{units-overlay/index.ts → layers/units.ts} +34 -84
  49. package/src/maps/unit-map.stories.ts +27 -12
  50. package/src/unit-details/age-range.ts +125 -47
  51. package/dist/maps/_shared/index.d.ts +0 -2
  52. package/dist/maps/_shared/inset-map.cjs.map +0 -1
  53. package/dist/maps/_shared/inset-map.js.map +0 -1
  54. package/dist/maps/_shared/styles.cjs +0 -73
  55. package/dist/maps/_shared/styles.cjs.map +0 -1
  56. package/dist/maps/_shared/styles.d.ts +0 -2
  57. package/dist/maps/_shared/styles.js +0 -73
  58. package/dist/maps/_shared/styles.js.map +0 -1
  59. package/dist/maps/units-overlay/index.cjs.map +0 -1
  60. package/dist/maps/units-overlay/index.js.map +0 -1
  61. package/src/maps/_shared/index.ts +0 -2
  62. package/src/maps/_shared/styles.ts +0 -76
  63. /package/dist/maps/{_shared/inset-map.d.ts → inset-map/index.d.ts} +0 -0
  64. /package/src/maps/{_shared/inset-map.ts → inset-map/index.ts} +0 -0
  65. /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 [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 },\n children,\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\nexport function IntervalProportions({ unit, onClickItem }) {\n /** Display the proportions of the unit that belong to the base and top intervals, if they are different */\n if (\n unit.b_int_id == null &&\n unit.t_int_id == null &&\n unit.b_prop == null &&\n unit.t_prop == null\n )\n return null;\n\n const i0 = unit.b_int_id;\n const i1 = unit.t_int_id;\n let b_prop = unit.b_prop ?? 0;\n let t_prop = unit.t_prop ?? 1;\n\n const intervalMap = useMacrostratDefs(\"intervals\");\n const int0 = intervalMap?.get(i0) ?? {};\n\n const interval0: IntervalShort = {\n ...int0,\n id: i0,\n name: unit.b_int_name,\n };\n\n let p0: any = null;\n const int1 = intervalMap?.get(i1) ?? {};\n const p1: any = 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 const clickable = onClickItem != null;\n\n const handleClick = (event: MouseEvent) => {\n if (onClickItem) {\n onClickItem(event, interval0);\n }\n };\n\n return h(ItemList, { className: \"interval-proportions\" }, [\n h(IntervalTag, {\n className: clickable ? \"clickable\" : \"\",\n onClick: clickable ? handleClick : undefined,\n interval: interval0,\n prefix: p0,\n }),\n h.if(i0 != i1)(\"span.discourage-break\", [\n h(\"span.sep\", \" to \"),\n h(IntervalTag, {\n className: clickable ? \"clickable\" : \"\",\n onClick: clickable ? handleClick : undefined,\n interval: {\n ...int1,\n id: i1,\n name: unit.t_int_name,\n },\n prefix: p1,\n }),\n ]),\n ]);\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":[],"mappings":"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"}
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 console.log(age, interval);\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.2.2",
3
+ "version": "3.3.0",
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.2",
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.1.0",
55
+ "@macrostrat/map-interface": "^2.2.0",
56
56
  "@macrostrat/map-styles": "^2.1.0",
57
- "@macrostrat/mapbox-react": "^3.0.2",
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 { buildColumnsStyle, InsetMap, InsetMapProps } from "../_shared";
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 { FeatureCollection } from "geojson";
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 "../../_shared";
10
+ import { InsetMap, type InsetMapProps } from "../../inset-map";
14
11
  import { geoCentroid } from "d3-geo";
15
- import {
16
- ColumnKeyboardNavigation,
17
- buildKeyboardNavigationStyle,
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(ColumnsLayer),
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
- function ColumnsLayer({ enabled = true }) {
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 selectedColumn = useColumnNavigationStore(
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
- if (columns == null) {
117
- return;
118
- }
119
- const data: FeatureCollection = {
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
- setGeoJSON(map, "columns", data);
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
- const hoveredFeature = event.features[0];
129
- setHoveredColumn(hoveredFeature.id);
220
+ onHover?.(event);
221
+ updateFeatureState(map, event.features);
130
222
  map.getCanvas().style.cursor = "pointer";
131
223
  };
132
- const mouseLeave = () => {
133
- setHoveredColumn(null);
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
- [columns, enabled],
239
+ [layers, onHover],
157
240
  );
241
+ return null;
242
+ }
158
243
 
159
- const hoveredColumnRef = useRef(null);
160
- useMapStyleOperator(
161
- (map) => {
162
- const prevHoveredColumn = hoveredColumnRef.current;
163
- if (hoveredColumn == prevHoveredColumn) return;
164
- if (prevHoveredColumn != null) {
165
- // Deselect previous column
166
- map.setFeatureState(
167
- { source: "columns", id: prevHoveredColumn },
168
- { hover: false },
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
- /** Set feature state for selected columns */
182
- const selectedColumnRef = useRef(null);
257
+ const mapRef = useMapRef();
258
+ const map = mapRef.current;
183
259
  const initialRenderRef = useRef(true);
184
- useMapStyleOperator(
185
- (map) => {
186
- if (columns == null) return;
187
- const prevSelectedColumn = selectedColumnRef.current;
188
- if (selectedColumn == prevSelectedColumn) return;
189
- if (prevSelectedColumn != null) {
190
- // Deselect previous column
191
- map.setFeatureState(
192
- { source: "columns", id: prevSelectedColumn },
193
- { selected: false },
194
- );
195
- }
196
-
197
- selectedColumnRef.current = selectedColumn;
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 { useMapRef, useMapStyleOperator } from "@macrostrat/mapbox-react";
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
@@ -1,4 +1,4 @@
1
1
  export * from "./column-navigation";
2
2
  export * from "./column-correlation";
3
- export * from "./_shared";
4
- export * from "./units-overlay";
3
+ export * from "./inset-map";
4
+ export * from "./layers";