Skip to content

Commit e76d201

Browse files
committed
[Map] Add support for rectangle
1 parent 7cb2a5b commit e76d201

File tree

47 files changed

+687
-41
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+687
-41
lines changed

src/Map/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
# CHANGELOG
22

3+
## 2.29
4+
5+
- Add support for creating `Rectangle` by passing two `Point` instances to the `Rectangle` constructor, e.g.:
6+
```php
7+
$map->addRectangle(new Rectangle(
8+
southWest: new Point(48.856613, 2.352222), // Paris
9+
northEast: new Point(48.856613, 2.362222) // A point 1km east of Paris
10+
));
11+
```
12+
313
## 2.28
414

515
- Add support for creating `Circle` by passing a `Point` and a radius (in meters) to the `Circle` constructor, e.g.:

src/Map/assets/dist/abstract_map_controller.d.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ export type CircleDefinition<CircleOptions, InfoWindowOptions> = WithIdentifier<
5656
rawOptions?: CircleOptions;
5757
extra: Record<string, unknown>;
5858
}>;
59+
export type RectangleDefinition<RectangleOptions, InfoWindowOptions> = WithIdentifier<{
60+
infoWindow?: InfoWindowWithoutPositionDefinition<InfoWindowOptions>;
61+
bounds: {
62+
northEast: Point;
63+
southWest: Point;
64+
};
65+
title: string | null;
66+
rawOptions?: RectangleOptions;
67+
extra: Record<string, unknown>;
68+
}>;
5969
export type InfoWindowDefinition<InfoWindowOptions> = {
6070
headerContent: string | null;
6171
content: string | null;
@@ -66,7 +76,7 @@ export type InfoWindowDefinition<InfoWindowOptions> = {
6676
extra: Record<string, unknown>;
6777
};
6878
export type InfoWindowWithoutPositionDefinition<InfoWindowOptions> = Omit<InfoWindowDefinition<InfoWindowOptions>, 'position'>;
69-
export default abstract class<MapOptions, Map, MarkerOptions, Marker, InfoWindowOptions, InfoWindow, PolygonOptions, Polygon, PolylineOptions, Polyline, CircleOptions, Circle> extends Controller<HTMLElement> {
79+
export default abstract class<MapOptions, Map, MarkerOptions, Marker, InfoWindowOptions, InfoWindow, PolygonOptions, Polygon, PolylineOptions, Polyline, CircleOptions, Circle, RectangleOptions, Rectangle> extends Controller<HTMLElement> {
7080
static values: {
7181
providerOptions: ObjectConstructor;
7282
center: ObjectConstructor;
@@ -76,6 +86,7 @@ export default abstract class<MapOptions, Map, MarkerOptions, Marker, InfoWindow
7686
polygons: ArrayConstructor;
7787
polylines: ArrayConstructor;
7888
circles: ArrayConstructor;
89+
rectangles: ArrayConstructor;
7990
options: ObjectConstructor;
8091
};
8192
centerValue: Point | null;
@@ -85,6 +96,7 @@ export default abstract class<MapOptions, Map, MarkerOptions, Marker, InfoWindow
8596
polygonsValue: Array<PolygonDefinition<PolygonOptions, InfoWindowOptions>>;
8697
polylinesValue: Array<PolylineDefinition<PolylineOptions, InfoWindowOptions>>;
8798
circlesValue: Array<CircleDefinition<CircleOptions, InfoWindowOptions>>;
99+
rectanglesValue: Array<RectangleDefinition<RectangleOptions, InfoWindowOptions>>;
88100
optionsValue: MapOptions;
89101
hasCenterValue: boolean;
90102
hasZoomValue: boolean;
@@ -93,30 +105,34 @@ export default abstract class<MapOptions, Map, MarkerOptions, Marker, InfoWindow
93105
hasPolygonsValue: boolean;
94106
hasPolylinesValue: boolean;
95107
hasCirclesValue: boolean;
108+
hasRectanglesValue: boolean;
96109
hasOptionsValue: boolean;
97110
protected map: Map;
98111
protected markers: globalThis.Map<string, Marker>;
99112
protected polygons: globalThis.Map<string, Polygon>;
100113
protected polylines: globalThis.Map<string, Polyline>;
101114
protected circles: globalThis.Map<string, Circle>;
115+
protected rectangles: globalThis.Map<string, Rectangle>;
102116
protected infoWindows: Array<InfoWindow>;
103117
private isConnected;
104118
private createMarker;
105119
private createPolygon;
106120
private createPolyline;
107121
private createCircle;
122+
private createRectangle;
108123
protected abstract dispatchEvent(name: string, payload: Record<string, unknown>): void;
109124
connect(): void;
110125
createInfoWindow({ definition, element, }: {
111126
definition: InfoWindowWithoutPositionDefinition<InfoWindowOptions>;
112-
element: Marker | Polygon | Polyline | Circle;
127+
element: Marker | Polygon | Polyline | Circle | Rectangle;
113128
}): InfoWindow;
114129
abstract centerValueChanged(): void;
115130
abstract zoomValueChanged(): void;
116131
markersValueChanged(): void;
117132
polygonsValueChanged(): void;
118133
polylinesValueChanged(): void;
119134
circlesValueChanged(): void;
135+
rectanglesValueChanged(): void;
120136
protected abstract doCreateMap({ center, zoom, options, }: {
121137
center: Point | null;
122138
zoom: number | null;
@@ -139,9 +155,13 @@ export default abstract class<MapOptions, Map, MarkerOptions, Marker, InfoWindow
139155
definition: CircleDefinition<CircleOptions, InfoWindowOptions>;
140156
}): Circle;
141157
protected abstract doRemoveCircle(circle: Circle): void;
158+
protected abstract doCreateRectangle({ definition, }: {
159+
definition: RectangleDefinition<RectangleOptions, InfoWindowOptions>;
160+
}): Rectangle;
161+
protected abstract doRemoveRectangle(rectangle: Rectangle): void;
142162
protected abstract doCreateInfoWindow({ definition, element, }: {
143163
definition: InfoWindowWithoutPositionDefinition<InfoWindowOptions>;
144-
element: Marker | Polygon | Polyline | Circle;
164+
element: Marker | Polygon | Polyline | Circle | Rectangle;
145165
}): InfoWindow;
146166
protected abstract doCreateIcon({ definition, element, }: {
147167
definition: Icon;

src/Map/assets/dist/abstract_map_controller.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class default_1 extends Controller {
1212
this.polygons = new Map();
1313
this.polylines = new Map();
1414
this.circles = new Map();
15+
this.rectangles = new Map();
1516
this.infoWindows = [];
1617
this.isConnected = false;
1718
}
@@ -22,6 +23,7 @@ class default_1 extends Controller {
2223
this.createPolygon = this.createDrawingFactory('polygon', this.polygons, this.doCreatePolygon.bind(this));
2324
this.createPolyline = this.createDrawingFactory('polyline', this.polylines, this.doCreatePolyline.bind(this));
2425
this.createCircle = this.createDrawingFactory('circle', this.circles, this.doCreateCircle.bind(this));
26+
this.createRectangle = this.createDrawingFactory('rectangle', this.rectangles, this.doCreateRectangle.bind(this));
2527
this.map = this.doCreateMap({
2628
center: this.hasCenterValue ? this.centerValue : null,
2729
zoom: this.hasZoomValue ? this.zoomValue : null,
@@ -31,6 +33,7 @@ class default_1 extends Controller {
3133
this.polygonsValue.forEach((definition) => this.createPolygon({ definition }));
3234
this.polylinesValue.forEach((definition) => this.createPolyline({ definition }));
3335
this.circlesValue.forEach((definition) => this.createCircle({ definition }));
36+
this.rectanglesValue.forEach((definition) => this.createRectangle({ definition }));
3437
if (this.fitBoundsToMarkersValue) {
3538
this.doFitBoundsToMarkers();
3639
}
@@ -40,6 +43,7 @@ class default_1 extends Controller {
4043
polygons: [...this.polygons.values()],
4144
polylines: [...this.polylines.values()],
4245
circles: [...this.circles.values()],
46+
rectangles: [...this.rectangles.values()],
4347
infoWindows: this.infoWindows,
4448
});
4549
this.isConnected = true;
@@ -78,6 +82,12 @@ class default_1 extends Controller {
7882
}
7983
this.onDrawChanged(this.circles, this.circlesValue, this.createCircle, this.doRemoveCircle);
8084
}
85+
rectanglesValueChanged() {
86+
if (!this.isConnected) {
87+
return;
88+
}
89+
this.onDrawChanged(this.rectangles, this.rectanglesValue, this.createRectangle, this.doRemoveRectangle);
90+
}
8191
createDrawingFactory(type, draws, factory) {
8292
const eventBefore = `${type}:before-create`;
8393
const eventAfter = `${type}:after-create`;
@@ -115,6 +125,7 @@ default_1.values = {
115125
polygons: Array,
116126
polylines: Array,
117127
circles: Array,
128+
rectangles: Array,
118129
options: Object,
119130
};
120131

src/Map/assets/src/abstract_map_controller.ts

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,23 @@ export type CircleDefinition<CircleOptions, InfoWindowOptions> = WithIdentifier<
9898
extra: Record<string, unknown>;
9999
}>;
100100

101+
export type RectangleDefinition<RectangleOptions, InfoWindowOptions> = WithIdentifier<{
102+
infoWindow?: InfoWindowWithoutPositionDefinition<InfoWindowOptions>;
103+
bounds: { northEast: Point; southWest: Point };
104+
title: string | null;
105+
/**
106+
* Raw options passed to the rectangle constructor, specific to the map provider (e.g.: `L.rectangle()` for Leaflet).
107+
*/
108+
rawOptions?: RectangleOptions;
109+
/**
110+
* Extra data defined by the developer.
111+
* They are not directly used by the Stimulus controller, but they can be used by the developer with event listeners:
112+
* - `ux:map:rectangle:before-create`
113+
* - `ux:map:rectangle:after-create`
114+
*/
115+
extra: Record<string, unknown>;
116+
}>;
117+
101118
export type InfoWindowDefinition<InfoWindowOptions> = {
102119
headerContent: string | null;
103120
content: string | null;
@@ -136,6 +153,8 @@ export default abstract class<
136153
Polyline,
137154
CircleOptions,
138155
Circle,
156+
RectangleOptions,
157+
Rectangle,
139158
> extends Controller<HTMLElement> {
140159
static values = {
141160
providerOptions: Object,
@@ -146,6 +165,7 @@ export default abstract class<
146165
polygons: Array,
147166
polylines: Array,
148167
circles: Array,
168+
rectangles: Array,
149169
options: Object,
150170
};
151171

@@ -156,6 +176,7 @@ export default abstract class<
156176
declare polygonsValue: Array<PolygonDefinition<PolygonOptions, InfoWindowOptions>>;
157177
declare polylinesValue: Array<PolylineDefinition<PolylineOptions, InfoWindowOptions>>;
158178
declare circlesValue: Array<CircleDefinition<CircleOptions, InfoWindowOptions>>;
179+
declare rectanglesValue: Array<RectangleDefinition<RectangleOptions, InfoWindowOptions>>;
159180
declare optionsValue: MapOptions;
160181

161182
declare hasCenterValue: boolean;
@@ -165,13 +186,15 @@ export default abstract class<
165186
declare hasPolygonsValue: boolean;
166187
declare hasPolylinesValue: boolean;
167188
declare hasCirclesValue: boolean;
189+
declare hasRectanglesValue: boolean;
168190
declare hasOptionsValue: boolean;
169191

170192
protected map: Map;
171193
protected markers = new Map<Identifier, Marker>();
172194
protected polygons = new Map<Identifier, Polygon>();
173195
protected polylines = new Map<Identifier, Polyline>();
174196
protected circles = new Map<Identifier, Circle>();
197+
protected rectangles = new Map<Identifier, Rectangle>();
175198
protected infoWindows: Array<InfoWindow> = [];
176199

177200
private isConnected = false;
@@ -187,6 +210,9 @@ export default abstract class<
187210
private createCircle: ({
188211
definition,
189212
}: { definition: CircleDefinition<CircleOptions, InfoWindowOptions> }) => Circle;
213+
private createRectangle: ({
214+
definition,
215+
}: { definition: RectangleDefinition<RectangleOptions, InfoWindowOptions> }) => Rectangle;
190216

191217
protected abstract dispatchEvent(name: string, payload: Record<string, unknown>): void;
192218

@@ -199,6 +225,11 @@ export default abstract class<
199225
this.createPolygon = this.createDrawingFactory('polygon', this.polygons, this.doCreatePolygon.bind(this));
200226
this.createPolyline = this.createDrawingFactory('polyline', this.polylines, this.doCreatePolyline.bind(this));
201227
this.createCircle = this.createDrawingFactory('circle', this.circles, this.doCreateCircle.bind(this));
228+
this.createRectangle = this.createDrawingFactory(
229+
'rectangle',
230+
this.rectangles,
231+
this.doCreateRectangle.bind(this)
232+
);
202233

203234
this.map = this.doCreateMap({
204235
center: this.hasCenterValue ? this.centerValue : null,
@@ -209,6 +240,7 @@ export default abstract class<
209240
this.polygonsValue.forEach((definition) => this.createPolygon({ definition }));
210241
this.polylinesValue.forEach((definition) => this.createPolyline({ definition }));
211242
this.circlesValue.forEach((definition) => this.createCircle({ definition }));
243+
this.rectanglesValue.forEach((definition) => this.createRectangle({ definition }));
212244

213245
if (this.fitBoundsToMarkersValue) {
214246
this.doFitBoundsToMarkers();
@@ -220,6 +252,7 @@ export default abstract class<
220252
polygons: [...this.polygons.values()],
221253
polylines: [...this.polylines.values()],
222254
circles: [...this.circles.values()],
255+
rectangles: [...this.rectangles.values()],
223256
infoWindows: this.infoWindows,
224257
});
225258

@@ -232,7 +265,7 @@ export default abstract class<
232265
element,
233266
}: {
234267
definition: InfoWindowWithoutPositionDefinition<InfoWindowOptions>;
235-
element: Marker | Polygon | Polyline | Circle;
268+
element: Marker | Polygon | Polyline | Circle | Rectangle;
236269
}): InfoWindow {
237270
this.dispatchEvent('info-window:before-create', { definition, element });
238271
const infoWindow = this.doCreateInfoWindow({ definition, element });
@@ -286,6 +319,14 @@ export default abstract class<
286319
this.onDrawChanged(this.circles, this.circlesValue, this.createCircle, this.doRemoveCircle);
287320
}
288321

322+
public rectanglesValueChanged(): void {
323+
if (!this.isConnected) {
324+
return;
325+
}
326+
327+
this.onDrawChanged(this.rectangles, this.rectanglesValue, this.createRectangle, this.doRemoveRectangle);
328+
}
329+
289330
//endregion
290331

291332
//region Abstract factory methods to be implemented by the concrete classes, they are specific to the map provider
@@ -331,12 +372,20 @@ export default abstract class<
331372

332373
protected abstract doRemoveCircle(circle: Circle): void;
333374

375+
protected abstract doCreateRectangle({
376+
definition,
377+
}: {
378+
definition: RectangleDefinition<RectangleOptions, InfoWindowOptions>;
379+
}): Rectangle;
380+
381+
protected abstract doRemoveRectangle(rectangle: Rectangle): void;
382+
334383
protected abstract doCreateInfoWindow({
335384
definition,
336385
element,
337386
}: {
338387
definition: InfoWindowWithoutPositionDefinition<InfoWindowOptions>;
339-
element: Marker | Polygon | Polyline | Circle;
388+
element: Marker | Polygon | Polyline | Circle | Rectangle;
340389
}): InfoWindow;
341390
protected abstract doCreateIcon({
342391
definition,
@@ -369,15 +418,21 @@ export default abstract class<
369418
draws: typeof this.circles,
370419
factory: typeof this.doCreateCircle
371420
): typeof this.doCreateCircle;
421+
private createDrawingFactory(
422+
type: 'rectangle',
423+
draws: typeof this.rectangles,
424+
factory: typeof this.doCreateRectangle
425+
): typeof this.doCreateRectangle;
372426
private createDrawingFactory<
373427
Factory extends
374428
| typeof this.doCreateMarker
375429
| typeof this.doCreatePolygon
376430
| typeof this.doCreatePolyline
377-
| typeof this.doCreateCircle,
431+
| typeof this.doCreateCircle
432+
| typeof this.doCreateRectangle,
378433
Draw extends ReturnType<Factory>,
379434
>(
380-
type: 'marker' | 'polygon' | 'polyline' | 'circle',
435+
type: 'marker' | 'polygon' | 'polyline' | 'circle' | 'rectangle',
381436
draws: globalThis.Map<WithIdentifier<any>, Draw>,
382437
factory: Factory
383438
): Factory {
@@ -421,6 +476,12 @@ export default abstract class<
421476
factory: typeof this.createCircle,
422477
remover: typeof this.doRemoveCircle
423478
): void;
479+
private onDrawChanged(
480+
draws: typeof this.rectangles,
481+
newDrawDefinitions: typeof this.rectanglesValue,
482+
factory: typeof this.createRectangle,
483+
remover: typeof this.doRemoveRectangle
484+
): void;
424485
private onDrawChanged<Draw, DrawDefinition extends WithIdentifier<Record<string, unknown>>>(
425486
draws: globalThis.Map<WithIdentifier<any>, Draw>,
426487
newDrawDefinitions: Array<DrawDefinition>,

0 commit comments

Comments
 (0)