@macrostrat/column-views 3.9.0 → 3.10.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 (118) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/index.cjs +15 -42
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.ts +2 -1
  5. package/dist/index.js +1 -34
  6. package/dist/index.js.map +1 -1
  7. package/dist/units/boxes.cjs +3 -3
  8. package/dist/units/boxes.cjs.map +1 -1
  9. package/dist/units/boxes.js +3 -3
  10. package/dist/units/boxes.js.map +1 -1
  11. package/dist/units/index.cjs +7 -11
  12. package/dist/units/index.cjs.map +1 -1
  13. package/dist/units/index.d.ts +0 -1
  14. package/dist/units/index.js +4 -9
  15. package/dist/units/index.js.map +1 -1
  16. package/package.json +6 -27
  17. package/src/index.ts +3 -1
  18. package/src/units/boxes.ts +7 -4
  19. package/src/units/index.ts +9 -26
  20. package/dist/maps/column-correlation/core.cjs +0 -288
  21. package/dist/maps/column-correlation/core.cjs.map +0 -1
  22. package/dist/maps/column-correlation/core.d.ts +0 -9
  23. package/dist/maps/column-correlation/core.js +0 -286
  24. package/dist/maps/column-correlation/core.js.map +0 -1
  25. package/dist/maps/column-correlation/index.d.ts +0 -2
  26. package/dist/maps/column-correlation/state.cjs +0 -193
  27. package/dist/maps/column-correlation/state.cjs.map +0 -1
  28. package/dist/maps/column-correlation/state.d.ts +0 -62
  29. package/dist/maps/column-correlation/state.js +0 -190
  30. package/dist/maps/column-correlation/state.js.map +0 -1
  31. package/dist/maps/column-navigation/index.d.ts +0 -2
  32. package/dist/maps/column-navigation/mapbox/index.cjs +0 -215
  33. package/dist/maps/column-navigation/mapbox/index.cjs.map +0 -1
  34. package/dist/maps/column-navigation/mapbox/index.d.ts +0 -38
  35. package/dist/maps/column-navigation/mapbox/index.js +0 -213
  36. package/dist/maps/column-navigation/mapbox/index.js.map +0 -1
  37. package/dist/maps/column-navigation/mapbox/keyboard-navigation.cjs +0 -105
  38. package/dist/maps/column-navigation/mapbox/keyboard-navigation.cjs.map +0 -1
  39. package/dist/maps/column-navigation/mapbox/keyboard-navigation.d.ts +0 -8
  40. package/dist/maps/column-navigation/mapbox/keyboard-navigation.js +0 -105
  41. package/dist/maps/column-navigation/mapbox/keyboard-navigation.js.map +0 -1
  42. package/dist/maps/column-navigation/mapbox/state.cjs +0 -73
  43. package/dist/maps/column-navigation/mapbox/state.cjs.map +0 -1
  44. package/dist/maps/column-navigation/mapbox/state.d.ts +0 -23
  45. package/dist/maps/column-navigation/mapbox/state.js +0 -71
  46. package/dist/maps/column-navigation/mapbox/state.js.map +0 -1
  47. package/dist/maps/column-navigation/svg/animated.d.ts +0 -1
  48. package/dist/maps/column-navigation/svg/data-fetcher.cjs +0 -25
  49. package/dist/maps/column-navigation/svg/data-fetcher.cjs.map +0 -1
  50. package/dist/maps/column-navigation/svg/data-fetcher.d.ts +0 -6
  51. package/dist/maps/column-navigation/svg/data-fetcher.js +0 -25
  52. package/dist/maps/column-navigation/svg/data-fetcher.js.map +0 -1
  53. package/dist/maps/column-navigation/svg/index.cjs +0 -94
  54. package/dist/maps/column-navigation/svg/index.cjs.map +0 -1
  55. package/dist/maps/column-navigation/svg/index.d.ts +0 -9
  56. package/dist/maps/column-navigation/svg/index.js +0 -93
  57. package/dist/maps/column-navigation/svg/index.js.map +0 -1
  58. package/dist/maps/column-navigation/svg/layers.cjs +0 -177
  59. package/dist/maps/column-navigation/svg/layers.cjs.map +0 -1
  60. package/dist/maps/column-navigation/svg/layers.d.ts +0 -54
  61. package/dist/maps/column-navigation/svg/layers.js +0 -174
  62. package/dist/maps/column-navigation/svg/layers.js.map +0 -1
  63. package/dist/maps/column-navigation/utils/keyboard-navigation.cjs +0 -50
  64. package/dist/maps/column-navigation/utils/keyboard-navigation.cjs.map +0 -1
  65. package/dist/maps/column-navigation/utils/keyboard-navigation.d.ts +0 -10
  66. package/dist/maps/column-navigation/utils/keyboard-navigation.js +0 -50
  67. package/dist/maps/column-navigation/utils/keyboard-navigation.js.map +0 -1
  68. package/dist/maps/index.d.ts +0 -4
  69. package/dist/maps/inset-map/index.cjs +0 -71
  70. package/dist/maps/inset-map/index.cjs.map +0 -1
  71. package/dist/maps/inset-map/index.d.ts +0 -16
  72. package/dist/maps/inset-map/index.js +0 -69
  73. package/dist/maps/inset-map/index.js.map +0 -1
  74. package/dist/maps/layers/columns.cjs +0 -165
  75. package/dist/maps/layers/columns.cjs.map +0 -1
  76. package/dist/maps/layers/columns.d.ts +0 -28
  77. package/dist/maps/layers/columns.js +0 -165
  78. package/dist/maps/layers/columns.js.map +0 -1
  79. package/dist/maps/layers/index.d.ts +0 -2
  80. package/dist/maps/layers/units.cjs +0 -207
  81. package/dist/maps/layers/units.cjs.map +0 -1
  82. package/dist/maps/layers/units.d.ts +0 -14
  83. package/dist/maps/layers/units.js +0 -204
  84. package/dist/maps/layers/units.js.map +0 -1
  85. package/dist/units/colors.cjs +0 -115
  86. package/dist/units/colors.cjs.map +0 -1
  87. package/dist/units/colors.d.ts +0 -20
  88. package/dist/units/colors.js +0 -113
  89. package/dist/units/colors.js.map +0 -1
  90. package/dist/units/resolvers.cjs +0 -125
  91. package/dist/units/resolvers.cjs.map +0 -1
  92. package/dist/units/resolvers.d.ts +0 -8
  93. package/dist/units/resolvers.js +0 -125
  94. package/dist/units/resolvers.js.map +0 -1
  95. package/src/maps/column-correlation/column-correlation-map.stories.ts +0 -108
  96. package/src/maps/column-correlation/core.ts +0 -342
  97. package/src/maps/column-correlation/index.ts +0 -2
  98. package/src/maps/column-correlation/state.ts +0 -315
  99. package/src/maps/column-navigation/index.ts +0 -2
  100. package/src/maps/column-navigation/mapbox/column-navigation-map.stories.ts +0 -278
  101. package/src/maps/column-navigation/mapbox/index.ts +0 -276
  102. package/src/maps/column-navigation/mapbox/keyboard-navigation.ts +0 -133
  103. package/src/maps/column-navigation/mapbox/state.ts +0 -119
  104. package/src/maps/column-navigation/svg/animated.ts +0 -78
  105. package/src/maps/column-navigation/svg/column-navigation-svg-map.stories.ts +0 -46
  106. package/src/maps/column-navigation/svg/data-fetcher.ts +0 -34
  107. package/src/maps/column-navigation/svg/index.ts +0 -96
  108. package/src/maps/column-navigation/svg/layers.ts +0 -233
  109. package/src/maps/column-navigation/utils/keyboard-navigation.ts +0 -58
  110. package/src/maps/index.ts +0 -4
  111. package/src/maps/inset-map/index.ts +0 -87
  112. package/src/maps/inset-map/inset-map.stories.ts +0 -20
  113. package/src/maps/layers/columns.ts +0 -216
  114. package/src/maps/layers/index.ts +0 -2
  115. package/src/maps/layers/units.ts +0 -286
  116. package/src/maps/unit-map.stories.ts +0 -79
  117. package/src/units/colors.ts +0 -183
  118. package/src/units/resolvers.ts +0 -141
