Skip to content

Commit

Permalink
Merge pull request #16533 from highcharts/feature/topojson
Browse files Browse the repository at this point in the history
Maps: native TopoJSON support
  • Loading branch information
TorsteinHonsi committed Dec 9, 2021
2 parents 4790c06 + fa6cbc6 commit d88ad82
Show file tree
Hide file tree
Showing 48 changed files with 778 additions and 351 deletions.
2 changes: 1 addition & 1 deletion docs/maps/adding-points-and-lines.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ Adding points and lines

Map points and lines are added to the map by coordinates. The coordinate system used in most of our maps is a custom one, where both the X and Y values range from 0 to some thousands. The rationale for not using latitude and longitude coordinates in version 1 of the [Map Collection](https://code.highcharts.com/mapdata/) is partly to save downloading weight, partly to not have to deal with projection on the client side, and partly because many of the maps are composite. For example Alaska is moved into the Pacific next to the US mainland on most US maps, thus Alaska would need its own projection within the same map. With the support of the _proj4js_ library, points can be placed by latitude and longitude. See the [Latitude/longitude](latlon) article.

Since Highcharts v9.3 there is beta support for built-in projections, and points and lines can be added as [geometry](https://api.highcharts.com/highmaps/series.map.data.geometry), like in geoJSON. A new version of the Map Collection is planned (as of 2021), where the maps will be encoded as topoJSON and projection handled internally in Highcharts Maps.
Since Highcharts v9.3 there is beta support for built-in projections, and points and lines can be added as [geometry](https://api.highcharts.com/highmaps/series.map.data.geometry), like in GeoJSON. A new version of the Map Collection is planned (as of 2021), where the maps will be encoded as TopoJSON and projection handled internally in Highcharts Maps.

Points are added as x, y pairs on the same coordinate system as the map. Maplines however are given as paths. In order to ease the process of placing your own points on the map, we have created [a utility script](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/maps/chart/events-click-getcoordinates/) that allows you to click around in the map, then view and copy-paste the coordinates into your own map setup.
7 changes: 6 additions & 1 deletion docs/maps/custom-geojson-maps.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ This article contains information on creating maps from data in common mapping f

We see that many users have map data in ESRI Shapefile format or other common mapping formats. These can easily be converted for use with Highcharts Maps using an editor with GeoJSON exporting capabilities, as Highcharts Maps supports the GeoJSON format natively. Most full-featured GIS editors will be able to perform this conversion. [QGIS](https://qgis.org "QGIS") is a free alternative that supports both Shapefile, KML, and a number of other formats. See [this demo](https://highcharts.com/maps/demo/geojson "GeoJSON demo") for an example of how to load polygonal data from a GeoJSON file, and [this demo](https://highcharts.com/maps/demo/geojson-multiple-types "GeoJSON multiple types demo") for a more complex example with line and point data.

The Highcharts Maps map collection is supplied in both SVG and GeoJSON formats, and can be edited using any compatible editor. Simple changes can be made using a text editor. [InkScape](https://inkscape.org "InkScape") is a free visual editor for SVG files. Please note that different coordinate systems are used in the SVG and GeoJSON files, mainly for optimization reasons. The map collection is also supplied as executable Javascript files. These Javascript files are identical to the GeoJSON files, except for a small amount of wrapping code.
The Highcharts Maps map collection is supplied in both SVG, GeoJSON and TopoJSON formats, and can be edited using any compatible editor. Simple changes can be made using a text editor. [InkScape](https://inkscape.org "InkScape") is a free visual editor for SVG files. The map collection is also supplied as executable JavaScript files. These Javascript files are identical to the GeoJSON files, except for a small amount of wrapping code.

Please note that different coordinate systems are used in the Map Collection's SVG, GeoJSON and TopoJSON files, mainly for optimization reasons.
- **TopoJSON** files, available since Map Collection v1.1.4, are not projected, meaning coordinates are given as `[longitude, latitude]`. This relies on projection being done in Highcharts, which is more intuitive and allows easier navigation, re-projection, addition of points and lines etc.
- **GeoJSON** files in the Map Collection date back to when projection was not supported natively in Highcharts. The coordinates are pre-projected with the projection given in the `crs` property, in addition to some compression defined in `hc-transform`. In order to deal with longitude and latitude on the client side, the `proj4.js` library must be used. Since v9.3, Highcharts has built-in support for projection, so custom GeoJSON maps may dropp pre-projection.
- **SVG** files don't deal with geographic information at all. In general, these are only recommended for simple choropleth maps.

Creating maps for Highcharts Maps
--------------------------
Expand Down
4 changes: 2 additions & 2 deletions docs/maps/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ If you already have Highcharts installed in the web page and want to run Highcha
Load the map
------------

Highcharts Maps loads its maps from [GeoJSON](https://en.wikipedia.org/wiki/GeoJSON), an open standard for description of geographic features. Most GIS software supports this format as export from for instance Shapefile or KML export. Read more in the [API reference](https://api.highcharts.com/class-reference/Highcharts.GeoJSON) and [see the live demo](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/maps/demo/geojson-multiple-types/).
Highcharts Maps loads its maps from [GeoJSON](https://en.wikipedia.org/wiki/GeoJSON) or [TopoJSON](https://github.com/topojson/topojson) which are open standards for description of geographic features. Most GIS software supports these formats as export from for instance Shapefile or KML export. Read more in the [API reference](https://api.highcharts.com/class-reference/Highcharts.GeoJSON) and [see the live demo](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/maps/demo/geojson-multiple-types/).

There are three basic sources for your map:

Expand All @@ -41,4 +41,4 @@ Add and join data

Once the empty map is in place, we're ready to add the data to the [series.data](https://api.highcharts.com/highmaps/series.map.data) option. For the joining to work, each data point must have some identifier that relates to the same identifier in the map data set. This or these identifiers are then specified in the [joinBy](https://api.highcharts.com/highmaps/plotOptions.series.joinBy) option. See detailed documentation and examples there.

Another way to join the data is to simply skip the mapData and set the [path](https://api.highcharts.com/highmaps/series.map.data.path) directly on the data point. This mixes the data and the structure and is not generally recommended, but it performs faster, and may be considered in situations where you have static data and a backend to perform the joining.
Another way to join the data is to simply skip the `mapData` and set the [geometry](https://api.highcharts.com/highmaps/series.map.data.geometry) directly on the data point. This mixes the data and the structure and is not generally recommended, but it performs faster, and may be considered in situations where you have static data and a backend to perform the joining.
2 changes: 1 addition & 1 deletion docs/maps/latlon.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Latitude/longitude

Highcharts Maps from version 1.1.0 comes with support for latitude/longitude. This feature requires that the [proj4js](http://proj4js.org) library has been loaded before Highcharts Maps. The latest version of the _proj4js_ library can be loaded from [cdnjs](https://cdnjs.com/libraries/proj4js).

Note: since Highcharts v9.3, experimental projection is built in, allowing the use of `lat` and `lon` properties to be handled without the use of proj4js, as well as applying geoJSON-compliant [geometry](https://api.highcharts.com/highmaps/series.data.geometry) configuration to points, maplines and map points directly.
Note: since Highcharts v9.3, experimental projection is built in, allowing the use of `lat` and `lon` properties to be handled without the use of proj4js, as well as applying GeoJSON-compliant [geometry](https://api.highcharts.com/highmaps/series.data.geometry) configuration to points, maplines and map points directly.


<!-- Example of loading from CDNJS: -->
Expand Down
23 changes: 14 additions & 9 deletions docs/maps/map-collection.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
Map collection
===

For your convenience, Highcharts Maps offers a free [collection of maps](https://code.highcharts.com/mapdata/), optimized for use with Highcharts Maps. For common maps, it saves you the trouble of finding or drawing suitable SVG or GeoJSON maps. Instead, you can choose between hundreds of pre-generated maps of countries, regions and other administration levels.
For your convenience, Highcharts Maps offers a free [collection of maps](https://code.highcharts.com/mapdata/), optimized for use with Highcharts Maps. For common maps, it saves you the trouble of finding or drawing suitable SVG or GeoJSON/TopoJSON maps. Instead, you can choose between hundreds of pre-generated maps of countries, regions and other administration levels.

License
-------

The Highcharts Maps Map Collection comes with the license of the source data. For Admin0 (countries) and Admin1 (US states, German Bundesländer, Dutch regions etc), the source data is [Natural Earth](https://www.naturalearthdata.com/), which is [Public Domain](https://en.wikipedia.org/wiki/Public_domain). For Admin2, we have only compiled selected countries, and these maps are created from national files with their own license which is specified on the SVG map and in the other format files as meta data. If your country is missing from the list, please contact us and we'll try to find a suitable shapefile and generate more maps. 

For maps loaded using the default GeoJSON input into the mapData option, a short version of the copyright will be printed in the chart's credits label.
For maps loaded using the default TopoJSON or GeoJSON input into the `mapData` option, a short version of the copyright will be printed in the chart's credits label.

Using the map collection
------------------------
Expand Down Expand Up @@ -37,7 +37,7 @@ map: 'custom/world'
```

3. Join your data with the map. By default Highcharts Maps is set up to map your data against the `hc-key` property of the map collection, allowing you to define your data like this:
```js
```js
data: [['us-ny', 0], ['us-mi', 5], ['us-tx', 3], ['us-ak', 5]]
```
For other data joining options, see the [`series.joinBy`](https://api.highcharts.com/highmaps/plotOptions.series.joinBy) and [`series.keys`](https://api.highcharts.com/highcharts/plotOptions.series.keys) options.
Expand All @@ -51,18 +51,18 @@ npm i @highcharts/map-collection

To load a map in Node.js and use it in Highcharts Maps you can do the following:

```js
var Highcharts = require('highcharts/highmaps.js'),
map = require('@highcharts/map-collection/custom/world.geo.json');
```js
const Highcharts = require('highcharts/highmaps.js'),
map = require('@highcharts/map-collection/custom/world.topo.json');

Highcharts.mapChart('container', {
chart: {
map: geojson
map
},
// ...
});
```


Map properties
--------------
Expand Down Expand Up @@ -109,6 +109,11 @@ Using parts of a map

If you can't find the exact map that you want in the collection, it is easy to use only selected parts of a larger area. Say you want a comparative map of Canada, USA and Mexico. Since we don't have that exact combination in the collection (as of now), you can use the map called "North America without Central". This map also contains Greenland as well as Caribbean islands. So we apply a data set only for the three countries we want, and set the [allAreas](https://api.highcharts.com/highmaps/plotOptions.map.allAreas) option to false. This option makes sure all null points (the countries that don't have data), are hidden. See [demo on jsFiddle](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/maps/plotoptions/series-allareas-false/).

Combine maps
____________

Another way to approach the same problem, is to combine two or more map sources into the same chart. This is supported since Highcharts v9.3, where client-side projection is available. To achive this, the unprojected TopoJSON maps must be used. See the [demo on jsFiddle](https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/maps/series/mapdata-multiple/).

Modify our maps
---------------

Expand Down
6 changes: 3 additions & 3 deletions docs/maps/map-series.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ For an overview of the `map` series options see the [API reference](https://api

Load the map
------------
Highcharts Maps loads its maps from GeoJSON.
A more detailed instruction on how to work with it is written here: [Load the map](https://www.highcharts.com/docs/maps/getting-started#load-the-map)
Highcharts Maps loads its maps from TopoJSON or GeoJSON.
A more detailed instruction on how to work with it is written here: [Load the map](https://www.highcharts.com/docs/maps/getting-started#load-the-map)

Add and join data
-----------------
In this [link](https://www.highcharts.com/docs/maps/getting-started#add-and-join-data), you can find detailed descriptions of how to work with [series.map.data](https://api.highcharts.com/highmaps/series.map.data), and [series.joinBy](https://api.highcharts.com/highmaps/plotOptions.series.joinBy).
In this [link](https://www.highcharts.com/docs/maps/getting-started#add-and-join-data), you can find detailed descriptions of how to work with [series.map.data](https://api.highcharts.com/highmaps/series.map.data), and [series.joinBy](https://api.highcharts.com/highmaps/plotOptions.series.joinBy).

You can also find there another way of joining the data by omitting [mapData](https://api.highcharts.com/highmaps/series.map.mapData) and setting the [path](https://api.highcharts.com/highmaps/series.map.data.path) directly on the data point.
1 change: 0 additions & 1 deletion samples/data/europe.topo.json

This file was deleted.

1 change: 0 additions & 1 deletion samples/data/world-countries.topo.json

This file was deleted.

168 changes: 168 additions & 0 deletions samples/highcharts/studies/all-maps/demo.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#demo-wrapper {
max-width: 1000px;
margin: 0 auto;
height: 560px;
background: white;
}

#map-box {
width: 80%;
float: left;
}

#container {
height: 500px;
}

#side-box {
float: right;
width: 16%;
margin: 100px 1% 0;
padding-left: 1%;
border-left: 1px solid silver;
display: none;
}

#info-box {
margin-top: 10px;
}

.or-view-as {
margin: 0.5em 0;
}

#up {
line-height: 30px;
height: 30px;
max-width: 400px;
margin: 0 auto;
}

#up a {
cursor: pointer;
padding-left: 40px;
}

.selector {
height: 40px;
max-width: 400px;
margin: 0 auto;
position: relative;
}

.selector .prev-next {
position: absolute;
padding: 0 10px;
font-size: 30px;
line-height: 20px;
background: white;
font-weight: bold;
color: #999;
top: -2px;
display: none;
border: none;
}

.selector .custom-combobox {
display: block;
position: absolute;
left: 40px;
right: 65px;
}

.selector .custom-combobox .custom-combobox-input {
position: absolute;
font-size: 14px;
color: silver;
border-radius: 3px 0 0 3px;
height: 32px;
display: block;
background: url("https://www.highcharts.com/samples/graphics/search.png") 5px 8px no-repeat white;
padding: 1px 5px 1px 30px;
width: 100%;
box-sizing: border-box;
}

.selector .custom-combobox .ui-autocomplete-input:focus {
color: black;
}

.selector .custom-combobox .ui-autocomplete-input.valid {
color: black;
}

.selector .custom-combobox-toggle {
position: absolute;
display: block;
right: -32px;
border-radius: 0 3px 3px 0;
height: 32px;
width: 32px;
}

.selector #btn-next-map {
right: -12px;
}

.ui-autocomplete {
max-height: 500px;
overflow: auto;
}

.ui-autocomplete .option-header {
font-style: italic;
font-weight: bold;
margin: 5px 0;
font-size: 1.2em;
color: gray;
}

.loading {
margin-top: 10em;
text-align: center;
color: gray;
}

.ui-button-icon-only .ui-button-text {
height: 26px;
padding: 0 !important;
background: white;
}

#info-box .button {
border: none;
border-radius: 3px;
background: #a4edba;
padding: 5px;
color: black;
text-decoration: none;
font-size: 12px;
white-space: nowrap;
cursor: pointer;
margin: 0 3px;
line-height: 30px;
}

@media (max-width: 768px) {
#demo-wrapper {
width: auto;
height: auto;
}

#map-box {
width: auto;
float: none;
}

#container {
height: 310px;
}

#side-box {
float: none;
width: auto;
margin-top: 0;
border-left: none;
border-top: 1px solid silver;
}
}
7 changes: 7 additions & 0 deletions samples/highcharts/studies/all-maps/demo.details
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: Overview
authors:
- Torstein Hønsi
js_wrap: b
requiresManualTesting: true
...
29 changes: 29 additions & 0 deletions samples/highcharts/studies/all-maps/demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<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/mapdata/index.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script>
<script src="https://www.highcharts.com/samples/static/jquery.combobox.js"></script>

<link href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet">
<link href="https://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">

<div id="demo-wrapper">
<div id="map-box">
<div id="up"></div>
<div class="selector">
<button id="btn-prev-map" class="prev-next"><i class="fa fa-angle-left"></i></button>
<select id="mapDropdown" class="ui-widget combobox"></select>
<button id="btn-next-map" class="prev-next"><i class="fa fa-angle-right"></i></button>
</div>
<div id="container"></div>
</div>
<div id="side-box">

<input type="checkbox" id="chkDataLabels" checked='checked' />
<label for="chkDataLabels" style="display: inline">Data labels</label>
<div id="info-box">
<h4>This map</h4>
<div id="download"></div>
</div>
</div>
</div>

0 comments on commit d88ad82

Please sign in to comment.