@dynatrace/strato-geo 1.3.4 → 1.4.2

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 (80) hide show
  1. package/esm/map/MapView.js +31 -24
  2. package/esm/map/MapView.js.map +2 -2
  3. package/esm/map/components/MapContent.js +43 -4
  4. package/esm/map/components/MapContent.js.map +2 -2
  5. package/esm/map/components/toolbar/buttons/MapResetButton.js +6 -1
  6. package/esm/map/components/toolbar/buttons/MapResetButton.js.map +2 -2
  7. package/esm/map/components/toolbar/buttons/MapZoomInOutButtons.js +4 -4
  8. package/esm/map/components/toolbar/buttons/MapZoomInOutButtons.js.map +2 -2
  9. package/esm/map/components/toolbar/buttons/MapZoomToFitButton.js +6 -1
  10. package/esm/map/components/toolbar/buttons/MapZoomToFitButton.js.map +2 -2
  11. package/esm/map/components/toolbar/utils/zoom-state-utils.js +36 -0
  12. package/esm/map/components/toolbar/utils/zoom-state-utils.js.map +7 -0
  13. package/esm/map/constants.js +6 -0
  14. package/esm/map/constants.js.map +2 -2
  15. package/esm/map/contexts/map-data-bounding-box.context.js +3 -1
  16. package/esm/map/contexts/map-data-bounding-box.context.js.map +2 -2
  17. package/esm/map/hooks/use-active-interaction.js +16 -12
  18. package/esm/map/hooks/use-active-interaction.js.map +2 -2
  19. package/esm/map/hooks/use-resolve-color.js +5 -2
  20. package/esm/map/hooks/use-resolve-color.js.map +2 -2
  21. package/esm/map/providers/color-scale.provider.js +2 -1
  22. package/esm/map/providers/color-scale.provider.js.map +2 -2
  23. package/esm/map/providers/imperative-handler.provider.js +7 -1
  24. package/esm/map/providers/imperative-handler.provider.js.map +2 -2
  25. package/esm/map/store/map-store.context.js +7 -1
  26. package/esm/map/store/map-store.context.js.map +2 -2
  27. package/esm/map/store/selectors.js +2 -0
  28. package/esm/map/store/selectors.js.map +2 -2
  29. package/esm/map/store/store.js +13 -0
  30. package/esm/map/store/store.js.map +2 -2
  31. package/esm/map/utils/build-scale-from-legend-config.js +4 -2
  32. package/esm/map/utils/build-scale-from-legend-config.js.map +2 -2
  33. package/esm/map/utils/extract-layers-data.js +4 -4
  34. package/esm/map/utils/extract-layers-data.js.map +2 -2
  35. package/esm/map/utils/get-data-layers-bounding-box.js +1 -1
  36. package/esm/map/utils/get-data-layers-bounding-box.js.map +2 -2
  37. package/esm/map/utils/iterate-config-slots.js +7 -1
  38. package/esm/map/utils/iterate-config-slots.js.map +2 -2
  39. package/esm/map/utils/replace-infinite-values-in-ranges.js +30 -0
  40. package/esm/map/utils/replace-infinite-values-in-ranges.js.map +7 -0
  41. package/esm/map/utils/to-mapbox-initial-view-state.js.map +2 -2
  42. package/index.js +3 -3
  43. package/map/MapView.js +31 -24
  44. package/map/components/MapContent.js +36 -2
  45. package/map/components/toolbar/buttons/MapResetButton.js +6 -1
  46. package/map/components/toolbar/buttons/MapZoomInOutButtons.js +4 -4
  47. package/map/components/toolbar/buttons/MapZoomToFitButton.js +6 -1
  48. package/map/components/toolbar/utils/zoom-state-utils.d.ts +4 -0
  49. package/map/components/toolbar/utils/zoom-state-utils.js +47 -0
  50. package/map/constants.d.ts +5 -1
  51. package/map/constants.js +6 -0
  52. package/map/contexts/map-data-bounding-box.context.d.ts +2 -1
  53. package/map/contexts/map-data-bounding-box.context.js +3 -1
  54. package/map/hooks/use-active-interaction.js +16 -12
  55. package/map/hooks/use-data-bounding-box.d.ts +1 -1
  56. package/map/hooks/use-resolve-color.js +1 -1
  57. package/map/providers/color-scale.provider.d.ts +3 -1
  58. package/map/providers/color-scale.provider.js +2 -1
  59. package/map/providers/imperative-handler.provider.js +7 -1
  60. package/map/store/map-store.context.d.ts +6 -0
  61. package/map/store/map-store.context.js +7 -1
  62. package/map/store/selectors.d.ts +1 -0
  63. package/map/store/selectors.js +2 -0
  64. package/map/store/store.d.ts +2 -1
  65. package/map/store/store.js +13 -0
  66. package/map/types/map-view.d.ts +2 -0
  67. package/map/types/state.d.ts +8 -0
  68. package/map/utils/build-scale-from-legend-config.d.ts +1 -1
  69. package/map/utils/build-scale-from-legend-config.js +4 -2
  70. package/map/utils/extract-layers-data.js +4 -4
  71. package/map/utils/get-data-layers-bounding-box.d.ts +2 -1
  72. package/map/utils/get-data-layers-bounding-box.js +1 -1
  73. package/map/utils/iterate-config-slots.js +7 -1
  74. package/map/utils/replace-infinite-values-in-ranges.d.ts +6 -0
  75. package/map/{components/legend/utils/resolve-color.js → utils/replace-infinite-values-in-ranges.js} +27 -18
  76. package/map/utils/to-mapbox-initial-view-state.d.ts +6 -4
  77. package/package.json +4 -4
  78. package/esm/map/components/legend/utils/resolve-color.js +0 -21
  79. package/esm/map/components/legend/utils/resolve-color.js.map +0 -7
  80. package/map/components/legend/utils/resolve-color.d.ts +0 -8
