@symfony/ux-google-map 2.23.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/dist/map_controller.d.ts +37 -0
- package/dist/map_controller.js +284 -0
- package/package.json +56 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { LoaderOptions } from '@googlemaps/js-api-loader';
|
|
2
|
+
import AbstractMapController from '@symfony/ux-map';
|
|
3
|
+
import type { InfoWindowWithoutPositionDefinition, MarkerDefinition, Point, PolygonDefinition, PolylineDefinition } from '@symfony/ux-map';
|
|
4
|
+
type MapOptions = Pick<google.maps.MapOptions, 'mapId' | 'gestureHandling' | 'backgroundColor' | 'disableDoubleClickZoom' | 'zoomControl' | 'zoomControlOptions' | 'mapTypeControl' | 'mapTypeControlOptions' | 'streetViewControl' | 'streetViewControlOptions' | 'fullscreenControl' | 'fullscreenControlOptions'>;
|
|
5
|
+
export default class extends AbstractMapController<MapOptions, google.maps.Map, google.maps.marker.AdvancedMarkerElementOptions, google.maps.marker.AdvancedMarkerElement, google.maps.InfoWindowOptions, google.maps.InfoWindow, google.maps.PolygonOptions, google.maps.Polygon, google.maps.PolylineOptions, google.maps.Polyline> {
|
|
6
|
+
providerOptionsValue: Pick<LoaderOptions, 'apiKey' | 'id' | 'language' | 'region' | 'nonce' | 'retries' | 'url' | 'version' | 'libraries'>;
|
|
7
|
+
map: google.maps.Map;
|
|
8
|
+
connect(): Promise<void>;
|
|
9
|
+
centerValueChanged(): void;
|
|
10
|
+
zoomValueChanged(): void;
|
|
11
|
+
protected dispatchEvent(name: string, payload?: Record<string, unknown>): void;
|
|
12
|
+
protected doCreateMap({ center, zoom, options, }: {
|
|
13
|
+
center: Point | null;
|
|
14
|
+
zoom: number | null;
|
|
15
|
+
options: MapOptions;
|
|
16
|
+
}): google.maps.Map;
|
|
17
|
+
protected doCreateMarker({ definition, }: {
|
|
18
|
+
definition: MarkerDefinition<google.maps.marker.AdvancedMarkerElementOptions, google.maps.InfoWindowOptions>;
|
|
19
|
+
}): google.maps.marker.AdvancedMarkerElement;
|
|
20
|
+
protected doRemoveMarker(marker: google.maps.marker.AdvancedMarkerElement): void;
|
|
21
|
+
protected doCreatePolygon({ definition, }: {
|
|
22
|
+
definition: PolygonDefinition<google.maps.PolygonOptions, google.maps.InfoWindowOptions>;
|
|
23
|
+
}): google.maps.Polygon;
|
|
24
|
+
protected doRemovePolygon(polygon: google.maps.Polygon): void;
|
|
25
|
+
protected doCreatePolyline({ definition, }: {
|
|
26
|
+
definition: PolylineDefinition<google.maps.PolylineOptions, google.maps.InfoWindowOptions>;
|
|
27
|
+
}): google.maps.Polyline;
|
|
28
|
+
protected doRemovePolyline(polyline: google.maps.Polyline): void;
|
|
29
|
+
protected doCreateInfoWindow({ definition, element, }: {
|
|
30
|
+
definition: InfoWindowWithoutPositionDefinition<google.maps.InfoWindowOptions>;
|
|
31
|
+
element: google.maps.marker.AdvancedMarkerElement | google.maps.Polygon | google.maps.Polyline;
|
|
32
|
+
}): google.maps.InfoWindow;
|
|
33
|
+
protected doFitBoundsToMarkers(): void;
|
|
34
|
+
private createTextOrElement;
|
|
35
|
+
private closeInfoWindowsExcept;
|
|
36
|
+
}
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { Loader } from '@googlemaps/js-api-loader';
|
|
2
|
+
import { Controller } from '@hotwired/stimulus';
|
|
3
|
+
|
|
4
|
+
class default_1 extends Controller {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(...arguments);
|
|
7
|
+
this.markers = new Map();
|
|
8
|
+
this.polygons = new Map();
|
|
9
|
+
this.polylines = new Map();
|
|
10
|
+
this.infoWindows = [];
|
|
11
|
+
this.isConnected = false;
|
|
12
|
+
}
|
|
13
|
+
connect() {
|
|
14
|
+
const options = this.optionsValue;
|
|
15
|
+
this.dispatchEvent('pre-connect', { options });
|
|
16
|
+
this.createMarker = this.createDrawingFactory('marker', this.markers, this.doCreateMarker.bind(this));
|
|
17
|
+
this.createPolygon = this.createDrawingFactory('polygon', this.polygons, this.doCreatePolygon.bind(this));
|
|
18
|
+
this.createPolyline = this.createDrawingFactory('polyline', this.polylines, this.doCreatePolyline.bind(this));
|
|
19
|
+
this.map = this.doCreateMap({
|
|
20
|
+
center: this.hasCenterValue ? this.centerValue : null,
|
|
21
|
+
zoom: this.hasZoomValue ? this.zoomValue : null,
|
|
22
|
+
options,
|
|
23
|
+
});
|
|
24
|
+
this.markersValue.forEach((definition) => this.createMarker({ definition }));
|
|
25
|
+
this.polygonsValue.forEach((definition) => this.createPolygon({ definition }));
|
|
26
|
+
this.polylinesValue.forEach((definition) => this.createPolyline({ definition }));
|
|
27
|
+
if (this.fitBoundsToMarkersValue) {
|
|
28
|
+
this.doFitBoundsToMarkers();
|
|
29
|
+
}
|
|
30
|
+
this.dispatchEvent('connect', {
|
|
31
|
+
map: this.map,
|
|
32
|
+
markers: [...this.markers.values()],
|
|
33
|
+
polygons: [...this.polygons.values()],
|
|
34
|
+
polylines: [...this.polylines.values()],
|
|
35
|
+
infoWindows: this.infoWindows,
|
|
36
|
+
});
|
|
37
|
+
this.isConnected = true;
|
|
38
|
+
}
|
|
39
|
+
createInfoWindow({ definition, element, }) {
|
|
40
|
+
this.dispatchEvent('info-window:before-create', { definition, element });
|
|
41
|
+
const infoWindow = this.doCreateInfoWindow({ definition, element });
|
|
42
|
+
this.dispatchEvent('info-window:after-create', { infoWindow, element });
|
|
43
|
+
this.infoWindows.push(infoWindow);
|
|
44
|
+
return infoWindow;
|
|
45
|
+
}
|
|
46
|
+
markersValueChanged() {
|
|
47
|
+
if (!this.isConnected) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
this.onDrawChanged(this.markers, this.markersValue, this.createMarker, this.doRemoveMarker);
|
|
51
|
+
if (this.fitBoundsToMarkersValue) {
|
|
52
|
+
this.doFitBoundsToMarkers();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
polygonsValueChanged() {
|
|
56
|
+
if (!this.isConnected) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
this.onDrawChanged(this.polygons, this.polygonsValue, this.createPolygon, this.doRemovePolygon);
|
|
60
|
+
}
|
|
61
|
+
polylinesValueChanged() {
|
|
62
|
+
if (!this.isConnected) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
this.onDrawChanged(this.polylines, this.polylinesValue, this.createPolyline, this.doRemovePolyline);
|
|
66
|
+
}
|
|
67
|
+
createDrawingFactory(type, draws, factory) {
|
|
68
|
+
const eventBefore = `${type}:before-create`;
|
|
69
|
+
const eventAfter = `${type}:after-create`;
|
|
70
|
+
return ({ definition }) => {
|
|
71
|
+
this.dispatchEvent(eventBefore, { definition });
|
|
72
|
+
const drawing = factory({ definition });
|
|
73
|
+
this.dispatchEvent(eventAfter, { [type]: drawing });
|
|
74
|
+
draws.set(definition['@id'], drawing);
|
|
75
|
+
return drawing;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
onDrawChanged(draws, newDrawDefinitions, factory, remover) {
|
|
79
|
+
const idsToRemove = new Set(draws.keys());
|
|
80
|
+
newDrawDefinitions.forEach((definition) => {
|
|
81
|
+
idsToRemove.delete(definition['@id']);
|
|
82
|
+
});
|
|
83
|
+
idsToRemove.forEach((id) => {
|
|
84
|
+
const draw = draws.get(id);
|
|
85
|
+
remover(draw);
|
|
86
|
+
draws.delete(id);
|
|
87
|
+
});
|
|
88
|
+
newDrawDefinitions.forEach((definition) => {
|
|
89
|
+
if (!draws.has(definition['@id'])) {
|
|
90
|
+
factory({ definition });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
default_1.values = {
|
|
96
|
+
providerOptions: Object,
|
|
97
|
+
center: Object,
|
|
98
|
+
zoom: Number,
|
|
99
|
+
fitBoundsToMarkers: Boolean,
|
|
100
|
+
markers: Array,
|
|
101
|
+
polygons: Array,
|
|
102
|
+
polylines: Array,
|
|
103
|
+
options: Object,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
let _google;
|
|
107
|
+
class map_controller extends default_1 {
|
|
108
|
+
async connect() {
|
|
109
|
+
if (!_google) {
|
|
110
|
+
_google = { maps: {} };
|
|
111
|
+
let { libraries = [], ...loaderOptions } = this.providerOptionsValue;
|
|
112
|
+
const loader = new Loader(loaderOptions);
|
|
113
|
+
libraries = ['core', ...libraries.filter((library) => library !== 'core')];
|
|
114
|
+
const librariesImplementations = await Promise.all(libraries.map((library) => loader.importLibrary(library)));
|
|
115
|
+
librariesImplementations.map((libraryImplementation, index) => {
|
|
116
|
+
if (typeof libraryImplementation !== 'object' || libraryImplementation === null) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const library = libraries[index];
|
|
120
|
+
if (['marker', 'places', 'geometry', 'journeySharing', 'drawing', 'visualization'].includes(library)) {
|
|
121
|
+
_google.maps[library] = libraryImplementation;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
_google.maps = { ..._google.maps, ...libraryImplementation };
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
super.connect();
|
|
129
|
+
}
|
|
130
|
+
centerValueChanged() {
|
|
131
|
+
if (this.map && this.hasCenterValue && this.centerValue) {
|
|
132
|
+
this.map.setCenter(this.centerValue);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
zoomValueChanged() {
|
|
136
|
+
if (this.map && this.hasZoomValue && this.zoomValue) {
|
|
137
|
+
this.map.setZoom(this.zoomValue);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
dispatchEvent(name, payload = {}) {
|
|
141
|
+
this.dispatch(name, {
|
|
142
|
+
prefix: 'ux:map',
|
|
143
|
+
detail: {
|
|
144
|
+
...payload,
|
|
145
|
+
google: _google,
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
doCreateMap({ center, zoom, options, }) {
|
|
150
|
+
options.zoomControl = typeof options.zoomControlOptions !== 'undefined';
|
|
151
|
+
options.mapTypeControl = typeof options.mapTypeControlOptions !== 'undefined';
|
|
152
|
+
options.streetViewControl = typeof options.streetViewControlOptions !== 'undefined';
|
|
153
|
+
options.fullscreenControl = typeof options.fullscreenControlOptions !== 'undefined';
|
|
154
|
+
return new _google.maps.Map(this.element, {
|
|
155
|
+
...options,
|
|
156
|
+
center,
|
|
157
|
+
zoom,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
doCreateMarker({ definition, }) {
|
|
161
|
+
const { '@id': _id, position, title, infoWindow, extra, rawOptions = {}, ...otherOptions } = definition;
|
|
162
|
+
const marker = new _google.maps.marker.AdvancedMarkerElement({
|
|
163
|
+
position,
|
|
164
|
+
title,
|
|
165
|
+
...otherOptions,
|
|
166
|
+
...rawOptions,
|
|
167
|
+
map: this.map,
|
|
168
|
+
});
|
|
169
|
+
if (infoWindow) {
|
|
170
|
+
this.createInfoWindow({ definition: infoWindow, element: marker });
|
|
171
|
+
}
|
|
172
|
+
return marker;
|
|
173
|
+
}
|
|
174
|
+
doRemoveMarker(marker) {
|
|
175
|
+
marker.map = null;
|
|
176
|
+
}
|
|
177
|
+
doCreatePolygon({ definition, }) {
|
|
178
|
+
const { '@id': _id, points, title, infoWindow, rawOptions = {} } = definition;
|
|
179
|
+
const polygon = new _google.maps.Polygon({
|
|
180
|
+
...rawOptions,
|
|
181
|
+
paths: points,
|
|
182
|
+
map: this.map,
|
|
183
|
+
});
|
|
184
|
+
if (title) {
|
|
185
|
+
polygon.set('title', title);
|
|
186
|
+
}
|
|
187
|
+
if (infoWindow) {
|
|
188
|
+
this.createInfoWindow({ definition: infoWindow, element: polygon });
|
|
189
|
+
}
|
|
190
|
+
return polygon;
|
|
191
|
+
}
|
|
192
|
+
doRemovePolygon(polygon) {
|
|
193
|
+
polygon.setMap(null);
|
|
194
|
+
}
|
|
195
|
+
doCreatePolyline({ definition, }) {
|
|
196
|
+
const { '@id': _id, points, title, infoWindow, rawOptions = {} } = definition;
|
|
197
|
+
const polyline = new _google.maps.Polyline({
|
|
198
|
+
...rawOptions,
|
|
199
|
+
path: points,
|
|
200
|
+
map: this.map,
|
|
201
|
+
});
|
|
202
|
+
if (title) {
|
|
203
|
+
polyline.set('title', title);
|
|
204
|
+
}
|
|
205
|
+
if (infoWindow) {
|
|
206
|
+
this.createInfoWindow({ definition: infoWindow, element: polyline });
|
|
207
|
+
}
|
|
208
|
+
return polyline;
|
|
209
|
+
}
|
|
210
|
+
doRemovePolyline(polyline) {
|
|
211
|
+
polyline.setMap(null);
|
|
212
|
+
}
|
|
213
|
+
doCreateInfoWindow({ definition, element, }) {
|
|
214
|
+
const { headerContent, content, extra, rawOptions = {}, ...otherOptions } = definition;
|
|
215
|
+
const infoWindow = new _google.maps.InfoWindow({
|
|
216
|
+
headerContent: this.createTextOrElement(headerContent),
|
|
217
|
+
content: this.createTextOrElement(content),
|
|
218
|
+
...otherOptions,
|
|
219
|
+
...rawOptions,
|
|
220
|
+
});
|
|
221
|
+
if (element instanceof google.maps.marker.AdvancedMarkerElement) {
|
|
222
|
+
element.addListener('click', () => {
|
|
223
|
+
if (definition.autoClose) {
|
|
224
|
+
this.closeInfoWindowsExcept(infoWindow);
|
|
225
|
+
}
|
|
226
|
+
infoWindow.open({ map: this.map, anchor: element });
|
|
227
|
+
});
|
|
228
|
+
if (definition.opened) {
|
|
229
|
+
infoWindow.open({ map: this.map, anchor: element });
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
else if (element instanceof google.maps.Polygon) {
|
|
233
|
+
element.addListener('click', (event) => {
|
|
234
|
+
if (definition.autoClose) {
|
|
235
|
+
this.closeInfoWindowsExcept(infoWindow);
|
|
236
|
+
}
|
|
237
|
+
infoWindow.setPosition(event.latLng);
|
|
238
|
+
infoWindow.open(this.map);
|
|
239
|
+
});
|
|
240
|
+
if (definition.opened) {
|
|
241
|
+
const bounds = new google.maps.LatLngBounds();
|
|
242
|
+
element.getPath().forEach((point) => {
|
|
243
|
+
bounds.extend(point);
|
|
244
|
+
});
|
|
245
|
+
infoWindow.setPosition(bounds.getCenter());
|
|
246
|
+
infoWindow.open({ map: this.map, anchor: element });
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return infoWindow;
|
|
250
|
+
}
|
|
251
|
+
doFitBoundsToMarkers() {
|
|
252
|
+
if (this.markers.size === 0) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
const bounds = new google.maps.LatLngBounds();
|
|
256
|
+
this.markers.forEach((marker) => {
|
|
257
|
+
if (!marker.position) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
bounds.extend(marker.position);
|
|
261
|
+
});
|
|
262
|
+
this.map.fitBounds(bounds);
|
|
263
|
+
}
|
|
264
|
+
createTextOrElement(content) {
|
|
265
|
+
if (!content) {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
if (content.includes('<')) {
|
|
269
|
+
const div = document.createElement('div');
|
|
270
|
+
div.innerHTML = content;
|
|
271
|
+
return div;
|
|
272
|
+
}
|
|
273
|
+
return content;
|
|
274
|
+
}
|
|
275
|
+
closeInfoWindowsExcept(infoWindow) {
|
|
276
|
+
this.infoWindows.forEach((otherInfoWindow) => {
|
|
277
|
+
if (otherInfoWindow !== infoWindow) {
|
|
278
|
+
otherInfoWindow.close();
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export { map_controller as default };
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@symfony/ux-google-map",
|
|
3
|
+
"description": "GoogleMaps bridge for Symfony UX Map, integrate interactive maps in your Symfony applications",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"version": "2.23.0",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"symfony-ux",
|
|
8
|
+
"google-maps",
|
|
9
|
+
"map"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://ux.symfony.com/map",
|
|
12
|
+
"repository": "https://github.com/symfony/ux-google-map",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"main": "dist/map_controller.js",
|
|
18
|
+
"types": "dist/map_controller.d.ts",
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "node ../../../../../../bin/build_package.js .",
|
|
21
|
+
"watch": "node ../../../../../../bin/build_package.js . --watch",
|
|
22
|
+
"test": "../../../../../../bin/test_package.sh .",
|
|
23
|
+
"check": "biome check",
|
|
24
|
+
"ci": "biome ci"
|
|
25
|
+
},
|
|
26
|
+
"symfony": {
|
|
27
|
+
"controllers": {
|
|
28
|
+
"map": {
|
|
29
|
+
"main": "dist/map_controller.js",
|
|
30
|
+
"webpackMode": "lazy",
|
|
31
|
+
"fetch": "lazy",
|
|
32
|
+
"enabled": true
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"importmap": {
|
|
36
|
+
"@hotwired/stimulus": "^3.0.0",
|
|
37
|
+
"@googlemaps/js-api-loader": "^1.16.6",
|
|
38
|
+
"@symfony/ux-google-map": "path:%PACKAGE%/dist/map_controller.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@googlemaps/js-api-loader": "^1.16.6",
|
|
43
|
+
"@hotwired/stimulus": "^3.0.0"
|
|
44
|
+
},
|
|
45
|
+
"peerDependenciesMeta": {
|
|
46
|
+
"@googlemaps/js-api-loader": {
|
|
47
|
+
"optional": false
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@googlemaps/js-api-loader": "^1.16.6",
|
|
52
|
+
"@hotwired/stimulus": "^3.0.0",
|
|
53
|
+
"@symfony/ux-map": "2.23.0",
|
|
54
|
+
"@types/google.maps": "^3.55.9"
|
|
55
|
+
}
|
|
56
|
+
}
|