zcreativelabs / react-simple-maps

Beautiful React SVG maps with d3-geo and topojson using a declarative api.
https://www.react-simple-maps.io/
MIT License
3.12k stars 426 forks source link

Map view does not match the coordinates #247

Closed DoneDeal0 closed 3 years ago

DoneDeal0 commented 3 years ago

I have read the official example on your website. It works great, but as soon as I change the coordinates to a place not currently represented by the map (ex: new-york: [40,74] instead of Paris), the map doesn't update and I can't see the new point.

How to make sure the rendered map always update to the right world part?

It is not a simple React rendering issue. When refreshing the page, the map remains at the wrong location. Basically, it doesn't understands that it has to display the area surrounding the new location.

Here is the official sandbox: https://codesandbox.io/s/basic-annotation-0qt1g?from-embed=&file=/src/MapChart.js

How to fix this? Thanks, great library!

zimrick commented 3 years ago

Hi @DoneDeal0,

Thanks for using react-simple-maps. I'm glad you like the library!

Ok, so as I understand it you are trying to update the marker coordinates to focus on New York and you would like the map to move along with these new marker coordinates. There are a few ways of doing this with react-simple-maps. It depends largely what kind of map you are using and also what projection you want to use.

Solution 1

In the basic annotation example I use the geoAzimuthalEqualArea projection. This is a great projection when mapping anything up to a hemisphere. The downside of this projection is that shapes further away from the center of the map will be more severely distorted (but they preserve the correct size). You can prevent this by updating the rotation parameter in projectionConfig thereby re-centering the projection. This may be a bit confusing in the example since this rotation parameter is not the same as the annotation coordinates (I focused it on Europe, rather than Paris). The key here is that rotation in d3 is specified as an inverse of the coordinates. If you want it to focus on Paris, you would set the rotation to: [-2.3522, -48.8566, 0]. If you want the map to move to New York with the annotation (located at [-74, 40]), you just set the first (x) and second (y) attribute of the rotation property inside projectionConfig to the negative coordinates of your annotation. For New York this would mean setting rotation to [74, -40, 0]. The coordinates inside rotation are set as the inverse of [lon, lat, z]. This can be an issue since different platforms use different ordering for longitude and latitude. Google seems to be doing it the other way around than d3, so just make sure to pay attention to the order of the coordinates and whether they are negative or positive.

Here's a codesandbox showing this solution in action: https://codesandbox.io/s/switching-locations-with-annotation-f4nvq?file=/src/MapChart.js

Solution 2

If you decide to use a different projection that is meant for maps showing the whole world (e.g. geoEqualEarth), you could also use the ZoomableGroup component. This component just pans the map around without changing the rotation parameter of your projection. You will get some distortion when focusing on New Zealand, or other parts of the world that are further away from the default center (which is the [0, 0]), but overall performance will be better since the projection is not recomputed. Then you can just set the center prop of the ZoomableGroup component to the same coordinates as your annotation. The small added bonus here is that you could animate the map moving from location to location.

I hope this helps you create the map you want

DoneDeal0 commented 3 years ago

Hi @zimrick , thanks a lot for your detailed answer, I appreciate it! The first solution works better with a 1600px scale. Have a great day, congratulation again for your library!