initial commit

This commit is contained in:
2021-07-10 16:25:16 +02:00
parent bff57cbf45
commit 20fb7267a8
2426 changed files with 792090 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,138 @@
/**
* (c) 2010-2019 Torstein Honsi
*
* License: www.highcharts.com/license
*/
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
var defined = H.defined,
noop = H.noop,
seriesTypes = H.seriesTypes;
/**
* Mixin for maps and heatmaps
*
* @private
* @mixin Highcharts.colorPointMixin
*/
H.colorPointMixin = {
/**
* Color points have a value option that determines whether or not it is
* a null point
*
* @function Highcharts.colorPointMixin.isValid
*
* @return {boolean}
*/
isValid: function () {
// undefined is allowed
return (
this.value !== null &&
this.value !== Infinity &&
this.value !== -Infinity
);
},
/**
* Set the visibility of a single point
*
* @function Highcharts.colorPointMixin.setVisible
*
* @param {boolean} visible
*/
setVisible: function (vis) {
var point = this,
method = vis ? 'show' : 'hide';
point.visible = Boolean(vis);
// Show and hide associated elements
['graphic', 'dataLabel'].forEach(function (key) {
if (point[key]) {
point[key][method]();
}
});
},
/**
* @function Highcharts.colorPointMixin.setState
*
* @param {string} state
*/
setState: function (state) {
H.Point.prototype.setState.call(this, state);
if (this.graphic) {
this.graphic.attr({
zIndex: state === 'hover' ? 1 : 0
});
}
}
};
/**
* @private
* @mixin Highcharts.colorSeriesMixin
*/
H.colorSeriesMixin = {
pointArrayMap: ['value'],
axisTypes: ['xAxis', 'yAxis', 'colorAxis'],
optionalAxis: 'colorAxis',
trackerGroups: ['group', 'markerGroup', 'dataLabelsGroup'],
getSymbol: noop,
parallelArrays: ['x', 'y', 'value'],
colorKey: 'value',
pointAttribs: seriesTypes.column.prototype.pointAttribs,
/**
* In choropleth maps, the color is a result of the value, so this needs
* translation too
*
* @function Highcharts.colorSeriesMixin.translateColors
*/
translateColors: function () {
var series = this,
nullColor = this.options.nullColor,
colorAxis = this.colorAxis,
colorKey = this.colorKey;
this.data.forEach(function (point) {
var value = point[colorKey],
color;
color = point.options.color ||
(
point.isNull ?
nullColor :
(colorAxis && value !== undefined) ?
colorAxis.toColor(value, point) :
point.color || series.color
);
if (color) {
point.color = color;
}
});
},
/**
* Get the color attibutes to apply on the graphic
*
* @function Highcharts.colorSeriesMixin.colorAttribs
*
* @param {Highcharts.Point} point
*
* @return {Highcharts.Dictionary<Highcharts.ColorString>}
*/
colorAttribs: function (point) {
var ret = {};
if (defined(point.color)) {
ret[this.colorProp || 'fill'] = point.color;
}
return ret;
}
};
@@ -0,0 +1,435 @@
/**
* (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
});
}
});
@@ -0,0 +1,474 @@
/**
* (c) 2010-2019 Torstein Honsi
*
* License: www.highcharts.com/license
*/
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
import '../parts/Options.js';
import '../parts/Point.js';
import '../parts/Series.js';
import '../parts/Legend.js';
import './ColorSeriesMixin.js';
var colorPointMixin = H.colorPointMixin,
colorSeriesMixin = H.colorSeriesMixin,
LegendSymbolMixin = H.LegendSymbolMixin,
merge = H.merge,
noop = H.noop,
pick = H.pick,
Series = H.Series,
seriesType = H.seriesType,
seriesTypes = H.seriesTypes;
/**
* @private
* @class
* @name Highcharts.seriesTypes.heatmap
*
* @augments Highcharts.Series
*/
seriesType(
'heatmap',
'scatter',
/**
* A heatmap is a graphical representation of data where the individual
* values contained in a matrix are represented as colors.
*
* @sample highcharts/demo/heatmap/
* Simple heatmap
* @sample highcharts/demo/heatmap-canvas/
* Heavy heatmap
*
* @extends plotOptions.scatter
* @excluding animationLimit, connectEnds, connectNulls, dashStyle,
* findNearestPointBy, getExtremesFromAll, jitter, linecap,
* lineWidth, marker, pointInterval, pointIntervalUnit,
* pointRange, pointStart, shadow, softThreshold, stacking,
* step, threshold
* @product highcharts highmaps
* @optionparent plotOptions.heatmap
*/
{
/**
* Animation is disabled by default on the heatmap series.
*/
animation: false,
/**
* The border width for each heat map item.
*/
borderWidth: 0,
/**
* Padding between the points in the heatmap.
*
* @type {number}
* @default 0
* @since 6.0
* @apioption plotOptions.heatmap.pointPadding
*/
/**
* The main color of the series. In heat maps this color is rarely used,
* as we mostly use the color to denote the value of each point. Unless
* options are set in the [colorAxis](#colorAxis), the default value
* is pulled from the [options.colors](#colors) array.
*
* @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
* @since 4.0
* @product highcharts
* @apioption plotOptions.heatmap.color
*/
/**
* The column size - how many X axis units each column in the heatmap
* should span.
*
* @sample {highcharts} maps/demo/heatmap/
* One day
* @sample {highmaps} maps/demo/heatmap/
* One day
*
* @type {number}
* @default 1
* @since 4.0
* @product highcharts highmaps
* @apioption plotOptions.heatmap.colsize
*/
/**
* The row size - how many Y axis units each heatmap row should span.
*
* @sample {highcharts} maps/demo/heatmap/
* 1 by default
* @sample {highmaps} maps/demo/heatmap/
* 1 by default
*
* @type {number}
* @default 1
* @since 4.0
* @product highcharts highmaps
* @apioption plotOptions.heatmap.rowsize
*/
/**
* The color applied to null points. In styled mode, a general CSS class
* is applied instead.
*
* @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
*/
nullColor: '#f7f7f7',
dataLabels: {
formatter: function () { // #2945
return this.point.value;
},
inside: true,
verticalAlign: 'middle',
crop: false,
overflow: false,
padding: 0 // #3837
},
/** @ignore */
marker: null,
/**
* @ignore
*/
pointRange: null, // dynamically set to colsize by default
tooltip: {
pointFormat: '{point.x}, {point.y}: {point.value}<br/>'
},
states: {
hover: {
/** @ignore */
halo: false, // #3406, halo is disabled on heatmaps by default
/**
* How much to brighten the point on interaction. Requires the main
* color to be defined in hex or rgb(a) format.
*
* In styled mode, the hover brightening is by default replaced with
* a fill-opacity set in the `.highcharts-point:hover` rule.
*/
brightness: 0.2
}
}
}, merge(colorSeriesMixin, {
pointArrayMap: ['y', 'value'],
hasPointSpecificOptions: true,
getExtremesFromAll: true,
directTouch: true,
/**
* Override the init method to add point ranges on both axes.
*
* @private
* @function Highcharts.seriesTypes.heatmap#init
*/
init: function () {
var options;
seriesTypes.scatter.prototype.init.apply(this, arguments);
options = this.options;
// #3758, prevent resetting in setData
options.pointRange = pick(options.pointRange, options.colsize || 1);
// general point range
this.yAxis.axisPointRange = options.rowsize || 1;
},
/**
* @private
* @function Highcharts.seriesTypes.heatmap#translate
*/
translate: function () {
var series = this,
options = series.options,
xAxis = series.xAxis,
yAxis = series.yAxis,
seriesPointPadding = options.pointPadding || 0,
between = function (x, a, b) {
return Math.min(Math.max(a, x), b);
},
pointPlacement = series.pointPlacementToXValue(); // #7860
series.generatePoints();
series.points.forEach(function (point) {
var xPad = (options.colsize || 1) / 2,
yPad = (options.rowsize || 1) / 2,
x1 = between(
Math.round(
xAxis.len -
xAxis.translate(point.x - xPad,
0,
1,
0,
1,
-pointPlacement)
),
-xAxis.len, 2 * xAxis.len
),
x2 = between(
Math.round(
xAxis.len -
xAxis.translate(point.x + xPad,
0,
1,
0,
1,
-pointPlacement)
),
-xAxis.len, 2 * xAxis.len
),
y1 = between(
Math.round(yAxis.translate(point.y - yPad, 0, 1, 0, 1)),
-yAxis.len, 2 * yAxis.len
),
y2 = between(
Math.round(yAxis.translate(point.y + yPad, 0, 1, 0, 1)),
-yAxis.len, 2 * yAxis.len
),
pointPadding = pick(point.pointPadding, seriesPointPadding);
// Set plotX and plotY for use in K-D-Tree and more
point.plotX = point.clientX = (x1 + x2) / 2;
point.plotY = (y1 + y2) / 2;
point.shapeType = 'rect';
point.shapeArgs = {
x: Math.min(x1, x2) + pointPadding,
y: Math.min(y1, y2) + pointPadding,
width: Math.abs(x2 - x1) - pointPadding * 2,
height: Math.abs(y2 - y1) - pointPadding * 2
};
});
series.translateColors();
},
/**
* @private
* @function Highcharts.seriesTypes.heatmap#drawPoints
*/
drawPoints: function () {
// In styled mode, use CSS, otherwise the fill used in the style
// sheet will take precedence over the fill attribute.
var func = this.chart.styledMode ? 'css' : 'attr';
seriesTypes.column.prototype.drawPoints.call(this);
this.points.forEach(function (point) {
point.graphic[func](this.colorAttribs(point));
}, this);
},
// Override to also allow null points, used when building the k-d-tree
// for tooltips in boost mode.
getValidPoints: function (points, insideOnly) {
return Series.prototype.getValidPoints.call(
this,
points,
insideOnly,
true
);
},
/**
* @ignore
* @deprecated
* @function Highcharts.seriesTypes.heatmap#animate
*/
animate: noop,
/**
* @ignore
* @deprecated
* @function Highcharts.seriesTypes.heatmap#getBox
*/
getBox: noop,
/**
* @private
* @borrows Highcharts.LegendSymbolMixin.drawRectangle as Highcharts.seriesTypes.heatmap#drawLegendSymbol
*/
drawLegendSymbol: LegendSymbolMixin.drawRectangle,
/**
* @private
* @borrows Highcharts.seriesTypes.column#alignDataLabel as Highcharts.seriesTypes.heatmap#alignDataLabel
*/
alignDataLabel: seriesTypes.column.prototype.alignDataLabel,
/**
* @private
* @function Highcharts.seriesTypes.heatmap#getExtremes
*/
getExtremes: function () {
// Get the extremes from the value data
Series.prototype.getExtremes.call(this, this.valueData);
this.valueMin = this.dataMin;
this.valueMax = this.dataMax;
// Get the extremes from the y data
Series.prototype.getExtremes.call(this);
}
}), H.extend({
/**
* @private
* @function Highcharts.Point#haloPath
*
* @param {number} size
*
* @return {Highcharts.SVGPathArray}
*/
haloPath: function (size) {
if (!size) {
return [];
}
var rect = this.shapeArgs;
return [
'M', rect.x - size, rect.y - size,
'L', rect.x - size, rect.y + rect.height + size,
rect.x + rect.width + size, rect.y + rect.height + size,
rect.x + rect.width + size, rect.y - size,
'Z'
];
}
}, colorPointMixin)
);
/**
* A `heatmap` series. If the [type](#series.heatmap.type) option is
* not specified, it is inherited from [chart.type](#chart.type).
*
* @extends series,plotOptions.heatmap
* @excluding dataParser, dataURL, marker, pointRange, stack
* @product highcharts highmaps
* @apioption series.heatmap
*/
/**
* An array of data points for the series. For the `heatmap` series
* type, points can be given in the following ways:
*
* 1. An array of arrays with 3 or 2 values. In this case, the values
* correspond to `x,y,value`. If the first value is a string, it is
* applied as the name of the point, and the `x` value is inferred.
* The `x` value can also be omitted, in which case the inner arrays
* should be of length 2\. Then the `x` value is automatically calculated,
* either starting at 0 and incremented by 1, or from `pointStart`
* and `pointInterval` given in the series options.
*
* ```js
* data: [
* [0, 9, 7],
* [1, 10, 4],
* [2, 6, 3]
* ]
* ```
*
* 2. An array of objects with named values. The following snippet shows only a
* few settings, see the complete options set below. If the total number of data
* points exceeds the series' [turboThreshold](#series.heatmap.turboThreshold),
* this option is not available.
*
* ```js
* data: [{
* x: 1,
* y: 3,
* value: 10,
* name: "Point2",
* color: "#00FF00"
* }, {
* x: 1,
* y: 7,
* value: 10,
* name: "Point1",
* color: "#FF00FF"
* }]
* ```
*
* @sample {highcharts} highcharts/chart/reflow-true/
* Numerical values
* @sample {highcharts} highcharts/series/data-array-of-arrays/
* Arrays of numeric x and y
* @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
* Arrays of datetime x and y
* @sample {highcharts} highcharts/series/data-array-of-name-value/
* Arrays of point.name and y
* @sample {highcharts} highcharts/series/data-array-of-objects/
* Config objects
*
* @type {Array<Array<number>|*>}
* @extends series.line.data
* @excluding marker
* @product highcharts highmaps
* @apioption series.heatmap.data
*/
/**
* The color of the point. In heat maps the point color is rarely set
* explicitly, as we use the color to denote the `value`. Options for
* this are set in the [colorAxis](#colorAxis) configuration.
*
* @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
* @product highcharts highmaps
* @apioption series.heatmap.data.color
*/
/**
* The value of the point, resulting in a color controled by options
* as set in the [colorAxis](#colorAxis) configuration.
*
* @type {number}
* @product highcharts highmaps
* @apioption series.heatmap.data.value
*/
/**
* The x value of the point. For datetime axes,
* the X value is the timestamp in milliseconds since 1970.
*
* @type {number}
* @product highcharts highmaps
* @apioption series.heatmap.data.x
*/
/**
* The y value of the point.
*
* @type {number}
* @product highcharts highmaps
* @apioption series.heatmap.data.y
*/
/**
* Point padding for a single point.
*
* @sample maps/plotoptions/tilemap-pointpadding
* Point padding on tiles
*
* @type {number}
* @product highcharts highmaps
* @apioption series.heatmap.data.pointPadding
*/
@@ -0,0 +1,477 @@
/**
* (c) 2010-2019 Torstein Honsi
*
* License: www.highcharts.com/license
*/
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
import '../parts/Options.js';
import '../parts/Chart.js';
import '../parts/SvgRenderer.js';
var Chart = H.Chart,
defaultOptions = H.defaultOptions,
extend = H.extend,
merge = H.merge,
pick = H.pick,
Renderer = H.Renderer,
SVGRenderer = H.SVGRenderer,
VMLRenderer = H.VMLRenderer;
// Add language
extend(defaultOptions.lang, {
zoomIn: 'Zoom in',
zoomOut: 'Zoom out'
});
// Set the default map navigation options
/**
* @product highmaps
* @optionparent mapNavigation
*/
defaultOptions.mapNavigation = {
/**
* General options for the map navigation buttons. Individual options
* can be given from the [mapNavigation.buttons](#mapNavigation.buttons)
* option set.
*
* @sample {highmaps} maps/mapnavigation/button-theme/
* Theming the navigation buttons
*/
buttonOptions: {
/**
* What box to align the buttons to. Possible values are `plotBox`
* and `spacingBox`.
*
* @validvalue ["plotBox", "spacingBox"]
*/
alignTo: 'plotBox',
/**
* The alignment of the navigation buttons.
*
* @type {Highcharts.AlignType}
*/
align: 'left',
/**
* The vertical alignment of the buttons. Individual alignment can
* be adjusted by each button's `y` offset.
*
* @type {Highcharts.VerticalAlignType}
*/
verticalAlign: 'top',
/**
* The X offset of the buttons relative to its `align` setting.
*/
x: 0,
/**
* The width of the map navigation buttons.
*/
width: 18,
/**
* The pixel height of the map navigation buttons.
*/
height: 18,
/**
* Padding for the navigation buttons.
*
* @since 5.0.0
*/
padding: 5,
/**
* Text styles for the map navigation buttons.
*
* @type {Highcharts.CSSObject}
* @default {"fontSize": "15px", "fontWeight": "bold"}
*/
style: {
/** @ignore */
fontSize: '15px',
/** @ignore */
fontWeight: 'bold'
},
/**
* A configuration object for the button theme. The object accepts
* SVG properties like `stroke-width`, `stroke` and `fill`. Tri-state
* button styles are supported by the `states.hover` and `states.select`
* objects.
*
* @sample {highmaps} maps/mapnavigation/button-theme/
* Themed navigation buttons
*
* @type {Highcharts.SVGAttributes}
* @default {"stroke-width": 1, "text-align": "center"}
*/
theme: {
/** @ignore */
'stroke-width': 1,
/** @ignore */
'text-align': 'center'
}
},
/**
* The individual buttons for the map navigation. This usually includes
* the zoom in and zoom out buttons. Properties for each button is
* inherited from
* [mapNavigation.buttonOptions](#mapNavigation.buttonOptions), while
* individual options can be overridden. But default, the `onclick`, `text`
* and `y` options are individual.
*/
buttons: {
/**
* Options for the zoom in button. Properties for the zoom in and zoom
* out buttons are inherited from
* [mapNavigation.buttonOptions](#mapNavigation.buttonOptions), while
* individual options can be overridden. By default, the `onclick`,
* `text` and `y` options are individual.
*
* @extends mapNavigation.buttonOptions
*/
zoomIn: {
/**
* Click handler for the button.
*
* @type {Function}
* @default function () { this.mapZoom(0.5); }
*/
onclick: function () {
this.mapZoom(0.5);
},
/**
* The text for the button. The tooltip (title) is a language option
* given by [lang.zoomIn](#lang.zoomIn).
*/
text: '+',
/**
* The position of the zoomIn button relative to the vertical
* alignment.
*/
y: 0
},
/**
* Options for the zoom out button. Properties for the zoom in and
* zoom out buttons are inherited from
* [mapNavigation.buttonOptions](#mapNavigation.buttonOptions), while
* individual options can be overridden. By default, the `onclick`,
* `text` and `y` options are individual.
*
* @extends mapNavigation.buttonOptions
*/
zoomOut: {
/**
* Click handler for the button.
*
* @type {Function}
* @default function () { this.mapZoom(2); }
*/
onclick: function () {
this.mapZoom(2);
},
/**
* The text for the button. The tooltip (title) is a language option
* given by [lang.zoomOut](#lang.zoomIn).
*/
text: '-',
/**
* The position of the zoomOut button relative to the vertical
* alignment.
*/
y: 28
}
},
/**
* Whether to enable navigation buttons. By default it inherits the
* [enabled](#mapNavigation.enabled) setting.
*
* @type {boolean}
* @apioption mapNavigation.enableButtons
*/
/**
* Whether to enable map navigation. The default is not to enable
* navigation, as many choropleth maps are simple and don't need it.
* Additionally, when touch zoom and mousewheel zoom is enabled, it breaks
* the default behaviour of these interactions in the website, and the
* implementer should be aware of this.
*
* Individual interactions can be enabled separately, namely buttons,
* multitouch zoom, double click zoom, double click zoom to element and
* mousewheel zoom.
*
* @type {boolean}
* @default false
* @apioption mapNavigation.enabled
*/
/**
* Enables zooming in on an area on double clicking in the map. By default
* it inherits the [enabled](#mapNavigation.enabled) setting.
*
* @type {boolean}
* @apioption mapNavigation.enableDoubleClickZoom
*/
/**
* Whether to zoom in on an area when that area is double clicked.
*
* @sample {highmaps} maps/mapnavigation/doubleclickzoomto/
* Enable double click zoom to
*
* @type {boolean}
* @default false
* @apioption mapNavigation.enableDoubleClickZoomTo
*/
/**
* Enables zooming by mouse wheel. By default it inherits the [enabled](
* #mapNavigation.enabled) setting.
*
* @type {boolean}
* @apioption mapNavigation.enableMouseWheelZoom
*/
/**
* Whether to enable multitouch zooming. Note that if the chart covers the
* viewport, this prevents the user from using multitouch and touchdrag on
* the web page, so you should make sure the user is not trapped inside the
* chart. By default it inherits the [enabled](#mapNavigation.enabled)
* setting.
*
* @type {boolean}
* @apioption mapNavigation.enableTouchZoom
*/
/**
* Sensitivity of mouse wheel or trackpad scrolling. 1 is no sensitivity,
* while with 2, one mousewheel delta will zoom in 50%.
*
* @since 4.2.4
*/
mouseWheelSensitivity: 1.1
// enabled: false,
// enableButtons: null, // inherit from enabled
// enableTouchZoom: null, // inherit from enabled
// enableDoubleClickZoom: null, // inherit from enabled
// enableDoubleClickZoomTo: false
// enableMouseWheelZoom: null, // inherit from enabled
};
/**
* Utility for reading SVG paths directly.
*
* @requires module:modules/map
*
* @function Highcharts.splitPath
*
* @param {string} path
*
* @return {Highcharts.SVGPathArray}
*/
H.splitPath = function (path) {
var i;
// Move letters apart
path = path.replace(/([A-Za-z])/g, ' $1 ');
// Trim
path = path.replace(/^\s*/, '').replace(/\s*$/, '');
// Split on spaces and commas
path = path.split(/[ ,]+/); // Extra comma to escape gulp.scripts task
// Parse numbers
for (i = 0; i < path.length; i++) {
if (!/[a-zA-Z]/.test(path[i])) {
path[i] = parseFloat(path[i]);
}
}
return path;
};
/**
* Contains all loaded map data for Highmaps.
*
* @requires module:modules/map
*
* @name Highcharts.maps
* @type {Highcharts.Dictionary<Highcharts.MapDataObject>}
*/
H.maps = {};
// Create symbols for the zoom buttons
function selectiveRoundedRect(
x,
y,
w,
h,
rTopLeft,
rTopRight,
rBottomRight,
rBottomLeft
) {
return [
'M', x + rTopLeft, y,
// top side
'L', x + w - rTopRight, y,
// top right corner
'C', x + w - rTopRight / 2,
y, x + w,
y + rTopRight / 2, x + w, y + rTopRight,
// right side
'L', x + w, y + h - rBottomRight,
// bottom right corner
'C', x + w, y + h - rBottomRight / 2,
x + w - rBottomRight / 2, y + h,
x + w - rBottomRight, y + h,
// bottom side
'L', x + rBottomLeft, y + h,
// bottom left corner
'C', x + rBottomLeft / 2, y + h,
x, y + h - rBottomLeft / 2,
x, y + h - rBottomLeft,
// left side
'L', x, y + rTopLeft,
// top left corner
'C', x, y + rTopLeft / 2,
x + rTopLeft / 2, y,
x + rTopLeft, y,
'Z'
];
}
SVGRenderer.prototype.symbols.topbutton = function (x, y, w, h, attr) {
return selectiveRoundedRect(x - 1, y - 1, w, h, attr.r, attr.r, 0, 0);
};
SVGRenderer.prototype.symbols.bottombutton = function (x, y, w, h, attr) {
return selectiveRoundedRect(x - 1, y - 1, w, h, 0, 0, attr.r, attr.r);
};
// The symbol callbacks are generated on the SVGRenderer object in all browsers.
// Even VML browsers need this in order to generate shapes in export. Now share
// them with the VMLRenderer.
if (Renderer === VMLRenderer) {
['topbutton', 'bottombutton'].forEach(function (shape) {
VMLRenderer.prototype.symbols[shape] =
SVGRenderer.prototype.symbols[shape];
});
}
/**
* The factory function for creating new map charts. Creates a new {@link
* Highcharts.Chart|Chart} object with different default options than the basic
* Chart.
*
* @requires module:modules/map
*
* @function Highcharts.mapChart
*
* @param {string|Highcharts.HTMLDOMElement} [renderTo]
* The DOM element to render to, or its id.
*
* @param {Highcharts.Options} options
* The chart options structure as described in the
* [options reference](https://api.highcharts.com/highstock).
*
* @param {Highcharts.ChartCallbackFunction} [callback]
* A function to execute when the chart object is finished loading and
* rendering. In most cases the chart is built in one thread, but in
* Internet Explorer version 8 or less the chart is sometimes
* initialized before the document is ready, and in these cases the
* chart object will not be finished synchronously. As a consequence,
* code that relies on the newly built Chart object should always run in
* the callback. Defining a
* [chart.events.load](https://api.highcharts.com/highstock/chart.events.load)
* handler is equivalent.
*
* @return {Highcharts.Chart}
* The chart object.
*/
H.Map = H.mapChart = function (a, b, c) {
var hasRenderToArg = typeof a === 'string' || a.nodeName,
options = arguments[hasRenderToArg ? 1 : 0],
userOptions = options,
hiddenAxis = {
endOnTick: false,
visible: false,
minPadding: 0,
maxPadding: 0,
startOnTick: false
},
seriesOptions,
defaultCreditsOptions = H.getOptions().credits;
/* For visual testing
hiddenAxis.gridLineWidth = 1;
hiddenAxis.gridZIndex = 10;
hiddenAxis.tickPositions = undefined;
// */
// Don't merge the data
seriesOptions = options.series;
options.series = null;
options = merge(
{
chart: {
panning: 'xy',
type: 'map'
},
credits: {
mapText: pick(
defaultCreditsOptions.mapText,
' \u00a9 <a href="{geojson.copyrightUrl}">' +
'{geojson.copyrightShort}</a>'
),
mapTextFull: pick(
defaultCreditsOptions.mapTextFull,
'{geojson.copyright}'
)
},
tooltip: {
followTouchMove: false
},
xAxis: hiddenAxis,
yAxis: merge(hiddenAxis, { reversed: true })
},
options, // user's options
{ // forced options
chart: {
inverted: false,
alignTicks: false
}
}
);
options.series = userOptions.series = seriesOptions;
return hasRenderToArg ?
new Chart(a, options, c) :
new Chart(options, b);
};
@@ -0,0 +1,124 @@
/**
* (c) 2010-2019 Torstein Honsi
*
* License: www.highcharts.com/license
*/
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
import '../parts/Axis.js';
var addEvent = H.addEvent,
Axis = H.Axis,
pick = H.pick;
// Override to use the extreme coordinates from the SVG shape, not the data
// values
addEvent(Axis, 'getSeriesExtremes', function () {
var xData = [];
// Remove the xData array and cache it locally so that the proceed method
// doesn't use it
if (this.isXAxis) {
this.series.forEach(function (series, i) {
if (series.useMapGeometry) {
xData[i] = series.xData;
series.xData = [];
}
});
this.seriesXData = xData;
}
});
addEvent(Axis, 'afterGetSeriesExtremes', function () {
var xData = this.seriesXData,
dataMin,
dataMax,
useMapGeometry;
// Run extremes logic for map and mapline
if (this.isXAxis) {
dataMin = pick(this.dataMin, Number.MAX_VALUE);
dataMax = pick(this.dataMax, -Number.MAX_VALUE);
this.series.forEach(function (series, i) {
if (series.useMapGeometry) {
dataMin = Math.min(dataMin, pick(series.minX, dataMin));
dataMax = Math.max(dataMax, pick(series.maxX, dataMax));
series.xData = xData[i]; // Reset xData array
useMapGeometry = true;
}
});
if (useMapGeometry) {
this.dataMin = dataMin;
this.dataMax = dataMax;
}
delete this.seriesXData;
}
});
// Override axis translation to make sure the aspect ratio is always kept
addEvent(Axis, 'afterSetAxisTranslation', function () {
var chart = this.chart,
mapRatio,
plotRatio = chart.plotWidth / chart.plotHeight,
adjustedAxisLength,
xAxis = chart.xAxis[0],
padAxis,
fixTo,
fixDiff,
preserveAspectRatio;
// Check for map-like series
if (this.coll === 'yAxis' && xAxis.transA !== undefined) {
this.series.forEach(function (series) {
if (series.preserveAspectRatio) {
preserveAspectRatio = true;
}
});
}
// On Y axis, handle both
if (preserveAspectRatio) {
// Use the same translation for both axes
this.transA = xAxis.transA = Math.min(this.transA, xAxis.transA);
mapRatio = plotRatio /
((xAxis.max - xAxis.min) / (this.max - this.min));
// What axis to pad to put the map in the middle
padAxis = mapRatio < 1 ? this : xAxis;
// Pad it
adjustedAxisLength = (padAxis.max - padAxis.min) * padAxis.transA;
padAxis.pixelPadding = padAxis.len - adjustedAxisLength;
padAxis.minPixelPadding = padAxis.pixelPadding / 2;
fixTo = padAxis.fixTo;
if (fixTo) {
fixDiff = fixTo[1] - padAxis.toValue(fixTo[0], true);
fixDiff *= padAxis.transA;
if (
Math.abs(fixDiff) > padAxis.minPixelPadding ||
(
padAxis.min === padAxis.dataMin &&
padAxis.max === padAxis.dataMax
)
) { // zooming out again, keep within restricted area
fixDiff = 0;
}
padAxis.minPixelPadding -= fixDiff;
}
}
});
// Override Axis.render in order to delete the fixTo prop
addEvent(Axis, 'render', function () {
this.fixTo = null;
});
@@ -0,0 +1,274 @@
/**
* (c) 2010-2019 Torstein Honsi
*
* License: www.highcharts.com/license
*/
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
import '../parts/Options.js';
import '../parts/Point.js';
import '../parts-more/BubbleSeries.js';
var merge = H.merge,
Point = H.Point,
seriesType = H.seriesType,
seriesTypes = H.seriesTypes;
// The mapbubble series type
if (seriesTypes.bubble) {
/**
* @private
* @class
* @name Highcharts.seriesTypes.mapbubble
*
* @augments Highcharts.Series
*/
seriesType('mapbubble', 'bubble'
/**
* A map bubble series is a bubble series laid out on top of a map series,
* where each bubble is tied to a specific map area.
*
* @sample maps/demo/map-bubble/
* Map bubble chart
*
* @extends plotOptions.bubble
* @product highmaps
* @optionparent plotOptions.mapbubble
*/
, {
/**
* The main color of the series. This color affects both the fill and
* the stroke of the bubble. For enhanced control, use `marker` options.
*
* @sample {highmaps} maps/plotoptions/mapbubble-color/
* Pink bubbles
*
* @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
* @apioption plotOptions.mapbubble.color
*/
/**
* Whether to display negative sized bubbles. The threshold is given
* by the [zThreshold](#plotOptions.mapbubble.zThreshold) option, and
* negative bubbles can be visualized by setting [negativeColor](
* #plotOptions.bubble.negativeColor).
*
* @type {boolean}
* @default true
* @apioption plotOptions.mapbubble.displayNegative
*/
/**
* @sample {highmaps} maps/demo/map-bubble/
* Bubble size
*
* @apioption plotOptions.mapbubble.maxSize
*/
/**
* @sample {highmaps} maps/demo/map-bubble/
* Bubble size
*
* @apioption plotOptions.mapbubble.minSize
*/
/**
* When a point's Z value is below the
* [zThreshold](#plotOptions.mapbubble.zThreshold) setting, this color
* is used.
*
* @sample {highmaps} maps/plotoptions/mapbubble-negativecolor/
* Negative color below a threshold
*
* @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
* @apioption plotOptions.mapbubble.negativeColor
*/
/**
* Whether the bubble's value should be represented by the area or the
* width of the bubble. The default, `area`, corresponds best to the
* human perception of the size of each bubble.
*
* @type {string}
* @default area
* @validvalue ["area", "width"]
* @apioption plotOptions.mapbubble.sizeBy
*/
/**
* When this is true, the absolute value of z determines the size of
* the bubble. This means that with the default `zThreshold` of 0, a
* bubble of value -1 will have the same size as a bubble of value 1,
* while a bubble of value 0 will have a smaller size according to
* `minSize`.
*
* @sample {highmaps} highcharts/plotoptions/bubble-sizebyabsolutevalue/
* Size by absolute value, various thresholds
*
* @type {boolean}
* @default false
* @since 1.1.9
* @apioption plotOptions.mapbubble.sizeByAbsoluteValue
*/
/**
* The minimum for the Z value range. Defaults to the highest Z value
* in the data.
*
* @see [zMax](#plotOptions.mapbubble.zMin)
*
* @sample {highmaps} highcharts/plotoptions/bubble-zmin-zmax/
* Z has a possible range of 0-100
*
* @type {number}
* @since 1.0.3
* @apioption plotOptions.mapbubble.zMax
*/
/**
* The minimum for the Z value range. Defaults to the lowest Z value
* in the data.
*
* @see [zMax](#plotOptions.mapbubble.zMax)
*
* @sample {highmaps} highcharts/plotoptions/bubble-zmin-zmax/
* Z has a possible range of 0-100
*
* @type {number}
* @since 1.0.3
* @apioption plotOptions.mapbubble.zMin
*/
/**
* When [displayNegative](#plotOptions.mapbubble.displayNegative) is
* `false`, bubbles with lower Z values are skipped. When
* `displayNegative` is `true` and a [negativeColor](
* #plotOptions.mapbubble.negativeColor) is given, points with lower Z
* is colored.
*
* @sample {highmaps} maps/plotoptions/mapbubble-negativecolor/
* Negative color below a threshold
*
* @type {number}
* @default 0
* @apioption plotOptions.mapbubble.zThreshold
*/
animationLimit: 500,
tooltip: {
pointFormat: '{point.name}: {point.z}'
}
// Prototype members
}, {
xyFromShape: true,
type: 'mapbubble',
// If one single value is passed, it is interpreted as z
pointArrayMap: ['z'],
// Return the map area identified by the dataJoinBy option
getMapData: seriesTypes.map.prototype.getMapData,
getBox: seriesTypes.map.prototype.getBox,
setData: seriesTypes.map.prototype.setData
// Point class
}, {
applyOptions: function (options, x) {
var point;
if (
options &&
options.lat !== undefined &&
options.lon !== undefined
) {
point = Point.prototype.applyOptions.call(
this,
merge(
options,
this.series.chart.fromLatLonToPoint(options)
),
x
);
} else {
point = seriesTypes.map.prototype.pointClass.prototype
.applyOptions.call(this, options, x);
}
return point;
},
isValid: function () {
return typeof this.z === 'number';
},
ttBelow: false
});
}
/**
* A `mapbubble` series. If the [type](#series.mapbubble.type) option
* is not specified, it is inherited from [chart.type](#chart.type).
*
* @extends series,plotOptions.mapbubble
* @excluding dataParser, dataURL
* @product highmaps
* @apioption series.mapbubble
*/
/**
* An array of data points for the series. For the `mapbubble` series
* type, points can be given in the following ways:
*
* 1. An array of numerical values. In this case, the numerical values
* will be interpreted as `z` options. Example:
*
* ```js
* data: [0, 5, 3, 5]
* ```
*
* 2. An array of objects with named values. The following snippet shows only a
* few settings, see the complete options set below. If the total number of data
* points exceeds the series' [turboThreshold](
* #series.mapbubble.turboThreshold),
* this option is not available.
*
* ```js
* data: [{
* z: 9,
* name: "Point2",
* color: "#00FF00"
* }, {
* z: 10,
* name: "Point1",
* color: "#FF00FF"
* }]
* ```
*
* @type {Array<number|*>}
* @extends series.mappoint.data
* @excluding labelrank, middleX, middleY, path, value, x, y, lat, lon
* @product highmaps
* @apioption series.mapbubble.data
*/
/**
* While the `x` and `y` values of the bubble are determined by the
* underlying map, the `z` indicates the actual value that gives the
* size of the bubble.
*
* @sample {highmaps} maps/demo/map-bubble/
* Bubble
*
* @type {number}
* @product highmaps
* @apioption series.mapbubble.data.z
*/
/**
* @excluding enabled, enabledThreshold, height, radius, width
* @apioption series.mapbubble.marker
*/
@@ -0,0 +1,143 @@
/**
* (c) 2010-2019 Torstein Honsi
*
* License: www.highcharts.com/license
*/
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
import '../parts/Options.js';
var seriesType = H.seriesType,
seriesTypes = H.seriesTypes;
/**
* @private
* @class
* @name Highcharts.seriesTypes.mapline
*
* @augments Highcharts.Series
*/
seriesType('mapline', 'map'
/**
* A mapline series is a special case of the map series where the value
* colors are applied to the strokes rather than the fills. It can also be
* used for freeform drawing, like dividers, in the map.
*
* @sample maps/demo/mapline-mappoint/
* Mapline and map-point chart
*
* @extends plotOptions.map
* @product highmaps
* @optionparent plotOptions.mapline
*/
, {
/**
* The width of the map line.
*/
lineWidth: 1,
/**
* Fill color for the map line shapes
*
* @type {Highcharts.ColorString}
*/
fillColor: 'none'
}, {
type: 'mapline',
colorProp: 'stroke',
pointAttrToOptions: {
'stroke': 'color',
'stroke-width': 'lineWidth'
},
/**
* Get presentational attributes
*
* @private
* @function Highcharts.seriesTypes.mapline#pointAttribs
*
* @param {Highcharts.Point} point
*
* @param {string} state
*
* @return {Highcharts.Dictionary<*>}
*/
pointAttribs: function (point, state) {
var attr = seriesTypes.map.prototype.pointAttribs.call(
this,
point,
state
);
// The difference from a map series is that the stroke takes the
// point color
attr.fill = this.options.fillColor;
return attr;
},
drawLegendSymbol: seriesTypes.line.prototype.drawLegendSymbol
});
/**
* A `mapline` series. If the [type](#series.mapline.type) option is
* not specified, it is inherited from [chart.type](#chart.type).
*
* @extends series,plotOptions.mapline
* @excluding dataParser, dataURL, marker
* @product highmaps
* @apioption series.mapline
*/
/**
* An array of data points for the series. For the `mapline` series type,
* points can be given in the following ways:
*
* 1. An array of numerical values. In this case, the numerical values
* will be interpreted as `value` options. Example:
*
* ```js
* data: [0, 5, 3, 5]
* ```
*
* 2. An array of arrays with 2 values. In this case, the values correspond
* to `[hc-key, value]`. Example:
*
* ```js
* data: [
* ['us-ny', 0],
* ['us-mi', 5],
* ['us-tx', 3],
* ['us-ak', 5]
* ]
* ```
*
* 3. An array of objects with named values. The following snippet shows only a
* few settings, see the complete options set below. If the total number of data
* points exceeds the series' [turboThreshold](#series.map.turboThreshold),
* this option is not available.
*
* ```js
* data: [{
* value: 6,
* name: "Point2",
* color: "#00FF00"
* }, {
* value: 6,
* name: "Point1",
* color: "#FF00FF"
* }]
* ```
*
* @type {Array<number|Array<string,number>|object>}
* @product highmaps
* @apioption series.mapline.data
*/
@@ -0,0 +1,357 @@
/**
* (c) 2010-2019 Torstein Honsi
*
* License: www.highcharts.com/license
*/
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
import '../parts/Chart.js';
var addEvent = H.addEvent,
Chart = H.Chart,
doc = H.doc,
extend = H.extend,
merge = H.merge,
pick = H.pick;
function stopEvent(e) {
if (e) {
if (e.preventDefault) {
e.preventDefault();
}
if (e.stopPropagation) {
e.stopPropagation();
}
e.cancelBubble = true;
}
}
/**
* The MapNavigation handles buttons for navigation in addition to mousewheel
* and doubleclick handlers for chart zooming.
*
* @private
* @class
* @name MapNavigation
*
* @param {Highcharts.Chart} chart
* The Chart instance.
*/
function MapNavigation(chart) {
this.init(chart);
}
/**
* Initialize function.
*
* @function MapNavigation#init
*
* @param {Highcharts.Chart} chart
* The Chart instance.
*/
MapNavigation.prototype.init = function (chart) {
this.chart = chart;
chart.mapNavButtons = [];
};
/**
* Update the map navigation with new options. Calling this is the same as
* calling `chart.update({ mapNavigation: {} })`.
*
* @function MapNavigation#update
*
* @param {Highcharts.MapNavigationOptions} options
* New options for the map navigation.
*/
MapNavigation.prototype.update = function (options) {
var chart = this.chart,
o = chart.options.mapNavigation,
buttonOptions,
attr,
states,
hoverStates,
selectStates,
outerHandler = function (e) {
this.handler.call(chart, e);
stopEvent(e); // Stop default click event (#4444)
},
mapNavButtons = chart.mapNavButtons;
// Merge in new options in case of update, and register back to chart
// options.
if (options) {
o = chart.options.mapNavigation =
merge(chart.options.mapNavigation, options);
}
// Destroy buttons in case of dynamic update
while (mapNavButtons.length) {
mapNavButtons.pop().destroy();
}
if (pick(o.enableButtons, o.enabled) && !chart.renderer.forExport) {
H.objectEach(o.buttons, function (button, n) {
buttonOptions = merge(o.buttonOptions, button);
// Presentational
if (!chart.styledMode) {
attr = buttonOptions.theme;
attr.style = merge(
buttonOptions.theme.style,
buttonOptions.style // #3203
);
states = attr.states;
hoverStates = states && states.hover;
selectStates = states && states.select;
}
button = chart.renderer.button(
buttonOptions.text,
0,
0,
outerHandler,
attr,
hoverStates,
selectStates,
0,
n === 'zoomIn' ? 'topbutton' : 'bottombutton'
)
.addClass('highcharts-map-navigation highcharts-' + {
zoomIn: 'zoom-in',
zoomOut: 'zoom-out'
}[n])
.attr({
width: buttonOptions.width,
height: buttonOptions.height,
title: chart.options.lang[n],
padding: buttonOptions.padding,
zIndex: 5
})
.add();
button.handler = buttonOptions.onclick;
button.align(
extend(buttonOptions, {
width: button.width,
height: 2 * button.height
}),
null,
buttonOptions.alignTo
);
// Stop double click event (#4444)
addEvent(button.element, 'dblclick', stopEvent);
mapNavButtons.push(button);
});
}
this.updateEvents(o);
};
/**
* Update events, called internally from the update function. Add new event
* handlers, or unbinds events if disabled.
*
* @function MapNavigation#updateEvents
*
* @param {Highcharts.MapNavigationOptions} options
* Options for map navigation.
*/
MapNavigation.prototype.updateEvents = function (options) {
var chart = this.chart;
// Add the double click event
if (
pick(options.enableDoubleClickZoom, options.enabled) ||
options.enableDoubleClickZoomTo
) {
this.unbindDblClick = this.unbindDblClick || addEvent(
chart.container,
'dblclick',
function (e) {
chart.pointer.onContainerDblClick(e);
}
);
} else if (this.unbindDblClick) {
// Unbind and set unbinder to undefined
this.unbindDblClick = this.unbindDblClick();
}
// Add the mousewheel event
if (pick(options.enableMouseWheelZoom, options.enabled)) {
this.unbindMouseWheel = this.unbindMouseWheel || addEvent(
chart.container,
doc.onmousewheel === undefined ? 'DOMMouseScroll' : 'mousewheel',
function (e) {
chart.pointer.onContainerMouseWheel(e);
// Issue #5011, returning false from non-jQuery event does
// not prevent default
stopEvent(e);
return false;
}
);
} else if (this.unbindMouseWheel) {
// Unbind and set unbinder to undefined
this.unbindMouseWheel = this.unbindMouseWheel();
}
};
// Add events to the Chart object itself
extend(Chart.prototype, /** @lends Chart.prototype */ {
/**
* Fit an inner box to an outer. If the inner box overflows left or right,
* align it to the sides of the outer. If it overflows both sides, fit it
* within the outer. This is a pattern that occurs more places in
* Highcharts, perhaps it should be elevated to a common utility function.
*
* @ignore
* @function Highcharts.Chart#fitToBox
*
* @param {Highcharts.BBoxObject} inner
*
* @param {Highcharts.BBoxObject} outer
*
* @return {Highcharts.BBoxObject}
* The inner box
*/
fitToBox: function (inner, outer) {
[['x', 'width'], ['y', 'height']].forEach(function (dim) {
var pos = dim[0],
size = dim[1];
if (inner[pos] + inner[size] > outer[pos] + outer[size]) { // right
// the general size is greater, fit fully to outer
if (inner[size] > outer[size]) {
inner[size] = outer[size];
inner[pos] = outer[pos];
} else { // align right
inner[pos] = outer[pos] + outer[size] - inner[size];
}
}
if (inner[size] > outer[size]) {
inner[size] = outer[size];
}
if (inner[pos] < outer[pos]) {
inner[pos] = outer[pos];
}
});
return inner;
},
/**
* Highmaps only. Zoom in or out of the map. See also {@link Point#zoomTo}.
* See {@link Chart#fromLatLonToPoint} for how to get the `centerX` and
* `centerY` parameters for a geographic location.
*
* @function Highcharts.Chart#mapZoom
*
* @param {number} [howMuch]
* How much to zoom the map. Values less than 1 zooms in. 0.5 zooms
* in to half the current view. 2 zooms to twice the current view. If
* omitted, the zoom is reset.
*
* @param {number} [centerX]
* The X axis position to center around if available space.
*
* @param {number} [centerY]
* The Y axis position to center around if available space.
*
* @param {number} [mouseX]
* Fix the zoom to this position if possible. This is used for
* example in mousewheel events, where the area under the mouse
* should be fixed as we zoom in.
*
* @param {number} [mouseY]
* Fix the zoom to this position if possible.
*/
mapZoom: function (howMuch, centerXArg, centerYArg, mouseX, mouseY) {
var chart = this,
xAxis = chart.xAxis[0],
xRange = xAxis.max - xAxis.min,
centerX = pick(centerXArg, xAxis.min + xRange / 2),
newXRange = xRange * howMuch,
yAxis = chart.yAxis[0],
yRange = yAxis.max - yAxis.min,
centerY = pick(centerYArg, yAxis.min + yRange / 2),
newYRange = yRange * howMuch,
fixToX = mouseX ? ((mouseX - xAxis.pos) / xAxis.len) : 0.5,
fixToY = mouseY ? ((mouseY - yAxis.pos) / yAxis.len) : 0.5,
newXMin = centerX - newXRange * fixToX,
newYMin = centerY - newYRange * fixToY,
newExt = chart.fitToBox({
x: newXMin,
y: newYMin,
width: newXRange,
height: newYRange
}, {
x: xAxis.dataMin,
y: yAxis.dataMin,
width: xAxis.dataMax - xAxis.dataMin,
height: yAxis.dataMax - yAxis.dataMin
}),
zoomOut = newExt.x <= xAxis.dataMin &&
newExt.width >= xAxis.dataMax - xAxis.dataMin &&
newExt.y <= yAxis.dataMin &&
newExt.height >= yAxis.dataMax - yAxis.dataMin;
// When mousewheel zooming, fix the point under the mouse
if (mouseX) {
xAxis.fixTo = [mouseX - xAxis.pos, centerXArg];
}
if (mouseY) {
yAxis.fixTo = [mouseY - yAxis.pos, centerYArg];
}
// Zoom
if (howMuch !== undefined && !zoomOut) {
xAxis.setExtremes(newExt.x, newExt.x + newExt.width, false);
yAxis.setExtremes(newExt.y, newExt.y + newExt.height, false);
// Reset zoom
} else {
xAxis.setExtremes(undefined, undefined, false);
yAxis.setExtremes(undefined, undefined, false);
}
// Prevent zooming until this one is finished animating
/*
chart.holdMapZoom = true;
setTimeout(function () {
chart.holdMapZoom = false;
}, 200);
*/
/*
delay = animation ? animation.duration || 500 : 0;
if (delay) {
chart.isMapZooming = true;
setTimeout(function () {
chart.isMapZooming = false;
if (chart.mapZoomQueue) {
chart.mapZoom.apply(chart, chart.mapZoomQueue);
}
chart.mapZoomQueue = null;
}, delay);
}
*/
chart.redraw();
}
});
// Extend the Chart.render method to add zooming and panning
addEvent(Chart, 'beforeRender', function () {
// Render the plus and minus buttons. Doing this before the shapes makes
// getBBox much quicker, at least in Chrome.
this.mapNavigation = new MapNavigation(this);
this.mapNavigation.update();
});
H.MapNavigation = MapNavigation;
@@ -0,0 +1,187 @@
/**
* (c) 2010-2019 Torstein Honsi
*
* License: www.highcharts.com/license
*/
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
import '../parts/Options.js';
import '../parts/Point.js';
import '../parts/ScatterSeries.js';
var merge = H.merge,
Point = H.Point,
seriesType = H.seriesType;
/**
* @private
* @class
* @name Highcharts.seriesTypes.mappoint
*
* @augments Highcharts.Series
*/
seriesType(
'mappoint',
'scatter',
/**
* A mappoint series is a special form of scatter series where the points
* can be laid out in map coordinates on top of a map.
*
* @sample maps/demo/mapline-mappoint/
* Map-line and map-point series.
*
* @extends plotOptions.scatter
* @product highmaps
* @optionparent plotOptions.mappoint
*/
{
dataLabels: {
/**
* @default {point.name}
* @apioption plotOptions.mappoint.dataLabels.format
*/
enabled: true,
formatter: function () { // #2945
return this.point.name;
},
crop: false,
defer: false,
overflow: false,
style: {
color: '#000000'
}
}
// Prototype members
}, {
type: 'mappoint',
forceDL: true
// Point class
}, {
applyOptions: function (options, x) {
var mergedOptions = (
options.lat !== undefined &&
options.lon !== undefined ?
merge(
options, this.series.chart.fromLatLonToPoint(options)
) :
options
);
return Point.prototype.applyOptions.call(this, mergedOptions, x);
}
}
);
/**
* A `mappoint` series. If the [type](#series.mappoint.type) option
* is not specified, it is inherited from [chart.type](#chart.type).
*
*
* @extends series,plotOptions.mappoint
* @excluding dataParser, dataURL
* @product highmaps
* @apioption series.mappoint
*/
/**
* An array of data points for the series. For the `mappoint` series
* type, points can be given in the following ways:
*
* 1. An array of numerical values. In this case, the numerical values
* will be interpreted as `y` options. The `x` values will be automatically
* calculated, either starting at 0 and incremented by 1, or from `pointStart`
* and `pointInterval` given in the series options. If the axis has
* categories, these will be used. Example:
*
* ```js
* data: [0, 5, 3, 5]
* ```
*
* 2. An array of arrays with 2 values. In this case, the values correspond
* to `x,y`. If the first value is a string, it is applied as the name
* of the point, and the `x` value is inferred.
*
* ```js
* data: [
* [0, 1],
* [1, 8],
* [2, 7]
* ]
* ```
*
* 3. An array of objects with named values. The following snippet shows only a
* few settings, see the complete options set below. If the total number of data
* points exceeds the series' [turboThreshold](#series.mappoint.turboThreshold),
* this option is not available.
*
* ```js
* data: [{
* x: 1,
* y: 7,
* name: "Point2",
* color: "#00FF00"
* }, {
* x: 1,
* y: 4,
* name: "Point1",
* color: "#FF00FF"
* }]
* ```
*
* @type {Array<number|Array<number,number>|*>}
* @extends series.map.data
* @excluding labelrank, middleX, middleY, path, value
* @product highmaps
* @apioption series.mappoint.data
*/
/**
* The latitude of the point. Must be combined with the `lon` option
* to work. Overrides `x` and `y` values.
*
* @sample {highmaps} maps/demo/mappoint-latlon/
* Point position by lat/lon
*
* @type {number}
* @since 1.1.0
* @product highmaps
* @apioption series.mappoint.data.lat
*/
/**
* The longitude of the point. Must be combined with the `lon` option
* to work. Overrides `x` and `y` values.
*
* @sample {highmaps} maps/demo/mappoint-latlon/
* Point position by lat/lon
*
* @type {number}
* @since 1.1.0
* @product highmaps
* @apioption series.mappoint.data.lon
*/
/**
* The x coordinate of the point in terms of the map path coordinates.
*
* @sample {highmaps} maps/demo/mapline-mappoint/
* Map point demo
*
* @type {number}
* @product highmaps
* @apioption series.mappoint.data.x
*/
/**
* The x coordinate of the point in terms of the map path coordinates.
*
* @sample {highmaps} maps/demo/mapline-mappoint/
* Map point demo
*
* @type {number}
* @product highmaps
* @apioption series.mappoint.data.y
*/
@@ -0,0 +1,132 @@
/**
* (c) 2010-2019 Torstein Honsi
*
* License: www.highcharts.com/license
*/
'use strict';
import H from '../parts/Globals.js';
import '../parts/Utilities.js';
import '../parts/Pointer.js';
var extend = H.extend,
pick = H.pick,
Pointer = H.Pointer,
wrap = H.wrap;
// Extend the Pointer
extend(Pointer.prototype, {
// The event handler for the doubleclick event
onContainerDblClick: function (e) {
var chart = this.chart;
e = this.normalize(e);
if (chart.options.mapNavigation.enableDoubleClickZoomTo) {
if (
chart.pointer.inClass(e.target, 'highcharts-tracker') &&
chart.hoverPoint
) {
chart.hoverPoint.zoomTo();
}
} else if (
chart.isInsidePlot(
e.chartX - chart.plotLeft,
e.chartY - chart.plotTop
)
) {
chart.mapZoom(
0.5,
chart.xAxis[0].toValue(e.chartX),
chart.yAxis[0].toValue(e.chartY),
e.chartX,
e.chartY
);
}
},
// The event handler for the mouse scroll event
onContainerMouseWheel: function (e) {
var chart = this.chart,
delta;
e = this.normalize(e);
// Firefox uses e.detail, WebKit and IE uses wheelDelta
delta = e.detail || -(e.wheelDelta / 120);
if (chart.isInsidePlot(
e.chartX - chart.plotLeft,
e.chartY - chart.plotTop
)) {
chart.mapZoom(
Math.pow(
chart.options.mapNavigation.mouseWheelSensitivity,
delta
),
chart.xAxis[0].toValue(e.chartX),
chart.yAxis[0].toValue(e.chartY),
e.chartX,
e.chartY
);
}
}
});
// The pinchType is inferred from mapNavigation options.
wrap(Pointer.prototype, 'zoomOption', function (proceed) {
var mapNavigation = this.chart.options.mapNavigation;
// Pinch status
if (pick(mapNavigation.enableTouchZoom, mapNavigation.enabled)) {
this.chart.options.chart.pinchType = 'xy';
}
proceed.apply(this, [].slice.call(arguments, 1));
});
// Extend the pinchTranslate method to preserve fixed ratio when zooming
wrap(
Pointer.prototype,
'pinchTranslate',
function (
proceed,
pinchDown,
touches,
transform,
selectionMarker,
clip,
lastValidTouch
) {
var xBigger;
proceed.call(
this,
pinchDown,
touches,
transform,
selectionMarker,
clip,
lastValidTouch
);
// Keep ratio
if (this.chart.options.chart.type === 'map' && this.hasZoom) {
xBigger = transform.scaleX > transform.scaleY;
this.pinchTranslateDirection(
!xBigger,
pinchDown,
touches,
transform,
selectionMarker,
clip,
lastValidTouch,
xBigger ? transform.scaleX : transform.scaleY
);
}
}
);
File diff suppressed because it is too large Load Diff