Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Map] Adding polygons to google and leaflet + info window #2162

Merged
merged 1 commit into from
Sep 24, 2024

Conversation

rrr63
Copy link
Contributor

@rrr63 rrr63 commented Sep 14, 2024

Q A
Bug fix? no
New feature? yes
Issues
License MIT

Hello,

In my job i use to work a lot with maps, so i would love to work with symfony ux in next projects.
But i have to work with polygons, so i tried to implement it to the ux-map.

I added polygons on the Map component, and made it work on both bridge : google and leaflet.
I added a window popup on click also, the current version of window popup worked only with markers.
I had to rename createInfoWindow to createInfoWindowMarker. With that i could add a createInfoWindowPolygon.
The only difference with the infoWindow from marker is that his anchor will be the event cursor position, because the area of the polygon could be very large and we want a window on the click position.

You can try by adding a simple polygon on your map :

      ->addPolygon(new Polygon(
                points: [
                    new Point(45.7402741, 3.191185),
                    new Point(45.7314078, 3.1903267),
                    new Point(45.7307488, 3.208952),
                    new Point(45.7402741, 3.2112694)
                ],
                rawOptions:[
                    'fillColor' => 'green',
                    'color' => 'green',
                ],
                infoWindow: new InfoWindow(
                    headerContent: '<b>Polygon</b>',


                    content: 'I am a polygon'
                )
            ))

smallgreenrectangle

Here a full example that works with leaflet and google that show some of french regions via an api call

$polygons = json_decode(file_get_contents('api_url'), true);
        $polygons = $polygons['features'];
        
        $googleOptions = (new GoogleOptions())
            ->mapId('mapId')
        ;
    
        $map = (new Map('default', $googleOptions))
            ->center(new Point(45.8079318, 3))
            ->zoom(10)
            ;
    
        foreach ($polygons as $polygon) {
            $points = [];
            $title = $polygon['properties']['nom'];
            foreach ($polygon['geometry']['coordinates'][0] as $point) {
                if (count($point) == 2) {
                    $points[] = new Point($point[1], $point[0]);
                }
            }
    
            $map->addPolygon(new Polygon(
                points: $points,
                rawOptions:[
                    'fillColor' => 'red',
                    'color' => 'red',
                ],
                infoWindow: new InfoWindow(
                    headerContent: '<b>'.$title.'</b>',
                    content: 'The French region of '.$title.'.'
                )
            ));
        }

googleregions
leafletregions

I added tests for polygons and polygon info window
I hope I did it right, i listen for any suggestions or edits in the PR

@carsonbot carsonbot added Feature New Feature Map Status: Needs Review Needs to be reviewed labels Sep 14, 2024
@smnandre
Copy link
Collaborator

Thank you very much for this PR @rrr63 👍

I think @Kocal will lead the review here :)

@smnandre smnandre requested a review from Kocal September 14, 2024 15:08
Copy link
Collaborator

@Kocal Kocal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working on this @rrr63!

It's not far from perfect, but I do have a few comments.

Also, don't forget to update Map's CHANGELOG.md files, thanks :)

src/Map/assets/src/abstract_map_controller.ts Outdated Show resolved Hide resolved
const polygon = { polygon: 'polygon', title: definition.title };

if (definition.infoWindow) {
this.createInfoWindowPolygon({ definition: definition.infoWindow, polygon });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
this.createInfoWindowPolygon({ definition: definition.infoWindow, polygon });
this.createInfoWindow({ definition: definition.infoWindow, polygon });

src/Map/assets/test/abstract_map_controller.test.ts Outdated Show resolved Hide resolved
src/Map/src/Bridge/Leaflet/assets/src/map_controller.ts Outdated Show resolved Hide resolved
src/Map/src/Bridge/Leaflet/assets/src/map_controller.ts Outdated Show resolved Hide resolved
src/Map/src/Bridge/Leaflet/assets/src/map_controller.ts Outdated Show resolved Hide resolved
src/Map/src/Polygon.php Outdated Show resolved Hide resolved
@rrr63
Copy link
Contributor Author

rrr63 commented Sep 15, 2024

@Kocal Thank for your comments, i fixed it.
You are right ! It will not break any apps because of info-window:before-create & info-window:after-create.
And it seems more accessible for future additions

@rrr63
Copy link
Contributor Author

rrr63 commented Sep 15, 2024

However, I wonder because a test did not pass on the Autocomplete component by just changing the Map's changelog ...

@rrr63
Copy link
Contributor Author

rrr63 commented Sep 16, 2024

Weird, it works by adding the changelog : Polygons added but didnt work with Adding polygons ... :)

Copy link
Collaborator

@Kocal Kocal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor comments, and I think it will be good for me!
I will try to find some time to try what you did :)

Comment on lines 135 to 139
const latLngs = points.map((point) => ({ lat: point.lat, lng: point.lng }));

