Skip to content

Commit 577defc

Browse files
author
Danny van Wijk
committed
[Map] Add option to configure attribution and zoom control position
1 parent 8f02bd6 commit 577defc

20 files changed

+344
-15
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Using `new LeafletOptions(tileLayer: false)` will now disable the default `TileLayer`.
66
Useful when using a custom tiles layer rendering engine not configurable with `L.tileLayer().addTo(map)` method
77
(e.g.: [Esri/esri-leaflet-vector](https://github.com/Esri/esri-leaflet-vector))
8+
- Added option to configure attribution and zoom control position.
89

910
## 2.25
1011

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: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ class map_controller extends default_1 {
140140
});
141141
}
142142
doCreateMap({ center, zoom, options, }) {
143+
options.attributionControl = typeof options.attributionControlOptions !== 'undefined';
144+
options.zoomControl = typeof options.zoomControlOptions !== 'undefined';
143145
const map = L.map(this.element, {
144146
...options,
145147
center: center === null ? undefined : center,
@@ -151,6 +153,14 @@ class map_controller extends default_1 {
151153
...options.tileLayer.options,
152154
}).addTo(map);
153155
}
156+
if (options.attributionControl && options.attributionControlOptions) {
157+
map.attributionControl.remove();
158+
L.control.attribution({ ...options.attributionControlOptions }).addTo(map);
159+
}
160+
if (options.zoomControl && options.zoomControlOptions) {
161+
map.zoomControl.remove();
162+
L.control.zoom({ ...options.zoomControlOptions }).addTo(map);
163+
}
154164
return map;
155165
}
156166
doCreateMarker({ definition }) {

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

Lines changed: 18 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

@@ -75,6 +78,10 @@ export default class extends AbstractMapController<
7578
zoom,
7679
options,
7780
}: { center: Point | null; zoom: number | null; options: MapOptions }): L.Map {
81+
// We assume the following control options are enabled if their options are set
82+
options.attributionControl = typeof options.attributionControlOptions !== 'undefined';
83+
options.zoomControl = typeof options.zoomControlOptions !== 'undefined';
84+
7885
const map = L.map(this.element, {
7986
...options,
8087
center: center === null ? undefined : center,
@@ -88,6 +95,16 @@ export default class extends AbstractMapController<
8895
}).addTo(map);
8996
}
9097

98+
if (options.attributionControl && options.attributionControlOptions) {
99+
map.attributionControl.remove();
100+
L.control.attribution({ ...options.attributionControlOptions }).addTo(map);
101+
}
102+
103+
if (options.zoomControl && options.zoomControlOptions) {
104+
map.zoomControl.remove();
105+
L.control.zoom({ ...options.zoomControlOptions }).addTo(map);
106+
}
107+
91108
return map;
92109
}
93110

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+
}

0 commit comments

Comments
 (0)