跳到内容

Symfony UX 地图

编辑此页

实验性功能 此组件目前为实验性功能,可能会发生变化,甚至剧烈变化。

Symfony UX Map 是一个 Symfony 扩展包,用于在 Symfony 应用程序中集成交互式地图。它是 Symfony UX 倡议 的一部分。

安装

使用 Composer 和 Symfony Flex 安装此扩展包

1
$ composer require symfony/ux-map

如果您正在使用 WebpackEncore,请安装您的 assets 并重启 Encore (如果您正在使用 AssetMapper,则无需此操作)

1
2
$ npm install --force
$ npm run watch

配置

配置在您的 config/packages/ux_map.yaml 文件中完成

1
2
3
4
5
6
7
8
9
# config/packages/ux_map.yaml
ux_map:
    renderer: '%env(resolve:default::UX_MAP_DSN)%'

    # Google Maps specific configuration
    google_maps:
        # Configure the default Map Id (https://developers.google.com/maps/documentation/get-map-id),
        # without to manually configure it in each map instance (through "new GoogleOptions(mapId: 'your_map_id')").
        default_map_id: null

UX_MAP_DSN 环境变量配置要使用的渲染器。

地图渲染器

Symfony UX Map 扩展包支持多种渲染器。地图渲染器是一种服务,提供在浏览器中渲染地图并与之交互所需的代码和图形资源。

可用的渲染器

UX Map 附带两个渲染器:Google MapsLeaflet

渲染器  
Google Maps 安装: composer require symfony/ux-google-map
DSN: UX_MAP_DSN=google://GOOGLE_MAPS_API_KEY@default
Leaflet 安装: composer require symfony/ux-leaflet-map
DSN: UX_MAP_DSN=leaflet://default

提示

阅读 Symfony UX Map Leaflet 桥接文档Symfony UX Map Google Maps 桥接文档,了解每个渲染器可用的配置选项。

创建地图

通过调用 new Map() 创建地图。您可以配置中心、缩放级别和添加标记。首先创建一个新的地图实例

1
2
3
4
use Symfony\UX\Map\Map;

// Create a new map instance
$myMap = (new Map());

中心和缩放

您可以使用 center()zoom() 方法设置地图的中心和缩放级别

1
2
3
4
5
6
7
8
9
10
11
use Symfony\UX\Map\Map;
use Symfony\UX\Map\Point;

$myMap
    // Explicitly set the center and zoom
    ->center(new Point(46.903354, 1.888334))
    ->zoom(6)

    // Or automatically fit the bounds to the markers
    ->fitBoundsToMarkers()
;

添加标记

您可以使用 addMarker() 方法向地图添加标记

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$myMap
    ->addMarker(new Marker(
        position: new Point(48.8566, 2.3522),
        title: 'Paris'
    ))

    // With an info window associated to the marker:
    ->addMarker(new Marker(
        position: new Point(45.7640, 4.8357),
        title: 'Lyon',
        infoWindow: new InfoWindow(
            headerContent: '<b>Lyon</b>',
            content: 'The French town in the historic Rhône-Alpes region, located at the junction of the Rhône and Saône rivers.'
        )
    ))

    // You can also pass arbitrary data via the `extra` option in both the marker
    // and the infoWindow; you can later use this data in your custom Stimulus controllers
    ->addMarker(new Marker(
        position: new Point(45.7740, 4.8351),
        extra: [
            'icon_mask_url' => 'https://maps.gstatic.com/mapfiles/place_api/icons/v2/tree_pinlet.svg',
        ],
        infoWindow: new InfoWindow(
            // ...
            extra: [
                'num_items' => 3,
                'includes_link' => true,
            ],
        ),
    ))
;

从地图中移除元素

可以通过使用 Map::remove*() 方法移除元素,例如 MarkerPolygonPolyline 实例

1
2
3
4
5
6
7
8
9
// Add elements
$map->addMarker($marker = new Marker(/* ... */));
$map->addPolygon($polygon = new Polygon(/* ... */));
$map->addPolyline($polyline = new Polyline(/* ... */));

// And later, remove those elements
$map->removeMarker($marker);
$map->removePolygon($polygon);
$map->removePolyline($polyline);

不幸的是,如果您无法存储元素实例,您仍然可以通过传递标识符字符串来删除它们