package/index.js CHANGED
@@ -15,8 +15,8 @@ var __copyProps = (to, from, except, desc) => {
15
15
  return to;
16
16
  };
17
17
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
- var src_exports = {};
19
- __export(src_exports, {
18
+ var index_exports = {};
19
+ __export(index_exports, {
20
20
  BaseLayer: () => import_BaseLayer.BaseLayer,
21
21
  BubbleLayer: () => import_BubbleLayer.BubbleLayer,
22
22
  CategoricalLegend: () => import_CategoricalLegend.CategoricalLegend,
@@ -30,7 +30,7 @@ __export(src_exports, {
30
30
  Tooltip: () => import_Tooltip.Tooltip,
31
31
  TooltipAtoms: () => import_Tooltip.TooltipAtoms
32
32
  });
33
- module.exports = __toCommonJS(src_exports);
33
+ module.exports = __toCommonJS(index_exports);
34
34
  var import_ChartInteractions = require("./map/slots/ChartInteractions.js");
35
35
  var import_MapView = require("./map/MapView.js");
36
36
  var import_ConnectionLayer = require("./map/slots/ConnectionLayer.js");
package/map/MapView.js CHANGED
@@ -109,34 +109,41 @@ const _MapView = (0, import_react.forwardRef)(
109
109
  {
110
110
  value: truncationMode ?? import_constants.DEFAULT_TRUNCATION_MODE
111
111
  },
112
- /* @__PURE__ */ import_react.default.createElement(import_formatter_context.FormatterContext.Provider, { value: formatter }, /* @__PURE__ */ import_react.default.createElement(import_map_raw_data_context.MapRawDataContext.Provider, { value: layersData }, /* @__PURE__ */ import_react.default.createElement(import_map_store_provider.MapStoreProvider, null, /* @__PURE__ */ import_react.default.createElement(import_color_scale_provider.ColorScaleProvider, { categories }, /* @__PURE__ */ import_react.default.createElement(import_layer_color_strategy_provider.LayerColorStrategyProvider, null, /* @__PURE__ */ import_react.default.createElement(
113
- import_charts._ChartLayout,
112
+ /* @__PURE__ */ import_react.default.createElement(import_formatter_context.FormatterContext.Provider, { value: formatter }, /* @__PURE__ */ import_react.default.createElement(import_map_raw_data_context.MapRawDataContext.Provider, { value: layersData }, /* @__PURE__ */ import_react.default.createElement(import_map_store_provider.MapStoreProvider, null, /* @__PURE__ */ import_react.default.createElement(
113
+ import_color_scale_provider.ColorScaleProvider,
114
114
  {
115
- ref: chartLayoutRef,
116
- chartHeight,
117
- errorState,
118
- showLoader: loading || isLoading
115
+ categories,
116
+ dataMax: legendDomain[1]
119
117
  },
120
- /* @__PURE__ */ import_react.default.createElement(import_charts._ChartLayout.Graph, null, baseFeatureCollection && /* @__PURE__ */ import_react.default.createElement(
121
- import_MapContent.MapContent,
118
+ /* @__PURE__ */ import_react.default.createElement(import_layer_color_strategy_provider.LayerColorStrategyProvider, null, /* @__PURE__ */ import_react.default.createElement(
119
+ import_charts._ChartLayout,
122
120
  {
123
- ref: forwardedRef,
124
- onMapLoad: () => setIsMapLoaded(true),
125
- ...remaining
121
+ ref: chartLayoutRef,
122
+ chartHeight,
123
+ errorState,
124
+ showLoader: loading || isLoading
126
125
  },
127
- parsedChildren
128
- )),
129
- !isLegendHidden && /* @__PURE__ */ import_react.default.createElement(
130
- import_charts._ChartLayout.Legend,
131
- {
132
- position: legendPosition,
133
- ratio: legendRatio,
134
- ratioBoundaries: import_constants.DEFAULT_LEGEND_SIZES,
135
- onResize: legendOnRatioChange
136
- },
137
- /* @__PURE__ */ import_react.default.createElement(import_MapLegendRenderer.MapLegendRenderer, null)
138
- )
139
- ))))))
126
+ /* @__PURE__ */ import_react.default.createElement(import_charts._ChartLayout.Graph, null, baseFeatureCollection && /* @__PURE__ */ import_react.default.createElement(
127
+ import_MapContent.MapContent,
128
+ {
129
+ ref: forwardedRef,
130
+ onMapLoad: () => setIsMapLoaded(true),
131
+ ...remaining
132
+ },
133
+ parsedChildren
134
+ )),
135
+ !isLegendHidden && /* @__PURE__ */ import_react.default.createElement(
136
+ import_charts._ChartLayout.Legend,
137
+ {
138
+ position: legendPosition,
139
+ ratio: legendRatio,
140
+ ratioBoundaries: import_constants.DEFAULT_LEGEND_SIZES,
141
+ onResize: legendOnRatioChange
142
+ },
143
+ /* @__PURE__ */ import_react.default.createElement(import_MapLegendRenderer.MapLegendRenderer, null)
144
+ )
145
+ ))
146
+ ))))
140
147
  )))
141
148
  ))
