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
1 change: 1 addition & 0 deletions src/Map/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- The importmap entry `@symfony/ux-map/abstract-map-controller` can be removed
from your importmap, it is no longer needed.
- Add `Polygon` support
- Add `Polyline` support
smnandre marked this conversation as resolved.
Show resolved Hide resolved

## 2.19

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
10 changes: 10 additions & 0 deletions 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;
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
37 changes: 33 additions & 4 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;

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:86 ❯ 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 @@ -161,6 +186,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 @@
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 @@
"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 @@
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 @@
{ polygon: 'polygon', title: 'Polygon 1' },
{ polygon: 'polygon', title: 'Polygon 2' },
]);
expect(controller.polylines).toEqual([

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

View workflow job for this annotation

GitHub Actions / tests-js

test/abstract_map_controller.test.ts > AbstractMapController > connect and create map, marker, polygon, polyline and info window

AssertionError: expected [] to deeply equal [ Array(2) ] - Expected + Received - Array [ - Object { - "polyline": "polyline", - "title": "Polyline 1", - }, - Object { - "polyline": "polyline", - "title": "Polyline 2", - }, - ] + Array [] ❯ test/abstract_map_controller.test.ts:181:38
{ polyline: 'polyline', title: 'Polyline 1' },
{ polyline: 'polyline', title: 'Polyline 2' },
]);
expect(controller.infoWindows).toEqual([
{
headerContent: '<b>Lyon</b>',
Expand All @@ -151,6 +193,11 @@
infoWindow: 'infoWindow',
polygon: 'Polygon 2',
},
{
headerContent: '<b>Polyline 2</b>',
infoWindow: 'infoWindow',
polyline: 'Polyline 2',
},
]);
});
});
19 changes: 17 additions & 2 deletions 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,22 @@ You can add markers to a map using the ``addMarker()`` method::
)
;

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',
),
));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also move this section under Add Polygons please? Thanks :)

Suggested change
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',
),
));
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',
),
));


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

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

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

To render a map in your Twig template, use the ``ux_map`` Twig function, e.g.:

Expand Down
9 changes: 5 additions & 4 deletions src/Map/src/Bridge/Google/assets/dist/map_controller.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import AbstractMapController from '@symfony/ux-map';
import type { Point, MarkerDefinition, PolygonDefinition } from '@symfony/ux-map';
import type { Point, MarkerDefinition, PolygonDefinition, PolylineDefinition } from '@symfony/ux-map';
import type { LoaderOptions } from '@googlemaps/js-api-loader';
type MapOptions = Pick<google.maps.MapOptions, 'mapId' | 'gestureHandling' | 'backgroundColor' | 'disableDoubleClickZoom' | 'zoomControl' | 'zoomControlOptions' | 'mapTypeControl' | 'mapTypeControlOptions' | 'streetViewControl' | 'streetViewControlOptions' | 'fullscreenControl' | 'fullscreenControlOptions'>;
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> {
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> {
static values: {
providerOptions: ObjectConstructor;
};
Expand All @@ -16,9 +16,10 @@ export default class extends AbstractMapController<MapOptions, google.maps.Map,
}): google.maps.Map;
protected doCreateMarker(definition: MarkerDefinition<google.maps.marker.AdvancedMarkerElementOptions, google.maps.InfoWindowOptions>): google.maps.marker.AdvancedMarkerElement;
protected doCreatePolygon(definition: PolygonDefinition<google.maps.Polygon, google.maps.InfoWindowOptions>): google.maps.Polygon;
protected doCreatePolyline(definition: PolylineDefinition<google.maps.Polyline, google.maps.InfoWindowOptions>): google.maps.Polyline;
protected doCreateInfoWindow({ definition, element, }: {
definition: MarkerDefinition<google.maps.marker.AdvancedMarkerElementOptions, google.maps.InfoWindowOptions>['infoWindow'] | PolygonDefinition<google.maps.Polygon, google.maps.InfoWindowOptions>['infoWindow'];
element: google.maps.marker.AdvancedMarkerElement | google.maps.Polygon;
definition: MarkerDefinition<google.maps.marker.AdvancedMarkerElementOptions, google.maps.InfoWindowOptions>['infoWindow'] | PolygonDefinition<google.maps.Polygon, google.maps.InfoWindowOptions>['infoWindow'] | PolylineDefinition<google.maps.Polyline, google.maps.InfoWindowOptions>['infoWindow'];
element: google.maps.marker.AdvancedMarkerElement | google.maps.Polygon | google.maps.Polyline;
}): google.maps.InfoWindow;
private createTextOrElement;
private closeInfoWindowsExcept;
Expand Down
Loading
Loading