123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- /**
- * (c) 2010-2019 Torstein Honsi
- *
- * License: www.highcharts.com/license
- */
- /**
- * A latitude/longitude object.
- *
- * @interface Highcharts.MapLatLonObject
- *//**
- * The latitude.
- * @name Highcharts.MapLatLonObject#lat
- * @type {number}
- *//**
- * The longitude.
- * @name Highcharts.MapLatLonObject#lon
- * @type {number}
- */
- /**
- * Result object of a map transformation.
- *
- * @interface Highcharts.MapCoordinateObject
- *//**
- * X coordinate on the map.
- * @name Highcharts.MapCoordinateObject#x
- * @type {number}
- *//**
- * Y coordinate on the map.
- * @name Highcharts.MapCoordinateObject#y
- * @type {number}
- */
- 'use strict';
- import H from '../parts/Globals.js';
- import '../parts/Utilities.js';
- import '../parts/Options.js';
- import '../parts/Chart.js';
- var Chart = H.Chart,
- extend = H.extend,
- format = H.format,
- merge = H.merge,
- win = H.win,
- wrap = H.wrap;
- /* *
- * Test for point in polygon. Polygon defined as array of [x,y] points.
- */
- function pointInPolygon(point, polygon) {
- var i,
- j,
- rel1,
- rel2,
- c = false,
- x = point.x,
- y = point.y;
- for (i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
- rel1 = polygon[i][1] > y;
- rel2 = polygon[j][1] > y;
- if (
- rel1 !== rel2 &&
- (
- x < (polygon[j][0] -
- polygon[i][0]) * (y - polygon[i][1]) /
- (polygon[j][1] - polygon[i][1]) +
- polygon[i][0]
- )
- ) {
- c = !c;
- }
- }
- return c;
- }
- /**
- * Highmaps only. Get point from latitude and longitude using specified
- * transform definition.
- *
- * @requires module:modules/map
- *
- * @sample maps/series/latlon-transform/
- * Use specific transformation for lat/lon
- *
- * @function Highcharts.Chart#transformFromLatLon
- *
- * @param {Highcharts.MapLatLonObject} latLon
- * A latitude/longitude object.
- *
- * @param {object} transform
- * The transform definition to use as explained in the
- * {@link https://www.highcharts.com/docs/maps/latlon|documentation}.
- *
- * @return {Highcharts.MapCoordinateObject}
- * An object with `x` and `y` properties.
- */
- Chart.prototype.transformFromLatLon = function (latLon, transform) {
- if (win.proj4 === undefined) {
- H.error(21, false, this);
- return {
- x: 0,
- y: null
- };
- }
- var projected = win.proj4(transform.crs, [latLon.lon, latLon.lat]),
- cosAngle = transform.cosAngle ||
- (transform.rotation && Math.cos(transform.rotation)),
- sinAngle = transform.sinAngle ||
- (transform.rotation && Math.sin(transform.rotation)),
- rotated = transform.rotation ? [
- projected[0] * cosAngle + projected[1] * sinAngle,
- -projected[0] * sinAngle + projected[1] * cosAngle
- ] : projected;
- return {
- x: (
- (rotated[0] - (transform.xoffset || 0)) * (transform.scale || 1) +
- (transform.xpan || 0)
- ) * (transform.jsonres || 1) +
- (transform.jsonmarginX || 0),
- y: (
- ((transform.yoffset || 0) - rotated[1]) * (transform.scale || 1) +
- (transform.ypan || 0)
- ) * (transform.jsonres || 1) -
- (transform.jsonmarginY || 0)
- };
- };
- /**
- * Highmaps only. Get latLon from point using specified transform definition.
- * The method returns an object with the numeric properties `lat` and `lon`.
- *
- * @requires module:modules/map
- *
- * @sample maps/series/latlon-transform/
- * Use specific transformation for lat/lon
- *
- * @function Highcharts.Chart#transformToLatLon
- *
- * @param {Highcharts.Point|Highcharts.MapCoordinateObject} point
- * A `Point` instance, or any object containing the properties `x` and
- * `y` with numeric values.
- *
- * @param {object} transform
- * The transform definition to use as explained in the
- * {@link https://www.highcharts.com/docs/maps/latlon|documentation}.
- *
- * @return {Highcharts.MapLatLonObject}
- * An object with `lat` and `lon` properties.
- */
- Chart.prototype.transformToLatLon = function (point, transform) {
- if (win.proj4 === undefined) {
- H.error(21, false, this);
- return;
- }
- var normalized = {
- x: (
- (
- point.x -
- (transform.jsonmarginX || 0)
- ) / (transform.jsonres || 1) -
- (transform.xpan || 0)
- ) / (transform.scale || 1) +
- (transform.xoffset || 0),
- y: (
- (
- -point.y - (transform.jsonmarginY || 0)
- ) / (transform.jsonres || 1) +
- (transform.ypan || 0)
- ) / (transform.scale || 1) +
- (transform.yoffset || 0)
- },
- cosAngle = transform.cosAngle ||
- (transform.rotation && Math.cos(transform.rotation)),
- sinAngle = transform.sinAngle ||
- (transform.rotation && Math.sin(transform.rotation)),
- // Note: Inverted sinAngle to reverse rotation direction
- projected = win.proj4(transform.crs, 'WGS84', transform.rotation ? {
- x: normalized.x * cosAngle + normalized.y * -sinAngle,
- y: normalized.x * sinAngle + normalized.y * cosAngle
- } : normalized);
- return { lat: projected.y, lon: projected.x };
- };
- /**
- * Highmaps only. Calculate latitude/longitude values for a point. Returns an
- * object with the numeric properties `lat` and `lon`.
- *
- * @requires module:modules/map
- *
- * @sample maps/demo/latlon-advanced/
- * Advanced lat/lon demo
- *
- * @function Highcharts.Chart#fromPointToLatLon
- *
- * @param {Highcharts.Point|Highcharts.MapCoordinateObject} point
- * A `Point` instance or anything containing `x` and `y` properties with
- * numeric values.
- *
- * @return {Highcharts.MapLatLonObject}
- * An object with `lat` and `lon` properties.
- */
- Chart.prototype.fromPointToLatLon = function (point) {
- var transforms = this.mapTransforms,
- transform;
- if (!transforms) {
- H.error(22, false, this);
- return;
- }
- for (transform in transforms) {
- if (
- transforms.hasOwnProperty(transform) &&
- transforms[transform].hitZone &&
- pointInPolygon(
- { x: point.x, y: -point.y },
- transforms[transform].hitZone.coordinates[0]
- )
- ) {
- return this.transformToLatLon(point, transforms[transform]);
- }
- }
- return this.transformToLatLon(
- point,
- transforms['default'] // eslint-disable-line dot-notation
- );
- };
- /**
- * Highmaps only. Get chart coordinates from latitude/longitude. Returns an
- * object with x and y values corresponding to the `xAxis` and `yAxis`.
- *
- * @requires module:modules/map
- *
- * @sample maps/series/latlon-to-point/
- * Find a point from lat/lon
- *
- * @function Highcharts.Chart#fromLatLonToPoint
- *
- * @param {Highcharts.MapLatLonObject} latLon
- * Coordinates.
- *
- * @return {Highcharts.MapCoordinateObject}
- * X and Y coordinates in terms of chart axis values.
- */
- Chart.prototype.fromLatLonToPoint = function (latLon) {
- var transforms = this.mapTransforms,
- transform,
- coords;
- if (!transforms) {
- H.error(22, false, this);
- return {
- x: 0,
- y: null
- };
- }
- for (transform in transforms) {
- if (
- transforms.hasOwnProperty(transform) &&
- transforms[transform].hitZone
- ) {
- coords = this.transformFromLatLon(latLon, transforms[transform]);
- if (pointInPolygon(
- { x: coords.x, y: -coords.y },
- transforms[transform].hitZone.coordinates[0]
- )) {
- return coords;
- }
- }
- }
- return this.transformFromLatLon(
- latLon,
- transforms['default'] // eslint-disable-line dot-notation
- );
- };
- /**
- * Highmaps only. Restructure a GeoJSON object in preparation to be read
- * directly by the
- * {@link https://api.highcharts.com/highmaps/plotOptions.series.mapData|series.mapData}
- * option. The GeoJSON will be broken down to fit a specific Highcharts type,
- * either `map`, `mapline` or `mappoint`. Meta data in GeoJSON's properties
- * object will be copied directly over to {@link Point.properties} in Highmaps.
- *
- * @requires module:modules/map
- *
- * @sample maps/demo/geojson/
- * Simple areas
- * @sample maps/demo/geojson-multiple-types/
- * Multiple types
- *
- * @function Highcharts.geojson
- *
- * @param {object} geojson
- * The GeoJSON structure to parse, represented as a JavaScript object
- * rather than a JSON string.
- *
- * @param {string} [hType=map]
- * The Highmaps series type to prepare for. Setting "map" will return
- * GeoJSON polygons and multipolygons. Setting "mapline" will return
- * GeoJSON linestrings and multilinestrings. Setting "mappoint" will
- * return GeoJSON points and multipoints.
- *
- * @return {Array<object>}
- * An object ready for the `mapData` option.
- */
- H.geojson = function (geojson, hType, series) {
- var mapData = [],
- path = [],
- polygonToPath = function (polygon) {
- var i,
- len = polygon.length;
- path.push('M');
- for (i = 0; i < len; i++) {
- if (i === 1) {
- path.push('L');
- }
- path.push(polygon[i][0], -polygon[i][1]);
- }
- };
- hType = hType || 'map';
- geojson.features.forEach(function (feature) {
- var geometry = feature.geometry,
- type = geometry.type,
- coordinates = geometry.coordinates,
- properties = feature.properties,
- point;
- path = [];
- if (hType === 'map' || hType === 'mapbubble') {
- if (type === 'Polygon') {
- coordinates.forEach(polygonToPath);
- path.push('Z');
- } else if (type === 'MultiPolygon') {
- coordinates.forEach(function (items) {
- items.forEach(polygonToPath);
- });
- path.push('Z');
- }
- if (path.length) {
- point = { path: path };
- }
- } else if (hType === 'mapline') {
- if (type === 'LineString') {
- polygonToPath(coordinates);
- } else if (type === 'MultiLineString') {
- coordinates.forEach(polygonToPath);
- }
- if (path.length) {
- point = { path: path };
- }
- } else if (hType === 'mappoint') {
- if (type === 'Point') {
- point = {
- x: coordinates[0],
- y: -coordinates[1]
- };
- }
- }
- if (point) {
- mapData.push(extend(point, {
- name: properties.name || properties.NAME,
- /**
- * In Highmaps, when data is loaded from GeoJSON, the GeoJSON
- * item's properies are copied over here.
- *
- * @requires module:modules/map
- * @name Highcharts.Point#properties
- * @type {*}
- */
- properties: properties
- }));
- }
- });
- // Create a credits text that includes map source, to be picked up in
- // Chart.addCredits
- if (series && geojson.copyrightShort) {
- series.chart.mapCredits = format(
- series.chart.options.credits.mapText,
- { geojson: geojson }
- );
- series.chart.mapCreditsFull = format(
- series.chart.options.credits.mapTextFull,
- { geojson: geojson }
- );
- }
- return mapData;
- };
- // Override addCredits to include map source by default
- wrap(Chart.prototype, 'addCredits', function (proceed, credits) {
- credits = merge(true, this.options.credits, credits);
- // Disable credits link if map credits enabled. This to allow for in-text
- // anchors.
- if (this.mapCredits) {
- credits.href = null;
- }
- proceed.call(this, credits);
- // Add full map credits to hover
- if (this.credits && this.mapCreditsFull) {
- this.credits.attr({
- title: this.mapCreditsFull
- });
- }
- });
|