@@ -1,96 +0,0 @@
1
- import { useRef } from "react";
2
- import h from "@macrostrat/hyper";
3
- import { Globe, LandLayer } from "@macrostrat/svg-map-components";
4
- import { geoCentroid } from "d3-geo";
5
- import { useElementSize } from "@macrostrat/ui-components";
6
- import { Columns, CurrentColumn } from "./layers";
7
- import type { LngLatLike } from "mapbox-gl";
8
-
9
- export function ResizableMapFrame(props) {
10
- const { center, children, style, margin, className, allowZoom, ...rest } =
11
- props;
12
- let { scale } = props;
13
- const ref = useRef(null);
14
- const sz = useElementSize(ref);
15
- const { width, height } = sz ?? { width: 0, height: 0 };
16
- if (scale == null) {
17
- scale = Math.min(width, height) + 2 * margin;
18
- }
19
-
20
- let zoomScaleExtent = null;
21
-
22
- if (allowZoom) {
23
- zoomScaleExtent = [
24
- 0.1 * Math.min(width, height),
25
- 2 * Math.max(width, height),
26
- ];
27
- }
28
-
29
- return h("div.map-area", { ref, style, className }, [
30
- h(
31
- Globe,
32
- {
33
- width,
34
- height,
35
- margin,
36
- center,
37
- allowDrag: true,
38
- allowZoom,
39
- keepNorthUp: true,
40
- zoomScaleExtent,
41
- ...rest,
42
- scale,
43
- },
44
- [h(LandLayer), children],
45
- ),
46
- ]);
47
- }
48
-
49
- type ColumnNavigationSVGMapProps = any;
50
- export type { ColumnNavigationSVGMapProps };
51
-
52
- export function ColumnNavigationSVGMap(props) {
53
- const {
54
- currentColumn,
55
- setCurrentColumn,
56
- children,
57
- style,
58
- margin = 10,
59
- scale,
60
- className,
61
- showInProcessColumns = false,
62
- showDebugLayers = false,
63
- center,
64
- ...rest
65
- } = props;
66
-
67
- let _center: LngLatLike | null = center ?? [-100, 38];
68
- // Override center if currentColumn is set
69
- if (currentColumn != null) {
70
- _center = geoCentroid(currentColumn);
71
- }
72
-
73
- return h(
74
- ResizableMapFrame,
75
- { center: _center, style, margin, scale, className },
76
- [
77
- children,
78
- h(Columns, {
79
- onChange: setCurrentColumn,
80
- col_id: currentColumn?.properties.col_id,
81
- showDebugLayers,
82
- ...rest,
83
- }),
84
- h.if(showInProcessColumns)(Columns, {
85
- onChange: setCurrentColumn,
86
- col_id: currentColumn?.properties.col_id,
87
- status_code: "in process",
88
- color: "rgba(200,150,150, 0.5)",
89
- ...rest,
90
- }),
91
- h.if(currentColumn != null)(CurrentColumn, { feature: currentColumn }),
92
- ],
93
- );
94
- }
95
-
96
- export * from "./layers";
@@ -1,233 +0,0 @@
1
- import h from "@macrostrat/hyper";
2
- import {
3
- Feature,
4
- FeatureLayer,
5
- MapContext,
6
- } from "@macrostrat/svg-map-components";
7
- import { useAPIResult, useKeyHandler } from "@macrostrat/ui-components";
8
- import chroma from "chroma-js";
9
- import { ExtendedFeature } from "d3-geo";
10
- import { Polygon } from "geojson";
11
- import { useContext, useMemo } from "react";
12
- import { useColumnFeatures } from "./data-fetcher";
13
- import {
14
- buildKeyMapping,
15
- buildTriangulation,
16
- } from "../utils/keyboard-navigation";
17
-
18
- const defaultStyle = {
19
- fill: "rgb(239, 180, 249)",
20
- stroke: "magenta",
21
- };
22
-
23
- export function MeasurementsLayer(props) {
24
- const { style = defaultStyle, ...params } = props;
25
- const res: any = useAPIResult("/measurements", {
26
- ...params,
27
- format: "geojson",
28
- response: "light",
29
- });
30
- if (res == null) return null;
31
-
32
- return h(FeatureLayer, {
33
- useCanvas: false,
34
- style,
35
- features: res.features?.filter((d) => d.properties.unit_id != null) ?? [],
36
- });
37
- }
38
-
39
- type ColumnProps = { col_id: number };
40
-
41
- type ColumnFeature = ExtendedFeature<Polygon, ColumnProps>;
42
-
43
- function ColumnFeatures(props) {
44
- const {
45
- features,
46
- onClick,
47
- color = "rgba(150,150,150, 1)",
48
- singleFeature = true,
49
- } = props;
50
-
51
- const c = chroma(color);
52
-
53
- return h(
54
- FeatureLayer,
55
- {
56
- className: "columns",
57
- useCanvas: onClick == null,
58
- style: {
59
- fill: c.alpha(0.2).css(),
60
- stroke: c.alpha(0.4).css(),
61
- },
62
- },
63
- features?.map((f) => {
64
- return h(Feature, {
65
- id: f.id ?? f.properties.col_id,
66
- onClick,
67
- feature: f,
68
- });
69
- }),
70
- );
71
- }
72
-
73
- enum MacrostratStatusCode {
74
- InProcess = "in process",
75
- }
76
-
77
- interface ColumnNavProps {
78
- col_id: number;
79
- status_code?: MacrostratStatusCode;
80
- project_id?: number;
81
- onChange(col_id: number): void;
82
- }
83
-
84
- interface KeyboardNavProps extends ColumnNavProps {
85
- features: ColumnFeature[];
86
- showLayers: boolean;
87
- }
88
-
89
- function ColumnKeyboardNavigation(props: KeyboardNavProps) {
90
- /** Keyboard navigation of columns using a Delaunay triangulation */
91
- const {
92
- features = [],
93
- col_id = null,
94
- onChange,
95
- showLayers = false,
96
- ...projectArgs
97
- } = props;
98
- const { projection } = useContext(MapContext);
99
- const { centroids, tri } = useMemo(
100
- () => buildTriangulation(features),
101
- [features],
102
- );
103
-
104
- const currentIndex = useMemo(() => {
105
- return features.findIndex((d) => d.properties.col_id == col_id);
106
- }, [features, col_id]);
107
-
108
- const neighbors = tri.delaunay.neighbors[currentIndex];
109
-
110
- const keyMapping = useMemo(() => {
111
- return buildKeyMapping(neighbors, centroids, currentIndex, projection);
112
- }, [neighbors, currentIndex]);
113
-
114
- useKeyHandler(
115
- (event) => {
116
- const nextColumnIx = keyMapping[event.keyCode];
117
- if (nextColumnIx == null) return;
118
- // @ts-ignore
119
- onChange(features[nextColumnIx]);
120
- },
121
- [keyMapping],
122
- );
123
-
124
- if (neighbors == null) return null;
125
- const neighborFeatures = neighbors.map((d) => features[d]);
126
-
127
- return h.if(showLayers)([
128
- h(FeatureLayer, {
129
- features: tri.links().features,
130
- useCanvas: false,
131
- style: {
132
- stroke: "purple",
133
- fill: "transparent",
134
- },
135
- }),
136
- h(FeatureLayer, {
137
- features: neighborFeatures,
138
- useCanvas: false,
139
- style: {
140
- stroke: "rgb(93, 101, 212)",
141
- strokeWidth: 3,
142
- fill: "rgba(93, 101, 212, 0.5)",
143
- },
144
- }),
145
- h(FeatureLayer, {
146
- features: [
147
- {
148
- type: "Feature",
149
- geometry: {
150
- type: "MultiPoint",
151
- coordinates: centroids,
152
- },
153
- },
154
- ],
155
- useCanvas: false,
156
- style: {
157
- r: 1,
158
- fill: "purple",
159
- },
160
- }),
161
- ]);
162
- }
163
-
164
- interface ColumnExtraInfo {
165
- apiRoute?: string;
166
- color?: string;
167
- filterColumns?(d: ColumnFeature): boolean;
168
- showDebugLayers?: boolean;
169
- format?: "topojson" | "geojson";
170
- }
171
-
172
- const Columns = (props: ColumnNavProps & ColumnExtraInfo) => {
173
- const {
174
- apiRoute = "/columns",
175
- onChange,
176
- col_id = null,
177
- status_code,
178
- project_id,
179
- color,
180
- filterColumns,
181
- showDebugLayers = false,
182
- format = "topojson",
183
- } = props;
184
-
185
- let features: any[] = useColumnFeatures({
186
- apiRoute,
187
- status_code,
188
- project_id,
189
- format,
190
- }) as any;
191
-
192
- if (features == null) return null;
193
-
194
- if (filterColumns != null) {
195
- features = features.filter(filterColumns);
196
- }
197
-
198
- return h([
199
- h(ColumnKeyboardNavigation, {
200
- features,
201
- col_id,
202
- onChange,
203
- status_code,
204
- project_id,
205
- showLayers: showDebugLayers,
206
- }),
207
- h(ColumnFeatures, { features, onClick: onChange, color }),
208
- ]);
209
- };
210
-
211
- const ColumnCenters = (props: ColumnNavProps) => {
212
- return h(Columns, { apiRoute: "/defs/columns", ...props });
213
- };
214
-
215
- const CurrentColumn = (props) => {
216
- const { feature } = props;
217
- return h(FeatureLayer, {
218
- features: [feature],
219
- style: {
220
- fill: "rgba(255,0,0,0.4)",
221
- stroke: "rgba(255,0,0,0.6)",
222
- strokeWidth: 2,
223
- },
224
- });
225
- };
226
-
227
- export {
228
- Columns,
229
- CurrentColumn,
230
- ColumnCenters,
231
- ColumnFeatures,
232
- ColumnKeyboardNavigation,
233
- };
@@ -1,58 +0,0 @@
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
- }
package/src/maps/index.ts DELETED
@@ -1,4 +0,0 @@
1
- export * from "./column-navigation";
2
- export * from "./column-correlation";
3
- export * from "./inset-map";
4
- export * from "./layers";
@@ -1,87 +0,0 @@
1
- import { useCallback, useMemo } from "react";
2
- import {
3
- MapView,
4
- getBasicMapStyle,
5
- MapViewProps,
6
- } from "@macrostrat/map-interface";
7
- import h from "@macrostrat/hyper";
8
- import { MapboxMapProvider } from "@macrostrat/mapbox-react";
9
- import { useInDarkMode } from "@macrostrat/ui-components";
10
- import {
11
- removeMapLabels,
12
- removeSourceFromStyle,
13
- } from "@macrostrat/mapbox-utils";
14
- import type { ReactNode, CSSProperties } from "react";
15
-
16
- export interface InsetMapProps extends Omit<MapViewProps, "style"> {
17
- controls?: ReactNode;
18
- className?: string;
19
- children?: ReactNode;
20
- style?: CSSProperties;
21
- mapStyle?: mapboxgl.Style | string;
22
- showLabels?: boolean;
23
- showAdmin?: boolean;
24
- showRoads?: boolean;
25
- }
26
-
27
- export function InsetMap({
28
- controls,
29
- className,
30
- children,
31
- style,
32
- mapStyle,
33
- accessToken,
34
- showLabels = false,
35
- showAdmin = false,
36
- showRoads = false,
37
- ...rest
38
- }: InsetMapProps) {
39
- const inDarkMode = useInDarkMode();
40
- const _style = useMemo((): mapboxgl.Style | string => {
41
- return mapStyle ?? getBasicMapStyle({ inDarkMode });
42
- }, [mapStyle, inDarkMode]);
43
-
44
- const transformStyle = useCallback(
45
- (style) => {
46
- let newStyle = style;
47
- if (!showLabels) {
48
- newStyle = removeMapLabels(newStyle);
49
- }
50
- if (!showAdmin) {
51
- newStyle = removeSourceFromStyle(newStyle, null, "admin");
52
- }
53
- if (!showRoads) {
54
- newStyle = removeSourceFromStyle(newStyle, null, "road");
55
- newStyle = removeSourceFromStyle(newStyle, null, "aeroway");
56
- }
57
- return newStyle;
58
- },
59
- [mapStyle, showLabels, showRoads, showAdmin],
60
- );
61
-
62
- return h("div.inset-map", { className, style }, [
63
- h(MapboxMapProvider, [
64
- controls,
65
- h(
66
- MapView,
67
- {
68
- style: _style,
69
- accessToken,
70
- standalone: true,
71
- /* Default map position that centers on the bulk of Macrostrat columns
72
- */
73
- mapPosition: {
74
- camera: {
75
- lng: -100,
76
- lat: 38,
77
- altitude: 5000000,
78
- },
79
- },
80
- transformStyle,
81
- ...rest,
82
- },
83
- children,
84
- ),
85
- ]),
86
- ]);
87
- }
@@ -1,20 +0,0 @@
1
- import h from "@macrostrat/hyper";
2
-
3
- const mapboxToken = import.meta.env.VITE_MAPBOX_API_TOKEN;
4
-
5
- import { Meta } from "@storybook/react-vite";
6
- import { InsetMap } from ".";
7
-
8
- // More on default export: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
9
- export default {
10
- title: "Column views/Maps/Inset map",
11
- component: InsetMap,
12
- description: "A basic inset map",
13
- } as Meta<typeof InsetMap>;
14
-
15
- export function BasicInsetMap() {
16
- return h(InsetMap, {
17
- style: { width: "800px", height: "600px" },
18
- accessToken: mapboxToken,
19
- });
20
- }
@@ -1,216 +0,0 @@
1
- import { useMapStyleOperator, useOverlayStyle } from "@macrostrat/mapbox-react";
2
- import { setGeoJSON } from "@macrostrat/mapbox-utils";
3
- import GeoJSON, { FeatureCollection } from "geojson";
4
- import { GeoJSONFeature } from "mapbox-gl";
5
- import { getCSSVariable } from "@macrostrat/color-utils";
6
- import { buildGeoJSONSource } from "@macrostrat/mapbox-utils";
7
- import { StyleFragment } from "@macrostrat/mapbox-react";
8
-
9
- export interface ColumnsStyleOptions {
10
- color?: string | any[];
11
- selectedColor?: string | any[];
12
- opacity?: number | any[];
13
- circleRadius?: number | any[];
14
- lineOpacity?: number | any[];
15
- lineWidth?: number | any[];
16
- lineColor?: string | any[];
17
- }
18
-
19
- interface ColumnLayerOptions extends ColumnsStyleOptions {
20
- enabled: boolean;
21
- columns: FeatureCollection | GeoJSONFeature[];
22
- }
23
-
24
- export function BaseColumnsLayer({
25
- enabled = true,
26
- columns,
27
- ...rest
28
- }: ColumnLayerOptions) {
29
- useOverlayStyle(() => (enabled ? buildColumnsStyle(rest) : null), [enabled]);
30
-
31
- useMapStyleOperator(
32
- (map) => {
33
- if (columns == null) {
34
- return;
35
- }
36
-
37
- setGeoJSON(map, "columns", promoteToFeatureCollection(columns));
38
- },
39
- [columns, enabled],
40
- );
41
- return null;
42
- }
43
-
44
- function promoteToFeatureCollection(
45
- data: FeatureCollection | GeoJSONFeature | GeoJSONFeature[] | null,
46
- ): FeatureCollection | null {
47
- if (data == null) return null;
48
- if ("type" in data && data.type == "Feature") {
49
- return {
50
- type: "FeatureCollection",
51
- features: [data],
52
- };
53
- }
54
- if (
55
- "type" in data &&
56
- data.type == "FeatureCollection" &&
57
- "features" in data
58
- ) {
59
- return data;
60
- }
61
- return {
62
- type: "FeatureCollection",
63
- features: data,
64
- };
65
- }
66
-
67
- export function buildColumnsStyle(
68
- opts: ColumnsStyleOptions = {},
69
- ): StyleFragment {
70
- const { color } = opts;
71
- const columnBaseColor =
72
- color ?? getCSSVariable("--text-subtle-color", "black");
73
- let columnColor: any = columnBaseColor;
74
- const columnSelectedColor =
75
- opts.selectedColor ?? getCSSVariable("--selection-color", "purple");
76
-
77
- const lineColor = opts.lineColor ?? columnBaseColor;
78
- // Highlight on either direct map hover or an externally-driven highlight
79
- // (e.g. hovering the corresponding column header elsewhere in the UI).
80
- const isHovered = [
81
- "any",
82
- ["boolean", ["feature-state", "hover"], false],
83
- ["boolean", ["feature-state", "highlighted"], false],
84
- ];
85
- // If color is in the feature state or geojson properties, use that as second choice
86
- if (typeof columnColor === "string") {
87
- columnColor = [
88
- "coalesce",
89
- ["feature-state", "color"],
90
- ["get", "color"],
91
- columnColor,
92
- ];
93
- }
94
-
95
- const fillOpacity = opts.opacity ?? 0.1;
96
-
97
- const lineOpacity = opts.lineOpacity ?? 0.5;
98
- const lineWidth = opts.lineWidth ?? 2;
99
-
100
- const circleRadius = opts.circleRadius ?? 4;
101
-
102
- return {
103
- sources: {
104
- columns: buildGeoJSONSource(),
105
- },
106
- version: 8,
107
- layers: [
108
- {
109
- id: "columns-fill",
110
- type: "fill",
111
- source: "columns",
112
- paint: {
113
- "fill-color": columnColor,
114
- "fill-opacity": fillOpacity,
115
- },
116
- },
117
- {
118
- id: "columns-points",
119
- type: "circle",
120
- source: "columns",
121
- paint: {
122
- "circle-radius": circleRadius,
123
- "circle-color": columnColor,
124
- "circle-opacity": fillOpacity,
125
- },
126
- filter: ["==", "$type", "Point"],
127
- },
128
- {
129
- id: "columns-line",
130
- type: "line",
131
- source: "columns",
132
- paint: {
133
- "line-color": ["case", isHovered, columnSelectedColor, lineColor],
134
- "line-width": lineWidth,
135
- "line-opacity": ["case", isHovered, 1.0, lineOpacity],
136
- },
137
- },
138
- ],
139
- };
140
- }
141
-
142
- export type ColumnFeature = GeoJSON.Feature & { id: number };
143
-
144
- const selectedColumnSourceID = "selectedColumn";
145
-
146
- export function SelectedColumnOverlay({
147
- selectedColumn,
148
- ...styleOpts
149
- }: { selectedColumn: ColumnFeature | null } & SelectedColumnStyleOpts) {
150
- useOverlayStyle(() => buildSelectedColumnStyle(styleOpts), []);
151
-
152
- useMapStyleOperator(
153
- (map) => {
154
- setGeoJSON(
155
- map,
156
- selectedColumnSourceID,
157
- promoteToFeatureCollection(selectedColumn as GeoJSONFeature | null),
158
- );
159
- },
160
- [selectedColumn],
161
- );
162
-
163
- return null;
164
- }
165
-
166
- interface SelectedColumnStyleOpts {
167
- color?: string | any[];
168
- }
169
-
170
- function buildSelectedColumnStyle(
171
- opts: SelectedColumnStyleOpts = {},
172
- ): StyleFragment {
173
- const columnSelectedColor: any =
174
- opts.color ?? getCSSVariable("--selection-color", "purple");
175
-
176
- return {
177
- sources: {
178
- selectedColumn: buildGeoJSONSource(),
179
- },
180
- version: 8,
181
- layers: [
182
- {
183
- id: "selected-column-highlight",
184
- type: "fill",
185
- source: selectedColumnSourceID,
186
- paint: {
187
- "fill-color": columnSelectedColor,
188
- "fill-opacity": 0.5,
189
- },
190
- filter: ["==", "$type", "Polygon"],
191
- },
192
- {
193
- id: "selected-column-edge",
194
- type: "line",
195
- source: selectedColumnSourceID,
196
- paint: {
197
- "line-color": columnSelectedColor,
198
- "line-width": 2,
199
- "line-opacity": 1.0,
200
- },
201
- filter: ["==", "$type", "Polygon"],
202
- },
203
- {
204
- id: "selected-column-point",
205
- type: "circle",
206
- source: selectedColumnSourceID,
207
- paint: {
208
- "circle-radius": 6,
209
- "circle-color": columnSelectedColor,
210
- "circle-opacity": 1.0,
211
- },
212
- filter: ["==", "$type", "Point"],
213
- },
214
- ],
215
- };
216
- }