symfony / ux

Symfony UX initiative: a JavaScript ecosystem for Symfony
https://ux.symfony.com/
MIT License
781 stars 274 forks source link

[Map] Create Map component #1937

Open Kocal opened 1 week ago

Kocal commented 1 week ago
Q A
Bug fix? no
New feature? yes
Issues Fix #38
License MIT

Hi :)

This PR is a proposal for #38 a replacement for #39.

Symfony UX Map is a new Symfony UX component that makes it easy to create, customize and use interactive JavaScript maps.

Currently, only the Google Maps and Leaflet providers are supported.

For each provider, there is:

Here an example to render a Google Maps, with a custom MapId, custom center and zoom, some markers and info windows:

    public function index(MapFactoryInterface $mapFactory): Response
    {
        /** @var GoogleMaps\Map $mapGoogle */
        $map = $mapFactory->createMap('google_maps_map_1');
        $map
            // All following methods are optional
            ->setMapId("2b2d73ba4b8c7b41")
            ->setCenter(new LatLng(46.903354, 1.888334))
            ->setZoom(6)
            ->addMarker($paris = new GoogleMaps\Marker(position: new LatLng(48.8566, 2.3522), title: 'Paris'))
            ->addMarker($lyon = new GoogleMaps\Marker(position: new LatLng(45.7640, 4.8357), title: 'Lyon'))
            ->addMarker(new GoogleMaps\Marker(position: new LatLng(43.2965, 5.3698), title: 'Marseille'))
            ->addMarker(new GoogleMaps\Marker(position: new LatLng(43.7102, 7.2620), title: 'Nice'))
            ->addMarker(new GoogleMaps\Marker(position: new LatLng(47.2184, -1.5536), title: 'Nantes'))
            ->addInfoWindow(new GoogleMaps\InfoWindow(
                headerContent: '<b>Paris</b>', 
                content: "Capitale de la France, est une grande ville européenne et un centre mondial de l'art, de la mode, de la gastronomie et de la culture.",
                marker: $paris,
                opened: true,
            ))
            ->addInfoWindow(new GoogleMaps\InfoWindow(
                headerContent: '<b>Lyon</b>', 
                content: 'Ville française de la région historique Rhône-Alpes, se trouve à la jonction du Rhône et de la Saône.', 
                marker: $lyon
            ))
            ->enableStreetViewControl(false)
            ->enableMapTypeControl(false)
            ->setFullscreenControlOptions(new GoogleMaps\FullscreenControlOptions(
                position: GoogleMaps\ControlPosition::BLOCK_START_INLINE_START,
            ))
            ->setZoomControlOptions(new GoogleMaps\ZoomControlOptions(
                position: GoogleMaps\ControlPosition::BLOCK_START_INLINE_END,
            ));
        ;

        return $this->render('home/index.html.twig', [
            'map' => $map,
        ]);
    }

The Twig code:

{{ render_map(map_google, { style: 'height: 700px; width: 1024px; margin: 10px' }) }}

It gives you this interactive Google Maps map:

image

I'm opening the PR this morning, and I'll try to comment on some of my choices as soon as possible before you start the review :)

seb-jean commented 1 week ago

Very useful component :)

simondaigre commented 1 week ago

That's awesome ! Thank you for this PR ! I checked my projects with Google Maps integration, there is some features missing here :

Kocal commented 1 week ago

Hi @simondaigre, and thank you! :)

allow to set a custom icon on Marker

It's already on my list! I will need this feature aswell for my website where I use custom marker icons: image

But I don't wanted to do too much things in a single PR. Implementing PinElement PHP-side is a small challenge which I think can already be done user-side with event listeners.

allow to customize map styles (styles parameter as array ?)

I've started to implement the API/configuration for map styles (with some classes and enums), but I've finally removed it when I knew about Cloud-based maps styling. You can pass the mapId or call ->setMapId('...') to customize your map styles.

on some projects I also use @googlemaps/markerclusterer. Not sure if you should include it in ux/maps but I'll do a doc PR with explanations if you want

I think we would not include it in Symfony UX Map by default, a documentation would be enough IMO :)

smnandre commented 4 days ago

(i will make a big review this week-end ;) )

smnandre commented 4 days ago

A first comment before touching the real work :)

It is not possible to use Google Map without explicit consent of the user in Europe, California i think, Japan maybe, Australia too

You are of course not responsible of this, but i think some use case or implementation consequences should be discussed now

Kocal commented 4 days ago

... 😮‍💨 , but yeah you're right, thanks for pointing it out.

I think the easiest way to do that is to:

For example with the Didomi CMP:

<script>
    window.didomiOnReady = window.didomiOnReady || [];
    window.didomiOnReady.push(() => {
        function loadGoogleMapsIfConsentGiven() {
            const googleMapsPurposeId = '...';
            const googleMapsVendorId = '...';

            const userStatus = Didomi.getUserStatus();
            const enabledPurposeConsent = userStatus.purposes.consent.enabled;
            const enabledVendorConsent = userStatus.vendors.consent.enabled;

            if (enabledPurposeConsent.includes(googleMapsPurposeId) && enabledVendorConsent.includes(googleMapsVendorId)) {
                window.loadSymfonyUxGoogleMaps();
            }
        }

        if (Didomi.shouldConsentBeCollected()) {
            window.didomiEventListeners = window.didomiEventListeners || [];
            window.didomiEventListeners.push({
                event: 'consent.changed',
                listener: function (event) {
                    loadGoogleMapsIfConsentGiven();
                }
            });
        } else {
            loadGoogleMapsIfConsentGiven();
        }
    });
</script>

WDYT?