@orioro/react-maplibre-util 0.5.3 → 0.6.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 CHANGED
@@ -1,5 +1,16 @@
1
1
  # @orioro/react-maplibre-util
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - update all dependencies and multiple internal deps
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @orioro/react-chart-util@0.3.0
13
+
3
14
  ## 0.5.3
4
15
 
5
16
  ### Patch Changes
@@ -1,2 +1,5 @@
1
1
  export * from './DynamicImages';
2
2
  export * from './svgImages';
3
+ export * from './svgPatterns';
4
+ import * as SVG_PATTERNS from './svgPatterns';
5
+ export { SVG_PATTERNS };
@@ -0,0 +1,9 @@
1
+ export type IconPathToSvgOptions = {
2
+ size?: number;
3
+ fill?: string;
4
+ stroke?: string;
5
+ strokeWidth?: string | number;
6
+ viewBox?: string;
7
+ style?: string;
8
+ };
9
+ export declare function iconPathToSvg(path: string, { size, fill, stroke, strokeWidth, viewBox, style, }?: IconPathToSvgOptions): string;
@@ -1,30 +1,8 @@
1
- import { StyleImageMetadata } from 'maplibre-gl';
2
- type IconPathToSvgOptions = {
3
- size?: number;
4
- fill?: string;
5
- stroke?: string;
6
- strokeWidth?: string | number;
7
- viewBox?: string;
8
- style?: string;
9
- };
10
- export declare function iconPathToSvg(path: string, { size, fill, stroke, strokeWidth, viewBox, style, }?: IconPathToSvgOptions): string;
11
- /**
12
- * Renders an SVG string onto a canvas and returns an object compatible with maplibre `addImage`.
13
- *
14
- * @param svgString - The SVG markup as a string
15
- * @param pixelRatio - (Optional) device pixel ratio, defaults to window.devicePixelRatio
16
- * @returns Promise resolving to { width, height, data, pixelRatio }
17
- */
18
- export declare function svgToMaplibreImage(svgString: string, pixelRatio?: number): Promise<[
19
- {
20
- width: number;
21
- height: number;
22
- data: Uint8ClampedArray;
23
- },
24
- Partial<StyleImageMetadata>
25
- ]>;
26
- export declare function svgIconId(iconId: string, options?: IconPathToSvgOptions): string;
27
- type SvgIconGeneratorReturn<T extends Record<string, string>> = {
1
+ import { type IconPathToSvgOptions } from './iconPathToSvg';
2
+ import type { StyleImageMetadata } from 'maplibre-gl';
3
+ export declare function svgImageId(imageId: string, options?: IconPathToSvgOptions): string;
4
+ type SvgIconSpecsById = Record<string, string | ((options: Record<string, any>) => string)>;
5
+ type SvgIconGeneratorReturn<T extends SvgIconSpecsById> = {
28
6
  (imageId: string): Promise<[
29
7
  {
30
8
  width: number;
@@ -36,5 +14,6 @@ type SvgIconGeneratorReturn<T extends Record<string, string>> = {
36
14
  } & {
37
15
  [K in keyof T]: (options?: IconPathToSvgOptions) => string;
38
16
  };
39
- export declare function svgIconGenerator<T extends Record<string, string>>(iconPathsById: T): SvgIconGeneratorReturn<T>;
17
+ export declare function svgImageGenerator<T extends SvgIconSpecsById>(svgImageSpecsById: T): SvgIconGeneratorReturn<T>;
18
+ export declare function svgIconGenerator(...args: any[]): SvgIconGeneratorReturn<any>;
40
19
  export {};
@@ -0,0 +1,16 @@
1
+ import type { StyleImageMetadata } from 'maplibre-gl';
2
+ /**
3
+ * Renders an SVG string onto a canvas and returns an object compatible with maplibre `addImage`.
4
+ *
5
+ * @param svgString - The SVG markup as a string
6
+ * @param pixelRatio - (Optional) device pixel ratio, defaults to window.devicePixelRatio
7
+ * @returns Promise resolving to { width, height, data, pixelRatio }
8
+ */
9
+ export declare function svgToMaplibreImage(svgString: string, inputPixelRatio?: number): Promise<[
10
+ {
11
+ width: number;
12
+ height: number;
13
+ data: Uint8ClampedArray;
14
+ },
15
+ Partial<StyleImageMetadata>
16
+ ]>;
@@ -0,0 +1,8 @@
1
+ export declare const squares_1: (data: Record<string, any>) => string;
2
+ export declare const triangles_1: (data: Record<string, any>) => string;
3
+ export declare const diamonds_1: (data: Record<string, any>) => string;
4
+ export declare const cross_1: (data: Record<string, any>) => string;
5
+ export declare const mosaic_1: (data: Record<string, any>) => string;
6
+ export declare const waves_1: (data: Record<string, any>) => string;
7
+ export declare const circles_1: (data: Record<string, any>) => string;
8
+ export declare const lines_1: (data: Record<string, any>) => string;
@@ -3,7 +3,7 @@ import { Merge } from 'type-fest';
3
3
  type ClickableFeature = Merge<MapGeoJSONFeature, {
4
4
  layer: {
5
5
  id: string;
6
- onClick: (feature: MapGeoJSONFeature, event: AugmentedMouseEvent) => any;
6
+ onClick: (feature: MapGeoJSONFeature, event: AugmentedMouseEvent, context: Record<string, any>) => any;
7
7
  };
8
8
  }>;
9
9
  type AugmentedMouseEvent = Merge<MapMouseEvent, {
@@ -11,6 +11,7 @@ type AugmentedMouseEvent = Merge<MapMouseEvent, {
11
11
  }>;
12
12
  type LayeredMapOnClickHandlerProps = {
13
13
  resolveTargetFeature?: (features: AugmentedMouseEvent['features'], event: AugmentedMouseEvent) => ClickableFeature | Promise<ClickableFeature>;
14
+ context?: Record<string, any>;
14
15
  };
15
- export declare function layeredMapOnClickHandler({ resolveTargetFeature, }?: LayeredMapOnClickHandlerProps): (e: AugmentedMouseEvent) => Promise<void>;
16
+ export declare function layeredMapOnClickHandler({ resolveTargetFeature, context, }?: LayeredMapOnClickHandlerProps): (e: AugmentedMouseEvent) => Promise<void>;
16
17
  export {};
@@ -1 +1,3 @@
1
1
  export * from './SyncedMaps';
2
+ export * from './useTilesLoading';
3
+ export * from './useMapRegistry';
@@ -0,0 +1,7 @@
1
+ import type { Map } from 'maplibre-gl';
2
+ import type { MapEvent } from 'react-map-gl/maplibre';
3
+ export declare function useMapRegistry(): {
4
+ maps: Map[];
5
+ onLoad: (evt: MapEvent) => NodeJS.Timeout;
6
+ onRemove: (evt: MapEvent) => void;
7
+ };
@@ -0,0 +1,2 @@
1
+ import type { Map } from 'maplibre-gl';
2
+ export declare function useTilesLoading(maps: Map | Map[]): boolean;
package/dist/index.mjs CHANGED
@@ -6,19 +6,27 @@ import { Flex, useRefByKey, useLocalState, DropdownMenu } from '@orioro/react-ui
6
6
  import styled from 'styled-components';
7
7
  import { usePrevious } from 'react-use';
8
8
  import { mergeRefs } from 'react-merge-refs';
9
- import { strExpr } from '@orioro/util';
9
+ import { mdiCloseCircleOutline, mdiCheck, mdiTerrain, mdiVideo3d } from '@mdi/js';
10
+ import { interpolate, strExpr } from '@orioro/util';
10
11
  import { ckmeans } from 'simple-statistics';
11
12
  import { schemeYlOrRd } from 'd3-scale-chromatic';
12
13
  import { maxIndex, range, variance, sum } from 'd3';
13
14
  import { bbox } from '@turf/turf';
14
15
  import { createPortal } from 'react-dom';
15
- import { mdiCheck, mdiTerrain, mdiVideo3d } from '@mdi/js';
16
16
  import { Icon } from '@mdi/react';
17
17
  import { Tooltip } from '@radix-ui/themes';
18
18
  import maplibregl from 'maplibre-gl';
19
19
  import mlcontour from 'maplibre-contour';
20
20
  import MaplibreInspect from '@maplibre/maplibre-gl-inspect';
21
21
 
22
+ function _validZIndex(zIndex) {
23
+ return typeof zIndex === 'number' && !Number.isNaN(zIndex);
24
+ }
25
+ // Return 1 makes layerB come first in array order
26
+ // and layerA later, so it will be
27
+ // rendered on top of layerB
28
+ var LAYER_A_ON_TOP_OF_B = 1;
29
+ var LAYER_B_ON_TOP_OF_A = -1;
22
30
  function sortLayers(layers, _a) {
23
31
  var existingLayers = _a.existingLayers;
24
32
  var existingLayersById = existingLayers ? Object.fromEntries(existingLayers.map(function (layer) {
@@ -31,7 +39,27 @@ function sortLayers(layers, _a) {
31
39
  // - Later in the list → Rendered on top (higher z-index).
32
40
  // - Earlier in the list → Rendered below.
33
41
  //
34
- return layers.map(function (layer, index) {
42
+ return layers
43
+ //
44
+ // PREVIOUS SORT:
45
+ // .map((layer, index) => ({
46
+ // ...layer,
47
+ // //
48
+ // // Allow for zIndex overriding
49
+ // // In case no zIndex is set, respect the order in which
50
+ // // layers were provided.
51
+ // //
52
+ // // Layers that come after are rendered on top of previous layers
53
+ // //
54
+ // zIndex: typeof layer.zIndex === 'number' ? layer.zIndex : index,
55
+ // }))
56
+ // //
57
+ // // Order layers in ascending zIndex order, so that
58
+ // // layers with higher zIndex are rendered later and on top of
59
+ // // previous ones
60
+ // //
61
+ // .sort((layerA, layerB) => (layerA.zIndex >= layerB.zIndex ? 1 : -1))
62
+ .map(function (layer, index) {
35
63
  return __assign(__assign({}, layer), {
36
64
  //
37
65
  // Allow for zIndex overriding
@@ -40,7 +68,8 @@ function sortLayers(layers, _a) {
40
68
  //
41
69
  // Layers that come after are rendered on top of previous layers
42
70
  //
43
- zIndex: typeof layer.zIndex === 'number' ? layer.zIndex : index
71
+ _inputOrderIndex: index,
72
+ zIndex: typeof layer.zIndex === 'number' ? layer.zIndex : null
44
73
  });
45
74
  })
46
75
  //
@@ -48,9 +77,38 @@ function sortLayers(layers, _a) {
48
77
  // layers with higher zIndex are rendered later and on top of
49
78
  // previous ones
50
79
  //
80
+ // Layers without zIndex are always rendered beneath
81
+ // those with zIndex
82
+ //
83
+ // Layers with the same zIndex are compared using _inputOrderIndex
84
+ //
51
85
  .sort(function (layerA, layerB) {
52
- return layerA.zIndex >= layerB.zIndex ? 1 : -1;
53
- }).map(function (layer, index, sortedLayers) {
86
+ var aValid = _validZIndex(layerA.zIndex);
87
+ var bValid = _validZIndex(layerB.zIndex);
88
+ var aZIndex = layerA.zIndex;
89
+ var bZIndex = layerB.zIndex;
90
+ if (aValid && !bValid) {
91
+ return LAYER_A_ON_TOP_OF_B;
92
+ } else if (!aValid && bValid) {
93
+ return LAYER_B_ON_TOP_OF_A;
94
+ } else if (!aValid && !bValid || aZIndex === bZIndex) {
95
+ return layerA._inputOrderIndex >= layerB._inputOrderIndex ? LAYER_A_ON_TOP_OF_B : LAYER_B_ON_TOP_OF_A;
96
+ } else {
97
+ return aZIndex > bZIndex ? LAYER_A_ON_TOP_OF_B : LAYER_B_ON_TOP_OF_A;
98
+ }
99
+ })
100
+ //
101
+ // This was a strategy to use beforeId to
102
+ // sync map order. We've faced some pitfalls:
103
+ // - Some layers do not exist when multiple layers
104
+ // are created at once, thus maplibre fails to
105
+ // apply beforeId (and throws errors)
106
+ // - There are issues related to layer dynamic ordering,
107
+ // see: https://github.com/visgl/react-map-gl/issues/939#issuecomment-1515395161
108
+ // - We've opted for manually syncing layer orders when
109
+ // layers update
110
+ //
111
+ .map(function (layer, index, sortedLayers) {
54
112
  if (index === sortedLayers.length - 1) {
55
113
  // is last layer
56
114
  return __assign(__assign({}, layer), {
@@ -211,7 +269,11 @@ function syncLayerOrder(_a) {
211
269
  if (!map.getLayer(beneathLayerId)) {
212
270
  return;
213
271
  }
214
- map.moveLayer(layerId, beneathLayerId);
272
+ try {
273
+ map.moveLayer(layerId, beneathLayerId);
274
+ } catch (err) {
275
+ console.warn("failed to move ".concat(layerId, " beneath ").concat(beneathLayerId));
276
+ }
215
277
  }
216
278
  });
217
279
  }
@@ -291,7 +353,7 @@ var LayeredMap = /*#__PURE__*/forwardRef(function LayeredMapInner(_a, layeredMap
291
353
  return;
292
354
  }
293
355
  // Timeout ensures layers are added to map before moving
294
- setTimeout(function () {
356
+ var timeoutId = setTimeout(function () {
295
357
  var expectedLayerOrderId = parsed.layers.map(function (layer) {
296
358
  return layer.id;
297
359
  });
@@ -300,6 +362,9 @@ var LayeredMap = /*#__PURE__*/forwardRef(function LayeredMapInner(_a, layeredMap
300
362
  map: mapRef.current
301
363
  });
302
364
  }, 0);
365
+ return function () {
366
+ clearTimeout(timeoutId);
367
+ };
303
368
  }, [parsed === null || parsed === void 0 ? void 0 : parsed.layers]);
304
369
  return /*#__PURE__*/React.createElement(Map, __assign({
305
370
  ref: mapRef,
@@ -330,7 +395,9 @@ function selectFirstClickableFeature(features) {
330
395
  function layeredMapOnClickHandler(_a) {
331
396
  var _b = _a === void 0 ? {} : _a,
332
397
  _c = _b.resolveTargetFeature,
333
- resolveTargetFeature = _c === void 0 ? selectFirstClickableFeature : _c;
398
+ resolveTargetFeature = _c === void 0 ? selectFirstClickableFeature : _c,
399
+ _d = _b.context,
400
+ context = _d === void 0 ? {} : _d;
334
401
  return function onClick(e) {
335
402
  return __awaiter(this, void 0, void 0, function () {
336
403
  var features, clickableFeatures, targetFeature, _a;
@@ -353,7 +420,7 @@ function layeredMapOnClickHandler(_a) {
353
420
  _b.label = 3;
354
421
  case 3:
355
422
  targetFeature = _a;
356
- targetFeature.layer.onClick(targetFeature, e);
423
+ targetFeature.layer.onClick(targetFeature, e, context);
357
424
  _b.label = 4;
358
425
  case 4:
359
426
  return [2 /*return*/];
@@ -367,6 +434,9 @@ var Container = styled.div(templateObject_1$2 || (templateObject_1$2 = __makeTem
367
434
  var DataSectionHeading = styled.h3(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n margin: 0;\n line-height: 1.2;\n font-size: 1rem;\n"], ["\n margin: 0;\n line-height: 1.2;\n font-size: 1rem;\n"])));
368
435
  var DataSectionContainer = styled(Flex)(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n padding: 15px 10px;\n"], ["\n padding: 15px 10px;\n"])));
369
436
  var EntriesList = styled.ul(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n padding: 0;\n list-style: none;\n margin-top: 0;\n margin-bottom: 0;\n > li + li {\n margin-top: 4px;\n }\n"], ["\n padding: 0;\n list-style: none;\n margin-top: 0;\n margin-bottom: 0;\n > li + li {\n margin-top: 4px;\n }\n"])));
437
+ function _notEmpty(value) {
438
+ return typeof value !== 'undefined' && value !== null && value !== '';
439
+ }
370
440
  function DataSection(_a) {
371
441
  var title = _a.title,
372
442
  entries = _a.entries,
@@ -374,12 +444,12 @@ function DataSection(_a) {
374
444
  return Array.isArray(entries) && entries.length > 0 && (/*#__PURE__*/React.createElement(DataSectionContainer, __assign({
375
445
  direction: "column",
376
446
  gap: "10px"
377
- }, props), title && /*#__PURE__*/React.createElement(DataSectionHeading, null, title), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(EntriesList, null, entries.map(function (_a, index) {
447
+ }, props), title && /*#__PURE__*/React.createElement(DataSectionHeading, null, title), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(EntriesList, null, entries.filter(Boolean).map(function (_a, index) {
378
448
  var label = _a[0],
379
449
  value = _a[1];
380
450
  return /*#__PURE__*/React.createElement("li", {
381
451
  key: index
382
- }, typeof label === 'string' ? /*#__PURE__*/React.createElement("span", null, label, ": ") : label, typeof value === 'string' ? (/*#__PURE__*/React.createElement("span", {
452
+ }, typeof label === 'string' ? (/*#__PURE__*/React.createElement("span", null, "".concat(label).concat(_notEmpty(value) ? ': ' : ''))) : label, typeof value === 'string' ? (/*#__PURE__*/React.createElement("span", {
383
453
  style: {
384
454
  fontWeight: 'bold'
385
455
  }
@@ -907,6 +977,14 @@ function makeSyncedMaps(_a) {
907
977
  mapInstances: mapInstanceRefs
908
978
  };
909
979
  }, [mapInstanceRefs]);
980
+ // Let's review, this might have performance impact
981
+ var cursor = useMemo(function () {
982
+ var _a;
983
+ return isDragging ? 'grabbing' : (((_a = hoverInfo === null || hoverInfo === void 0 ? void 0 : hoverInfo.features) === null || _a === void 0 ? void 0 : _a.length) || 0) > 0 ? hoverInfo.features.some(function (feat) {
984
+ var _a;
985
+ return typeof ((_a = feat.layer) === null || _a === void 0 ? void 0 : _a.onClick) === 'function';
986
+ }) ? 'pointer' : 'default' : 'default';
987
+ }, [isDragging, hoverInfo]);
910
988
  return /*#__PURE__*/React.createElement(Flex, {
911
989
  ref: containerRef,
912
990
  direction: "row",
@@ -932,7 +1010,9 @@ function makeSyncedMaps(_a) {
932
1010
  }
933
1011
  })) : null, Array.isArray(tooltips) && tooltips[index], /*#__PURE__*/React.createElement(MapComponent, __assign({
934
1012
  ref: setMapInstanceRef(index),
935
- cursor: isDragging ? 'grabbing' : 'default'
1013
+ // cursor={isDragging ? 'grabbing' : 'default'}
1014
+ // Let's review, this might have performance impact
1015
+ cursor: cursor
936
1016
  }, baseMapProps, mapProps, maps.length > 1 ? viewState || {} : {}, {
937
1017
  style: __assign(__assign({}, mapProps.style || {}), {
938
1018
  position: 'absolute',
@@ -968,6 +1048,70 @@ var SyncedMaps = makeSyncedMaps({
968
1048
  });
969
1049
  var templateObject_1;
970
1050
 
1051
+ function useTilesLoading(maps) {
1052
+ maps = Array.isArray(maps) ? maps : [maps];
1053
+ var _a = useState(false),
1054
+ loading = _a[0],
1055
+ setLoading = _a[1];
1056
+ var checkLoading = function checkLoading() {
1057
+ var loading = maps.some(function (map) {
1058
+ return !map.areTilesLoaded();
1059
+ });
1060
+ setLoading(loading);
1061
+ };
1062
+ useEffect(function () {
1063
+ var handlers = maps.map(function (map) {
1064
+ var update = function update() {
1065
+ return checkLoading();
1066
+ };
1067
+ map.on('dataloading', update);
1068
+ // map.on('data', update)
1069
+ map.on('idle', update);
1070
+ return function () {
1071
+ map.off('dataloading', update);
1072
+ // map.off('data', update)
1073
+ map.off('idle', update);
1074
+ };
1075
+ });
1076
+ checkLoading(); // initial
1077
+ return function () {
1078
+ return handlers.forEach(function (off) {
1079
+ return off();
1080
+ });
1081
+ };
1082
+ }, [maps]);
1083
+ return loading;
1084
+ }
1085
+
1086
+ function useMapRegistry() {
1087
+ var _a = useState([]),
1088
+ maps = _a[0],
1089
+ setMaps = _a[1];
1090
+ var onLoad = useCallback(function (evt) {
1091
+ //
1092
+ // Set maps in next tick, so that does not interfere
1093
+ // in map element rendering
1094
+ //
1095
+ return setTimeout(function () {
1096
+ return setMaps(function (currMaps) {
1097
+ return __spreadArray(__spreadArray([], currMaps, true), [evt.target], false);
1098
+ });
1099
+ }, 0);
1100
+ }, []);
1101
+ var onRemove = useCallback(function (evt) {
1102
+ return setMaps(function (currMaps) {
1103
+ return currMaps.filter(function (map) {
1104
+ return map !== evt.target;
1105
+ });
1106
+ });
1107
+ }, []);
1108
+ return {
1109
+ maps: maps,
1110
+ onLoad: onLoad,
1111
+ onRemove: onRemove
1112
+ };
1113
+ }
1114
+
971
1115
  function DynamicImages(_a) {
972
1116
  var _this = this;
973
1117
  var onGenerateImage = _a.onGenerateImage;
@@ -1032,6 +1176,7 @@ function iconPathToSvg(path, _a) {
1032
1176
  var pathAttrs = ["fill=\"".concat(fill, "\""), style ? "style=\"".concat(style, "\"") : ''].filter(Boolean).join(' ');
1033
1177
  return "<svg ".concat(svgAttrs, "><path ").concat(pathAttrs, " d=\"").concat(path, "\" /></svg>");
1034
1178
  }
1179
+
1035
1180
  /**
1036
1181
  * Renders an SVG string onto a canvas and returns an object compatible with maplibre `addImage`.
1037
1182
  *
@@ -1040,9 +1185,9 @@ function iconPathToSvg(path, _a) {
1040
1185
  * @returns Promise resolving to { width, height, data, pixelRatio }
1041
1186
  */
1042
1187
  function svgToMaplibreImage(svgString_1) {
1043
- return __awaiter(this, arguments, void 0, function (svgString, pixelRatio) {
1044
- if (pixelRatio === void 0) {
1045
- pixelRatio = typeof window !== 'undefined' ? window.devicePixelRatio : 1;
1188
+ return __awaiter(this, arguments, void 0, function (svgString, inputPixelRatio) {
1189
+ if (inputPixelRatio === void 0) {
1190
+ inputPixelRatio = typeof window !== 'undefined' ? window.devicePixelRatio : 1;
1046
1191
  }
1047
1192
  return __generator(this, function (_a) {
1048
1193
  return [2 /*return*/, new Promise(function (resolve, reject) {
@@ -1052,6 +1197,8 @@ function svgToMaplibreImage(svgString_1) {
1052
1197
  var url = URL.createObjectURL(svgBlob);
1053
1198
  var img = new Image();
1054
1199
  img.onload = function () {
1200
+ // Normalize pixel ratio: integer and at least 1
1201
+ var pixelRatio = Math.max(1, Math.round(inputPixelRatio || 1));
1055
1202
  var width = img.width * pixelRatio;
1056
1203
  var height = img.height * pixelRatio;
1057
1204
  var canvas = document.createElement('canvas');
@@ -1079,21 +1226,64 @@ function svgToMaplibreImage(svgString_1) {
1079
1226
  });
1080
1227
  });
1081
1228
  }
1082
- function svgIconId(iconId, options) {
1083
- return options ? "".concat(iconId, "(").concat(JSON.stringify(options), ")") : iconId;
1229
+
1230
+ function svgImageId(imageId, options) {
1231
+ return options ? "".concat(imageId, "(").concat(JSON.stringify(options), ")") : imageId;
1084
1232
  }
1085
- function svgIconGenerator(iconPathsById) {
1086
- var fns = Object.fromEntries(Object.entries(iconPathsById).map(function (_a) {
1087
- var iconId = _a[0],
1088
- iconPath = _a[1];
1089
- return [iconId, function (options) {
1090
- if (options === void 0) {
1091
- options = {};
1092
- }
1093
- return function () {
1094
- return iconPathToSvg(iconPath, options);
1095
- };
1096
- }];
1233
+ var ERROR_ICON_EXPR = function ERROR_ICON_EXPR(options) {
1234
+ if (options === void 0) {
1235
+ options = {};
1236
+ }
1237
+ return function () {
1238
+ return iconPathToSvg(mdiCloseCircleOutline, __assign({
1239
+ fill: 'red'
1240
+ }, options));
1241
+ };
1242
+ };
1243
+ function svgImageGenerator(svgImageSpecsById) {
1244
+ var fns = Object.fromEntries(Object.entries(svgImageSpecsById).map(function (_a) {
1245
+ var imageId = _a[0],
1246
+ iconSpec = _a[1];
1247
+ if (typeof iconSpec === 'string' && iconSpec.startsWith('<svg')) {
1248
+ //
1249
+ // Full svg
1250
+ //
1251
+ return [imageId, function (options) {
1252
+ if (options === void 0) {
1253
+ options = {};
1254
+ }
1255
+ return function () {
1256
+ return interpolate(iconSpec, options);
1257
+ };
1258
+ }];
1259
+ } else if (typeof iconSpec === 'string') {
1260
+ //
1261
+ // Its a string, assume it is an svg path
1262
+ //
1263
+ return [imageId, function (options) {
1264
+ if (options === void 0) {
1265
+ options = {};
1266
+ }
1267
+ return function () {
1268
+ return iconPathToSvg(iconSpec, options);
1269
+ };
1270
+ }];
1271
+ } else if (typeof iconSpec === 'function') {
1272
+ //
1273
+ // Function that returns custom svg
1274
+ //
1275
+ return [imageId, function (options) {
1276
+ if (options === void 0) {
1277
+ options = {};
1278
+ }
1279
+ return function () {
1280
+ return iconSpec(options);
1281
+ };
1282
+ }];
1283
+ } else {
1284
+ console.warn("Invalid icon spec for ".concat(imageId, ", will ignore"), iconSpec);
1285
+ return [imageId, ERROR_ICON_EXPR];
1286
+ }
1097
1287
  }));
1098
1288
  var expr = strExpr({
1099
1289
  expressions: fns
@@ -1114,13 +1304,89 @@ function svgIconGenerator(iconPathsById) {
1114
1304
  });
1115
1305
  });
1116
1306
  }
1117
- Object.assign(onGenerateSvgImage, Object.fromEntries(Object.keys(iconPathsById).map(function (iconId) {
1118
- return [iconId, function (options) {
1119
- return svgIconId(iconId, options);
1307
+ //
1308
+ // Expose generator fns
1309
+ //
1310
+ Object.assign(onGenerateSvgImage, Object.fromEntries(Object.keys(svgImageSpecsById).map(function (imageId) {
1311
+ return [imageId, function (options) {
1312
+ return svgImageId(imageId, options);
1120
1313
  }];
1121
1314
  })));
1122
1315
  return onGenerateSvgImage;
1123
1316
  }
1317
+ function svgIconGenerator() {
1318
+ var args = [];
1319
+ for (var _i = 0; _i < arguments.length; _i++) {
1320
+ args[_i] = arguments[_i];
1321
+ }
1322
+ console.warn('svgIconGenerator is deprecated, migrate to svgImageGenerator');
1323
+ return svgImageGenerator.apply(void 0, args);
1324
+ }
1325
+
1326
+ function _pattern(strTemplate) {
1327
+ return function (data) {
1328
+ return interpolate(strTemplate, data);
1329
+ };
1330
+ }
1331
+ function _svgViewBox(_a) {
1332
+ var height = _a.height,
1333
+ width = _a.width;
1334
+ return "viewBox=\"0 0 ".concat(width, " ").concat(height, "\" height=\"").concat(height, "\" width=\"").concat(width, "\"");
1335
+ }
1336
+ function _bgRect() {
1337
+ return "<rect\n width=\"100%\"\n height=\"100%\"\n fill=\"${ fill = transparent }\"\n />";
1338
+ }
1339
+ // Source:
1340
+ // https://pattern.monster/cross-section
1341
+ var squares_1 = _pattern("<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n ".concat(_svgViewBox({
1342
+ height: 20,
1343
+ width: 20
1344
+ }), ">\n <defs>\n <pattern\n patternTransform=\"scale(${ scale = 1 })\"\n id=\"a\"\n width=\"20\"\n height=\"20\"\n patternUnits=\"userSpaceOnUse\"\n >\n ").concat(_bgRect(), "\n <path\n fill=\"transparent\"\n stroke=\"${ stroke = #000000 }\"\n stroke-width=\"2\"\n d=\"M10 0v20ZM0 10h20Z\"\n />\n </pattern>\n </defs>\n <rect width=\"800%\" height=\"800%\" fill=\"url(#a)\" />\n</svg>"));
1345
+ // Source:
1346
+ // https://pattern.monster/triangles-4
1347
+ var triangles_1 = _pattern("<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n ".concat(_svgViewBox({
1348
+ height: 40,
1349
+ width: 20
1350
+ }), ">\n <defs>\n <pattern\n patternTransform=\"scale(${ scale = 1 })\"\n id=\"a\"\n width=\"20\"\n height=\"40\"\n patternUnits=\"userSpaceOnUse\"\n >\n ").concat(_bgRect(), "\n <path\n fill=\"transparent\"\n stroke=\"${ stroke = #000000 }\"\n stroke-width=\"${ strokeWidth = 2 }\"\n d=\"M0 30h20L10 50zm-10-20h20L0 30zm20 0h20L20 30zM0-10h20L10 10z\"\n />\n </pattern>\n </defs>\n <rect width=\"800%\" height=\"800%\" fill=\"url(#a)\" />\n</svg>"));
1351
+ // Source:
1352
+ // https://pattern.monster/diamonds-1
1353
+ var diamonds_1 = _pattern("<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n ".concat(_svgViewBox({
1354
+ height: 50,
1355
+ width: 50
1356
+ }), ">\n <defs>\n <pattern\n patternTransform=\"scale(${ scale = 1 })\"\n id=\"a\"\n width=\"50\"\n height=\"50\"\n patternUnits=\"userSpaceOnUse\"\n >\n ").concat(_bgRect(), "\n <path\n fill=\"transparent\"\n stroke=\"${ stroke = #000000 }\"\n stroke-width=\"${ strokeWidth = 2 }\"\n d=\"M50 25 37.5 50 25 25 37.5 0zm-25 0L12.5 50 0 25 12.5 0z\"\n />\n </pattern>\n </defs>\n <rect width=\"800%\" height=\"800%\" fill=\"url(#a)\" />\n</svg>"));
1357
+ var cross_1 = _pattern("<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n ".concat(_svgViewBox({
1358
+ height: 20,
1359
+ width: 20
1360
+ }), ">\n <defs>\n <pattern\n patternTransform=\"scale(${ scale = 1 })\"\n id=\"a\"\n width=\"20\"\n height=\"20\"\n patternUnits=\"userSpaceOnUse\"\n >\n ").concat(_bgRect(), "\n <path\n fill=\"transparent\"\n stroke=\"${ stroke = #000000 }\"\n stroke-width=\"${ strokeWidth = 2 }\"\n stroke-linecap=\"square\"\n d=\"M3.25 10h13.5M10 3.25v13.5\"\n />\n </pattern>\n </defs>\n <rect width=\"800%\" height=\"800%\" fill=\"url(#a)\" />\n</svg>"));
1361
+ // https://pattern.monster/cubes-1
1362
+ var mosaic_1 = _pattern("<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n ".concat(_svgViewBox({
1363
+ width: 60,
1364
+ height: 60
1365
+ }), ">\n <defs>\n <pattern\n patternTransform=\"scale(${ scale = 1 })\"\n id=\"a\"\n width=\"60\"\n height=\"60\"\n patternUnits=\"userSpaceOnUse\">\n ").concat(_bgRect(), "\n <path\n fill=\"transparent\"\n stroke=\"${ stroke = #000000 }\"\n stroke-width=\"${ strokeWidth = 2 }\"\n d=\"M15 30v30m-7.5 0V30h15v30m7.5 0H0V30h30M45 0v30m7.5-30v30m-15 0V0M30 0h30v30M30 45h30m-30-7.5h30m0 15H30M30 30h30v30H30zM0 15h30M0 7.5h30m0 15H0M0 0h30v30H0z\"\n />\n </pattern>\n </defs>\n <rect width=\"800%\" height=\"800%\" fill=\"url(#a)\" />\n</svg>"));
1366
+ var waves_1 = _pattern("<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n ".concat(_svgViewBox({
1367
+ width: 120,
1368
+ height: 80
1369
+ }), ">\n <defs>\n <pattern\n patternTransform=\"scale(${ scale = 1 })\"\n id=\"a\"\n width=\"120\"\n height=\"80\"\n patternUnits=\"userSpaceOnUse\">\n ").concat(_bgRect(), "\n <path\n fill=\"transparent\"\n stroke=\"${ stroke = #000000 }\"\n stroke-width=\"${ strokeWidth = 2 }\"\n d=\"M-50.129 12.685C-33.346 12.358-16.786 4.918 0 5c16.787.082 43.213 10 60 10s43.213-9.918 60-10 33.346 7.358 50.129 7.685\"\n />\n <path\n fill=\"transparent\"\n stroke=\"${ stroke = #000000 }\"\n stroke-width=\"${ strokeWidth = 2 }\"\n d=\"M-50.129 32.685C-33.346 32.358-16.786 24.918 0 25c16.787.082 43.213 10 60 10s43.213-9.918 60-10 33.346 7.358 50.129 7.685\"\n />\n <path\n fill=\"transparent\"\n stroke=\"${ stroke = #000000 }\"\n stroke-width=\"${ strokeWidth = 2 }\"\n d=\"M-50.129 52.685C-33.346 52.358-16.786 44.918 0 45c16.787.082 43.213 10 60 10s43.213-9.918 60-10 33.346 7.358 50.129 7.685\"\n />\n <path\n fill=\"transparent\"\n stroke=\"${ stroke = #000000 }\"\n stroke-width=\"${ strokeWidth = 2 }\"\n d=\"M-50.129 72.685C-33.346 72.358-16.786 64.918 0 65c16.787.082 43.213 10 60 10s43.213-9.918 60-10 33.346 7.358 50.129 7.685\"\n />\n </pattern>\n </defs>\n <rect width=\"800%\" height=\"800%\" fill=\"url(#a)\" />\n</svg>"));
1370
+ var circles_1 = _pattern("<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n ".concat(_svgViewBox({
1371
+ width: 20,
1372
+ height: 20
1373
+ }), ">\n <defs>\n <pattern\n patternTransform=\"scale(${ scale = 1 })\"\n id=\"a\"\n width=\"20\"\n height=\"20\"\n patternUnits=\"userSpaceOnUse\">\n ").concat(_bgRect(), "\n <path\n fill=\"transparent\"\n stroke=\"${ stroke = #000000 }\"\n stroke-width=\"${ strokeWidth = 2 }\"\n d=\"M10 15a5 5 0 1 1 0-10 5 5 0 0 1 0 10z\"\n />\n </pattern>\n </defs>\n <rect width=\"800%\" height=\"800%\" fill=\"url(#a)\" />\n</svg>"));
1374
+ var lines_1 = _pattern("<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n ".concat(_svgViewBox({
1375
+ width: 20,
1376
+ height: 80
1377
+ }), ">\n <defs>\n <pattern\n patternTransform=\"scale(${ scale = 1 })\"\n id=\"a\"\n width=\"20\"\n height=\"80\"\n patternUnits=\"userSpaceOnUse\">\n ").concat(_bgRect(), "\n <path\n fill=\"transparent\"\n stroke=\"${ stroke = #000000 }\"\n stroke-width=\"${ strokeWidth = 2 }\"\n d=\"M0 10h20z\"\n />\n <path\n fill=\"transparent\"\n stroke=\"${ stroke = #000000 }\"\n stroke-width=\"${ strokeWidth = 2 }\"\n d=\"M0 30h20z\"\n />\n <path\n fill=\"transparent\"\n stroke=\"${ stroke = #000000 }\"\n stroke-width=\"${ strokeWidth = 2 }\"\n d=\"M0 50h20z\"\n />\n <path\n fill=\"transparent\"\n stroke=\"${ stroke = #000000 }\"\n stroke-width=\"${ strokeWidth = 2 }\"\n d=\"M0 70h20z\"\n />\n </pattern>\n </defs>\n <rect width=\"800%\" height=\"800%\" fill=\"url(#a)\" />\n</svg>"));
1378
+
1379
+ var index = /*#__PURE__*/Object.freeze({
1380
+ __proto__: null,
1381
+ circles_1: circles_1,
1382
+ cross_1: cross_1,
1383
+ diamonds_1: diamonds_1,
1384
+ lines_1: lines_1,
1385
+ mosaic_1: mosaic_1,
1386
+ squares_1: squares_1,
1387
+ triangles_1: triangles_1,
1388
+ waves_1: waves_1
1389
+ });
1124
1390
 
1125
1391
  var DEFAULT_MIN_K = 3;
1126
1392
  var DEFAULT_MAX_K = 9;
@@ -1642,4 +1908,4 @@ function InspectControl(props) {
1642
1908
  return null;
1643
1909
  }
1644
1910
 
1645
- export { $naturalBreaks, ControlContainer, DynamicImages, HoverTooltip, InspectControl, LayeredMap, MapWindow, SyncedMaps, TerrainControl, applyReactStyle, augmentFeature, ensureAddLayer, ensureAddSource, ensureRemoveLayer, ensureRemoveSource, fitGeometry, fmtLayerAbsoluteId, getSrcLayer, getSrcViewByLayerId, hoverParseEvent, iconPathToSvg, layeredMapOnClickHandler, makeSyncedMaps, mapSetFeaturesState, naturalBreakBounds, parseMapViews, scaleNaturalBreaks, sortLayers, svgIconGenerator, svgIconId, svgToMaplibreImage, useClientRect, useHover, useLayeredMap, withHover };
1911
+ export { $naturalBreaks, ControlContainer, DynamicImages, HoverTooltip, InspectControl, LayeredMap, MapWindow, index as SVG_PATTERNS, SyncedMaps, TerrainControl, applyReactStyle, augmentFeature, circles_1, cross_1, diamonds_1, ensureAddLayer, ensureAddSource, ensureRemoveLayer, ensureRemoveSource, fitGeometry, fmtLayerAbsoluteId, getSrcLayer, getSrcViewByLayerId, hoverParseEvent, layeredMapOnClickHandler, lines_1, makeSyncedMaps, mapSetFeaturesState, mosaic_1, naturalBreakBounds, parseMapViews, scaleNaturalBreaks, sortLayers, squares_1, svgIconGenerator, svgImageGenerator, svgImageId, triangles_1, useClientRect, useHover, useLayeredMap, useMapRegistry, useTilesLoading, waves_1, withHover };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orioro/react-maplibre-util",
3
- "version": "0.5.3",
3
+ "version": "0.6.0",
4
4
  "packageManager": "yarn@4.0.2",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -51,12 +51,12 @@
51
51
  "@maplibre/maplibre-gl-inspect": "^1.7.1",
52
52
  "@mdi/js": "^7.4.47",
53
53
  "@mdi/react": "^1.6.1",
54
- "@orioro/react-chart-util": "^0.2.0",
54
+ "@orioro/react-chart-util": "^0.3.0",
55
55
  "@orioro/react-select": "^3.0.2",
56
- "@orioro/react-ui-core": "^0.0.6",
57
- "@orioro/resolve": "^0.1.2",
56
+ "@orioro/react-ui-core": "^0.0.14",
57
+ "@orioro/resolve": "^0.1.9",
58
58
  "@orioro/scale-util": "^0.0.2",
59
- "@orioro/util": "^0.13.0",
59
+ "@orioro/util": "^0.15.1",
60
60
  "@turf/turf": "^7.2.0",
61
61
  "d3": "^7.9.0",
62
62
  "d3-scale-chromatic": "^3.1.0",