1
2
3
4
5
6
7
8
9
10
$map = new Map(/* ... */);
// Add elements
$map->addMarker(new Marker(id: 'my-marker', /* ... */));
$map->addPolygon(new Polygon(id: 'my-polygon', /* ... */));
$map->addPolyline(new Polyline(id: 'my-marker', /* ... */));

// And later, remove those elements
$map->removeMarker('my-marker');
$map->removePolygon('my-polygon');
$map->removePolyline('my-marker');

添加多边形

您还可以添加多边形(Polygons),它表示由一系列 Point 实例封闭的区域

1
2
3
4
5
6
7
8
9
10
11
$myMap->addPolygon(new Polygon(
    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: 'Paris, Lyon, Marseille, Bordeaux',
    ),
));

添加折线

您可以添加折线(Polylines),它表示由一系列 Point 实例组成的路径

1
2
3
4
5
6
7
8
9
10
11
$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',
    ),
));

渲染地图

要在您的 Twig 模板中渲染地图,请使用 ux_map Twig 函数,例如

为了可见,地图必须具有定义的高度

1
{{ ux_map(my_map, { style: 'height: 300px' }) }}

您也可以添加自定义 HTML 属性

1
{{ ux_map(my_map, { style: 'height: 300px', id: 'events-map', class: 'mb-3' }) }}

Twig 函数 ux_map()

ux_map() Twig 函数允许您在 Twig 模板中创建和渲染地图。该函数接受与 Map 类相同的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{{ ux_map(
    center: [51.5074, 0.1278],
    zoom: 3,
    markers: [
        { position: [51.5074, 0.1278], title: 'London' },
        { position: [48.8566, 2.3522], title: 'Paris' },
        {
            position: [40.7128, -74.0060],
            title: 'New York',
            infoWindow: { content: 'Welcome to <b>New York</b>' }
        },
    ],
    attributes: {
        class: 'foo',
        style: 'height: 800px; width: 100%; border: 4px solid red; margin-block: 10vh;',
    }
) }}

Twig 组件 <twig:ux:map />

或者,您可以使用 <twig:ux:map /> 组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<twig:ux:map
    center="[51.5074, 0.1278]"
    zoom="3"
    markers='[
        {"position": [51.5074, 0.1278], "title": "London"},
        {"position": [48.8566, 2.3522], "title": "Paris"},
        {
            "position": [40.7128, -74.0060],
            "title": "New York",
            "infoWindow": {"content": "Welcome to <b>New York</b>"}
        }
    ]'
    class="foo"
    style="height: 800px; width: 100%; border: 4px solid red; margin-block: 10vh;"
/>

<twig:ux:map /> 组件需要 Twig Component 扩展包。

1
$ composer require symfony/ux-twig-component

与地图交互

Symfony UX Map 允许您使用自定义 Stimulus 控制器扩展其默认行为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// assets/controllers/mymap_controller.js

import { Controller } from '@hotwired/stimulus';

export default class extends Controller {
    connect() {
        this.element.addEventListener('ux:map:pre-connect', this._onPreConnect);
        this.element.addEventListener('ux:map:connect', this._onConnect);
        this.element.addEventListener('ux:map:marker:before-create', this._onMarkerBeforeCreate);
        this.element.addEventListener('ux:map:marker:after-create', this._onMarkerAfterCreate);
        this.element.addEventListener('ux:map:info-window:before-create', this._onInfoWindowBeforeCreate);
        this.element.addEventListener('ux:map:info-window:after-create', this._onInfoWindowAfterCreate);
    }

    disconnect() {
        // You should always remove listeners when the controller is disconnected to avoid side effects
        this.element.removeEventListener('ux:map:pre-connect', this._onPreConnect);
        this.element.removeEventListener('ux:map:connect', this._onConnect);
        this.element.removeEventListener('ux:map:marker:before-create', this._onMarkerBeforeCreate);
        this.element.removeEventListener('ux:map:marker:after-create', this._onMarkerAfterCreate);
        this.element.removeEventListener('ux:map:info-window:before-create', this._onInfoWindowBeforeCreate);
        this.element.removeEventListener('ux:map:info-window:after-create', this._onInfoWindowAfterCreate);
    }

