Skip to content

Commit d60ece0

Browse files
author
Danny van Wijk
committed
[Map] Add option to configure attribution and zoom control position
1 parent bb13764 commit d60ece0

20 files changed

+341
-15
lines changed

src/Map/src/Bridge/Leaflet/CHANGELOG.md

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

3+
## 2.27
4+
5+
- Added option to configure attribution and zoom control positions.
6+
37
## 2.26
48

59
- Using `new LeafletOptions(tileLayer: false)` will now disable the default `TileLayer`.

src/Map/src/Bridge/Leaflet/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ You can use the `LeafletOptions` class to configure your `Map`::
3333

3434
```php
3535
use Symfony\UX\Map\Bridge\Leaflet\LeafletOptions;
36+
use Symfony\UX\Map\Bridge\Leaflet\Option\AttributionControlOptions;
37+
use Symfony\UX\Map\Bridge\Leaflet\Option\ControlPosition;
3638
use Symfony\UX\Map\Bridge\Leaflet\Option\TileLayer;
39+
use Symfony\UX\Map\Bridge\Leaflet\Option\ZoomControlOptions;
3740
use Symfony\UX\Map\Point;
3841
use Symfony\UX\Map\Map;
3942

@@ -50,6 +53,10 @@ $leafletOptions = (new LeafletOptions())
5053
'maxZoom' => 10,
5154
]
5255
))
56+
->attributionControl(false)
57+
->attributionControlOptions(new AttributionControlOptions(ControlPosition::BOTTOM_LEFT))
58+
->zoomControl(false)
59+
->zoomControlOptions(new ZoomControlOptions(ControlPosition::TOP_LEFT))
5360
;
5461

5562
// Add the custom options to the map

src/Map/src/Bridge/Leaflet/assets/dist/map_controller.d.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,15 @@ import AbstractMapController from '@symfony/ux-map';
22
import type { Icon, InfoWindowWithoutPositionDefinition, MarkerDefinition, Point, PolygonDefinition, PolylineDefinition } from '@symfony/ux-map';
33
import 'leaflet/dist/leaflet.min.css';
44
import * as L from 'leaflet';
5-
import type { MapOptions as LeafletMapOptions, MarkerOptions, PolylineOptions as PolygonOptions, PolylineOptions, PopupOptions } from 'leaflet';
6-
type MapOptions = Pick<LeafletMapOptions, 'center' | 'zoom'> & {
5+
import type { ControlPosition, MapOptions as LeafletMapOptions, MarkerOptions, PolylineOptions as PolygonOptions, PolylineOptions, PopupOptions } from 'leaflet';
6+
type MapOptions = Pick<LeafletMapOptions, 'center' | 'zoom' | 'attributionControl' | 'zoomControl'> & {
7+
attributionControlOptions?: {
8+
position: ControlPosition;
9+
prefix: string | false;
10+
};
11+
zoomControlOptions?: {
12+
position: ControlPosition;
13+
};
714
tileLayer: {
815
url: string;
916
attribution: string;

src/Map/src/Bridge/Leaflet/assets/dist/map_controller.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,21 @@ class map_controller extends default_1 {
144144
...options,
145145
center: center === null ? undefined : center,
146146
zoom: zoom === null ? undefined : zoom,
147+
attributionControl: false,
148+
zoomControl: false,
147149
});
148150
if (options.tileLayer) {
149151
L.tileLayer(options.tileLayer.url, {
150152
attribution: options.tileLayer.attribution,
151153
...options.tileLayer.options,
152154
}).addTo(map);
153155
}
156+
if (typeof options.attributionControlOptions !== 'undefined') {
157+
L.control.attribution({ ...options.attributionControlOptions }).addTo(map);
158+
}
159+
if (typeof options.zoomControlOptions !== 'undefined') {
160+
L.control.zoom({ ...options.zoomControlOptions }).addTo(map);
161+
}
154162
return map;
155163
}
156164
doCreateMarker({ definition }) {

src/Map/src/Bridge/Leaflet/assets/src/map_controller.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type {
1010
import 'leaflet/dist/leaflet.min.css';
1111
import * as L from 'leaflet';
1212
import type {
13+
ControlPosition,
1314
LatLngBoundsExpression,
1415
MapOptions as LeafletMapOptions,
1516
MarkerOptions,
@@ -18,7 +19,9 @@ import type {
1819
PopupOptions,
1920
} from 'leaflet';
2021

21-
type MapOptions = Pick<LeafletMapOptions, 'center' | 'zoom'> & {
22+
type MapOptions = Pick<LeafletMapOptions, 'center' | 'zoom' | 'attributionControl' | 'zoomControl'> & {
23+
attributionControlOptions?: { position: ControlPosition; prefix: string | false };
24+
zoomControlOptions?: { position: ControlPosition };
2225
tileLayer: { url: string; attribution: string; options: Record<string, unknown> } | false;
2326
};
2427

@@ -79,6 +82,8 @@ export default class extends AbstractMapController<
7982
...options,
8083
center: center === null ? undefined : center,
8184
zoom: zoom === null ? undefined : zoom,
85+
attributionControl: false,
86+
zoomControl: false,
8287
});
8388

8489
if (options.tileLayer) {
@@ -88,6 +93,14 @@ export default class extends AbstractMapController<
8893
}).addTo(map);
8994
}
9095

96+
if (typeof options.attributionControlOptions !== 'undefined') {
97+
L.control.attribution({ ...options.attributionControlOptions }).addTo(map);
98+
}
99+
100+
if (typeof options.zoomControlOptions !== 'undefined') {
101+
L.control.zoom({ ...options.zoomControlOptions }).addTo(map);
102+
}
103+
91104
return map;
92105
}
93106

src/Map/src/Bridge/Leaflet/src/LeafletOptions.php

Lines changed: 64 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111

1212
namespace Symfony\UX\Map\Bridge\Leaflet;
1313

14+
use Symfony\UX\Map\Bridge\Leaflet\Option\AttributionControlOptions;
1415
use Symfony\UX\Map\Bridge\Leaflet\Option\TileLayer;
16+
use Symfony\UX\Map\Bridge\Leaflet\Option\ZoomControlOptions;
1517
use Symfony\UX\Map\MapOptionsInterface;
1618

1719
/**
@@ -24,6 +26,10 @@ public function __construct(
2426
url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
2527
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
2628
),
29+
private bool $attributionControl = true,
30+
private AttributionControlOptions $attributionControlOptions = new AttributionControlOptions(),
31+
private bool $zoomControl = true,
32+
private ZoomControlOptions $zoomControlOptions = new ZoomControlOptions(),
2733
) {
2834
}
2935

@@ -34,23 +40,77 @@ public function tileLayer(TileLayer|false $tileLayer): self
3440
return $this;
3541
}
3642

43+
public function attributionControl(bool $enable = true): self
44+
{
45+
$this->attributionControl = $enable;
46+
47+
return $this;
48+
}
49+
50+
public function attributionControlOptions(AttributionControlOptions $attributionControlOptions): self
51+
{
52+
$this->attributionControl = true;
53+
$this->attributionControlOptions = $attributionControlOptions;
54+
55+
return $this;
56+
}
57+
58+
public function zoomControl(bool $enable = true): self
59+
{
60+
$this->zoomControl = $enable;
61+
62+
return $this;
63+
}
64+
65+
public function zoomControlOptions(ZoomControlOptions $zoomControlOptions): self
66+
{
67+
$this->zoomControl = true;
68+
$this->zoomControlOptions = $zoomControlOptions;
69+
70+
return $this;
71+
}
72+
3773
/**
3874
* @internal
3975
*/
4076
public static function fromArray(array $array): MapOptionsInterface
4177
{
42-
return new self(
43-
tileLayer: $array['tileLayer'] ? TileLayer::fromArray($array['tileLayer']) : false,
44-
);
78+
$array += ['attributionControl' => false, 'zoomControl' => false, 'tileLayer' => false];
79+
80+
if ($array['tileLayer']) {
81+
$array['tileLayer'] = TileLayer::fromArray($array['tileLayer']);
82+
}
83+
84+
if (isset($array['attributionControlOptions'])) {
85+
$array['attributionControl'] = true;
86+
$array['attributionControlOptions'] = AttributionControlOptions::fromArray($array['attributionControlOptions']);
87+
}
88+
89+
if (isset($array['zoomControlOptions'])) {
90+
$array['zoomControl'] = true;
91+
$array['zoomControlOptions'] = ZoomControlOptions::fromArray($array['zoomControlOptions']);
92+
}
93+
94+
return new self(...$array);
4595
}
4696

4797
/**
4898
* @internal
4999
*/
50100
public function toArray(): array
51101
{
52-
return [
102+
$array = [
53103
'tileLayer' => $this->tileLayer ? $this->tileLayer->toArray() : false,
54104
];
105+
106+
if ($this->attributionControl) {
107+
$array['attributionControlOptions'] = $this->attributionControlOptions->toArray();
108+
}
109+
110+
if ($this->zoomControl) {
111+
$array['zoomControlOptions'] = $this->zoomControlOptions->toArray();
112+
}
113+
114+
return $array;
55115
}
56116
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\UX\Map\Bridge\Leaflet\Option;
13+
14+
/**
15+
* Options for the rendering of the attribution control.
16+
*
17+
* @see https://leafletjs.com/reference.html#control-zoom
18+
*/
19+
final class AttributionControlOptions
20+
{
21+
public function __construct(
22+
private readonly ControlPosition $position = ControlPosition::BOTTOM_RIGHT,
23+
private readonly string|false $prefix = 'Leaflet',
24+
) {
25+
}
26+
27+
/**
28+
* @internal
29+
*/
30+
public static function fromArray(array $array): self
31+
{
32+
return new self(
33+
position: ControlPosition::from($array['position']),
34+
prefix: $array['prefix'],
35+
);
36+
}
37+
38+
/**
39+
* @internal
40+
*/
41+
public function toArray(): array
42+
{
43+
return [
44+
'position' => $this->position->value,
45+
'prefix' => $this->prefix,
46+
];
47+
}
48+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\UX\Map\Bridge\Leaflet\Option;
13+
14+
/**
15+
* @see https://leafletjs.com/reference.html#control-position
16+
*/
17+
enum ControlPosition: string
18+
{
19+
case TOP_LEFT = 'topleft';
20+
case TOP_RIGHT = 'topright';
21+
case BOTTOM_LEFT = 'bottomleft';
22+
case BOTTOM_RIGHT = 'bottomright';
23+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\UX\Map\Bridge\Leaflet\Option;
13+
14+
/**
15+
* Options for the rendering of the zoom control.
16+
*
17+
* @see https://leafletjs.com/reference.html#control-zoom
18+
*/
19+
final class ZoomControlOptions
20+
{
21+
public function __construct(
22+
private readonly ControlPosition $position = ControlPosition::TOP_LEFT,
23+
) {
24+
}
25+
26+
/**
27+
* @internal
28+
*/
29+
public static function fromArray(array $array): self
30+
{
31+
return new self(
32+
position: ControlPosition::from($array['position']),
33+
);
34+
}
35+
36+
/**
37+
* @internal
38+
*/
39+
public function toArray(): array
40+
{
41+
return [
42+
'position' => $this->position->value,
43+
];
44+
}
45+
}

src/Map/src/Bridge/Leaflet/tests/LeafletOptionsTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ public function testWithMinimalConfiguration(): void
2727
'attribution' => '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
2828
'options' => [],
2929
],
30+
'attributionControlOptions' => [
31+
'position' => 'bottomright',
32+
'prefix' => 'Leaflet',
33+
],
34+
'zoomControlOptions' => [
35+
'position' => 'topleft',
36+
],
3037
], $leafletOptions->toArray());
3138

3239
self::assertEquals($leafletOptions, LeafletOptions::fromArray($leafletOptions->toArray()));
@@ -58,6 +65,13 @@ public function testWithMaximumConfiguration(): void
5865
'zoomOffset' => 0,
5966
],
6067
],
68+
'attributionControlOptions' => [
69+
'position' => 'bottomright',
70+
'prefix' => 'Leaflet',
71+
],
72+
'zoomControlOptions' => [
73+
'position' => 'topleft',
74+
],
6175
], $leafletOptions->toArray());
6276

6377
self::assertEquals($leafletOptions, LeafletOptions::fromArray($leafletOptions->toArray()));
@@ -69,6 +83,31 @@ public function testWithTileLayerFalse(): void
6983

7084
self::assertSame([
7185
'tileLayer' => false,
86+
'attributionControlOptions' => [
87+
'position' => 'bottomright',
88+
'prefix' => 'Leaflet',
89+
],
90+
'zoomControlOptions' => [
91+
'position' => 'topleft',
92+
],
93+
], $leafletOptions->toArray());
94+
95+
self::assertEquals($leafletOptions, LeafletOptions::fromArray($leafletOptions->toArray()));
96+
}
97+
98+
public function testWithoutControls(): void
99+
{
100+
$leafletOptions = new LeafletOptions(
101+
attributionControl: false,
102+
zoomControl: false,
103+
);
104+
105+
self::assertSame([
106+
'tileLayer' => [
107+
'url' => 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
108+
'attribution' => '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
109+
'options' => [],
110+
],
72111
], $leafletOptions->toArray());
73112

74113
self::assertEquals($leafletOptions, LeafletOptions::fromArray($leafletOptions->toArray()));

0 commit comments

Comments
 (0)