Skip to content
New issue

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

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

Already on GitHub? # 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
Member

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
Member

@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
Member

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
Member

@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
Member

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
Member

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
Member

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
Member

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
Member

Kocal commented Sep 19, 2024

I will see what I can do

@Kocal
Copy link
Member

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
Member

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
Member

@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
Member

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
Member

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
Member

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
Member

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
Member

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
Member

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

Kocal added a commit that referenced this pull request Nov 3, 2024
…nt, ...) (Kocal)

This PR was squashed before being merged into the 2.x branch.

Discussion
----------

[DX] Add per-package Yarn scripts (build, watch, test, lint, ...)

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | no <!-- please update src/**/CHANGELOG.md files -->
| Issues        | Fix #... <!-- prefix each issue number with "Fix #", no need to create an issue if none exist, explain below instead -->
| License       | MIT

<!--
Replace this notice by a description of your feature/bugfix.
This will help reviewers and should be a good start for the documentation.

Additionally (see https://symfony.com/releases):
 - Always add tests and ensure they pass.
 - For new features, provide some code snippets to help understand usage.
 - Features and deprecations must be submitted against branch main.
 - Changelog entry should follow https://symfony.com/doc/current/contributing/code/conventions.html#writing-a-changelog-entry
 - Never break backward compatibility (see https://symfony.com/bc).
-->

When working in UX Map, it was very painful to build or watch modifications on `.ts` files, I had investigate how the building process worked, and had to run Rollup like this, which is far from ideal (not documented and not obvious):
```
./node_modules/.bin/rollup -c --environment INPUT_FILE:src/Map/assets/src/abstract_map_controller.ts -w
./node_modules/.bin/rollup -c --environment INPUT_FILE:src/Map/src/Bridge/Google/assets/src/map_controller.ts -w
./node_modules/.bin/rollup -c --environment INPUT_FILE:src/Map/src/Bridge/Leaflet/assets/src/map_controller.ts -w
```

And I also felt sorry for `@rrr63` when he worked on adding Polygons on Map (#2162)...

This PR improves the way developers will work on UX, and makes their lives easier.

**Before**:
- `yarn build` compiled the assets from ALL packages, it was not possible to build packages from only one package (which is useful if you work on a single package)
- no `yarn watch`
- `yarn test` runned tests from ALL packages, like `yarn build`, it was not possible to run tests for only one package

**Now:**
- at the project root, `build`/`test`/`lint`/`format`/`check-lint`/`check-format` scripts will run on all assets **from all packages**. And it will be faster than before, when processing was sequential, but now it's parallelized.
- at a package root (ex:  `src/Map/assets`), `build`/`test`/`lint`/`format`/`check-lint`/`check-format` scripts will run on all assets **from this package only**
- `build` and `watch` scripts handles both TypeScript and CSS files in a single command

This is a first step to what we spoke about with `@smnandre` to write a contribution guide.
It is now much more easier and friendlier to tell a developer to run `yarn watch` inside a package root, instead of telling it to run `./node_modules/.bin/rollup -c --environment INPUT_FILE:src/Map/src/Bridge/Google/assets/src/map_controller.ts -w` (and more, if you have multiple files).

<img width="1210" alt="image" src="https://github.com/user-attachments/assets/f40d4efc-439d-4f83-a0f8-611b1a64b334">

Commits
-------

b8dc5fd Ignore `var` folder in Biome.js
8397b52 [DX] Rework testing process, add `test` script to packages package.json
bc1d63c [DX] Reconfigure lint/format tasks to not run the command for each workspace, since Biome is super fast (also include bin and test JS files)
1873b3e [DX] Rework building process, and add build/watch scripts to packages package.json
5517388 [DX] Add lint/format/check-lint/check-format scripts to packages package.json
# for free to join this conversation on GitHub. Already have an account? # 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