    _onPreConnect(event) {
        // The map is not created yet
        // You can use this event to configure the map before it is created
        console.log(event.detail.options);
    }

    _onConnect(event) {
        // The map, markers and infoWindows are created
        // The instances depend on the renderer you are using
        console.log(event.detail.map);
        console.log(event.detail.markers);
        console.log(event.detail.infoWindows);
    }

    _onMarkerBeforeCreate(event) {
        // The marker is not created yet
        // You can use this event to configure the marker before it is created
        console.log(event.detail.definition);
    }

    _onMarkerAfterCreate(event) {
        // The marker is created
        // The instance depends on the renderer you are using
        console.log(event.detail.marker);
    }

    _onInfoWindowBeforeCreate(event) {
        // The infoWindow is not created yet
        // You can use this event to configure the infoWindow before it is created
        console.log(event.detail.definition);
        // The associated marker instance is also available
        console.log(event.detail.marker);
    }

    _onInfoWindowAfterCreate(event) {
        // The infoWindow is created
        // The instance depends on the renderer you are using
        console.log(event.detail.infoWindow);
        // The associated marker instance is also available
        console.log(event.detail.marker);
    }
}

然后,您可以在您的模板中使用此控制器

1
{{ ux_map(my_map, { 'data-controller': 'mymap', style: 'height: 300px' }) }}

提示

阅读 Symfony UX Map Leaflet 桥接文档Symfony UX Map Google Maps 桥接文档,了解自定义标记所需的准确代码。

与 Live 组件一起使用

2.22

在 Live 组件内部渲染地图并与之交互的功能在 Map 2.22 中添加。

要在 Live 组件内部使用地图,您需要使用 ComponentWithMapTrait trait 并实现 instantiateMap 方法以返回一个 Map 实例。

您可以使用 LiveAction 属性与地图交互

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
namespace App\Twig\Components;

use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
use Symfony\UX\LiveComponent\Attribute\LiveAction;
use Symfony\UX\LiveComponent\DefaultActionTrait;
use Symfony\UX\Map\InfoWindow;
use Symfony\UX\Map\Live\ComponentWithMapTrait;
use Symfony\UX\Map\Map;
use Symfony\UX\Map\Marker;
use Symfony\UX\Map\Point;

#[AsLiveComponent]
final class MapLivePlayground
{
    use DefaultActionTrait;
    use ComponentWithMapTrait;

    protected function instantiateMap(): Map
    {
        return (new Map())
            ->center(new Point(48.8566, 2.3522))
            ->zoom(7)
            ->addMarker(new Marker(position: new Point(48.8566, 2.3522), title: 'Paris', infoWindow: new InfoWindow('Paris')))
            ->addMarker(new Marker(position: new Point(45.75, 4.85), title: 'Lyon', infoWindow: new InfoWindow('Lyon')))
        ;
    }
}

然后,您可以使用 ux_map() 在您的组件模板中渲染地图

1
2
3
<div{{ attributes }}>
    {{ ux_map(map, {style: 'height: 300px'}) }}
</div>

然后,您可以定义 Live Actions 以从客户端与地图交互。您可以使用 getMap() 方法检索地图实例,并更改地图中心、缩放级别、添加标记等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#[LiveAction]
public function doSomething(): void
{
    // Change the map center
    $this->getMap()->center(new Point(45.7640, 4.8357));

    // Change the map zoom
    $this->getMap()->zoom(6);

    // Add a new marker
    $this->getMap()->addMarker(new Marker(position: new Point(43.2965, 5.3698), title: 'Marseille', infoWindow: new InfoWindow('Marseille')));

    // Add a new polygon
    $this->getMap()->addPolygon(new Polygon(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('Paris, Lyon, Marseille, Bordeaux')));
}
1
2
3
4
5
6
7
8
9
10
11
<div{{ attributes.defaults() }}>
    {{ ux_map(map, { style: 'height: 300px' }) }}

    <button
        type="button"
        data-action="live#action"
        data-live-action-param="doSomething"
    >
        Do something with the map
    </button>
</div>

向后兼容性承诺

此扩展包旨在遵循与 Symfony 框架相同的向后兼容性承诺:http://symfony.ac.cn/doc/current/contributing/code/bc.html

本作品,包括代码示例,根据 Creative Commons BY-SA 3.0 许可协议获得许可。
目录
    版本