@symfony/ux-leaflet-map
Advanced tools
+31
-13
@@ -0,7 +1,18 @@ | ||
| import type { CircleDefinition, Icon, InfoWindowDefinition, MapDefinition, MarkerDefinition, PolygonDefinition, PolylineDefinition, RectangleDefinition } from '@symfony/ux-map'; | ||
| import AbstractMapController from '@symfony/ux-map'; | ||
| import type { Icon, InfoWindowWithoutPositionDefinition, MarkerDefinition, Point, PolygonDefinition, PolylineDefinition } from '@symfony/ux-map'; | ||
| import 'leaflet/dist/leaflet.min.css'; | ||
| import type { CircleOptions, ControlPosition, MapOptions as LeafletMapOptions, MarkerOptions, PolylineOptions as PolygonOptions, PolylineOptions, PopupOptions, PolylineOptions as RectangleOptions } from 'leaflet'; | ||
| import * as L from 'leaflet'; | ||
| import type { MapOptions as LeafletMapOptions, MarkerOptions, PolylineOptions as PolygonOptions, PolylineOptions, PopupOptions } from 'leaflet'; | ||
| type MapOptions = Pick<LeafletMapOptions, 'center' | 'zoom'> & { | ||
| type MapOptions = Pick<LeafletMapOptions, 'attributionControl' | 'zoomControl'> & { | ||
| attributionControlOptions?: { | ||
| position: ControlPosition; | ||
| prefix: string | false; | ||
| }; | ||
| zoomControlOptions?: { | ||
| position: ControlPosition; | ||
| zoomInText: string; | ||
| zoomInTitle: string; | ||
| zoomOutText: string; | ||
| zoomOutTitle: string; | ||
| }; | ||
| tileLayer: { | ||
@@ -13,3 +24,3 @@ url: string; | ||
| }; | ||
| export default class extends AbstractMapController<MapOptions, L.Map, MarkerOptions, L.Marker, PopupOptions, L.Popup, PolygonOptions, L.Polygon, PolylineOptions, L.Polyline> { | ||
| export default class extends AbstractMapController<MapOptions, LeafletMapOptions, L.Map, MarkerOptions, L.Marker, PopupOptions, L.Popup, PolygonOptions, L.Polygon, PolylineOptions, L.Polyline, CircleOptions, L.Circle, RectangleOptions, L.Rectangle> { | ||
| map: L.Map; | ||
@@ -20,6 +31,4 @@ connect(): void; | ||
| protected dispatchEvent(name: string, payload?: Record<string, unknown>): void; | ||
| protected doCreateMap({ center, zoom, options, }: { | ||
| center: Point | null; | ||
| zoom: number | null; | ||
| options: MapOptions; | ||
| protected doCreateMap({ definition }: { | ||
| definition: MapDefinition<MapOptions, LeafletMapOptions>; | ||
| }): L.Map; | ||
@@ -30,15 +39,23 @@ protected doCreateMarker({ definition }: { | ||
| protected doRemoveMarker(marker: L.Marker): void; | ||
| protected doCreatePolygon({ definition, }: { | ||
| protected doCreatePolygon({ definition }: { | ||
| definition: PolygonDefinition<PolygonOptions, PopupOptions>; | ||
| }): L.Polygon; | ||
| protected doRemovePolygon(polygon: L.Polygon): void; | ||
| protected doCreatePolyline({ definition, }: { | ||
| protected doCreatePolyline({ definition }: { | ||
| definition: PolylineDefinition<PolylineOptions, PopupOptions>; | ||
| }): L.Polyline; | ||
| protected doRemovePolyline(polyline: L.Polyline): void; | ||
| protected doCreateCircle({ definition }: { | ||
| definition: CircleDefinition<CircleOptions, PopupOptions>; | ||
| }): L.Circle; | ||
| protected doRemoveCircle(circle: L.Circle): void; | ||
| protected doCreateRectangle({ definition }: { | ||
| definition: RectangleDefinition<RectangleOptions, PopupOptions>; | ||
| }): L.Rectangle; | ||
| protected doRemoveRectangle(rectangle: L.Rectangle): void; | ||
| protected doCreateInfoWindow({ definition, element, }: { | ||
| definition: InfoWindowWithoutPositionDefinition<PopupOptions>; | ||
| element: L.Marker | L.Polygon | L.Polyline; | ||
| definition: Omit<InfoWindowDefinition<PopupOptions>, 'position'>; | ||
| element: L.Marker | L.Polygon | L.Polyline | L.Circle | L.Rectangle; | ||
| }): L.Popup; | ||
| protected doCreateIcon({ definition, element, }: { | ||
| protected doCreateIcon({ definition, element }: { | ||
| definition: Icon; | ||
@@ -48,3 +65,4 @@ element: L.Marker; | ||
| protected doFitBoundsToMarkers(): void; | ||
| private closePopups; | ||
| } | ||
| export {}; |
+114
-25
@@ -16,2 +16,4 @@ import { Controller } from '@hotwired/stimulus'; | ||
| this.polylines = new Map(); | ||
| this.circles = new Map(); | ||
| this.rectangles = new Map(); | ||
| this.infoWindows = []; | ||
@@ -21,15 +23,21 @@ this.isConnected = false; | ||
| connect() { | ||
| const options = this.optionsValue; | ||
| this.dispatchEvent('pre-connect', { options }); | ||
| const extra = this.hasExtraValue ? this.extraValue : {}; | ||
| const mapDefinition = { | ||
| center: this.hasCenterValue ? this.centerValue : null, | ||
| zoom: this.hasZoomValue ? this.zoomValue : null, | ||
| options: this.optionsValue, | ||
| extra, | ||
| }; | ||
| this.dispatchEvent('pre-connect', mapDefinition); | ||
| this.createMarker = this.createDrawingFactory('marker', this.markers, this.doCreateMarker.bind(this)); | ||
| this.createPolygon = this.createDrawingFactory('polygon', this.polygons, this.doCreatePolygon.bind(this)); | ||
| this.createPolyline = this.createDrawingFactory('polyline', this.polylines, this.doCreatePolyline.bind(this)); | ||
| this.map = this.doCreateMap({ | ||
| center: this.hasCenterValue ? this.centerValue : null, | ||
| zoom: this.hasZoomValue ? this.zoomValue : null, | ||
| options, | ||
| }); | ||
| this.createCircle = this.createDrawingFactory('circle', this.circles, this.doCreateCircle.bind(this)); | ||
| this.createRectangle = this.createDrawingFactory('rectangle', this.rectangles, this.doCreateRectangle.bind(this)); | ||
| this.map = this.doCreateMap({ definition: mapDefinition }); | ||
| this.markersValue.forEach((definition) => this.createMarker({ definition })); | ||
| this.polygonsValue.forEach((definition) => this.createPolygon({ definition })); | ||
| this.polylinesValue.forEach((definition) => this.createPolyline({ definition })); | ||
| this.circlesValue.forEach((definition) => this.createCircle({ definition })); | ||
| this.rectanglesValue.forEach((definition) => this.createRectangle({ definition })); | ||
| if (this.fitBoundsToMarkersValue) { | ||
@@ -43,3 +51,6 @@ this.doFitBoundsToMarkers(); | ||
| polylines: [...this.polylines.values()], | ||
| circles: [...this.circles.values()], | ||
| rectangles: [...this.rectangles.values()], | ||
| infoWindows: this.infoWindows, | ||
| extra, | ||
| }); | ||
@@ -76,2 +87,14 @@ this.isConnected = true; | ||
| } | ||
| circlesValueChanged() { | ||
| if (!this.isConnected) { | ||
| return; | ||
| } | ||
| this.onDrawChanged(this.circles, this.circlesValue, this.createCircle, this.doRemoveCircle); | ||
| } | ||
| rectanglesValueChanged() { | ||
| if (!this.isConnected) { | ||
| return; | ||
| } | ||
| this.onDrawChanged(this.rectangles, this.rectanglesValue, this.createRectangle, this.doRemoveRectangle); | ||
| } | ||
| createDrawingFactory(type, draws, factory) { | ||
@@ -82,2 +105,5 @@ const eventBefore = `${type}:before-create`; | ||
| this.dispatchEvent(eventBefore, { definition }); | ||
| if (typeof definition.rawOptions !== 'undefined') { | ||
| console.warn(`[Symfony UX Map] The event "${eventBefore}" added a deprecated "rawOptions" property to the definition, it will be removed in a next major version, replace it with "bridgeOptions" instead.`, definition); | ||
| } | ||
| const drawing = factory({ definition }); | ||
@@ -114,3 +140,6 @@ this.dispatchEvent(eventAfter, { [type]: drawing, definition }); | ||
| polylines: Array, | ||
| circles: Array, | ||
| rectangles: Array, | ||
| options: Object, | ||
| extra: Object, | ||
| }; | ||
@@ -140,15 +169,17 @@ | ||
| dispatchEvent(name, payload = {}) { | ||
| payload.L = L; | ||
| this.dispatch(name, { | ||
| prefix: 'ux:map', | ||
| detail: { | ||
| ...payload, | ||
| L, | ||
| }, | ||
| detail: payload, | ||
| }); | ||
| } | ||
| doCreateMap({ center, zoom, options, }) { | ||
| doCreateMap({ definition }) { | ||
| const { center, zoom, options, bridgeOptions = {} } = definition; | ||
| const map = L.map(this.element, { | ||
| ...options, | ||
| center: center === null ? undefined : center, | ||
| zoom: zoom === null ? undefined : zoom, | ||
| attributionControl: false, | ||
| zoomControl: false, | ||
| ...options, | ||
| ...bridgeOptions, | ||
| }); | ||
@@ -161,7 +192,18 @@ if (options.tileLayer) { | ||
| } | ||
| if (typeof options.attributionControlOptions !== 'undefined') { | ||
| L.control.attribution({ ...options.attributionControlOptions }).addTo(map); | ||
| } | ||
| if (typeof options.zoomControlOptions !== 'undefined') { | ||
| L.control.zoom({ ...options.zoomControlOptions }).addTo(map); | ||
| } | ||
| return map; | ||
| } | ||
| doCreateMarker({ definition }) { | ||
| const { '@id': _id, position, title, infoWindow, icon, extra, rawOptions = {}, ...otherOptions } = definition; | ||
| const marker = L.marker(position, { title: title || undefined, ...otherOptions, ...rawOptions }).addTo(this.map); | ||
| const { '@id': _id, position, title, infoWindow, icon, rawOptions = {}, bridgeOptions = {} } = definition; | ||
| const marker = L.marker(position, { | ||
| title: title || undefined, | ||
| ...rawOptions, | ||
| ...bridgeOptions, | ||
| riseOnHover: true, | ||
| }).addTo(this.map); | ||
| if (infoWindow) { | ||
@@ -178,5 +220,5 @@ this.createInfoWindow({ definition: infoWindow, element: marker }); | ||
| } | ||
| doCreatePolygon({ definition, }) { | ||
| const { '@id': _id, points, title, infoWindow, rawOptions = {} } = definition; | ||
| const polygon = L.polygon(points, { ...rawOptions }).addTo(this.map); | ||
| doCreatePolygon({ definition }) { | ||
| const { '@id': _id, points, title, infoWindow, rawOptions = {}, bridgeOptions = {} } = definition; | ||
| const polygon = L.polygon(points, { ...rawOptions, ...bridgeOptions }).addTo(this.map); | ||
| if (title) { | ||
@@ -193,5 +235,5 @@ polygon.bindPopup(title); | ||
| } | ||
| doCreatePolyline({ definition, }) { | ||
| const { '@id': _id, points, title, infoWindow, rawOptions = {} } = definition; | ||
| const polyline = L.polyline(points, { ...rawOptions }).addTo(this.map); | ||
| doCreatePolyline({ definition }) { | ||
| const { '@id': _id, points, title, infoWindow, rawOptions = {}, bridgeOptions = {} } = definition; | ||
| const polyline = L.polyline(points, { ...rawOptions, ...bridgeOptions }).addTo(this.map); | ||
| if (title) { | ||
@@ -208,6 +250,40 @@ polyline.bindPopup(title); | ||
| } | ||
| doCreateCircle({ definition }) { | ||
| const { '@id': _id, center, radius, title, infoWindow, rawOptions = {}, bridgeOptions = {} } = definition; | ||
| const circle = L.circle(center, { radius, ...rawOptions, ...bridgeOptions }).addTo(this.map); | ||
| if (title) { | ||
| circle.bindPopup(title); | ||
| } | ||
| if (infoWindow) { | ||
| this.createInfoWindow({ definition: infoWindow, element: circle }); | ||
| } | ||
| return circle; | ||
| } | ||
| doRemoveCircle(circle) { | ||
| circle.remove(); | ||
| } | ||
| doCreateRectangle({ definition }) { | ||
| const { '@id': _id, southWest, northEast, title, infoWindow, rawOptions = {}, bridgeOptions = {} } = definition; | ||
| const rectangle = L.rectangle([ | ||
| [southWest.lat, southWest.lng], | ||
| [northEast.lat, northEast.lng], | ||
| ], { ...rawOptions, ...bridgeOptions }).addTo(this.map); | ||
| if (title) { | ||
| rectangle.bindPopup(title); | ||
| } | ||
| if (infoWindow) { | ||
| this.createInfoWindow({ definition: infoWindow, element: rectangle }); | ||
| } | ||
| return rectangle; | ||
| } | ||
| doRemoveRectangle(rectangle) { | ||
| rectangle.remove(); | ||
| } | ||
| doCreateInfoWindow({ definition, element, }) { | ||
| const { headerContent, content, rawOptions = {}, ...otherOptions } = definition; | ||
| element.bindPopup([headerContent, content].filter((x) => x).join('<br>'), { ...otherOptions, ...rawOptions }); | ||
| if (definition.opened) { | ||
| const { headerContent, content, opened, autoClose, rawOptions = {}, bridgeOptions = {} } = definition; | ||
| element.bindPopup([headerContent, content].filter((x) => x).join('<br>'), { ...rawOptions, ...bridgeOptions }); | ||
| if (opened) { | ||
| if (autoClose) { | ||
| this.closePopups(); | ||
| } | ||
| element.openPopup(); | ||
@@ -219,5 +295,10 @@ } | ||
| } | ||
| popup.on('click', () => { | ||
| if (autoClose) { | ||
| this.closePopups({ except: popup }); | ||
| } | ||
| }); | ||
| return popup; | ||
| } | ||
| doCreateIcon({ definition, element, }) { | ||
| doCreateIcon({ definition, element }) { | ||
| const { type, width, height } = definition; | ||
@@ -262,4 +343,12 @@ let icon; | ||
| } | ||
| closePopups(options = {}) { | ||
| this.infoWindows.forEach((popup) => { | ||
| if (options.except && popup === options.except) { | ||
| return; | ||
| } | ||
| popup.close(); | ||
| }); | ||
| } | ||
| } | ||
| export { map_controller as default }; |
+2
-2
@@ -5,3 +5,3 @@ { | ||
| "license": "MIT", | ||
| "version": "2.26.1", | ||
| "version": "2.27.0", | ||
| "keywords": [ | ||
@@ -53,3 +53,3 @@ "symfony-ux", | ||
| "@hotwired/stimulus": "^3.0.0", | ||
| "@symfony/ux-map": "2.26.1", | ||
| "@symfony/ux-map": "2.27.0", | ||
| "@types/leaflet": "^1.9.12", | ||
@@ -56,0 +56,0 @@ "leaflet": "^1.9.4" |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
20688
28.87%406
35.79%