@mwater/visualization 5.0.0 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/lib/MWaterContextComponent.js +1 -4
  2. package/lib/datagrids/DatagridComponent.d.ts +2 -0
  3. package/lib/datagrids/DatagridComponent.js +8 -2
  4. package/lib/datagrids/DatagridViewComponent.d.ts +2 -0
  5. package/lib/datagrids/DatagridViewComponent.js +3 -2
  6. package/lib/datagrids/LabeledExprGenerator.js +15 -0
  7. package/lib/dayjs.d.ts +2 -0
  8. package/lib/dayjs.js +9 -0
  9. package/lib/languages.js +5 -0
  10. package/lib/maps/DetailLevelSelectComponent.d.ts +1 -93
  11. package/lib/maps/Layer.js +7 -18
  12. package/lib/maps/MapComponent.js +1 -1
  13. package/lib/maps/RegionSelectComponent.d.ts +1 -33
  14. package/lib/maps/VectorMapViewComponent.js +21 -29
  15. package/lib/quickfilter/QuickfiltersComponent.d.ts +2 -186
  16. package/lib/quickfilter/QuickfiltersDesignComponent.js +1 -1
  17. package/lib/quickfilter/TextLiteralComponent.d.ts +2 -186
  18. package/lib/quickfilter/TextLiteralComponent.js +3 -0
  19. package/lib/valueFormatter.js +52 -1
  20. package/lib/widgets/charts/layered/LayeredChartCompiler.d.ts +1 -1
  21. package/lib/widgets/charts/pivot/PivotChartLayout.d.ts +3 -2
  22. package/lib/widgets/charts/pivot/PivotChartLayoutComponent.js +4 -1
  23. package/lib/widgets/charts/pivot/PivotChartQueryBuilder.js +1 -1
  24. package/lib/widgets/charts/table/TableChart.js +15 -4
  25. package/lib/widgets/charts/table/TableChartViewComponent.d.ts +2 -1
  26. package/lib/widgets/charts/table/TableChartViewComponent.js +9 -4
  27. package/package.json +8 -8
  28. package/src/MWaterAddRelatedIndicatorComponent.ts +1 -1
  29. package/src/MWaterContextComponent.ts +1 -4
  30. package/src/datagrids/DatagridComponent.ts +15 -1
  31. package/src/datagrids/DatagridViewComponent.ts +6 -2
  32. package/src/datagrids/LabeledExprGenerator.ts +15 -0
  33. package/src/dayjs.ts +5 -0
  34. package/src/languages.ts +5 -0
  35. package/src/maps/Layer.ts +6 -16
  36. package/src/maps/MapComponent.ts +1 -1
  37. package/src/maps/RasterMapViewComponent.ts +0 -1
  38. package/src/maps/VectorMapViewComponent.tsx +23 -36
  39. package/src/quickfilter/QuickfiltersDesignComponent.tsx +1 -1
  40. package/src/quickfilter/TextLiteralComponent.ts +4 -0
  41. package/src/valueFormatter.ts +54 -1
  42. package/src/widgets/charts/pivot/PivotChartLayout.ts +3 -2
  43. package/src/widgets/charts/pivot/PivotChartLayoutBuilder.ts +2 -2
  44. package/src/widgets/charts/pivot/PivotChartLayoutComponent.tsx +7 -3
  45. package/src/widgets/charts/pivot/PivotChartQueryBuilder.ts +1 -1
  46. package/src/widgets/charts/table/TableChart.ts +24 -14
  47. package/src/widgets/charts/table/TableChartViewComponent.ts +10 -5
  48. package/stories/dashboards.js +3 -3
@@ -91,11 +91,8 @@ class MWaterContextComponent extends react_1.default.Component {
91
91
  }
92
92
  return null;
93
93
  };
94
- // Always open indicator section
94
+ // Nothing initially open
95
95
  context.isScalarExprTreeSectionInitiallyOpen = (options) => {
96
- if (options.tableId.match(/^entities\./) && options.section.id === "!indicators") {
97
- return true;
98
- }
99
96
  return null;
100
97
  };
