javascripthighmaps

Manage projections in custom Highmaps


I'm generating html files from python (mainly using geopandas module) containing highmaps objects.

(The code is too long to fit here in stackoverflow as geojson are included in html files : please don't check the included code but refer to the fiddles instead).

The map datas are :

Both series are prealably converted in the same geodesic system using geopandas (which I think uses pyproj4 dll somewhere).

I got geodesics systems as proj4 strings from spatialreference, that is:

When I convert all datas in WGS 84, I get correct results (though the map looks distorded for French users) : see this fiddle.

When I convert all datas in 2154, I get serious errors (as you can see, cities are displayed erraticly, which seems to include some latitude inversion as well) ; see this fiddle.

When I keep all datas in WGS 84 and just set the hc-transform to epsg2154, I still have strange results, though I think this is the correct way referenced in the doc (I'm not 100% certain of that, as those are maps generated using distant geojson datas and I'm not used to program in javascript)...

I also tried using the x/y properties for the mappoint serie (instead of lon/lat) but this does not improve the result (though I checked datas in QGis and these coordinates are 100% right).

How should I do this ?

Code sample (please refer to fiddles for working example with geojson) :

<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.3.6/proj4.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="https://code.highcharts.com/maps/highmaps.js"></script>
<script src="https://code.highcharts.com/maps/modules/data.js"></script>
<script src="https://code.highcharts.com/maps/modules/exporting.js"></script>
<script src="https://code.highcharts.com/maps/modules/offline-exporting.js"></script>
<div id="container"></div>
<script type="text/javascript">
    Highcharts.mapChart("container", {
        title: {
            text: 'Testmap Highmaps Hauts-de-France'
        },                   

        mapNavigation: {
            enabled: true,
            buttonOptions: {
                verticalAlign: 'bottom'
            }
        },

        series: [
            {
                name: 'areas',
                type: 'map',
                mapData: {'type': 'FeatureCollection', 'features': [...], 'hc-transform': {'default': {'crs': '+proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs'}}, 'crs': '+proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs'},
            },
            {
                name: 'cities',
                type: 'mappoint',
                data: [{'lon': 727759.0000000142, 'lat': 6884382.999997055, 'name': 'Chateau-Thierry'}, ...],
                color: 'black',
                marker: {
                    radius: 2
                },
                dataLabels: {
                    align: 'left',
                    verticalAlign: 'middle'
                },
                animation: false,
                tooltip: {
                    pointFormat: '{point.name}'
                }
            },
        ]
    });
</script>
</body>
</html>

Solution

  • Ok, so this is an akward solution : I still don't understand how this could solve the problem, but it works... [EDIT : this is indeed the correct solution for the time beeing, see EDIT at the end of the post]

    What I did was :

    Note that :

    I think this is some kind of undocumented bug (I might be wrong still), I will try to refer if to highcharts'staff...

    See complete functional exemple in this fiddle.

    <html>
    <body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.3.6/proj4.js"></script>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <script src="https://code.highcharts.com/maps/highmaps.js"></script>
    <script src="https://code.highcharts.com/maps/modules/data.js"></script>
    <script src="https://code.highcharts.com/maps/modules/exporting.js"></script>
    <script src="https://code.highcharts.com/maps/modules/offline-exporting.js"></script>
    <div id="container"></div>
    <script type="text/javascript">
        Highcharts.mapChart("container", {
            title: {
                text: 'Testmap Highmaps Hauts-de-France'
            },                   
    
            mapNavigation: {
                enabled: true,
                buttonOptions: {
                    verticalAlign: 'bottom'
                }
            },
    
            yAxis: {
                reversed: true
            },
    
            series: [
                {
                    name: 'areas',
                    type: 'map',
                    mapData: {'type': 'FeatureCollection', 'features': [{'id': '1', 'type': 'Feature', 'properties': {'DEP': '02'}, 'geometry': {'type': 'Polygon', 'coordinates': [[[761574.9000000217, 6918670.299997976], [761648.2000000217, 6918469.799997974], ..., [699287.6999999998, 6901218.199997955]]]}}], 'hc-transform': {'default': {'crs': '+proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs'}}, 'crs': '+proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs'},
                },
                {
                    name: 'cities',
                    type: 'mappoint',
                    data: [{'x': 727759.0000000142, 'y': -6884382.999997055, 'name': 'Chateau-Thierry'}, ...],
                    color: 'black',
                    marker: {
                        radius: 2
                    },
                    dataLabels: {
                        align: 'left',
                        verticalAlign: 'middle'
                    },
                    animation: false,
                    tooltip: {
                        pointFormat: '{point.name}'
                    }
                },
            ]
        });
    </script>
    </body>
    </html>
    

    EDIT

    So this is indeed a tricky problem... I have been in touch with highsoft and there seem to be multiple facts to take in consideration : - first, the yAxis.reverse=true IS the default behaviour, regardless to what is currently stated in the doc ; - secondly, some inner algorithm about mapData corrects this behaviour, because this type of layer is assumed to be GeoJSON ; - 3rdly, this is not the case for mappoint aw well as mapbubble layers.

    Notice that if you set yAxis.reverse = false, you are up for some bad time. The mappoint layers may seem to be correctly superposed with your mapData (if I understood this correctly, this have something to do with the mappoint layer's y range to be more or less alike to those of the map area.

    Highsoft has opened an issue on this subject.

    Morality : my solution was in fact the good one (at least until they decide what to do with this "issue"). As for this version of Highmaps, always work with yAxis.reverse = true, and be aware that mapDatas passed as GeoJSON are not affected by this command.