142
149
  );
@@ -36,6 +36,7 @@ var import_react = __toESM(require("react"));
36
36
  var import_charts = require("@dynatrace/strato-components-preview/charts");
37
37
  var import_core = require("@dynatrace/strato-components-preview/core");
38
38
  var import_constants = require("../constants.js");
39
+ var import_store = require("../store/store.js");
39
40
  var import_MapToolbar = require("./toolbar/MapToolbar.js");
40
41
  var import_layer_ids_context = require("../contexts/layer-ids.context.js");
41
42
  var import_map_data_bounding_box_context = require("../contexts/map-data-bounding-box.context.js");
@@ -53,6 +54,7 @@ var import_get_color_from_token = require("../utils/get-color-from-token.js");
53
54
  var import_get_data_layers_bounding_box = require("../utils/get-data-layers-bounding-box.js");
54
55
  var import_to_mapbox_initial_view_state = require("../utils/to-mapbox-initial-view-state.js");
55
56
  var import_use_set_map_initial_configuration = require("../utils/use-set-map-initial-configuration.js");
57
+ var import_zoom_state_utils = require("./toolbar/utils/zoom-state-utils.js");
56
58
  const lineLayer = {
57
59
  id: import_constants.BASE_LAYER_LINE_ID,
58
60
  type: "line"
@@ -109,6 +111,8 @@ const MapContent = (0, import_react.forwardRef)((props, forwardedRef) => {
109
111
  ...remaining
110
112
  } = props;
111
113
  const loading = (0, import_use_map_loading.useMapLoading)();
114
+ const setZoomState = (0, import_store.useSetStateZoom)();
115
+ const [savedInitialViewState, setSavedInitialViewState] = (0, import_react.useState)();
112
116
  const mapContainerRef = (0, import_react.useRef)(null);
113
117
  const mergedRefs = (0, import_core.useMergeRefs)([
114
118
  mapContainerRef,
@@ -134,6 +138,28 @@ const MapContent = (0, import_react.forwardRef)((props, forwardedRef) => {
134
138
  } = (0, import_use_overlay_events.useOverlayEvents)();
135
139
  const initialViewState = initialViewStateProp ?? dataLayersBBox;
136
140
  const { onLoadHandler, onRenderHandler } = (0, import_use_map_performance.useMapPerformance)(mapContainerRef);
141
+ const calculatedInitialViewState = (0, import_to_mapbox_initial_view_state.toMapBoxInitialViewState)(initialViewState);
142
+ const { zoomToFitInProgress } = (0, import_store.useMapZoomState)();
143
+ const handleZoomEnd = (event) => {
144
+ if (savedInitialViewState) {
145
+ const zoomState = (0, import_zoom_state_utils.generateNewZoomState)(
146
+ event,
147
+ savedInitialViewState,
148
+ zoomToFitInProgress
149
+ );
150
+ setZoomState(zoomState);
151
+ }
152
+ };
153
+ const handleDragEnd = (event) => {
154
+ if (savedInitialViewState) {
155
+ const zoomState = (0, import_zoom_state_utils.generateNewZoomState)(
156
+ event,
157
+ savedInitialViewState,
158
+ zoomToFitInProgress
159
+ );
160
+ setZoomState(zoomState);
161
+ }
162
+ };
137
163
  return /* @__PURE__ */ import_react.default.createElement(
138
164
  "div",
139
165
  {
@@ -148,7 +174,7 @@ const MapContent = (0, import_react.forwardRef)((props, forwardedRef) => {
148
174
  onMove: (evt) => {
149
175
  onViewStateChange?.(evt.viewState);
150
176
  },
151
- initialViewState: (0, import_to_mapbox_initial_view_state.toMapBoxInitialViewState)(initialViewState),
177
+ initialViewState: calculatedInitialViewState,
152
178
  style: {
153
179
  width: graphWidth,
154
180
  height: `${graphHeight}px`,
@@ -166,12 +192,20 @@ const MapContent = (0, import_react.forwardRef)((props, forwardedRef) => {
166
192
  onMouseMove: (e) => handleMouseMove(e),
167
193
  onClick: (e) => handleMouseClick(e),
168
194
  onZoom: handleZoom,
195
+ onZoomEnd: handleZoomEnd,
169
196
  onDrag: handleDrag,
197
+ onDragEnd: handleDragEnd,
170
198
  attributionControl: false,
171
199
  onRender: () => onRenderHandler && onRenderHandler(),
172
- onLoad: () => {
200
+ onLoad: (e) => {
173
201
  onMapLoad();
174
202
  onLoadHandler && onLoadHandler();
203
+ const initialCenter = e.target.getCenter();
204
+ setSavedInitialViewState({
205
+ latitude: initialCenter.lat,
206
+ longitude: initialCenter.lng,
207
+ zoom: e.target.getZoom()
208
+ });
175
209
  },
176
210
  ref: (0, import_use_set_map_initial_configuration.useSetMapInitialConfiguration)(),
177
211
  interactive: true,
@@ -36,16 +36,20 @@ var import_react_intl = require("react-intl");
36
36
  var import_charts = require("@dynatrace/strato-components-preview/charts");
37
37
  var import_strato_icons = require("@dynatrace/strato-icons");
38
38
  var import_use_initial_view_context = require("../../../hooks/use-initial-view-context.js");
39
+ var import_store = require("../../../store/store.js");
39
40
  var import_constants = require("../constants.js");
40
41
  var import_use_a11y_toolbar_tab_index = require("../hooks/use-a11y-toolbar-tab-index.js");
41
42
  const MapResetButton = () => {
42
43
  const { current: map } = (0, import_react_maplibre.useMap)();
43
44
  const { longitude = 0, latitude = 0, zoom = 0 } = (0, import_use_initial_view_context.useInitialViewContext)();
44
45
  const intl = (0, import_react_intl.useIntl)();
46
+ const { resetEnabled } = (0, import_store.useMapZoomState)();
47
+ const setZoomState = (0, import_store.useSetStateZoom)();
45
48
  const resetButtonRef = (0, import_react.useRef)();
46
49
  const tabIndex = (0, import_use_a11y_toolbar_tab_index.useA11yToolbarTabIndex)("reset");
47
50
  const handleReset = () => {
48
51
  map?.flyTo({ center: [longitude, latitude], zoom });
52
+ setZoomState({ zoomToFitEnabled: true, resetEnabled: false });
49
53
  };
50
54
  const handleKeyDown = (event) => {
51
55
  if (event.code === "Enter") {
@@ -61,7 +65,8 @@ const MapResetButton = () => {
61
65
  testId: "map-toolbar-reset",
62
66
  onKeyDown: handleKeyDown,
63
67
  onClick: handleReset,
64
- tabIndex
68
+ tabIndex,
69
+ disabled: !resetEnabled
65
70
  }
66
71
  );
67
72
  };
@@ -35,12 +35,12 @@ var import_react = __toESM(require("react"));
35
35
  var import_react_intl = require("react-intl");
36
36
  var import_charts = require("@dynatrace/strato-components-preview/charts");
37
37
  var import_strato_icons = require("@dynatrace/strato-icons");
38
+ var import_selectors = require("../../../store/selectors.js");
38
39
  var import_constants = require("../constants.js");
39
40
  var import_use_a11y_toolbar_tab_index = require("../hooks/use-a11y-toolbar-tab-index.js");
40
41
  const MapZoomInOutButtons = () => {
41
42
  const { current: map } = (0, import_react_maplibre.useMap)();
42
- const isMaxZoom = map && map?.getMaxZoom() === map?.getZoom();
43
- const isMinZoom = map && map?.getMinZoom() === map?.getZoom();
43
+ const { zoomInEnabled, zoomOutEnabled } = (0, import_selectors.useMapZoomState)();
44
44
  const zoomInButtonRef = (0, import_react.useRef)();
45
45
  const zoomButtonOutRef = (0, import_react.useRef)();
46
46
  const intl = (0, import_react_intl.useIntl)();
@@ -69,7 +69,7 @@ const MapZoomInOutButtons = () => {
69
69
  onKeyDown: (event) => handleZoomKeyboardMode(event, "zoom-in"),
70
70
  onClick: () => handleZoomStepToolbarMode("zoom-in"),
71
71
  tabIndex: tabIndexIn,
72
- disabled: isMaxZoom
72
+ disabled: !zoomInEnabled
73
73
  }
74
74
  ), /* @__PURE__ */ import_react.default.createElement(
75
75
  import_charts._ChartToolbarRenderer.Control,
@@ -81,7 +81,7 @@ const MapZoomInOutButtons = () => {
81
81
  onKeyDown: (event) => handleZoomKeyboardMode(event, "zoom-out"),
82
82
  onClick: () => handleZoomStepToolbarMode("zoom-out"),
83
83
  tabIndex: tabIndexOut,
84
- disabled: isMinZoom
84
+ disabled: !zoomOutEnabled
85
85
  }
86
86
  ));
87
87
  };
@@ -37,6 +37,7 @@ var import_charts = require("@dynatrace/strato-components-preview/charts");
37
37
  var import_strato_icons = require("@dynatrace/strato-icons");
38
38
  var import_constants = require("../../../constants.js");
39
39
  var import_use_data_bounding_box = require("../../../hooks/use-data-bounding-box.js");
40
+ var import_store = require("../../../store/store.js");
40
41
  var import_constants2 = require("../constants.js");
41
42
  var import_use_a11y_toolbar_tab_index = require("../hooks/use-a11y-toolbar-tab-index.js");
42
43
  const MapZoomToFitButton = () => {
@@ -45,8 +46,11 @@ const MapZoomToFitButton = () => {
45
46
  const tabIndex = (0, import_use_a11y_toolbar_tab_index.useA11yToolbarTabIndex)("zoom-to-fit");
46
47
  const intl = (0, import_react_intl.useIntl)();
47
48
  const boundingBox = (0, import_use_data_bounding_box.useDataBoundingBox)();
49
+ const { zoomToFitEnabled } = (0, import_store.useMapZoomState)();
50
+ const setZoomState = (0, import_store.useSetStateZoom)();
48
51
  const handleZoomToFit = () => {
49
52
  map?.fitBounds(boundingBox, import_constants.FIT_BOUNDS_OPTIONS);
53
+ setZoomState({ zoomToFitEnabled: false, zoomToFitInProgress: true });
50
54
  };
51
55
  const handleKeyDown = (event) => {
52
56
  if (event.code === "Enter") {
@@ -62,7 +66,8 @@ const MapZoomToFitButton = () => {
62
66
  testId: "map-toolbar-zoom-to-fit",
63
67
  onKeyDown: handleKeyDown,
64
68
  onClick: handleZoomToFit,
65
- tabIndex
69
+ tabIndex,
70
+ disabled: !zoomToFitEnabled
66
71
  }
67
72
  );
68
73
  };
@@ -0,0 +1,4 @@
1
+ import { type ViewStateChangeEvent } from '@vis.gl/react-maplibre';
2
+ import type { ViewStateRequired } from '../../../types/map-view.js';
3
+ import type { ZoomState } from '../../../types/state.js';
4
+ export declare function generateNewZoomState(event: ViewStateChangeEvent, initialViewState: ViewStateRequired, zoomToFitInProgress?: boolean): Partial<ZoomState>;
@@ -0,0 +1,47 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var zoom_state_utils_exports = {};
19
+ __export(zoom_state_utils_exports, {
20
+ generateNewZoomState: () => generateNewZoomState
21
+ });
22
+ module.exports = __toCommonJS(zoom_state_utils_exports);
23
+ var import_constants = require("../../../constants.js");
24
+ function compareViewStates(currentViewState, initialViewState) {
25
+ return currentViewState.zoom.toFixed(import_constants.VIEW_STATE_PRECISION) === initialViewState.zoom.toFixed(import_constants.VIEW_STATE_PRECISION) && currentViewState.latitude.toFixed(import_constants.VIEW_STATE_PRECISION) === initialViewState.latitude.toFixed(import_constants.VIEW_STATE_PRECISION) && currentViewState.longitude.toFixed(import_constants.VIEW_STATE_PRECISION) === initialViewState.longitude.toFixed(import_constants.VIEW_STATE_PRECISION);
26
+ }
27
+ function isMinZoomReached(currentBounds) {
28
+ return currentBounds._ne.lat.toFixed(import_constants.MAX_BOUNDS_PRECISION) === import_constants.MAX_LATITUDE.toFixed(import_constants.MAX_BOUNDS_PRECISION) && currentBounds._sw.lat.toFixed(import_constants.MAX_BOUNDS_PRECISION) === import_constants.MIN_LATITUDE.toFixed(import_constants.MAX_BOUNDS_PRECISION) || currentBounds._ne.lng.toFixed(import_constants.MAX_BOUNDS_PRECISION) === import_constants.MAX_LONGITUDE.toFixed(import_constants.MAX_BOUNDS_PRECISION) && currentBounds._sw.lng.toFixed(import_constants.MAX_BOUNDS_PRECISION) === import_constants.MIN_LONGITUDE.toFixed(import_constants.MAX_BOUNDS_PRECISION);
29
+ }
30
+ function generateNewZoomState(event, initialViewState, zoomToFitInProgress) {
31
+ const map = event.target;
32
+ const viewState = event.viewState;
33
+ const currentBBox = map?.getBounds();
34
+ const zoomState = {};
35
+ if (event.type === "zoomend") {
36
+ zoomState.zoomInEnabled = map?.getMaxZoom() !== map?.getZoom();
37
+ zoomState.zoomOutEnabled = !isMinZoomReached(currentBBox);
38
+ }
39
+ if (zoomToFitInProgress) {
40
+ zoomState.zoomToFitEnabled = false;
41
+ zoomState.zoomToFitInProgress = false;
42
+ } else {
43
+ zoomState.zoomToFitEnabled = true;
44
+ }
45
+ zoomState.resetEnabled = !compareViewStates(viewState, initialViewState);
46
+ return zoomState;
47
+ }
@@ -1,6 +1,7 @@
1
1
  import type { ExpressionSpecification } from '@maplibre/maplibre-gl-style-spec';
2
2
  import type { _TruncationMode as TruncationMode } from '@dynatrace/strato-components/typography';
3
3
  import type { BaseLayerRules } from './types/base-layer.js';
4
+ import type { BoundingBoxCoords } from './types/map-view.js';
4
5
  export declare const DEFAULT_COUNTRIES_FILL_COLOR: string;
5
6
  export declare const DEFAULT_BOUNDARIES_BORDER_COLOR: string;
6
7
  export declare const COUNTRY_BORDER_WIDTH = 1;
@@ -10,7 +11,7 @@ export declare const MAX_LATITUDE = 85;
10
11
  export declare const MIN_LATITUDE = -60;
11
12
  export declare const MAX_LONGITUDE = 179.99;
12
13
  export declare const MIN_LONGITUDE = -179.99;
13
- export declare const WORLD_VIEW_MAX_BOUNDARIES: [number, number, number, number];
14
+ export declare const WORLD_VIEW_MAX_BOUNDARIES: BoundingBoxCoords;
14
15
  export declare const DEFAULT_COUNTRY_CODE = "default";
15
16
  export declare const FIT_BOUNDS_OPTIONS: {
16
17
  padding: number;
@@ -76,3 +77,6 @@ export declare const COPY_TO_CLIPBOARD_MESSAGES: {
76
77
  };
77
78
  };
78
79
  export declare const DEFAULT_BASE_LAYER_RULES: BaseLayerRules;
80
+ export declare const BOUNDING_BOX_PRECISION = 6;
81
+ export declare const VIEW_STATE_PRECISION = 4;
82
+ export declare const MAX_BOUNDS_PRECISION = 2;
package/map/constants.js CHANGED
@@ -33,6 +33,7 @@ __export(constants_exports, {
33
33
  BASE_LAYER_FILL_ID: () => BASE_LAYER_FILL_ID,
34
34
  BASE_LAYER_IDS: () => BASE_LAYER_IDS,
35
35
  BASE_LAYER_LINE_ID: () => BASE_LAYER_LINE_ID,
36
+ BOUNDING_BOX_PRECISION: () => BOUNDING_BOX_PRECISION,
36
37
  BUBBLE_DEFAULT_OPACITY: () => BUBBLE_DEFAULT_OPACITY,
37
38
  BUBBLE_OUTLINE_STROKE: () => BUBBLE_OUTLINE_STROKE,
38
39
  BUBBLE_STROKE: () => BUBBLE_STROKE,
@@ -74,6 +75,7 @@ __export(constants_exports, {
74
75
  ICON_BACKGROUND_OPACITY: () => ICON_BACKGROUND_OPACITY,
75
76
  ICON_BACKGROUND_RADIUS: () => ICON_BACKGROUND_RADIUS,
76
77
  INCLUDE_ALL_WILDCARD_RULE: () => INCLUDE_ALL_WILDCARD_RULE,
78
+ MAX_BOUNDS_PRECISION: () => MAX_BOUNDS_PRECISION,
77
79
  MAX_LATITUDE: () => MAX_LATITUDE,
78
80
  MAX_LINE_THICKNESS: () => MAX_LINE_THICKNESS,
79
81
  MAX_LONGITUDE: () => MAX_LONGITUDE,
@@ -84,6 +86,7 @@ __export(constants_exports, {
84
86
  SHAPE_OPACITY_DEFAULT: () => SHAPE_OPACITY_DEFAULT,
85
87
  SHAPE_OPACITY_DIMMED: () => SHAPE_OPACITY_DIMMED,
86
88
  TRANSPARENT_BORDER_COLOR: () => TRANSPARENT_BORDER_COLOR,
89
+ VIEW_STATE_PRECISION: () => VIEW_STATE_PRECISION,
87
90
  WORLD_VIEW_MAX_BOUNDARIES: () => WORLD_VIEW_MAX_BOUNDARIES
88
91
  });
89
92
  module.exports = __toCommonJS(constants_exports);
@@ -175,3 +178,6 @@ const DEFAULT_BASE_LAYER_RULES = {
175
178
  include: [INCLUDE_ALL_WILDCARD_RULE],
176
179
  exclude: []
177
180
  };
181
+ const BOUNDING_BOX_PRECISION = 6;
182
+ const VIEW_STATE_PRECISION = 4;
183
+ const MAX_BOUNDS_PRECISION = 2;
@@ -1,2 +1,3 @@
1
1
  import React from 'react';
2
- export declare const MapDataBoundingBoxContext: React.Context<[number, number, number, number]>;
2
+ import type { BoundingBoxCoords } from '../types/map-view.js';
3
+ export declare const MapDataBoundingBoxContext: React.Context<BoundingBoxCoords>;
@@ -32,4 +32,6 @@ __export(map_data_bounding_box_context_exports, {
32
32
  module.exports = __toCommonJS(map_data_bounding_box_context_exports);
33
33
  var import_react = __toESM(require("react"));
34
34
  var import_constants = require("../constants.js");
35
- const MapDataBoundingBoxContext = import_react.default.createContext(import_constants.WORLD_VIEW_MAX_BOUNDARIES);
35
+ const MapDataBoundingBoxContext = import_react.default.createContext(
36
+ import_constants.WORLD_VIEW_MAX_BOUNDARIES
37
+ );
@@ -49,24 +49,28 @@ const useActiveInteraction = () => {
49
49
  { source: sourceId, id: featureId },
50
50
  { active: !activeState }
51
51
  );
52
- allFeatures.map(
53
- (feature) => map.setFeatureState(
54
- { source: feature.layer.source, id: feature.id },
55
- { isAnyActive: !activeState }
56
- )
57
- );
52
+ allFeatures.forEach((feature) => {
53
+ if (feature.id !== void 0 && feature.layer.source !== void 0) {
54
+ map.setFeatureState(
55
+ { source: feature.layer.source, id: feature.id },
56
+ { isAnyActive: !activeState }
57
+ );
58
+ }
59
+ });
58
60
  } else {
59
61
  if (!(0, import_lodash_es.isUndefined)(featureId) && !(0, import_lodash_es.isUndefined)(sourceId)) {
60
62
  map.setFeatureState(
61
63
  { source: sourceId, id: featureId },
62
64
  { active: false }
63
65
  );
64
- allFeatures.map(
65
- (feature) => map.setFeatureState(
66
- { source: feature.layer.source, id: feature.id },
67
- { isAnyActive: false }
68
- )
69
- );
66
+ allFeatures.forEach((feature) => {
67
+ if (feature.id !== void 0 && feature.layer.source !== void 0) {
68
+ map.setFeatureState(
69
+ { source: feature.layer.source, id: feature.id },
70
+ { isAnyActive: false }
71
+ );
72
+ }
73
+ });
70
74
  }
71
75
  }
72
76
  },
@@ -1 +1 @@
1
- export declare const useDataBoundingBox: () => [number, number, number, number];
1
+ export declare const useDataBoundingBox: () => import("../types/map-view.js").BoundingBoxCoords;
@@ -36,7 +36,7 @@ const useResolveColor = (defaultColor, props, colorParser) => {
36
36
  if (!(0, import_coloring.isLegendColoring)(props)) {
37
37
  return props.color ?? defaultColor;
38
38
  }
39
- const fallbackColor = !(0, import_lodash_es.isUndefined)(legend) && (0, import_build_scale_from_legend_config.isSequentialLegend)(legend) ? import_constants.DEFAULT_RANGE_COLOR : defaultColor;
39
+ const fallbackColor = !(0, import_lodash_es.isUndefined)(legend) && ((0, import_build_scale_from_legend_config.isSequentialLegend)(legend) || (0, import_build_scale_from_legend_config.isThresholdLegend)(legend)) ? import_constants.DEFAULT_RANGE_COLOR : defaultColor;
40
40
  let colorLegend = fallbackColor;
41
41
  if (!(0, import_lodash_es.isUndefined)(legendColoring) && !(0, import_lodash_es.isUndefined)(colorParser)) {
42
42
  colorLegend = (item) => {
@@ -11,8 +11,10 @@ import React, { type PropsWithChildren } from 'react';
11
11
  * @see {@link LayerColorStrategyProvider}
12
12
  * @example to build a legend the raw scale could be needed
13
13
  * @param categories - Available categories to be shown in the legend
14
+ * @param dataMax - Maximum value present in the data
14
15
  * @param children -
15
16
  */
16
- export declare const ColorScaleProvider: ({ categories, children, }: PropsWithChildren<{
17
+ export declare const ColorScaleProvider: ({ categories, dataMax, children, }: PropsWithChildren<{
17
18
  categories: string[];
19
+ dataMax: number;
18
20
  }>) => React.JSX.Element;
@@ -37,6 +37,7 @@ var import_use_map_config = require("../hooks/use-map-config.js");
37
37
  var import_build_scale_from_legend_config = require("../utils/build-scale-from-legend-config.js");
38
38
  const ColorScaleProvider = ({
39
39
  categories,
40
+ dataMax,
40
41
  children
41
42
  }) => {
42
43
  const { legend } = (0, import_use_map_config.useMapConfig)();
@@ -44,6 +45,6 @@ const ColorScaleProvider = ({
44
45
  return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, children);
45
46
  }
46
47
  const categoriesArray = "categories" in legend && legend.categories ? legend.categories : categories;
47
- const scale = (0, import_build_scale_from_legend_config.buildScaleFromLegendConfig)(legend, categoriesArray);
48
+ const scale = (0, import_build_scale_from_legend_config.buildScaleFromLegendConfig)(legend, categoriesArray, dataMax);
48
49
  return /* @__PURE__ */ import_react.default.createElement(import_color_scale_context.ColorScaleContext.Provider, { value: scale }, children);
49
50
  };
@@ -26,6 +26,7 @@ var import_constants = require("../constants.js");
26
26
  var import_use_data_bounding_box = require("../hooks/use-data-bounding-box.js");
27
27
  var import_use_initial_view_context = require("../hooks/use-initial-view-context.js");
28
28
  var import_use_map_raw_data = require("../hooks/use-map-raw-data.js");
29
+ var import_store = require("../store/store.js");
29
30
  var import_build_and_download_csv = require("../utils/build-and-download-csv.js");
30
31
  const MapViewImperativeHandler = ({
31
32
  forwardedRef,
@@ -36,8 +37,13 @@ const MapViewImperativeHandler = ({
36
37
  const { current: map } = (0, import_react_maplibre.useMap)();
37
38
  const { longitude = 0, latitude = 0, zoom = 0 } = (0, import_use_initial_view_context.useInitialViewContext)();
38
39
  const boundingBox = (0, import_use_data_bounding_box.useDataBoundingBox)();
40
+ const setZoomState = (0, import_store.useSetStateZoom)();
39
41
  const zoomOutEnabled = map && map?.getMinZoom() !== map?.getZoom();
40
42
  const zoomInEnabled = map && map?.getMaxZoom() !== map?.getZoom();
43
+ const handleZoomToFit = () => {
44
+ map?.fitBounds(boundingBox, import_constants.FIT_BOUNDS_OPTIONS);
45
+ setZoomState({ zoomToFitEnabled: false, zoomToFitInProgress: true });
46
+ };
41
47
  (0, import_react.useImperativeHandle)(forwardedRef, () => ({
42
48
  element: containerRef.current,
43
49
  downloadData: () => {
@@ -45,7 +51,7 @@ const MapViewImperativeHandler = ({
45
51
  },
46
52
  zoomIn: () => zoomInEnabled && map?.zoomIn(),
47
53
  zoomOut: () => zoomOutEnabled && map?.zoomOut(),
48
- zoomToFit: () => map?.fitBounds(boundingBox, import_constants.FIT_BOUNDS_OPTIONS),
54
+ zoomToFit: () => handleZoomToFit(),
49
55
  reset: () => map?.flyTo({ center: [longitude, latitude], zoom })
50
56
  }));
51
57
  return children;
@@ -17,5 +17,11 @@ export declare const initialState: {
17
17
  highlightedSeries: undefined;
18
18
  visible: undefined;
19
19
  };
20
+ zoom: {
21
+ zoomInEnabled: boolean;
22
+ zoomOutEnabled: boolean;
23
+ zoomToFitEnabled: boolean;
24
+ resetEnabled: boolean;
25
+ };
20
26
  };
21
27
  export declare const MapStore: React.Context<Store<MapState<unknown>>>;
@@ -46,7 +46,13 @@ const initialState = {
46
46
  overlay: {
47
47
  mouseInBounds: false
48
48
  },
49
- selection: initialSelection
49
+ selection: initialSelection,
50
+ zoom: {
51
+ zoomInEnabled: true,
52
+ zoomOutEnabled: true,
53
+ zoomToFitEnabled: true,
54
+ resetEnabled: false
55
+ }
50
56
  };
51
57
  const MapStore = import_react.default.createContext(
52
58
  (0, import_core.createStore)(initialState)
@@ -13,3 +13,4 @@ export declare const useMapTooltipState: <T>() => {
13
13
  };
14
14
  export declare const useMapTooltipPinnedState: <T>() => boolean;
15
15
  export declare const useMapOverlayState: <T>() => import("../types/state.js").MapOverlayState;
16
+ export declare const useMapZoomState: <T>() => import("../types/state.js").ZoomState;
@@ -21,6 +21,7 @@ __export(selectors_exports, {
21
21
  useMapSelectionState: () => useMapSelectionState,
22
22
  useMapTooltipPinnedState: () => useMapTooltipPinnedState,
23
23
  useMapTooltipState: () => useMapTooltipState,
24
+ useMapZoomState: () => useMapZoomState,
24
25
  useSelector: () => useSelector
25
26
  });
26
27
  module.exports = __toCommonJS(selectors_exports);
@@ -38,3 +39,4 @@ const useMapTooltipPinnedState = () => useSelector(({ tooltip }) => {
38
39
  return pinned;
39
40
  });
40
41
  const useMapOverlayState = () => useSelector(({ overlay }) => overlay);
42
+ const useMapZoomState = () => useSelector(({ zoom }) => zoom);
@@ -1,7 +1,8 @@
1
- import type { MapOverlayState, MapSelectionState, MapTooltipState } from '../types/state.js';
1
+ import type { MapOverlayState, MapSelectionState, MapTooltipState, ZoomState } from '../types/state.js';
2
2
  export declare const useSetState: () => (action: import("../types/state.js").MapState<unknown> | ((prev: import("../types/state.js").MapState<unknown>) => import("../types/state.js").MapState<unknown>)) => void;
3
3
  export * from './selectors.js';
4
4
  export declare const useSetStateSelection: () => (newSelectionState: Partial<MapSelectionState>) => void;
5
5
  export declare const useSetStateTooltip: <T>() => (newTooltipState: Partial<MapTooltipState<T>>) => void;
6
6
  export declare const useSetStateOverlay: () => (newOverlayState: Partial<MapOverlayState>) => void;
7
7
  export declare const useToggleStatePinnedTooltip: () => () => void;
8
+ export declare const useSetStateZoom: () => (newZoomState: Partial<ZoomState>) => void;
@@ -22,6 +22,7 @@ __export(store_exports, {
22
22
  useSetStateOverlay: () => useSetStateOverlay,
23
23
  useSetStateSelection: () => useSetStateSelection,
24
24
  useSetStateTooltip: () => useSetStateTooltip,
25
+ useSetStateZoom: () => useSetStateZoom,
25
26
  useToggleStatePinnedTooltip: () => useToggleStatePinnedTooltip
26
27
  });
27
28
  module.exports = __toCommonJS(store_exports);
@@ -85,3 +86,15 @@ const useToggleStatePinnedTooltip = () => {
85
86
  });
86
87
  };
87
88
  };
89
+ const useSetStateZoom = () => {
90
+ const setState = useSetState();
91
+ return (newZoomState) => {
92
+ setState((prev) => ({
93
+ ...prev,
94
+ zoom: {
95
+ ...prev.zoom,
96
+ ...newZoomState
97
+ }
98
+ }));
99
+ };
100
+ };
@@ -22,6 +22,8 @@ export interface ViewState {
22
22
  /** Map zoom level */
23
23
  zoom?: number;
24
24
  }
25
+ export type ViewStateRequired = Required<ViewState>;
26
+ export type BoundingBoxCoords = [number, number, number, number];
25
27
  /**
26
28
  * Type to use in a controlled Map.
27
29
  * It disallows the initial state and gives the user complete control over the interactions
@@ -17,8 +17,16 @@ export interface MapTooltipState<T> {
17
17
  export interface MapOverlayState {
18
18
  mouseInBounds: boolean;
19
19
  }
20
+ export interface ZoomState {
21
+ zoomInEnabled: boolean;
22
+ zoomOutEnabled: boolean;
23
+ zoomToFitEnabled: boolean;
24
+ resetEnabled: boolean;
25
+ zoomToFitInProgress?: boolean;
26
+ }
20
27
  export interface MapState<T = unknown> {
21
28
  selection: MapSelectionState;
22
29
  tooltip: MapTooltipState<T>;
23
30
  overlay: MapOverlayState;
31
+ zoom: ZoomState;
24
32
  }
@@ -5,4 +5,4 @@ export declare const isCategoricalLegend: (legendConfig: MapLegendConfig) => leg
5
5
  /**
6
6
  * Builds a scale for the corresponding map legend configuration
7
7
  */
8
- export declare const buildScaleFromLegendConfig: (mapLegendConfig: MapLegendConfig, categories?: string[]) => import("d3-scale").ScaleOrdinal<string, string, never> | import("d3-scale").ScaleThreshold<number, string, never> | undefined;
8
+ export declare const buildScaleFromLegendConfig: (mapLegendConfig: MapLegendConfig, categories?: string[], dataMax?: number) => import("d3-scale").ScaleOrdinal<string, string, never> | import("d3-scale").ScaleThreshold<number, string, never> | undefined;