101
98
  return context;
@@ -38,6 +38,7 @@ export default class DatagridComponent extends React.Component<DatagridComponent
38
38
  /** Height of quickfilters */
39
39
  quickfiltersHeight: number | null;
40
40
  quickfiltersValues: null | any[];
41
+ refreshKey: number;
41
42
  }> {
42
43
  datagridView?: DatagridViewComponent | null;
43
44
  quickfilters?: HTMLElement | null;
@@ -46,6 +47,7 @@ export default class DatagridComponent extends React.Component<DatagridComponent
46
47
  reload(): void | undefined;
47
48
  componentDidMount(): void;
48
49
  componentDidUpdate(): void;
50
+ handleRefreshData: () => void;
49
51
  updateHeight(): void;
50
52
  getQuickfilterValues: () => any[];
51
53
  getQuickfilterFilters: () => JsonQLFilter[];
@@ -30,7 +30,8 @@ class DatagridComponent extends react_1.default.Component {
30
30
  editingDesign: false,
31
31
  cellEditingEnabled: false,
32
32
  quickfiltersHeight: null,
33
- quickfiltersValues: null
33
+ quickfiltersValues: null,
34
+ refreshKey: 1
34
35
  };
35
36
  }
36
37
  reload() {
@@ -42,6 +43,10 @@ class DatagridComponent extends react_1.default.Component {
42
43
  componentDidUpdate() {
43
44
  return this.updateHeight();
44
45
  }
46
+ handleRefreshData = () => {
47
+ this.props.dataSource.clearCache?.();
48
+ this.setState({ refreshKey: this.state.refreshKey + 1 });
49
+ };
45
50
  updateHeight() {
46
51
  // Calculate quickfilters height
47
52
  if (this.quickfilters) {
@@ -159,7 +164,7 @@ class DatagridComponent extends react_1.default.Component {
159
164
  }, T("Find/Replace"));
160
165
  }
161
166
  renderTitleBar() {
162
- return R("div", { style: { position: "absolute", top: 0, left: 0, right: 0, height: 40, padding: 4 } }, R("div", { style: { float: "right" } }, this.renderFindReplace(), this.renderCellEdit(), this.renderEditButton(), this.props.extraTitleButtonsElem), this.props.titleElem);
167
+ return R("div", { style: { position: "absolute", top: 0, left: 0, right: 0, height: 40, padding: 4 } }, R("div", { style: { float: "right" } }, this.renderFindReplace(), this.renderCellEdit(), this.renderEditButton(), R("a", { key: "refresh", className: "btn btn-link btn-sm", onClick: this.handleRefreshData }, R("span", { className: "fas fa-sync" }), R("span", { className: "hide-600px" }, " Refresh")), this.props.extraTitleButtonsElem), this.props.titleElem);
163
168
  }
164
169
  renderQuickfilter() {
165
170
  return R("div", {
@@ -247,6 +252,7 @@ class DatagridComponent extends react_1.default.Component {
247
252
  onRowDoubleClick: this.props.onRowDoubleClick,
248
253
  canEditExpr: this.state.cellEditingEnabled ? this.props.canEditExpr : undefined,
249
254
  updateExprValues: this.state.cellEditingEnabled ? this.props.updateExprValues : undefined,
255
+ refreshKey: this.state.refreshKey
250
256
  });
251
257
  }
252
258
  else if (this.props.onDesignChange) {
@@ -25,6 +25,8 @@ export interface DatagridViewComponentProps {
25
25
  onRowDoubleClick?: (tableId: string, rowId: any, rowIndex: number) => void;
26
26
  /** Called when a row is clicked with (tableId, rowId, rowIndex) */
27
27
  onRowClick?: (tableId: string, rowId: any, rowIndex: number) => void;
28
+ /** Change to force a refresh */
29
+ refreshKey?: any;
28
30
  }
29
31
  /** Update to one row expression value */
30
32
  export interface RowUpdate {
@@ -31,7 +31,7 @@ class DatagridViewComponent extends react_1.default.Component {
31
31
  componentWillReceiveProps(nextProps) {
32
32
  // If design or filters changed, delete all rows
33
33
  // TODO won't this reload on column resize?
34
- if (!lodash_1.default.isEqual(nextProps.design, this.props.design) || !lodash_1.default.isEqual(nextProps.filters, this.props.filters)) {
34
+ if (!lodash_1.default.isEqual(nextProps.design, this.props.design) || !lodash_1.default.isEqual(nextProps.filters, this.props.filters) || nextProps.refreshKey !== this.props.refreshKey) {
35
35
  return this.setState({ rows: [], entirelyLoaded: false });
36
36
  }
37
37
  }
@@ -314,7 +314,8 @@ class DatagridViewComponent extends react_1.default.Component {
314
314
  onRowDoubleClick: this.handleRowDoubleClick,
315
315
  onRowClick: this.handleRowClick,
316
316
  isColumnResizing: false,
317
- onColumnResizeEndCallback: this.handleColumnResize
317
+ onColumnResizeEndCallback: this.handleColumnResize,
318
+ touchScrollEnabled: true
318
319
  }, this.renderColumns());
319
320
  }
320
321
  }
@@ -92,6 +92,21 @@ class LabeledExprGenerator {
92
92
  }
93
93
  ];
94
94
  }
95
+ else if (column.idTable.match(/^custom./)) { // Support cascading ref question
96
+ return this.schema
97
+ .getColumns(column.idTable)
98
+ .filter((c) => c.id[0] !== "_")
99
+ .map((c) => ({
100
+ expr: {
101
+ type: "scalar",
102
+ table,
103
+ joins: [column.id],
104
+ expr: { type: "field", table: column.idTable, column: c.id }
105
+ },
106
+ label: `${createLabel(column)} > ${createLabel(c)}`,
107
+ joins
108
+ }));
109
+ }
95
110
  else {
96
111
  // Use label, code, full name, or name of dest table
97
112
  const destTable = this.schema.getTable(column.idTable);
package/lib/dayjs.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ import dayjs from "dayjs";
2
+ export default dayjs;
package/lib/dayjs.js ADDED
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const dayjs_1 = __importDefault(require("dayjs"));
7
+ const localizedFormat_1 = __importDefault(require("dayjs/plugin/localizedFormat"));
8
+ dayjs_1.default.extend(localizedFormat_1.default);
9
+ exports.default = dayjs_1.default;
package/lib/languages.js CHANGED
@@ -508,6 +508,11 @@ exports.languages = [
508
508
  "name": "Māori",
509
509
  "en": "Maori"
510
510
  },
511
+ {
512
+ "code": "miq",
513
+ "name": "Miskitu",
514
+ "en": "Miskito"
515
+ },
511
516
  {
512
517
  "code": "mk",
513
518
  "name": "Македонски",
@@ -23,99 +23,7 @@ export default class DetailLevelSelectComponent extends React.Component<DetailLe
23
23
  componentWillMount(): any;
24
24
  componentWillReceiveProps(nextProps: any): any;
25
25
  loadLevels(props: any): any;
26
- render(): React.FunctionComponentElement<Omit<Pick<import("react-select/dist/declarations/src/Select").Props<unknown, boolean, import("react-select").GroupBase<unknown>>, "required" | "id" | "name" | "value" | "form" | "className" | "autoFocus" | "aria-errormessage" | "aria-invalid" | "aria-label" | "aria-labelledby" | "onFocus" | "onBlur" | "onChange" | "onKeyDown" | "isClearable" | "theme" | "ariaLiveMessages" | "classNamePrefix" | "delimiter" | "formatOptionLabel" | "hideSelectedOptions" | "inputValue" | "inputId" | "instanceId" | "isOptionSelected" | "menuPortalTarget" | "onInputChange" | "onMenuOpen" | "onMenuClose" | "onMenuScrollToTop" | "onMenuScrollToBottom"> & {
27
- tabIndex?: number | undefined;
28
- options?: import("react-select").OptionsOrGroups<unknown, import("react-select").GroupBase<unknown>> | undefined;
29
- placeholder?: React.ReactNode;
30
- 'aria-live'?: "off" | "assertive" | "polite" | undefined;
31
- styles?: import("react-select").StylesConfig<unknown, boolean, import("react-select").GroupBase<unknown>> | undefined;
32
- isLoading?: boolean | undefined;
33
- isDisabled?: boolean | undefined;
34
- isRtl?: boolean | undefined;
35
- isMulti?: boolean | undefined;
36
- controlShouldRenderValue?: boolean | undefined;
37
- loadingMessage?: ((obj: {
38
- inputValue: string;
39
- }) => React.ReactNode) | undefined;
40
- noOptionsMessage?: ((obj: {
41
- inputValue: string;
42
- }) => React.ReactNode) | undefined;
43
- backspaceRemovesValue?: boolean | undefined;
44
- blurInputOnSelect?: boolean | undefined;
45
- captureMenuScroll?: boolean | undefined;
46
- classNames?: import("react-select").ClassNamesConfig<unknown, boolean, import("react-select").GroupBase<unknown>> | undefined;
47
- closeMenuOnSelect?: boolean | undefined;
48
- closeMenuOnScroll?: boolean | ((event: Event) => boolean) | undefined;
49
- components?: Partial<import("react-select/dist/declarations/src/components").SelectComponents<unknown, boolean, import("react-select").GroupBase<unknown>>> | undefined;
50
- escapeClearsValue?: boolean | undefined;
51
- filterOption?: ((option: import("react-select/dist/declarations/src/filters").FilterOptionOption<unknown>, inputValue: string) => boolean) | null | undefined;
52
- formatGroupLabel?: ((group: import("react-select").GroupBase<unknown>) => React.ReactNode) | undefined;
53
- getOptionLabel?: import("react-select").GetOptionLabel<unknown> | undefined;
54
- getOptionValue?: import("react-select").GetOptionValue<unknown> | undefined;
55
- isOptionDisabled?: ((option: unknown, selectValue: import("react-select").Options<unknown>) => boolean) | undefined;
56
- isSearchable?: boolean | undefined;
57
- minMenuHeight?: number | undefined;
58
- maxMenuHeight?: number | undefined;
59
- menuIsOpen?: boolean | undefined;
60
- menuPlacement?: import("react-select").MenuPlacement | undefined;
61
- menuPosition?: import("react-select").MenuPosition | undefined;
62
- menuShouldBlockScroll?: boolean | undefined;
63
- menuShouldScrollIntoView?: boolean | undefined;
64
- openMenuOnFocus?: boolean | undefined;
65
- openMenuOnClick?: boolean | undefined;
66
- pageSize?: number | undefined;
67
- screenReaderStatus?: ((obj: {
68
- count: number;
69
- }) => string) | undefined;
70
- tabSelectsValue?: boolean | undefined;
71
- unstyled?: boolean | undefined;
72
- } & {}, "value" | "onChange" | "inputValue" | "menuIsOpen" | "onInputChange" | "onMenuOpen" | "onMenuClose"> & Partial<Pick<import("react-select/dist/declarations/src/Select").Props<unknown, boolean, import("react-select").GroupBase<unknown>>, "required" | "id" | "name" | "value" | "form" | "className" | "autoFocus" | "aria-errormessage" | "aria-invalid" | "aria-label" | "aria-labelledby" | "onFocus" | "onBlur" | "onChange" | "onKeyDown" | "isClearable" | "theme" | "ariaLiveMessages" | "classNamePrefix" | "delimiter" | "formatOptionLabel" | "hideSelectedOptions" | "inputValue" | "inputId" | "instanceId" | "isOptionSelected" | "menuPortalTarget" | "onInputChange" | "onMenuOpen" | "onMenuClose" | "onMenuScrollToTop" | "onMenuScrollToBottom"> & {
73
- tabIndex?: number | undefined;
74
- options?: import("react-select").OptionsOrGroups<unknown, import("react-select").GroupBase<unknown>> | undefined;
75
- placeholder?: React.ReactNode;
76
- 'aria-live'?: "off" | "assertive" | "polite" | undefined;
77
- styles?: import("react-select").StylesConfig<unknown, boolean, import("react-select").GroupBase<unknown>> | undefined;
78
- isLoading?: boolean | undefined;
79
- isDisabled?: boolean | undefined;
80
- isRtl?: boolean | undefined;
81
- isMulti?: boolean | undefined;
82
- controlShouldRenderValue?: boolean | undefined;
83
- loadingMessage?: ((obj: {
84
- inputValue: string;
85
- }) => React.ReactNode) | undefined;
86
- noOptionsMessage?: ((obj: {
87
- inputValue: string;
88
- }) => React.ReactNode) | undefined;
89
- backspaceRemovesValue?: boolean | undefined;
90
- blurInputOnSelect?: boolean | undefined;
91
- captureMenuScroll?: boolean | undefined;
92
- classNames?: import("react-select").ClassNamesConfig<unknown, boolean, import("react-select").GroupBase<unknown>> | undefined;
93
- closeMenuOnSelect?: boolean | undefined;
94
- closeMenuOnScroll?: boolean | ((event: Event) => boolean) | undefined;
95
- components?: Partial<import("react-select/dist/declarations/src/components").SelectComponents<unknown, boolean, import("react-select").GroupBase<unknown>>> | undefined;
96
- escapeClearsValue?: boolean | undefined;
97
- filterOption?: ((option: import("react-select/dist/declarations/src/filters").FilterOptionOption<unknown>, inputValue: string) => boolean) | null | undefined;
98
- formatGroupLabel?: ((group: import("react-select").GroupBase<unknown>) => React.ReactNode) | undefined;
99
- getOptionLabel?: import("react-select").GetOptionLabel<unknown> | undefined;
100
- getOptionValue?: import("react-select").GetOptionValue<unknown> | undefined;
101
- isOptionDisabled?: ((option: unknown, selectValue: import("react-select").Options<unknown>) => boolean) | undefined;
102
- isSearchable?: boolean | undefined;
103
- minMenuHeight?: number | undefined;
104
- maxMenuHeight?: number | undefined;
105
- menuIsOpen?: boolean | undefined;
106
- menuPlacement?: import("react-select").MenuPlacement | undefined;
107
- menuPosition?: import("react-select").MenuPosition | undefined;
108
- menuShouldBlockScroll?: boolean | undefined;
109
- menuShouldScrollIntoView?: boolean | undefined;
110
- openMenuOnFocus?: boolean | undefined;
111
- openMenuOnClick?: boolean | undefined;
112
- pageSize?: number | undefined;
113
- screenReaderStatus?: ((obj: {
114
- count: number;
115
- }) => string) | undefined;
116
- tabSelectsValue?: boolean | undefined;
117
- unstyled?: boolean | undefined;
118
- } & {}> & import("react-select/dist/declarations/src/useStateManager").StateManagerAdditionalProps<unknown> & React.RefAttributes<import("react-select/dist/declarations/src/Select").default<unknown, boolean, import("react-select").GroupBase<unknown>>>> | React.DetailedReactHTMLElement<{
26
+ render(): React.FunctionComponentElement<Omit<import("react-select/dist/declarations/src/Select").PublicBaseSelectProps<unknown, boolean, import("react-select").GroupBase<unknown>>, "value" | "onChange" | "inputValue" | "menuIsOpen" | "onInputChange" | "onMenuOpen" | "onMenuClose"> & Partial<import("react-select/dist/declarations/src/Select").PublicBaseSelectProps<unknown, boolean, import("react-select").GroupBase<unknown>>> & import("react-select/dist/declarations/src/useStateManager").StateManagerAdditionalProps<unknown> & React.RefAttributes<import("react-select/dist/declarations/src/Select").default<unknown, boolean, import("react-select").GroupBase<unknown>>>> | React.DetailedReactHTMLElement<{
119
27
  className: string;
120
28
  }, HTMLElement>;
121
29
  }
package/lib/maps/Layer.js CHANGED
@@ -166,24 +166,13 @@ class Layer {
166
166
  let bounds = null;
167
167
  if (results[0].bounds) {
168
168
  const [w, s, e, n] = (0, bbox_1.default)(results[0].bounds);
169
- // Pad to 10km if point
170
- if (w === e && n === s) {
171
- bounds = {
172
- w: w - 0.1,
173
- s: s - 0.1,
174
- e: e + 0.1,
175
- n: n + 0.1
176
- };
177
- // Pad bounds to prevent too small box (10m)
178
- }
179
- else {
180
- bounds = {
181
- w: w - 0.001,
182
- s: s - 0.001,
183
- e: e + 0.001,
184
- n: n + 0.001
185
- };
186
- }
169
+ // Pad bounds to prevent too small box (100m)
170
+ bounds = {
171
+ w: w - 0.001,
172
+ s: s - 0.001,
173
+ e: e + 0.001,
174
+ n: n + 0.001
175
+ };
187
176
  }
188
177
  return callback(null, bounds);
189
178
  }
@@ -180,7 +180,7 @@ class MapComponent extends react_1.default.Component {
180
180
  gridTemplateRows: "auto auto 1fr",
181
181
  gridTemplateAreas: `"header designer" "quickfilters designer" "view designer"`
182
182
  }
183
- }, this.renderHeader(), this.state.hideQuickfilters ? null : this.renderQuickfilter(), R("div", { style: { width: "100%", height: "100%", gridArea: "view", overflow: "hidden" } }, this.renderView()), designerVisible ? this.renderDesigner() : null);
183
+ }, this.props.hideTitleBar != true ? this.renderHeader() : null, this.state.hideQuickfilters ? null : this.renderQuickfilter(), R("div", { style: { width: "100%", height: "100%", gridArea: "view", overflow: "hidden" } }, this.renderView()), designerVisible ? this.renderDesigner() : null);
184
184
  }