const polygon = new _google.maps.Polygon({
...rawOptions,
paths: latLngs,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

points is already a list of { lat: number; lng: number }, so it should be enough no?

Suggested change
const latLngs = points.map((point) => ({ lat: point.lat, lng: point.lng }));
const polygon = new _google.maps.Polygon({
...rawOptions,
paths: latLngs,
const polygon = new _google.maps.Polygon({
...rawOptions,
paths: points,

src/Map/src/Polygon.php Outdated Show resolved Hide resolved
@Kocal
Copy link
Collaborator

Kocal commented Sep 18, 2024

I've just merged #2117, you will need to rebase your PR and add polygons support to ux_map() and <twig:ux:map> aswell, thanks 🙏🏻

Feel free to ask help if needed

@rrr63
Copy link
Contributor Author

rrr63 commented Sep 18, 2024

Hello @Kocal
Any tips on how could i resolved this conflicts ?
Do i have to do it locally or on github ?

Thanks

@smnandre
Copy link
Collaborator

smnandre commented Sep 18, 2024

Locally after a rebase on 2.x

You need to rebase / fix the conflcits / force-push here :)

Now it's a bit hard to review 90 files 😅

@smnandre
Copy link
Collaborator

smnandre commented Sep 18, 2024

I'll add then a couple of comments, regarding argument order and default values :)

@rrr63
Copy link
Contributor Author

rrr63 commented Sep 19, 2024

Oh so sorry,

Do you think it will be easier for you if I create a new PR?

@Kocal
Copy link
Collaborator

Kocal commented Sep 19, 2024

I will see what I can do

@Kocal
Copy link
Collaborator

Kocal commented Sep 19, 2024

It should be fine, the PR is back to ~10 commits and ~20 files
image

@rrr63
Copy link
Contributor Author

rrr63 commented Sep 19, 2024

It should be fine, the PR is back to ~10 commits and ~20 files
image

Thanks!!!

@smnandre
Copy link
Collaborator

I like it very much ! Would you agree, afterwards, to help me prepare a demo using polygons on the website ?

@rrr63
Copy link
Contributor Author

rrr63 commented Sep 21, 2024

Yes I could, with pleasure :)

Copy link
Collaborator

@Kocal Kocal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Final reviews 🙏🏻

Comment on lines 153 to 161
protected abstract doCreateInfoWindow({
definition,
marker,
element,
}: {
definition: MarkerDefinition<MarkerOptions, InfoWindowOptions>['infoWindow'];
marker: Marker;
definition:
| MarkerDefinition<MarkerOptions, InfoWindowOptions>['infoWindow']
| PolygonDefinition<PolygonOptions, InfoWindowOptions>['infoWindow'];
element: Marker | Polygon;
}): InfoWindow;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be improved to:

    protected abstract doCreateInfoWindow({
        definition,
        element,
    }: {
        definition: MarkerDefinition<MarkerOptions, InfoWindowOptions>['infoWindow'];
        element: Marker;
    } | {
        definition: PolygonDefinition<PolygonOptions, InfoWindowOptions>['infoWindow'];
        element: Polygon;
    }): InfoWindow;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, thanks for this review !

anchor: marker,
if (element instanceof google.maps.marker.AdvancedMarkerElement) {
element.addListener('click', () => {
if (definition.autoClose) this.closeInfoWindowsExcept(infoWindow);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a fan of one-lined condition + code, as it can easily introduce mistakes, please prefer keeping this form:

Suggested change
if (definition.autoClose) this.closeInfoWindowsExcept(infoWindow);
if (definition.autoClose) {
this.closeInfoWindowsExcept(infoWindow);
}

Note: I will see if Biome can prevent this

anchor: marker,
} else if (element instanceof google.maps.Polygon) {
element.addListener('click', (event: any) => {
if (definition.autoClose) this.closeInfoWindowsExcept(infoWindow);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a fan of one-lined condition + code, as it can easily introduce mistakes, please prefer keeping this form:

Suggested change
if (definition.autoClose) this.closeInfoWindowsExcept(infoWindow);
if (definition.autoClose) {
this.closeInfoWindowsExcept(infoWindow);
}

Note: I will see if Biome can prevent this

@Kocal
Copy link
Collaborator

Kocal commented Sep 24, 2024

I'm taking care of the rest, rebasing and fixing conflicts, testing the feature on my side, and merge :)

@Kocal
Copy link
Collaborator

Kocal commented Sep 24, 2024

Working as expected:
image
image

I've also added some documentation and squashed everything.
I'm merging after CI becomes green

@Kocal
Copy link
Collaborator

Kocal commented Sep 24, 2024

It took time, but here we go, this is in now. Thank you very much @rrr63.

@Kocal Kocal merged commit 01a1fa0 into symfony:2.x Sep 24, 2024
60 checks passed
@rrr63
Copy link
Contributor Author

rrr63 commented Sep 24, 2024

Thanks to you, @Kocal and @smnandre for your reviews

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature New Feature Map Status: Needs Review Needs to be reviewed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants