symfony/ux-map
Symfony UX Map adds interactive maps to Symfony apps with easy integration for providers like Leaflet and Google Maps. Part of the Symfony UX ecosystem; documentation and issue tracking live in the main symfony/ux repository.
Installation:
composer require symfony/ux-map
npm install @symfony/ux-map
Ensure your importmap.json includes:
{
"imports": {
"@symfony/ux-map": "node_modules/@symfony/ux-map/dist"
}
}
Basic Twig Usage:
<twig:ux:map
id="map"
center="{{ [48.856613, 2.352222] }}"
zoom="12"
renderer="leaflet"
/>
First Map Interaction (PHP):
use Symfony\UX\Map\Map;
use Symfony\UX\Map\Point;
use Symfony\UX\Map\Marker;
$map = new Map();
$map->addMarker(new Marker(
new Point(48.856613, 2.352222),
'Paris'
));
return $this->render('map.html.twig', ['map' => $map]);
Live Component Integration:
use Symfony\UX\Map\ComponentWithMapTrait;
class MapComponent extends AbstractController
{
use ComponentWithMapTrait;
public function index(): Response
{
$this->getMap()->addMarker(new Marker(
new Point(48.856613, 2.352222),
'Paris'
));
return $this->render('map_component.html.twig');
}
}
Static Maps:
<twig:ux:map
id="static-map"
center="{{ [lat, lng] }}"
zoom="10"
renderer="leaflet"
>
<twig:ux:map:marker
point="{{ [lat, lng] }}"
title="Location"
/>
</twig:ux:map>
Dynamic Maps (Live Components):
ComponentWithMapTrait for real-time updates:
class InteractiveMap extends AbstractController
{
use ComponentWithMapTrait;
public function __construct()
{
$this->getMap()->addMarker(new Marker(
new Point(48.856613, 2.352222),
'Paris'
));
}
#[Route('/add-marker', name: 'add_marker')]
public function addMarker(): Response
{
$this->getMap()->addMarker(new Marker(
new Point(48.853384, 2.348800),
'Eiffel Tower'
));
return $this->render('interactive_map.html.twig');
}
}
Geospatial Data Integration:
$points = $entityManager->createQueryBuilder()
->select('e.latitude, e.longitude, e.name')
->from('App\Entity\Location', 'e')
->getQuery()
->getResult();
foreach ($points as $point) {
$map->addMarker(new Marker(
new Point($point['latitude'], $point['longitude']),
$point['name']
));
}
Custom Renderers:
this.element.addEventListener('ux:map:pre-connect', (event) => {
event.detail.bridgeOptions = {
attributionControl: false,
zoomControl: false
};
});
Clustering Markers:
$map->setClusteringAlgorithm(new GridClusteringAlgorithm());
$map->addMarkers($markers);
Symfony UX 3.x Migration:
render_map() with ux_map() Twig function:
{{ ux_map({
id: 'map',
center: [48.856613, 2.352222],
zoom: 12,
renderer: 'leaflet'
}) }}
Live Component Best Practices:
fitBoundsToMarkers() for auto-zooming:
$this->getMap()->fitBoundsToMarkers(true);
Google Maps Integration:
config/packages/ux_map.yaml:
ux_map:
google_maps:
default_map_id: 'YOUR_MAP_ID'
Performance Optimization:
$this->getMap()->removeAllMarkers();
$this->getMap()->addMarkers($filteredMarkers);
Custom Icons:
$marker = new Marker(
new Point(48.856613, 2.352222),
'Paris',
new Icon('https://example.com/icon.svg')
);
Deprecated Methods:
render_map() (use ux_map() instead).title with infoWindow for polygons/lines/circles.Live Component Quirks:
fitBoundsToMarkers may behave unexpectedly in Live Components. Explicitly disable it if needed:
$this->getMap()->fitBoundsToMarkers(false);
Renderer-Specific Options:
bridgeOptions for renderer-specific configs:
event.detail.bridgeOptions = {
// Google Maps specific
mapId: 'YOUR_MAP_ID'
};
Event Listener Conflicts:
ux:map:pre-connect) are registered after the map is initialized.Coordinate Precision:
DistanceCalculatorInterface for accurate distance measurements:
$distance = (new HaversineDistanceCalculator())->calculate(
new Point(48.856613, 2.352222),
new Point(51.507351, -0.127758)
);
Console Logs:
ux:map:connect events for runtime options:
this.element.addEventListener('ux:map:connect', (event) => {
console.log('Map connected:', event.detail);
});
Twig Debugging:
{{ dump(map) }} to inspect map objects in Twig templates.Renderer-Specific Issues:
Live Component State:
Map objects are not recreated on every request. Use ComponentWithMapTrait for state persistence.Custom Renderers:
AbstractRenderer to support new map providers (e.g., Mapbox):
class MapboxRenderer extends AbstractRenderer
{
public function render(): string
{
// Custom Mapbox initialization logic
}
}
Geospatial Utilities:
CoordinateUtils for coordinate conversions:
$dms = CoordinateUtils::toDMS(48.856613);
Event-Driven Extensions:
ux:map:marker:click for custom interactions:
this.element.addEventListener('ux:map:marker:click', (event) => {
console.log('Marker clicked:', event.detail.marker);
});
Configuration Overrides:
ux_map.yaml:
ux_map:
default_options:
renderer: 'leaflet'
zoom: 12
Testing:
MapTestCase for unit testing:
use Symfony\UX\Map\Tests\MapTestCase;
class MyMapTest extends MapTestCase
{
public function testMarkerRendering(): void
{
$map = new Map();
$map->addMarker(new Marker(new Point(0, 0), 'Test'));
$this->assertHtmlContains($map->render(), 'Test');
}
}
How can I help you explore Laravel packages today?