185
185
  }
186
186
  exports.default = MapComponent;
@@ -19,37 +19,5 @@ export default class RegionSelectComponent extends React.Component<RegionSelectC
19
19
  regionsTable: string;
20
20
  };
21
21
  handleChange: (id: any) => void;
22
- render(): React.CElement<{
23
- value: string | number | null | undefined;
24
- onChange: (id: any) => void;
25
- idTable: string;
26
- schema: Schema;
27
- dataSource: DataSource;
28
- placeholder: string | undefined;
29
- orderBy: {
30
- expr: {
31
- type: string;
32
- tableAlias: string;
33
- column: string;
34
- };
35
- direction: string;
36
- }[];
37
- filter: import("@mwater/jsonql").JsonQLOp | undefined;
38
- }, React.Component<{
39
- value: string | number | null | undefined;
40
- onChange: (id: any) => void;
41
- idTable: string;
42
- schema: Schema;
43
- dataSource: DataSource;
44
- placeholder: string | undefined;
45
- orderBy: {
46
- expr: {
47
- type: string;
48
- tableAlias: string;
49
- column: string;
50
- };
51
- direction: string;
52
- }[];
53
- filter: import("@mwater/jsonql").JsonQLOp | undefined;
54
- }, any, any>>;
22
+ render(): React.DetailedReactHTMLElement<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
55
23
  }
@@ -27,14 +27,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.VectorMapViewComponent = void 0;
30
- const lodash_1 = __importDefault(require("lodash"));
30
+ const lodash_1 = __importStar(require("lodash"));
31
31
  const react_1 = __importStar(require("react"));
32
32
  const react_2 = require("react");
33
33
  const LayerFactory_1 = __importDefault(require("./LayerFactory"));
34
34
  const ModalPopupComponent_1 = __importDefault(require("@mwater/react-library/lib/ModalPopupComponent"));
35
35
  const useStableCallback_1 = require("@mwater/react-library/lib/useStableCallback");
36
36
  const MapUtils_1 = require("./MapUtils");
37
- const memoizedDebounce_1 = require("../memoizedDebounce");
38
37
  require("maplibre-gl/dist/maplibre-gl.css");
39
38
  require("./VectorMapViewComponent.css");
40
39
  const LayerSwitcherComponent_1 = require("./LayerSwitcherComponent");
@@ -104,6 +103,7 @@ function VectorMapViewComponent(props) {
104
103
  filters: getCompiledFilters()
105
104
  });
106
105
  if (!results) {
106
+ setHoverContents(null);
107
107
  return;
108
108
  }
109
109
  // Handle popup first
@@ -111,9 +111,6 @@ function VectorMapViewComponent(props) {
111
111
  setHoverContents(results.hoverOver);
112
112
  }
113
113
  });
114
- const handleLayerHoverDebounced = (0, memoizedDebounce_1.memoizedDebounce)((layerViewId, ev) => {
115
- handleLayerHover(layerViewId, ev);
116
- }, 250, { leading: true, trailing: false }, (layerViewId, ev) => ev.data.id);
117
114
  /** Handle a click on a layer */
118
115
  const handleLayerClick = (0, useStableCallback_1.useStableCallback)((layerViewId, ev) => {
119
116
  const layerView = props.design.layerViews.find(lv => lv.id == layerViewId);
@@ -394,7 +391,7 @@ function VectorMapViewComponent(props) {
394
391
  props.mapDataSource.getBounds(props.design, getCompiledFilters(), (error, bounds) => {
395
392
  setBusy(b => b - 1);
396
393
  if (bounds) {
397
- map.fitBounds([bounds.w, bounds.s, bounds.e, bounds.n], { padding: 20, duration: 3000 });
394
+ map.fitBounds([bounds.w, bounds.s, bounds.e, bounds.n], { padding: 20, duration: 2500 });
398
395
  // Also record if editable as part of bounds
399
396
  setBounds(bounds);
400
397
  }
@@ -456,39 +453,34 @@ function VectorMapViewComponent(props) {
456
453
  if (!map) {
457
454
  return;
458
455
  }
459
- const removes = [];
460
- for (const clickHandler of layerClickHandlers) {
461
- const onEnter = (ev) => {
462
- if (!ev.features || !ev.features[0].properties) {
456
+ const layers = layerClickHandlers.map(clickHandler => clickHandler.mapLayerId);
457
+ const onEnter = (ev) => {
458
+ let f = map.queryRenderedFeatures(ev.point, { layers });
459
+ if (f.length) {
460
+ if (f[0].layer.type === 'fill' && f[0].layer.paint?.['fill-color']?.toString() == 'rgba(0,0,0,0)') {
463
461
  lastFeature.current = undefined;
464
462
  setHoverContents(null);
465
463
  return;
466
464
  }
467
- if (ev.features[0].properties.id !== lastFeature.current) {
465
+ if (lastFeature.current !== f[0].properties.id) {
466
+ lastFeature.current = f[0].properties.id;
468
467
  setHoverContents(null);
469
- lastFeature.current = ev.features[0].properties.id;
468
+ const handler = (0, lodash_1.find)(layerClickHandlers, { mapLayerId: f[0].layer.id });
469
+ handleLayerHover(handler.layerViewId, {
470
+ data: f[0].properties,
471
+ event: ev
472
+ });
470
473
  }
471
- handleLayerHoverDebounced(clickHandler.layerViewId, {
472
- data: ev.features[0].properties,
473
- event: ev
474
- });
475
- };
476
- const onLeave = (ev) => {
474
+ }
475
+ else {
477
476
  lastFeature.current = undefined;
478
477
  setHoverContents(null);
479
- };
480
- map.on("mousemove", clickHandler.mapLayerId, onEnter);
481
- map.on("mouseleave", clickHandler.mapLayerId, onLeave);
482
- removes.push(() => {
483
- map.off("mousemove", clickHandler.mapLayerId, onEnter);
484
- map.off("mouseleave", clickHandler.mapLayerId, onLeave);
485
- });
486
- }
487
- return () => {
488
- for (const remove of removes) {
489
- remove();
490
478
  }
491
479
  };
480
+ map.on("mousemove", onEnter);
481
+ return () => {
482
+ map.off("mousemove", onEnter);
483
+ };
492
484
  }, [map, layerClickHandlers]);
493
485
  function renderLegend() {
494
486
  if (legendHidden) {