@emuanalytics/flow-rdf-core 4.0.4 → 4.0.5

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 (89) hide show
  1. package/README.md +1 -64
  2. package/dist/index.d.mts +36 -31
  3. package/dist/index.d.ts +36 -31
  4. package/dist/index.mjs +20 -3249
  5. package/dist/lib/context/context-registry.mjs +63 -0
  6. package/dist/lib/context/debugger.mjs +240 -0
  7. package/dist/lib/context/flow-context.mjs +61 -0
  8. package/dist/lib/context/global-state.mjs +70 -0
  9. package/dist/lib/context/map-registry.mjs +59 -0
  10. package/dist/lib/context/query-registry.mjs +53 -0
  11. package/dist/lib/errors/flow-error.mjs +10 -0
  12. package/dist/lib/errors/flow-expression-error.mjs +14 -0
  13. package/dist/lib/errors/flow-map-error.mjs +9 -0
  14. package/dist/lib/expressions/expression-parser.mjs +198 -0
  15. package/dist/lib/expressions/functions/from-palette.mjs +75 -0
  16. package/dist/lib/expressions/functions/regex.mjs +25 -0
  17. package/dist/lib/expressions/functions/state.mjs +25 -0
  18. package/dist/lib/expressions/parser-helpers.mjs +37 -0
  19. package/dist/lib/expressions/reactive-expression.mjs +253 -0
  20. package/dist/lib/map/flow-core-map.mjs +749 -0
  21. package/dist/lib/map/plugins/annotations/annotation-layers.mjs +163 -0
  22. package/dist/lib/map/plugins/annotations/annotation.events.mjs +27 -0
  23. package/dist/lib/map/plugins/annotations/annotation.plugin.mjs +498 -0
  24. package/dist/lib/map/plugins/annotations/maplibre-gl-draw-circle/lib/modes/DirectModeOverride.mjs +67 -0
  25. package/dist/lib/map/plugins/annotations/maplibre-gl-draw-circle/lib/modes/DragCircleMode.mjs +65 -0
  26. package/dist/lib/map/plugins/annotations/maplibre-gl-draw-circle/lib/utils/create_supplementary_points_circle.mjs +15 -0
  27. package/dist/lib/map/plugins/annotations/maplibre-gl-draw-circle/lib/utils/drag_pan.mjs +20 -0
  28. package/dist/lib/map/plugins/data-join.plugin.mjs +173 -0
  29. package/dist/lib/map/plugins/export/export.plugin.mjs +21 -0
  30. package/dist/lib/map/plugins/export/map-exporter.mjs +177 -0
  31. package/dist/lib/map/plugins/hover-effect.plugin.mjs +58 -0
  32. package/dist/lib/map/plugins/index.d.mts +37 -72
  33. package/dist/lib/map/plugins/index.d.ts +37 -72
  34. package/dist/lib/map/plugins/index.mjs +11 -1810
  35. package/dist/lib/map/plugins/keyboard-shortcut-manager.mjs +120 -0
  36. package/dist/lib/map/plugins/map-plugin-base.mjs +25 -0
  37. package/dist/lib/map/plugins/plugin-manager.mjs +135 -0
  38. package/dist/lib/map/plugins/popup.plugin.mjs +55 -0
  39. package/dist/lib/map/plugins/selection/selection.events.mjs +21 -0
  40. package/dist/lib/map/plugins/selection/selection.plugin.mjs +136 -0
  41. package/dist/lib/map/plugins/selection/source-selection.mjs +156 -0
  42. package/dist/lib/map/plugins/url-sync.plugin.mjs +55 -0
  43. package/dist/lib/map/support/image-registry.mjs +82 -0
  44. package/dist/lib/map/support/map-events.mjs +71 -0
  45. package/dist/lib/map/support/map-feature-stream.mjs +158 -0
  46. package/dist/lib/map/support/map-popup.mjs +159 -0
  47. package/dist/lib/map/types.mjs +7 -0
  48. package/dist/lib/map-style/map-data-source.mjs +192 -0
  49. package/dist/lib/map-style/map-layer-style-builder-generated.mjs +1307 -0
  50. package/dist/lib/map-style/map-layer-style-builder.mjs +86 -0
  51. package/dist/lib/map-style/map-layer.mjs +223 -0
  52. package/dist/lib/map-style/map-style.mjs +178 -0
  53. package/dist/lib/queries/async-committer.mjs +30 -0
  54. package/dist/lib/queries/query.mjs +172 -0
  55. package/dist/lib/state-store/decorators.mjs +83 -0
  56. package/dist/lib/state-store/state-store.mjs +534 -0
  57. package/dist/lib/state-store/utils.mjs +7 -0
  58. package/dist/lib/utils/announce.mjs +12 -0
  59. package/dist/lib/utils/assert.mjs +12 -0
  60. package/dist/{shared/flow-rdf-core.187cb345.mjs → lib/utils/debounce.mjs} +3 -39
  61. package/dist/lib/utils/decorators.mjs +59 -0
  62. package/dist/lib/utils/deferred.mjs +11 -0
  63. package/dist/lib/utils/ensure-array.mjs +16 -0
  64. package/dist/{shared/flow-rdf-core.1f0901c5.mjs → lib/utils/feature-type-checks.mjs} +2 -2
  65. package/dist/lib/utils/functional.mjs +22 -0
  66. package/dist/lib/utils/global.mjs +18 -0
  67. package/dist/lib/utils/index.mjs +8 -5
  68. package/dist/lib/utils/random-id.mjs +9 -0
  69. package/dist/lib/utils/string-utils.mjs +3 -0
  70. package/dist/lib/utils/throttle.mjs +20 -0
  71. package/dist/{shared/flow-rdf-core.25e5f6d7.mjs → lib/utils/type-checks.mjs} +1 -26
  72. package/dist/lib/utils/watchable-promise.mjs +55 -0
  73. package/dist/package.json.mjs +3 -0
  74. package/dist/shared/{flow-rdf-core.4dde996e.d.cts → flow-rdf-core.8b5acf14.d.mts} +1315 -172
  75. package/dist/shared/{flow-rdf-core.4dde996e.d.ts → flow-rdf-core.8b5acf14.d.ts} +1315 -172
  76. package/package.json +4 -8
  77. package/dist/index.cjs +0 -3316
  78. package/dist/index.d.cts +0 -90
  79. package/dist/lib/map/plugins/index.cjs +0 -1850
  80. package/dist/lib/map/plugins/index.d.cts +0 -345
  81. package/dist/lib/utils/index.cjs +0 -48
  82. package/dist/lib/utils/index.d.cts +0 -160
  83. package/dist/shared/flow-rdf-core.06e85a6c.cjs +0 -1394
  84. package/dist/shared/flow-rdf-core.4dde996e.d.mts +0 -1916
  85. package/dist/shared/flow-rdf-core.55c169ca.cjs +0 -150
  86. package/dist/shared/flow-rdf-core.63162669.d.cts +0 -10
  87. package/dist/shared/flow-rdf-core.65045caf.mjs +0 -1360
  88. package/dist/shared/flow-rdf-core.a82b9be4.cjs +0 -34
  89. package/dist/shared/flow-rdf-core.f50908f0.cjs +0 -102
