Receber por email
← Voltar para o catálogo

ux-map

Symfony UX Map oferece mapas interativos com Leaflet ou Google Maps, cobrindo marcadores, formas, janelas de informação e integração com LiveComponent para funcionalidades reativas. É ideal para exibir mapas, desenhar rotas, lidar com eventos e criar localizadores de lojas.

159estrelas
Atualizado há 4 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add smnandre/symfony-ux-skills

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/ux-map/svg)](https://www.skillteca.com.br/skills/ux-map)

Alerta por categoria

Receba novas skills de Design e Frontend toda segunda

1 email curto, só com as skills novas de Design e Frontend. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

UX Map

Interactive maps in Symfony with Leaflet or Google Maps. Build maps in PHP, render them in Twig, and extend them with Stimulus controllers. Supports markers, polygons, polylines, circles, info windows, and LiveComponent integration.

Installation

# Install the base package
composer require symfony/ux-map

# Then install ONE renderer:
composer require symfony/ux-leaflet-map    # Leaflet (free, open source)
# OR
composer require symfony/ux-google-map     # Google Maps (requires API key)

Quick Reference

Map                    PHP object, holds markers/shapes/options
Point                  latitude + longitude
Marker                 pin on the map, optional InfoWindow
Polygon                closed shape (array of Points)
Polyline               open line (array of Points)
Circle                 center Point + radius in meters
InfoWindow             popup attached to a Marker, Polygon, or Circle
ux_map(map, attrs)     Twig function to render a Map
<twig:ux:map />        Twig component (requires ux-twig-component)

Building a Map in PHP

use Symfony\UX\Map\Map;
use Symfony\UX\Map\Point;
use Symfony\UX\Map\Marker;
use Symfony\UX\Map\InfoWindow;
use Symfony\UX\Map\Polygon;
use Symfony\UX\Map\Polyline;
use Symfony\UX\Map\Circle;

$map = (new Map())
    ->center(new Point(48.8566, 2.3522))
    ->zoom(12)
    ->minZoom(3)
    ->maxZoom(18);

// Marker with info window
$map->addMarker(new Marker(
    position: new Point(48.8566, 2.3522),
    title: 'Paris',
    infoWindow: new InfoWindow(
        headerContent: '<b>Paris</b>',
        content: 'The capital of France',
    ),
));

// Marker with custom icon (UX Icons integration)
$map->addMarker(new Marker(
    position: new Point(48.8738, 2.2950),
    title: 'Eiffel Tower',
    icon: Icon::ux('mdi:tower-eiffel')->width(32)->height(32),
    extra: ['category' => 'landmark'],
));

// Polygon (closed area)
$map->addPolygon(new Polygon(
    points: [
        new Point(48.8566, 2.3522),
        new Point(48.8606, 2.3376),
        new Point(48.8530, 2.3499),
    ],
    infoWindow: new InfoWindow(content: 'Central Paris area'),
));

// Polyline (open line)
$map->addPolyline(new Polyline(
    points: [
        new Point(48.8566, 2.3522),
        new Point(48.8738, 2.2950),
    ],
));

// Circle (center + radius in meters)
$map->addCircle(new Circle(
    center: new Point(48.8566, 2.3522),
    radius: 500,
    infoWindow: new InfoWindow(content: '500m radius'),
));

// Auto-fit bounds to show all markers
$map->fitBoundsToMarkers();

Rendering in Twig

Twig Function

{# Basic rendering #}
{{ ux_map(map, {style: 'height: 400px; width: 100%;'}) }}

{# With custom attributes and Stimulus controller #}
{{ ux_map(map, {
    'data-controller': 'custom-map',
    style: 'height: 400px;',
    class: 'rounded shadow'
}) }}

Twig Component (HTML Syntax)

Requires symfony/ux-twig-component. Allows inline map definition without PHP:

<twig:ux:map
    :center="[48.8566, 2.3522]"
    zoom="12"
    :markers='[
        {"position": [48.8566, 2.3522], "title": "Paris"},
        {"position": [48.8738, 2.2950], "title": "Eiffel Tower",
         "infoWindow": {"content": "324m tall"}}
    ]'
    :fitBoundsToMarkers="true"
    style="height: 400px; width: 100%;"
    class="rounded shadow"
/>

Configuration

# config/packages/ux_map.yaml
ux_map:
    renderer: '%env(resolve:default::UX_MAP_DSN)%'

    # Google Maps specific
    google_maps:
        default_map_id: null    # Optional: default Map ID for all maps

Renderer DSN

Set in .env:

# Leaflet (free)
UX_MAP_DSN=leaflet://default

# Google Maps (requires API key)
UX_MAP_DSN=google://GOOGLE_MAPS_API_KEY@default

Renderer Options

Leaflet Options

use Symfony\UX\Map\Bridge\Leaflet\LeafletOptions;
use Symfony\UX\Map\Bridge\Leaflet\Option\TileLayer;
use Symfony\UX\Map\Bridge\Leaflet\Option\ZoomControlOptions;
use Symfony\UX\Map\Bridge\Leaflet\Option\AttributionControlOptions;
use Symfony\UX\Map\Bridge\Leaflet\Option\ControlPosition;

$leafletOptions = (new LeafletOptions())
    ->tileLayer(new TileLayer(
        url: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
        attribution: '&copy; OpenStreetMap contributors',
        options: ['minZoom' => 5, 'maxZoom' => 18],
    ))
    ->zoomControl(true)
    ->zoomControlOptions(new ZoomControlOptions(ControlPosition::TOP_LEFT))
    ->attributionControl(true)
    ->attributionControlOptions(new AttributionControlOptions(ControlPosition::BOTTOM_LEFT));

$map->options($leafletOptions);

Google Maps Options

use Symfony\UX\Map\Bridge\Google\GoogleOptions;
use Symfony\UX\Map\Bridge\Google\Option\ControlPosition;
use Symfony\UX\Map\Bridge\Google\Option\GestureHandling;
use Symfony\UX\Map\Bridge\Google\Option\MapTypeControlOptions;
use Symfony\UX\Map\Bridge\Google\Option\MapTypeControlStyle;
use Symfony\UX\Map\Bridge\Google\Option\ZoomControlOptions;
use Symfony\UX\Map\Bridge\Google\Option\StreetViewControlOptions;
use Symfony\UX\Map\Bridge\Google\Option\FullscreenControlOptions;

$googleOptions = (new GoogleOptions())
    ->mapId('YOUR_MAP_ID')
    ->gestureHandling(GestureHandling::GREEDY)
    ->backgroundColor('#f00')
    ->doubleClickZoom(true)
    ->zoomControlOptions(new ZoomControlOptions(
        position: ControlPosition::BLOCK_START_INLINE_END,
    ))
    ->mapTypeControlOptions(new MapTypeControlOptions(
        mapTypeIds: ['roadmap'],
        position: ControlPosition::INLINE_END_BLOCK_START,
        style: MapTypeControlStyle::DROPDOWN_MENU,
    ))
    ->streetViewControlOptions(new StreetViewControlOptions(
        position: ControlPosition::BLOCK_END_INLINE_START,
    ))
    ->fullscreenControlOptions(new FullscreenControlOptions(
        position: ControlPosition::INLINE_START_BLOCK_END,
    ));

$map->options($googleOptions);

To disable controls:

$googleOptions = (new GoogleOptions())
    ->mapId('YOUR_MAP_ID')
    ->zoomControl(false)
    ->mapTypeControl(false)
    ->streetViewControl(false)
    ->fullscreenControl(false);

Map Events (Stimulus)

Attach a custom Stimulus controller to interact with the underlying map:

// assets/controllers/custom-map_controller.js
import { Controller } from '@hotwired/stimulus';

export default class extends Controller {
    connect() {
        this.element.addEventListener('ux:map:connect', this._onConnect.bind(this));
        this.element.addEventListener('ux:map:marker:after-create', this._onMarkerCreated.bind(this));
    }

    _onConnect(event) {
        const { map, markers } = event.detail;
        console.log('Map ready:', map);
    }

    _onMarkerCreated(event) {
        const { marker, definition } = event.detail;
        if (definition.extra?.category === 'landmark') {
            console.log('Landmark marker created');
        }
    }
}
{{ ux_map(map, {'data-controller': 'custom-map', style: 'height: 400px;'}) }}

Available Events

| Event | Detail | Description | |-------|--------|-------------| | ux:map:connect | {map, markers} | Map is initialized and ready | | ux:map:marker:before-create | {definition} | Before a marker is added | | ux:map:marker:after-create | {marker, definition} | After a marker is added | | ux:map:polygon:before-create | {definition} | Before a polygon is added | | ux:map:polygon:after-create | {polygon, definition} | After a polygon is added | | ux:map:polyline:before-create | {definition} | Before a polyline is added | | ux:map:polyline:after-create | {polyline, definition} | After a polyline is added | | ux:map:circle:before-create | {definition} | Before a circle is added | | ux:map:circle:after-create | {circle, definition} | After a circle is added | | ux:map:info-window:before-create | {definition} | Before an info window is created | | ux:map:info-window:after-create | {infoWindow, definition} | After an

Compartilhar X LinkedIn