Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Map] add polyline support #2340

Open
wants to merge 14 commits into
base: 2.x
Choose a base branch
from
4 changes: 4 additions & 0 deletions src/Map/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG

## 2.22

- Add `Polyline` support

## 2.20

- Deprecate `render_map` Twig function (will be removed in 2.21). Use
Expand Down
24 changes: 19 additions & 5 deletions src/Map/assets/dist/abstract_map_controller.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ export type Point = {
lat: number;
lng: number;
};
export type MapView<Options, MarkerOptions, InfoWindowOptions, PolygonOptions> = {
export type MapView<Options, MarkerOptions, InfoWindowOptions, PolygonOptions, PolylineOptions> = {
center: Point | null;
zoom: number | null;
fitBoundsToMarkers: boolean;
markers: Array<MarkerDefinition<MarkerOptions, InfoWindowOptions>>;
polygons: Array<PolygonDefinition<PolygonOptions, InfoWindowOptions>>;
polylines: Array<PolylineDefinition<PolylineOptions, InfoWindowOptions>>;
options: Options;
};
export type MarkerDefinition<MarkerOptions, InfoWindowOptions> = {
Expand All @@ -25,6 +26,13 @@ export type PolygonDefinition<PolygonOptions, InfoWindowOptions> = {
rawOptions?: PolygonOptions;
extra: Record<string, unknown>;
};
export type PolylineDefinition<PolylineOptions, InfoWindowOptions> = {
infoWindow?: Omit<InfoWindowDefinition<InfoWindowOptions>, 'position'>;
points: Array<Point>;
title: string | null;
rawOptions?: PolylineOptions;
extra: Record<string, unknown>;
};
export type InfoWindowDefinition<InfoWindowOptions> = {
headerContent: string | null;
content: string | null;
Expand All @@ -34,16 +42,17 @@ export type InfoWindowDefinition<InfoWindowOptions> = {
rawOptions?: InfoWindowOptions;
extra: Record<string, unknown>;
};
export default abstract class<MapOptions, Map, MarkerOptions, Marker, InfoWindowOptions, InfoWindow, PolygonOptions, Polygon> extends Controller<HTMLElement> {
export default abstract class<MapOptions, Map, MarkerOptions, Marker, InfoWindowOptions, InfoWindow, PolygonOptions, Polygon, PolylineOptions, Polyline> extends Controller<HTMLElement> {
static values: {
providerOptions: ObjectConstructor;
view: ObjectConstructor;
};
viewValue: MapView<MapOptions, MarkerOptions, InfoWindowOptions, PolygonOptions>;
viewValue: MapView<MapOptions, MarkerOptions, InfoWindowOptions, PolygonOptions, PolylineOptions>;
protected map: Map;
protected markers: Array<Marker>;
protected infoWindows: Array<InfoWindow>;
protected polygons: Array<Polygon>;
protected polylines: Array<Polyline>;
connect(): void;
protected abstract doCreateMap({ center, zoom, options, }: {
center: Point | null;
Expand All @@ -52,18 +61,23 @@ export default abstract class<MapOptions, Map, MarkerOptions, Marker, InfoWindow
}): Map;
createMarker(definition: MarkerDefinition<MarkerOptions, InfoWindowOptions>): Marker;
createPolygon(definition: PolygonDefinition<PolygonOptions, InfoWindowOptions>): Polygon;
createPolyline(definition: PolylineDefinition<PolylineOptions, InfoWindowOptions>): Polyline;
protected abstract doCreateMarker(definition: MarkerDefinition<MarkerOptions, InfoWindowOptions>): Marker;
protected abstract doCreatePolygon(definition: PolygonDefinition<PolygonOptions, InfoWindowOptions>): Polygon;
protected abstract doCreatePolyline(definition: PolylineDefinition<PolylineOptions, InfoWindowOptions>): Polyline;
protected createInfoWindow({ definition, element, }: {
definition: MarkerDefinition<MarkerOptions, InfoWindowOptions>['infoWindow'] | PolygonDefinition<PolygonOptions, InfoWindowOptions>['infoWindow'];
element: Marker | Polygon;
definition: MarkerDefinition<MarkerOptions, InfoWindowOptions>['infoWindow'] | PolygonDefinition<PolygonOptions, InfoWindowOptions>['infoWindow'] | PolylineDefinition<PolylineOptions, InfoWindowOptions>['infoWindow'];
element: Marker | Polygon | Polyline;
}): InfoWindow;
protected abstract doCreateInfoWindow({ definition, element, }: {
definition: MarkerDefinition<MarkerOptions, InfoWindowOptions>['infoWindow'];
element: Marker;
} | {
definition: PolygonDefinition<PolygonOptions, InfoWindowOptions>['infoWindow'];
element: Polygon;
} | {
definition: PolylineDefinition<PolylineOptions, InfoWindowOptions>['infoWindow'];
element: Polyline;
}): InfoWindow;
protected abstract doFitBoundsToMarkers(): void;
protected abstract dispatchEvent(name: string, payload: Record<string, unknown>): void;
Expand Down
12 changes: 11 additions & 1 deletion src/Map/assets/dist/abstract_map_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,23 @@ class default_1 extends Controller {
this.markers = [];
this.infoWindows = [];
this.polygons = [];
this.polylines = [];
}
connect() {
const { center, zoom, options, markers, polygons, fitBoundsToMarkers } = this.viewValue;
const { center, zoom, options, markers, polygons, polylines, fitBoundsToMarkers } = this.viewValue;
this.dispatchEvent('pre-connect', { options });
this.map = this.doCreateMap({ center, zoom, options });
markers.forEach((marker) => this.createMarker(marker));
polygons.forEach((polygon) => this.createPolygon(polygon));
polylines.forEach((polyline) => this.createPolyline(polyline));
if (fitBoundsToMarkers) {
this.doFitBoundsToMarkers();
}
this.dispatchEvent('connect', {
map: this.map,
markers: this.markers,
polygons: this.polygons,
polylines: this.polylines,
infoWindows: this.infoWindows,
});
}
Expand All @@ -37,6 +40,13 @@ class default_1 extends Controller {
this.polygons.push(polygon);
return polygon;
}
createPolyline(definition) {
this.dispatchEvent('polyline:before-create', { definition });
const polyline = this.doCreatePolyline(definition);
this.dispatchEvent('polyline:after-create', { polyline });
this.polylines.push(polyline);
return polyline;
}
createInfoWindow({ definition, element, }) {
this.dispatchEvent('info-window:before-create', { definition, element });
const infoWindow = this.doCreateInfoWindow({ definition, element });
Expand Down
40 changes: 35 additions & 5 deletions src/Map/assets/src/abstract_map_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

export type Point = { lat: number; lng: number };

export type MapView<Options, MarkerOptions, InfoWindowOptions, PolygonOptions> = {
export type MapView<Options, MarkerOptions, InfoWindowOptions, PolygonOptions, PolylineOptions> = {
center: Point | null;
zoom: number | null;
fitBoundsToMarkers: boolean;
markers: Array<MarkerDefinition<MarkerOptions, InfoWindowOptions>>;
polygons: Array<PolygonDefinition<PolygonOptions, InfoWindowOptions>>;
polylines: Array<PolylineDefinition<PolylineOptions, InfoWindowOptions>>;
options: Options;
};

Expand Down Expand Up @@ -36,6 +37,14 @@
extra: Record<string, unknown>;
};

export type PolylineDefinition<PolylineOptions, InfoWindowOptions> = {
infoWindow?: Omit<InfoWindowDefinition<InfoWindowOptions>, 'position'>;
points: Array<Point>;
title: string | null;
rawOptions?: PolylineOptions;
extra: Record<string, unknown>;
};

export type InfoWindowDefinition<InfoWindowOptions> = {
headerContent: string | null;
content: string | null;
Expand Down Expand Up @@ -65,21 +74,24 @@
InfoWindow,
PolygonOptions,
Polygon,
PolylineOptions,
Polyline,
> extends Controller<HTMLElement> {
static values = {
providerOptions: Object,
view: Object,
};

declare viewValue: MapView<MapOptions, MarkerOptions, InfoWindowOptions, PolygonOptions>;
declare viewValue: MapView<MapOptions, MarkerOptions, InfoWindowOptions, PolygonOptions, PolylineOptions>;

protected map: Map;
protected markers: Array<Marker> = [];
protected infoWindows: Array<InfoWindow> = [];
protected polygons: Array<Polygon> = [];
protected polylines: Array<Polyline> = [];

connect() {
const { center, zoom, options, markers, polygons, fitBoundsToMarkers } = this.viewValue;
const { center, zoom, options, markers, polygons, polylines, fitBoundsToMarkers } = this.viewValue;

Check failure on line 94 in src/Map/assets/src/abstract_map_controller.ts

View workflow job for this annotation

GitHub Actions / tests-js

Unhandled error

SyntaxError: Unexpected non-whitespace character after JSON at position 853 (line 1 column 854) ❯ object ../../../../../../../../../../../node_modules/.vite/deps/@hotwired_stimulus.js:2245:25 ❯ extended.get ../../../../../../../../../../../node_modules/.vite/deps/@hotwired_stimulus.js:2113:18 ❯ extended.connect ../../../../assets/src/abstract_map_controller.ts:94:97 ❯ extended.connect src/map_controller.ts:81:14

this.dispatchEvent('pre-connect', { options });

Expand All @@ -89,6 +101,8 @@

polygons.forEach((polygon) => this.createPolygon(polygon));

polylines.forEach((polyline) => this.createPolyline(polyline));

if (fitBoundsToMarkers) {
this.doFitBoundsToMarkers();
}
Expand All @@ -97,6 +111,7 @@
map: this.map,
markers: this.markers,
polygons: this.polygons,
polylines: this.polylines,
infoWindows: this.infoWindows,
});
}
Expand Down Expand Up @@ -129,17 +144,27 @@
return polygon;
}

createPolyline(definition: PolylineDefinition<PolylineOptions, InfoWindowOptions>): Polyline {
this.dispatchEvent('polyline:before-create', { definition });
const polyline = this.doCreatePolyline(definition);
this.dispatchEvent('polyline:after-create', { polyline });
this.polylines.push(polyline);
return polyline;
}

protected abstract doCreateMarker(definition: MarkerDefinition<MarkerOptions, InfoWindowOptions>): Marker;
protected abstract doCreatePolygon(definition: PolygonDefinition<PolygonOptions, InfoWindowOptions>): Polygon;
protected abstract doCreatePolyline(definition: PolylineDefinition<PolylineOptions, InfoWindowOptions>): Polyline;

protected createInfoWindow({
definition,
element,
}: {
definition:
| MarkerDefinition<MarkerOptions, InfoWindowOptions>['infoWindow']
| PolygonDefinition<PolygonOptions, InfoWindowOptions>['infoWindow'];
element: Marker | Polygon;
| PolygonDefinition<PolygonOptions, InfoWindowOptions>['infoWindow']
| PolylineDefinition<PolylineOptions, InfoWindowOptions>['infoWindow'];
element: Marker | Polygon | Polyline;
}): InfoWindow {
this.dispatchEvent('info-window:before-create', { definition, element });
const infoWindow = this.doCreateInfoWindow({ definition, element });
Expand All @@ -150,6 +175,7 @@
return infoWindow;
}


protected abstract doCreateInfoWindow({
definition,
element,
Expand All @@ -161,6 +187,10 @@
| {
definition: PolygonDefinition<PolygonOptions, InfoWindowOptions>['infoWindow'];
element: Polygon;
}
| {
definition: PolylineDefinition<PolylineOptions, InfoWindowOptions>['infoWindow'];
element: Polyline;
}): InfoWindow;

protected abstract doFitBoundsToMarkers(): void;
Expand Down
49 changes: 48 additions & 1 deletion src/Map/assets/test/abstract_map_controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,25 @@ class MyMapController extends AbstractMapController {
return polygon;
}

doCreatePolyline(definition) {
const polyline = { polyline: 'polyline', title: definition.title };

if (definition.infoWindow) {
this.createInfoWindow({ definition: definition.infoWindow, element: polyline });
}
return polyline;
}

doCreateInfoWindow({ definition, element }) {
if (element.marker) {
return { infoWindow: 'infoWindow', headerContent: definition.headerContent, marker: element.title };
}
if (element.polygon) {
return { infoWindow: 'infoWindow', headerContent: definition.headerContent, polygon: element.title };
}
if (element.polyline) {
return { infoWindow: 'infoWindow', headerContent: definition.headerContent, polyline: element.title };
}
}

doFitBoundsToMarkers() {
Expand Down Expand Up @@ -113,6 +125,32 @@ describe('AbstractMapController', () => {
"autoClose": true
}
}
],
"polylines": [
{
"coordinates": [
{ "lat": 48.858844, "lng": 2.294351 },
{ "lat": 48.853, "lng": 2.3499 },
{ "lat": 48.8566, "lng": 2.3522 }
],
"title": "Polyline 1",
"infoWindow": null
},
{
"coordinates": [
{ "lat": 45.764043, "lng": 4.835659 },
{ "lat": 45.750000, "lng": 4.850000 },
{ "lat": 45.770000, "lng": 4.820000 }
],
"title": "Polyline 2",
"infoWindow": {
"headerContent": "<b>Polyline 2</b>",
"content": "A polyline around Lyon with some additional info.",
"position": null,
"opened": false,
"autoClose": true
}
}
]
}'>
</div>
Expand All @@ -123,7 +161,7 @@ describe('AbstractMapController', () => {
clearDOM();
});

it('connect and create map, marker, polygon and info window', async () => {
it('connect and create map, marker, polygon, polyline and info window', async () => {
const div = getByTestId(container, 'map');
expect(div).not.toHaveClass('connected');

Expand All @@ -140,6 +178,10 @@ describe('AbstractMapController', () => {
{ polygon: 'polygon', title: 'Polygon 1' },
{ polygon: 'polygon', title: 'Polygon 2' },
]);
expect(controller.polylines).toEqual([
{ polyline: 'polyline', title: 'Polyline 1' },
{ polyline: 'polyline', title: 'Polyline 2' },
]);
expect(controller.infoWindows).toEqual([
{
headerContent: '<b>Lyon</b>',
Expand All @@ -151,6 +193,11 @@ describe('AbstractMapController', () => {
infoWindow: 'infoWindow',
polygon: 'Polygon 2',
},
{
headerContent: '<b>Polyline 2</b>',
infoWindow: 'infoWindow',
polyline: 'Polyline 2',
},
]);
});
});
20 changes: 19 additions & 1 deletion src/Map/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ You can set the center and zoom of the map using the ``center()`` and ``zoom()``

use Symfony\UX\Map\Map;
use Symfony\UX\Map\Point;

$myMap
// Explicitly set the center and zoom
->center(new Point(46.903354, 1.888334))
Expand Down Expand Up @@ -130,6 +130,7 @@ You can add markers to a map using the ``addMarker()`` method::
)
;


Add Polygons
~~~~~~~~~~~~

Expand All @@ -147,6 +148,23 @@ You can also add Polygons, which represents an area enclosed by a series of ``Po
),
));

Add Polylines
~~~~~~~~~~~~~

You can add Polylines, which represents a path made by a series of `Point` instances
$myMap->addPolyline(new Polyline(
points: [
new Point(48.8566, 2.3522),
new Point(45.7640, 4.8357),
new Point(43.2965, 5.3698),
new Point(44.8378, -0.5792),
],
infoWindow: new InfoWindow(
content: 'A line passing through Paris, Lyon, Marseille, Bordeaux',
),
));


Render a map
------------
sblondeau marked this conversation as resolved.
Show resolved Hide resolved

Expand Down
Loading
Loading