@@ -0,0 +1,67 @@
1
+ import MapboxDraw from '@emuanalytics/mapbox-gl-draw';
2
+ import turfCircle from '@turf/circle';
3
+ import turfDistance from '@turf/distance';
4
+ import { point } from '@turf/helpers';
5
+ import createSupplementaryPointsForCircle from '../utils/create_supplementary_points_circle.mjs';
6
+
7
+ const DirectModeOverride = MapboxDraw.modes.direct_select;
8
+ const moveFeatures = MapboxDraw.lib.moveFeatures;
9
+ const constrainFeatureMovement = MapboxDraw.lib.constrainFeatureMovement;
10
+ const createSupplementaryPoints = MapboxDraw.lib.createSupplementaryPoints;
11
+ const Constants = MapboxDraw.constants;
12
+ DirectModeOverride.dragFeature = function(state, e, delta) {
13
+ moveFeatures(this.getSelected(), delta);
14
+ this.getSelected().filter((feature) => feature.properties.type === "Circle").map((circle) => circle.properties.circleCenter).forEach((center) => {
15
+ center[0] += delta.lng;
16
+ center[1] += delta.lat;
17
+ });
18
+ state.dragMoveLocation = e.lngLat;
19
+ };
20
+ DirectModeOverride.dragVertex = function(state, e, delta) {
21
+ if (state.feature.properties.type === "Circle") {
22
+ const center = state.feature.properties.circleCenter;
23
+ const movedVertex = [e.lngLat.lng, e.lngLat.lat];
24
+ const radius = turfDistance(point(center), point(movedVertex), { units: "kilometers" });
25
+ const circleFeature = turfCircle(center, radius);
26
+ state.feature.incomingCoords(circleFeature.geometry.coordinates);
27
+ state.feature.properties.circleRadius = radius;
28
+ } else {
29
+ const selectedCoords = state.selectedCoordPaths.map((coord_path) => state.feature.getCoordinate(coord_path));
30
+ const selectedCoordPoints = selectedCoords.map((coords) => ({
31
+ type: Constants.geojsonTypes.FEATURE,
32
+ properties: {},
33
+ geometry: {
34
+ type: Constants.geojsonTypes.POINT,
35
+ coordinates: coords
36
+ }
37
+ }));
38
+ const constrainedDelta = constrainFeatureMovement(selectedCoordPoints, delta);
39
+ for (let i = 0; i < selectedCoords.length; i++) {
40
+ const coord = selectedCoords[i];
41
+ state.feature.updateCoordinate(
42
+ state.selectedCoordPaths[i],
43
+ coord[0] + constrainedDelta.lng,
44
+ coord[1] + constrainedDelta.lat
45
+ );
46
+ }
47
+ }
48
+ };
49
+ DirectModeOverride.toDisplayFeatures = function(state, geojson, push) {
50
+ if (state.featureId === geojson.properties.id) {
51
+ geojson.properties.active = Constants.activeStates.ACTIVE;
52
+ push(geojson);
53
+ const supplementaryPoints = geojson.properties.user_type === "Circle" ? createSupplementaryPointsForCircle(geojson) : createSupplementaryPoints(geojson, {
54
+ map: this.map,
55
+ midpoints: true,
56
+ selectedPaths: state.selectedCoordPaths
57
+ });
58
+ supplementaryPoints.forEach(push);
59
+ } else {
60
+ geojson.properties.active = Constants.activeStates.INACTIVE;
61
+ push(geojson);
62
+ }
63
+ this.fireActionable(state);
64
+ };
65
+ const DirectMode = DirectModeOverride;
66
+
67
+ export { DirectMode as default };
@@ -0,0 +1,65 @@
1
+ import MapboxDraw from '@emuanalytics/mapbox-gl-draw';
2
+ import turfCircle from '@turf/circle';
3
+ import turfDistance from '@turf/distance';
4
+ import { point } from '@turf/helpers';
5
+ import dragPan from '../utils/drag_pan.mjs';
6
+
7
+ const DragCircleMode = { ...MapboxDraw.modes.draw_polygon };
8
+ const Constants = MapboxDraw.constants;
9
+ DragCircleMode.onSetup = function(opts) {
10
+ const polygon = this.newFeature({
11
+ type: Constants.geojsonTypes.FEATURE,
12
+ properties: {
13
+ type: "Circle",
14
+ circleCenter: []
15
+ },
16
+ geometry: {
17
+ type: Constants.geojsonTypes.POLYGON,
18
+ coordinates: []
19
+ }
20
+ });
21
+ this.addFeature(polygon);
22
+ this.clearSelectedFeatures();
23
+ dragPan.disable(this);
24
+ this.updateUIClasses({ mouse: Constants.cursors.ADD });
25
+ this.activateUIButton(Constants.types.POLYGON);
26
+ this.setActionableState({
27
+ trash: true
28
+ });
29
+ return {
30
+ polygon,
31
+ currentVertexPosition: 0
32
+ };
33
+ };
34
+ DragCircleMode.onMouseDown = DragCircleMode.onTouchStart = function(state, e) {
35
+ const currentCenter = state.polygon.properties.circleCenter;
36
+ if (currentCenter.length === 0) {
37
+ state.polygon.properties.circleCenter = [e.lngLat.lng, e.lngLat.lat];
38
+ }
39
+ };
40
+ DragCircleMode.onDrag = DragCircleMode.onMouseMove = function(state, e) {
41
+ const center = state.polygon.properties.circleCenter;
42
+ if (center.length > 0) {
43
+ const distanceInKm = turfDistance(point(center), point([e.lngLat.lng, e.lngLat.lat]), {
44
+ units: "kilometers"
45
+ });
46
+ const circleFeature = turfCircle(center, distanceInKm);
47
+ state.polygon.incomingCoords(circleFeature.geometry.coordinates);
48
+ state.polygon.properties.circleRadius = distanceInKm;
49
+ }
50
+ };
51
+ DragCircleMode.onMouseUp = DragCircleMode.onTouchEnd = function(state) {
52
+ dragPan.enable(this);
53
+ return this.changeMode(Constants.modes.SIMPLE_SELECT, { featureIds: [state.polygon.id] });
54
+ };
55
+ DragCircleMode.onClick = DragCircleMode.onTap = function(state) {
56
+ state.polygon.properties.circleCenter = [];
57
+ };
58
+ DragCircleMode.toDisplayFeatures = function(state, geojson, display) {
59
+ const isActivePolygon = geojson.properties.id === state.polygon.id;
60
+ geojson.properties.active = isActivePolygon ? Constants.activeStates.ACTIVE : Constants.activeStates.INACTIVE;
61
+ return display(geojson);
62
+ };
63
+ const DragCircleMode$1 = DragCircleMode;
64
+
65
+ export { DragCircleMode$1 as default };
@@ -0,0 +1,15 @@
1
+ import MapboxDraw from '@emuanalytics/mapbox-gl-draw';
2
+
3
+ function createSupplementaryPointsForCircle(geojson) {
4
+ const { properties, geometry } = geojson;
5
+ if (properties.user_type !== "Circle")
6
+ return null;
7
+ const supplementaryPoints = [];
8
+ const vertices = geometry.coordinates[0].slice(0, -1);
9
+ for (let index = 0; index < vertices.length; index += Math.round(vertices.length / 4)) {
10
+ supplementaryPoints.push(MapboxDraw.lib.createVertex(properties.id, vertices[index], `0.${index}`, false));
11
+ }
12
+ return supplementaryPoints;
13
+ }
14
+
15
+ export { createSupplementaryPointsForCircle as default };
@@ -0,0 +1,20 @@
1
+ const dragPan = {
2
+ enable(ctx) {
3
+ setTimeout(() => {
4
+ if (!ctx.map || !ctx.map.dragPan || !ctx._ctx || !ctx._ctx.store || !ctx._ctx.store.getInitialConfigValue)
5
+ return;
6
+ if (!ctx._ctx.store.getInitialConfigValue("dragPan"))
7
+ return;
8
+ ctx.map.dragPan.enable();
9
+ }, 0);
10
+ },
11
+ disable(ctx) {
12
+ setTimeout(() => {
13
+ if (!ctx.map || !ctx.map.doubleClickZoom)
14
+ return;
15
+ ctx.map.dragPan.disable();
16
+ }, 0);
17
+ }
18
+ };
19
+
20
+ export { dragPan as default };
@@ -0,0 +1,173 @@
1
+ import Debug from 'debug';
2
+ import { autorun, toJS } from 'mobx';
3
+ import { isString, isURL, isArrayFull, isNil, isNull } from '../../utils/type-checks.mjs';
4
+ import { MapPluginBase } from './map-plugin-base.mjs';
5
+ import { FlowCoreError } from '../../errors/flow-error.mjs';
6
+ import { ReactiveExpression } from '../../expressions/reactive-expression.mjs';
7
+
8
+ var __defProp = Object.defineProperty;
9
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
10
+ var __publicField = (obj, key, value) => {
11
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
12
+ return value;
13
+ };
14
+ const debug = Debug("flow:data-join-map-plugin");
15
+ const _DataJoin = class _DataJoin {
16
+ constructor(id, map, options) {
17
+ this.id = id;
18
+ this.map = map;
19
+ __publicField(this, "autorunDisposer", null);
20
+ __publicField(this, "dataExpression", null);
21
+ __publicField(this, "options");
22
+ __publicField(this, "parameterExpressions", {});
23
+ this.options = {
24
+ ..._DataJoin.defaultOptions,
25
+ ...options
26
+ };
27
+ }
28
+ get source() {
29
+ return this.options.source;
30
+ }
31
+ start() {
32
+ this.stop();
33
+ if (isString(this.options.data)) {
34
+ if (isURL(this.options.data))
35
+ this.options.data = `'${this.options.data}'`;
36
+ this.dataExpression = new ReactiveExpression(this.options.data);
37
+ this.dataExpression.bindState(this.map.context.state);
38
+ } else {
39
+ this.dataExpression = null;
40
+ }
41
+ if (isArrayFull(this.options.parameters)) {
42
+ this.parameterExpressions = this.options.parameters.reduce((accum, param) => {
43
+ const expr = new ReactiveExpression(param.value.toString());
44
+ expr.bindState(this.map.context.state);
45
+ accum[param.name] = expr;
46
+ return accum;
47
+ }, {});
48
+ }
49
+ this.autorunDisposer = autorun(
50
+ async () => {
51
+ let data = this.dataExpression ? toJS(this.dataExpression.value) : this.options.data;
52
+ const missingParams = this.options.parameters.map((p) => p.required && isNil(this.parameterExpressions[p.name].value) ? p.name : void 0).filter((p) => !!p);
53
+ if (isNull(data)) {
54
+ debug(`FlowMap<${this.map.id}>: Skipping data join '${this.id}' (null data)`);
55
+ return;
56
+ }
57
+ if (missingParams.length) {
58
+ debug(
59
+ `FlowMap<${this.map.id}>: Skipping data join '${this.id}' (null required parameters: ${missingParams.join(
60
+ ", "
61
+ )})`
62
+ );
63
+ return;
64
+ }
65
+ debug(`FlowMap<${this.map.id}>: Performing data join '${this.id}'`);
66
+ if (isString(data)) {
67
+ try {
68
+ data = await this.loadData(data);
69
+ } catch (e) {
70
+ this.map.emitError(`Failed to load data for data join '${this.id}' - ${e.message}`, e);
71
+ data = [];
72
+ }
73
+ }
74
+ this.doDataJoin(data);
75
+ },
76
+ { name: `FlowDataJoin.${this.map.id}.${this.id})` }
77
+ );
78
+ }
79
+ stop() {
80
+ if (this.autorunDisposer) {
81
+ this.autorunDisposer();
82
+ this.autorunDisposer = null;
83
+ }
84
+ }
85
+ doDataJoin(data) {
86
+ const source = this.map.getSource(this.options.source);
87
+ const sourceLayer = source.type === "vector" ? this.options.sourceLayer || "geometry" : void 0;
88
+ if (this.options.clear) {
89
+ this.map.removeFeatureState({ source: source.id, sourceLayer }, this.id);
90
+ }
91
+ const featureData = data.reduce((accum, d) => {
92
+ accum[d[this.options.foreignKey]] = { [this.id]: d };
93
+ return accum;
94
+ }, {});
95
+ this.map.setFeatureStateBulk({ source: source.id, sourceLayer }, featureData);
96
+ }
97
+ loadData(datasetOrUrl) {
98
+ if (isURL(datasetOrUrl)) {
99
+ const url = new URL(datasetOrUrl);
100
+ const params = new URLSearchParams(url.searchParams);
101
+ if (isArrayFull(this.options.parameters)) {
102
+ this.options.parameters.forEach((p) => {
103
+ params.append(p.name, this.parameterExpressions[p.name].value);
104
+ });
105
+ }
106
+ url.search = params.toString();
107
+ const headers = new Headers({ Accept: "application/json" });
108
+ const request = new Request(url.toString(), {
109
+ method: "GET",
110
+ mode: "cors",
111
+ headers,
112
+ cache: "default"
113
+ });
114
+ return fetch(request).then((response) => {
115
+ if (!response.ok) {
116
+ throw new Error(`status=${response.status} ${response.statusText}`);
117
+ }
118
+ return response.json();
119
+ });
120
+ } else {
121
+ const params = {};
122
+ if (isArrayFull(this.options.parameters)) {
123
+ this.options.parameters.forEach((p) => {
124
+ params[p.name] = this.parameterExpressions[p.name].value;
125
+ });
126
+ }
127
+ return this.map.context.flowClient.datasets.query(datasetOrUrl, {}, params);
128
+ }
129
+ }
130
+ };
131
+ __publicField(_DataJoin, "defaultOptions", {
132
+ clear: false,
133
+ parameters: []
134
+ });
135
+ let DataJoin = _DataJoin;
136
+ class DataJoinPlugin extends MapPluginBase {
137
+ constructor(pluginManager) {
138
+ super(pluginManager);
139
+ __publicField(this, "_joins", /* @__PURE__ */ new Map());
140
+ __publicField(this, "name", "DataJoinPlugin");
141
+ }
142
+ addDataJoin(id, options) {
143
+ const dataJoin = new DataJoin(id, this.map, options);
144
+ this._joins.set(id, dataJoin);
145
+ dataJoin.start();
146
+ }
147
+ bindState(state) {
148
+ this._joins.forEach((join) => join.start());
149
+ }
150
+ destroy() {
151
+ this._joins.forEach((join) => join.stop());
152
+ this._joins.clear();
153
+ }
154
+ handleSourceRemoved(event) {
155
+ this._joins.forEach((join) => {
156
+ if (join.source === event.source) {
157
+ join.stop();
158
+ this._joins.delete(join.id);
159
+ }
160
+ });
161
+ }
162
+ removeDataJoin(id) {
163
+ const dataJoin = this._joins.get(id);
164
+ if (dataJoin) {
165
+ dataJoin.stop();
166
+ this._joins.delete(id);
167
+ } else {
168
+ throw new FlowCoreError(`Cannot remove unrecognized data join '${id}'`);
169
+ }
170
+ }
171
+ }
172
+
173
+ export { DataJoin, DataJoinPlugin };
@@ -0,0 +1,21 @@
1
+ import { MapPluginBase } from '../map-plugin-base.mjs';
2
+ import { MapExporter } from './map-exporter.mjs';
3
+
4
+ var __defProp = Object.defineProperty;
5
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
+ var __publicField = (obj, key, value) => {
7
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
8
+ return value;
9
+ };
10
+ class ExportPlugin extends MapPluginBase {
11
+ constructor(pluginManager) {
12
+ super(pluginManager);
13
+ __publicField(this, "name", "ExportPlugin");
14
+ }
15
+ exportMap(options) {
16
+ const mapExporter = new MapExporter(this.map);
17
+ return mapExporter.export(options);
18
+ }
19
+ }
20
+
21
+ export { ExportPlugin };
@@ -0,0 +1,177 @@
1
+ import maplibre from '@emuanalytics/maplibre-gl';
2
+ import saveAs from 'file-saver';
3
+ import { randomId } from '../../../utils/random-id.mjs';
4
+ import { isFunction } from '../../../utils/type-checks.mjs';
5
+
6
+ var __defProp = Object.defineProperty;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __publicField = (obj, key, value) => {
9
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
10
+ return value;
11
+ };
12
+ const _MapExporter = class _MapExporter {
13
+ constructor(map) {
14
+ this.map = map;
15
+ __publicField(this, "nativePixelRatio", window.devicePixelRatio);
16
+ }
17
+ async export(options) {
18
+ options = { ..._MapExporter.defaultOptions, ...options };
19
+ const [container, mapCopy] = await this.createMapCopy(options);
20
+ return new Promise((resolve, reject) => {
21
+ const fileName = `${options.name}.${options.format}`;
22
+ const mapCanvas = mapCopy.getCanvas();
23
+ const exportCanvas = this.createExportCanvas(container, mapCanvas);
24
+ const exportContext = exportCanvas.getContext("2d");
25
+ if (!exportContext) {
26
+ this.destroyMapCopy(container, mapCopy);
27
+ reject(new Error("Failed to create export canvas context"));
28
+ return;
29
+ }
30
+ const drawOverlayCallback = (err) => {
31
+ if (err) {
32
+ this.destroyMapCopy(container, mapCopy);
33
+ reject(err);
34
+ } else {
35
+ switch (options.format) {
36
+ case "png":
37
+ exportCanvas.toBlob((blob) => {
38
+ blob && saveAs(blob, fileName);
39
+ });
40
+ break;
41
+ case "pdf":
42
+ throw new Error("Export to PDF is not currently supported");
43
+ }
44
+ this.destroyMapCopy(container, mapCopy);
45
+ resolve(fileName);
46
+ }
47
+ };
48
+ const mapImage = new Image();
49
+ mapImage.onload = () => {
50
+ exportContext.drawImage(mapImage, 0, 0);
51
+ if (isFunction(options.drawOverlayFn)) {
52
+ options.drawOverlayFn(
53
+ exportContext,
54
+ exportCanvas.width,
55
+ exportCanvas.height,
56
+ options.dpmm,
57
+ drawOverlayCallback
58
+ );
59
+ } else {
60
+ drawOverlayCallback(null);
61
+ }
62
+ };
63
+ mapImage.src = mapCopy.getCanvas().toDataURL();
64
+ });
65
+ }
66
+ createMapCopy(options) {
67
+ const geoBounds = options.bounds || this.map.maplibreMap.getBounds().toArray().flat();
68
+ const geoBottomLeft = [geoBounds[0], geoBounds[1]];
69
+ const geoTopRight = [geoBounds[2], geoBounds[3]];
70
+ const geoCenter = [
71
+ (geoBottomLeft[0] + geoTopRight[0]) / 2,
72
+ (geoBottomLeft[1] + geoTopRight[1]) / 2
73
+ ];
74
+ const pxBottomLeft = this.map.maplibreMap.project(geoBottomLeft);
75
+ const pxTopRight = this.map.maplibreMap.project(geoTopRight);
76
+ const pxWidth = pxTopRight.x - pxBottomLeft.x;
77
+ const pxHeight = pxBottomLeft.y - pxTopRight.y;
78
+ const exportWidth = options.width * options.dpmm;
79
+ const exportHeight = options.height * options.dpmm;
80
+ const aspectRatios = {
81
+ width: pxWidth / exportWidth,
82
+ height: pxHeight / exportHeight
83
+ };
84
+ const coverRatio = Math.max(aspectRatios.width, aspectRatios.height);
85
+ const copyWidth = exportWidth * coverRatio;
86
+ const copyHeight = exportHeight * coverRatio;
87
+ const pixelRatio = exportWidth / copyWidth;
88
+ this.setDevicePixelRatio(pixelRatio);
89
+ const container = document.createElement("div");
90
+ container.id = randomId("export");
91
+ container.classList.add("maplibregl-export-container");
92
+ container.style.width = `${copyWidth}px`;
93
+ container.style.height = `${copyHeight}px`;
94
+ this.map.container.insertBefore(container, this.map.container.firstChild);
95
+ const mapCopy = new maplibre.Map({
96
+ container,
97
+ center: geoCenter,
98
+ zoom: this.map.maplibreMap.getZoom(),
99
+ style: { ...this.map.maplibreMap.getStyle(), transition: { delay: 0, duration: 0 } },
100
+ bearing: this.map.maplibreMap.getBearing(),
101
+ pitch: this.map.maplibreMap.getPitch(),
102
+ interactive: false,
103
+ attributionControl: false,
104
+ fadeDuration: 0,
105
+ preserveDrawingBuffer: true,
106
+ transformRequest: this.transformMapRequest.bind(this)
107
+ });
108
+ mapCopy.on("styleimagemissing", this.handleMissingImage.bind(this));
109
+ return new Promise((resolve) => {
110
+ mapCopy.once("load", () => {
111
+ Object.keys(this.map.maplibreMap.style.sourceCaches).forEach((sourceId) => {
112
+ mapCopy.style.sourceCaches[sourceId]._state.stateChanges = this.map.maplibreMap.style.sourceCaches[sourceId]._state.state;
113
+ });
114
+ mapCopy._update();
115
+ setTimeout(() => resolve([container, mapCopy]), 500);
116
+ });
117
+ });
118
+ }
119
+ destroyMapCopy(container, map) {
120
+ this.setDevicePixelRatio(this.nativePixelRatio);
121
+ map.remove();
122
+ container.parentNode.removeChild(container);
123
+ }
124
+ createExportCanvas(container, mapCanvas) {
125
+ const canvasContainer = container.getElementsByClassName("maplibregl-canvas-container")[0];
126
+ const overlayCanvas = document.createElement("canvas");
127
+ overlayCanvas.id = randomId("overlay");
128
+ overlayCanvas.width = mapCanvas.width;
129
+ overlayCanvas.height = mapCanvas.height;
130
+ overlayCanvas.style.position = "absolute";
131
+ overlayCanvas.style.width = mapCanvas.style.width;
132
+ overlayCanvas.style.height = mapCanvas.style.height;
133
+ canvasContainer.appendChild(overlayCanvas);
134
+ return overlayCanvas;
135
+ }
136
+ setDevicePixelRatio(pixelRatio) {
137
+ Object.defineProperty(window, "devicePixelRatio", {
138
+ get: () => pixelRatio
139
+ });
140
+ }
141
+ async handleMissingImage(e) {
142
+ const imageInfo = this.map.imageRegistry.getImage(e.id);
143
+ if (imageInfo === this.map.imageRegistry.unknownImage) {
144
+ console.error(`Map ${this.map.id}: Image '${e.id}' not registered`);
145
+ }
146
+ if (!imageInfo.image.complete) {
147
+ imageInfo.image.onload = () => {
148
+ this.map.maplibreMap.updateImage(e.id, imageInfo.image);
149
+ this.map.maplibreMap.redraw();
150
+ };
151
+ }
152
+ this.map.maplibreMap.addImage(e.id, imageInfo.image, {
153
+ pixelRatio: imageInfo.pixelDensity,
154
+ sdf: imageInfo.recolor
155
+ });
156
+ }
157
+ transformMapRequest(url, _resourceType) {
158
+ if (this.map.context.flowClient.accessToken && url.startsWith(this.map.context.flowClient.baseUrl)) {
159
+ return {
160
+ url,
161
+ headers: { Authorization: `Bearer ${this.map.context.flowClient.accessToken}` }
162
+ };
163
+ } else {
164
+ return { url };
165
+ }
166
+ }
167
+ };
168
+ __publicField(_MapExporter, "defaultOptions", {
169
+ name: "map",
170
+ width: 297,
171
+ height: 210,
172
+ dpmm: 12,
173
+ format: "png"
174
+ });
175
+ let MapExporter = _MapExporter;
176
+
177
+ export { MapExporter };
@@ -0,0 +1,58 @@
1
+ import { isDefined, isObject } from '../../utils/type-checks.mjs';
2
+ import { isFeatureWithId } from '../types.mjs';
3
+ import { MapPluginBase } from './map-plugin-base.mjs';
4
+
5
+ var __defProp = Object.defineProperty;
6
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
+ var __publicField = (obj, key, value) => {
8
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
9
+ return value;
10
+ };
11
+ class HoverEffectPlugin extends MapPluginBase {
12
+ constructor(pluginManager) {
13
+ super(pluginManager);
14
+ __publicField(this, "hoveredFeature", null);
15
+ __publicField(this, "name", "HoverEffectPlugin");
16
+ }
17
+ handleMouseMove(event) {
18
+ const hoveredFeature = event.features[0];
19
+ if (hoveredFeature) {
20
+ this.map.maplibreMap._container.classList.add("feature-hovered");
21
+ } else {
22
+ this.map.maplibreMap._container.classList.remove("feature-hovered");
23
+ }
24
+ if (!this.compareFeatures(hoveredFeature, this.hoveredFeature)) {
25
+ this.clearHover();
26
+ if (isFeatureWithId(hoveredFeature) && isDefined(this.map.getSource(hoveredFeature.source)?.featureId)) {
27
+ this.map.setFeatureState(hoveredFeature, { hover: true }, false);
28
+ this.hoveredFeature = hoveredFeature;
29
+ }
30
+ }
31
+ }
32
+ handleMouseOut(event) {
33
+ this.clearHover();
34
+ }
35
+ handleSetExclusivePlugin(exclusivePlugins) {
36
+ if (exclusivePlugins.length) {
37
+ this.clearHover();
38
+ this.map.maplibreMap._container.classList.remove("feature-hovered");
39
+ }
40
+ }
41
+ compareFeatures(f1, f2) {
42
+ if (f1 === f2) {
43
+ return true;
44
+ }
45
+ if (isObject(f1) && isObject(f2)) {
46
+ return f1.id == f2.id && f1.source === f2.source && f1.sourceLayer == f2.sourceLayer;
47
+ }
48
+ return false;
49
+ }
50
+ clearHover() {
51
+ if (this.hoveredFeature && this.map.getSource(this.hoveredFeature.source)) {
52
+ this.map.removeFeatureState(this.hoveredFeature, "hover", false);
53
+ this.hoveredFeature = null;
54
+ }
55
+ }
56
+ }
57
+
58
+ export { HoverEffectPlugin };