Search code examples
highchartsvue.jsecmascript-6highmapsproj4js

How to import Proj4js to use with Highmaps?


I have a Vue application that is using highchart with the vue-highcart component to plot maps. I need to plot points on this maps based on the Latitude and Longitude and, according to Highmaps documentation, I have to use the Proj4js. In plain old javascript I would simply use a <script> to get it into my page but I can't figure out how to do it ES6-way. I have tried the following:

import Proj4 from 'proj4';
import Highcharts from 'highcharts';
import VueHighcharts from 'vue-highcharts';
import LoadHighmaps from 'highcharts/modules/map';

LoadHighmaps(Highcharts);
Vue.use(VueHighcharts, { Proj4, Highcharts })

// ....

<highmaps :options="options"></highmaps>

And it doesnt work. It fails silently. The map is plotted but no point is plotted on the map. It is the same behaviour you get if you remmove the Proj4Js on this fiddle: http://jsfiddle.net/r9hugxsu/

Any help? Thanks in advance.

Edit: I am aware that I can simply put the script tag on my index.html. But I was just wondering if there is an ES6-way to do this kind of "dependency-script-including".


Solution

  • I ran into this myself just recently. If you did manage to resolve this yourself already, then I'll at least leave this here as a quick answer to others running into this.

    There doesn't seem to be documentation from Highsoft on this particular part, yet. I should probably file a docs issue with them.

    Here's how I was able to resolve it in a React project I'm on.

    Step 1: Create a wrapper import for proj4 that puts it on `window`

    I made a separate "import wrapper" which, when I import it from anything that requires proj4 (which is just Highcharts) it imports the real proj4 from node_modules and sticks it on window as window.proj4. This is what Highmaps looks for when it's trying to find proj4.

    For the sake of example, pretend this file is in @/maps/lib/proj4.js.

    import proj4 from 'proj4';
    
    // NOTE: when dealing with server side rendering as we are, check for window before doing things with it.
    // If you're not doing server side rendering, then you don't need this check and can just assign straight to window.
    if (typeof window !== 'undefined') {
      window.proj4 = window.proj4 || proj4;
    }
    
    export default proj4;
    

    Step 2: Download and Install Maps

    One thing that initially confused me when trying to use Highmaps is that none of the examples seemed to work when I tried to reproduce them in the project I'm on. This turned out to be because Highmaps does not include any maps itself, rather we need to download and manually install them, usually from their map collection.

    As an aside, if you look at their JS map files, you'll see they basically just assign the map directly like so: Highcharts.maps["custom/world"] = {"title":"World, Miller projection, medium resolution",...}. For the project I'm on, I just downloaded the JSON version and did the assignment myself. I placed the map file itself at @/maps/custom/world.geo.json.

    I did this in another import wrapper type file, this time for Highcharts. This file is in @/maps/lib/Highcharts.js.

    import './proj4';
    import Highcharts from 'highcharts';
    import HighchartsMap from 'highcharts/modules/map';
    
    import customWorld from '@/maps/custom/world.geo.json';
    
    // NOTE: Again, if doing server side rendering, check for window before bothering.
    // Highcharts modules crash on the server.
    if (typeof window !== 'undefined') {
      HighchartsMap(Highcharts);
    
      Highcharts.maps['custom/world'] = customWorld;
    }
    
    export default Highcharts;
    

    Note above that I placed a local import before all the global imports, the import of @/maps/lib/proj4.js. While not strictly necessary, I did this to ensure that proj4 will always be installed before Highcharts is even imported, just in case.

    Step 3: Import Highcharts From Our Import Wrapper

    In the chart components, then, I can just import from our wrapper rather than the node_modules install.

    import Highcharts from '@/maps/lib/Highcharts';
    
    // do stuff with Highcharts itself...
    

    Aside: Series and Data

    Not sure why, but I had to always include a separate series for the map lines themselves.

    {
      // ...
      series: [
        // Series for the map.
        {
          name: 'Countries',
          color: '#E0E0E0',
          enableMouseTracking: false,
          showInLegend: false,
          zIndex: 1,
        },
        // Series for the data.  Have to remember to add data later using chart.series[1]
        // rather than chart.series[0].
        {
          type: 'mapbubble',
          name: 'Live Activity',
          data: [],
          // TODO: Format for datum... point.datum.userId, etc.
          tooltip: {
            pointFormat: '{point.datum.userId}',
          },
          minSize: 4,
          maxSize: 24,
          zIndex: 2,
        },
      ],
      // ...
    }