corrade-nucleus-nucleons

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 30  →  ?path2? @ 31
/doctor/004_doctor/doctor/node_modules/highcharts/modules/map.src.js
@@ -0,0 +1,4040 @@
/**
* @license Highmaps JS v5.0.14 (2017-07-28)
* Highmaps as a plugin for Highcharts 4.1.x or Highstock 2.1.x (x being the patch version of this file)
*
* (c) 2011-2017 Torstein Honsi
*
* License: www.highcharts.com/license
*/
'use strict';
(function(factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory;
} else {
factory(Highcharts);
}
}(function(Highcharts) {
(function(H) {
/**
* (c) 2010-2017 Torstein Honsi
*
* License: www.highcharts.com/license
*/
var Axis = H.Axis,
each = H.each,
pick = H.pick,
wrap = H.wrap;
/**
* Override to use the extreme coordinates from the SVG shape, not the
* data values
*/
wrap(Axis.prototype, 'getSeriesExtremes', function(proceed) {
var isXAxis = this.isXAxis,
dataMin,
dataMax,
xData = [],
useMapGeometry;
 
// Remove the xData array and cache it locally so that the proceed method doesn't use it
if (isXAxis) {
each(this.series, function(series, i) {
if (series.useMapGeometry) {
xData[i] = series.xData;
series.xData = [];
}
});
}
 
// Call base to reach normal cartesian series (like mappoint)
proceed.call(this);
 
// Run extremes logic for map and mapline
if (isXAxis) {
dataMin = pick(this.dataMin, Number.MAX_VALUE);
dataMax = pick(this.dataMax, -Number.MAX_VALUE);
each(this.series, 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;
}
}
});
 
/**
* Override axis translation to make sure the aspect ratio is always kept
*/
wrap(Axis.prototype, 'setAxisTranslation', function(proceed) {
var chart = this.chart,
mapRatio,
plotRatio = chart.plotWidth / chart.plotHeight,
adjustedAxisLength,
xAxis = chart.xAxis[0],
padAxis,
fixTo,
fixDiff,
preserveAspectRatio;
 
 
// Run the parent method
proceed.call(this);
 
// Check for map-like series
if (this.coll === 'yAxis' && xAxis.transA !== undefined) {
each(this.series, 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
*/
wrap(Axis.prototype, 'render', function(proceed) {
proceed.call(this);
this.fixTo = null;
});
 
}(Highcharts));
(function(H) {
/**
* (c) 2010-2017 Torstein Honsi
*
* License: www.highcharts.com/license
*/
var Axis = H.Axis,
Chart = H.Chart,
color = H.color,
ColorAxis,
each = H.each,
extend = H.extend,
isNumber = H.isNumber,
Legend = H.Legend,
LegendSymbolMixin = H.LegendSymbolMixin,
noop = H.noop,
merge = H.merge,
pick = H.pick,
wrap = H.wrap;
 
/**
* The ColorAxis object for inclusion in gradient legends
*/
ColorAxis = H.ColorAxis = function() {
this.init.apply(this, arguments);
};
extend(ColorAxis.prototype, Axis.prototype);
extend(ColorAxis.prototype, {
/**
* @extends {xAxis}
* @optionparent colorAxis
*/
defaultColorAxisOptions: {
 
/**
*/
lineWidth: 0,
 
/**
* Padding of the min value relative to the length of the axis. A
* padding of 0.05 will make a 100px axis 5px longer.
*
* @type {Number}
* @product highmaps
*/
minPadding: 0,
 
/**
* Padding of the max value relative to the length of the axis. A
* padding of 0.05 will make a 100px axis 5px longer.
*
* @type {Number}
* @product highmaps
*/
maxPadding: 0,
 
/**
* The width of the grid lines extending from the axis across the
* gradient of a scalar color axis.
*
* @type {Number}
* @sample {highmaps} maps/coloraxis/gridlines/ Grid lines demonstrated
* @default 1
* @product highmaps
*/
gridLineWidth: 1,
 
/**
* If [tickInterval](#colorAxis.tickInterval) is `null` this option
* sets the approximate pixel interval of the tick marks.
*
* @type {Number}
* @default 72
* @product highmaps
*/
tickPixelInterval: 72,
 
/**
* Whether to force the axis to start on a tick. Use this option with
* the `maxPadding` option to control the axis start.
*
* @type {Boolean}
* @default true
* @product highmaps
*/
startOnTick: true,
 
/**
* Whether to force the axis to end on a tick. Use this option with
* the [maxPadding](#colorAxis.maxPadding) option to control the axis
* end.
*
* @type {Boolean}
* @default true
* @product highmaps
*/
endOnTick: true,
 
/**
*/
offset: 0,
 
/**
* The triangular marker on a scalar color axis that points to the
* value of the hovered area. To disable the marker, set `marker:
* null`.
*
* @type {Object}
* @sample {highmaps} maps/coloraxis/marker/ Black marker
* @product highmaps
*/
marker: {
 
/**
* Animation for the marker as it moves between values. Set to `false`
* to disable animation. Defaults to `{ duration: 50 }`.
*
* @type {Object|Boolean}
* @product highmaps
*/
animation: {
 
/**
*/
duration: 50
},
 
/**
*/
width: 0.01,
 
 
/**
* The color of the marker.
*
* @type {Color}
* @default #999999
* @product highmaps
*/
color: '#999999'
 
},
 
/**
* The axis labels show the number for each tick.
*
* For more live examples on label options, see [xAxis.labels in the
* Highcharts API.](/highcharts#xAxis.labels)
*
* @type {Object}
* @extends xAxis.labels
* @product highmaps
*/
labels: {
 
/**
* How to handle overflowing labels on horizontal axis. Can be undefined
* or "justify". If "justify", labels will not render outside the
* plot area. If there is room to move it, it will be aligned to
* the edge, else it will be removed.
*
* @validvalue [null, "justify"]
* @type {String}
* @default justify
* @product highmaps
*/
overflow: 'justify',
 
/**
*/
rotation: 0
},
 
/**
* The color to represent the minimum of the color axis. Unless [dataClasses](#colorAxis.
* dataClasses) or [stops](#colorAxis.stops) are set, the gradient
* starts at this value.
*
* If dataClasses are set, the color is based on minColor and maxColor
* unless a color is set for each data class, or the [dataClassColor](#colorAxis.
* dataClassColor) is set.
*
* @type {Color}
* @sample {highmaps} maps/coloraxis/mincolor-maxcolor/ Min and max colors on scalar (gradient) axis
* @sample {highmaps} maps/coloraxis/mincolor-maxcolor-dataclasses/ On data classes
* @default #e6ebf5
* @product highmaps
*/
minColor: '#e6ebf5',
 
/**
* The color to represent the maximum of the color axis. Unless [dataClasses](#colorAxis.
* dataClasses) or [stops](#colorAxis.stops) are set, the gradient
* ends at this value.
*
* If dataClasses are set, the color is based on minColor and maxColor
* unless a color is set for each data class, or the [dataClassColor](#colorAxis.
* dataClassColor) is set.
*
* @type {Color}
* @sample {highmaps} maps/coloraxis/mincolor-maxcolor/ Min and max colors on scalar (gradient) axis
* @sample {highmaps} maps/coloraxis/mincolor-maxcolor-dataclasses/ On data classes
* @default #003399
* @product highmaps
*/
maxColor: '#003399',
 
/**
*/
tickLength: 5,
 
/**
* Whether to display the colorAxis in the legend.
*
* @type {Boolean}
* @see [heatmap.showInLegend](#series<heatmap>.showInLegend)
* @default true
* @since 4.2.7
* @product highmaps
*/
showInLegend: true
},
 
// Properties to preserve after destroy, for Axis.update (#5881, #6025)
keepProps: [
'legendGroup',
'legendItemHeight',
'legendItemWidth',
'legendItem',
'legendSymbol'
].concat(Axis.prototype.keepProps),
 
/**
* Initialize the color axis
*/
init: function(chart, userOptions) {
var horiz = chart.options.legend.layout !== 'vertical',
options;
 
this.coll = 'colorAxis';
 
// Build the options
options = merge(this.defaultColorAxisOptions, {
side: horiz ? 2 : 1,
reversed: !horiz
}, userOptions, {
opposite: !horiz,
showEmpty: false,
title: null
});
 
Axis.prototype.init.call(this, chart, options);
 
// Base init() pushes it to the xAxis array, now pop it again
// chart[this.isXAxis ? 'xAxis' : 'yAxis'].pop();
 
// Prepare data classes
if (userOptions.dataClasses) {
this.initDataClasses(userOptions);
}
this.initStops();
 
// Override original axis properties
this.horiz = horiz;
this.zoomEnabled = false;
 
// Add default values
this.defaultLegendLength = 200;
},
 
initDataClasses: function(userOptions) {
var chart = this.chart,
dataClasses,
colorCounter = 0,
colorCount = chart.options.chart.colorCount,
options = this.options,
len = userOptions.dataClasses.length;
this.dataClasses = dataClasses = [];
this.legendItems = [];
 
each(userOptions.dataClasses, function(dataClass, i) {
var colors;
 
dataClass = merge(dataClass);
dataClasses.push(dataClass);
 
 
if (dataClass.color) {
return;
}
 
if (options.dataClassColor === 'category') {
 
colors = chart.options.colors;
colorCount = colors.length;
dataClass.color = colors[colorCounter];
 
dataClass.colorIndex = colorCounter;
 
// increase and loop back to zero
colorCounter++;
if (colorCounter === colorCount) {
colorCounter = 0;
}
} else {
dataClass.color = color(options.minColor).tweenTo(
color(options.maxColor),
len < 2 ? 0.5 : i / (len - 1) // #3219
);
}
});
},
 
/**
* Override so that ticks are not added in data class axes (#6914)
*/
setTickPositions: function() {
if (!this.dataClasses) {
return Axis.prototype.setTickPositions.call(this);
}
},
 
 
initStops: function() {
this.stops = this.options.stops || [
[0, this.options.minColor],
[1, this.options.maxColor]
];
each(this.stops, function(stop) {
stop.color = color(stop[1]);
});
},
 
/**
* Extend the setOptions method to process extreme colors and color
* stops.
*/
setOptions: function(userOptions) {
Axis.prototype.setOptions.call(this, userOptions);
 
this.options.crosshair = this.options.marker;
},
 
setAxisSize: function() {
var symbol = this.legendSymbol,
chart = this.chart,
legendOptions = chart.options.legend || {},
x,
y,
width,
height;
 
if (symbol) {
this.left = x = symbol.attr('x');
this.top = y = symbol.attr('y');
this.width = width = symbol.attr('width');
this.height = height = symbol.attr('height');
this.right = chart.chartWidth - x - width;
this.bottom = chart.chartHeight - y - height;
 
this.len = this.horiz ? width : height;
this.pos = this.horiz ? x : y;
} else {
// Fake length for disabled legend to avoid tick issues
// and such (#5205)
this.len = (
this.horiz ?
legendOptions.symbolWidth :
legendOptions.symbolHeight
) || this.defaultLegendLength;
}
},
 
normalizedValue: function(value) {
if (this.isLog) {
value = this.val2lin(value);
}
return 1 - ((this.max - value) / ((this.max - this.min) || 1));
},
 
/**
* Translate from a value to a color
*/
toColor: function(value, point) {
var pos,
stops = this.stops,
from,
to,
color,
dataClasses = this.dataClasses,
dataClass,
i;
 
if (dataClasses) {
i = dataClasses.length;
while (i--) {
dataClass = dataClasses[i];
from = dataClass.from;
to = dataClass.to;
if (
(from === undefined || value >= from) &&
(to === undefined || value <= to)
) {
 
color = dataClass.color;
 
if (point) {
point.dataClass = i;
point.colorIndex = dataClass.colorIndex;
}
break;
}
}
 
} else {
 
pos = this.normalizedValue(value);
i = stops.length;
while (i--) {
if (pos > stops[i][0]) {
break;
}
}
from = stops[i] || stops[i + 1];
to = stops[i + 1] || from;
 
// The position within the gradient
pos = 1 - (to[0] - pos) / ((to[0] - from[0]) || 1);
 
color = from.color.tweenTo(
to.color,
pos
);
}
return color;
},
 
/**
* Override the getOffset method to add the whole axis groups inside
* the legend.
*/
getOffset: function() {
var group = this.legendGroup,
sideOffset = this.chart.axisOffset[this.side];
 
if (group) {
 
// Hook for the getOffset method to add groups to this parent group
this.axisParent = group;
 
// Call the base
Axis.prototype.getOffset.call(this);
 
// First time only
if (!this.added) {
 
this.added = true;
 
this.labelLeft = 0;
this.labelRight = this.width;
}
// Reset it to avoid color axis reserving space
this.chart.axisOffset[this.side] = sideOffset;
}
},
 
/**
* Create the color gradient
*/
setLegendColor: function() {
var grad,
horiz = this.horiz,
reversed = this.reversed,
one = reversed ? 1 : 0,
zero = reversed ? 0 : 1;
 
grad = horiz ? [one, 0, zero, 0] : [0, zero, 0, one]; // #3190
this.legendColor = {
linearGradient: {
x1: grad[0],
y1: grad[1],
x2: grad[2],
y2: grad[3]
},
stops: this.stops
};
},
 
/**
* The color axis appears inside the legend and has its own legend symbol
*/
drawLegendSymbol: function(legend, item) {
var padding = legend.padding,
legendOptions = legend.options,
horiz = this.horiz,
width = pick(
legendOptions.symbolWidth,
horiz ? this.defaultLegendLength : 12
),
height = pick(
legendOptions.symbolHeight,
horiz ? 12 : this.defaultLegendLength
),
labelPadding = pick(legendOptions.labelPadding, horiz ? 16 : 30),
itemDistance = pick(legendOptions.itemDistance, 10);
 
this.setLegendColor();
 
// Create the gradient
item.legendSymbol = this.chart.renderer.rect(
0,
legend.baseline - 11,
width,
height
).attr({
zIndex: 1
}).add(item.legendGroup);
 
// Set how much space this legend item takes up
this.legendItemWidth = width + padding +
(horiz ? itemDistance : labelPadding);
this.legendItemHeight = height + padding + (horiz ? labelPadding : 0);
},
/**
* Fool the legend
*/
setState: noop,
visible: true,
setVisible: noop,
getSeriesExtremes: function() {
var series = this.series,
i = series.length;
this.dataMin = Infinity;
this.dataMax = -Infinity;
while (i--) {
if (series[i].valueMin !== undefined) {
this.dataMin = Math.min(this.dataMin, series[i].valueMin);
this.dataMax = Math.max(this.dataMax, series[i].valueMax);
}
}
},
drawCrosshair: function(e, point) {
var plotX = point && point.plotX,
plotY = point && point.plotY,
crossPos,
axisPos = this.pos,
axisLen = this.len;
 
if (point) {
crossPos = this.toPixels(point[point.series.colorKey]);
if (crossPos < axisPos) {
crossPos = axisPos - 2;
} else if (crossPos > axisPos + axisLen) {
crossPos = axisPos + axisLen + 2;
}
 
point.plotX = crossPos;
point.plotY = this.len - crossPos;
Axis.prototype.drawCrosshair.call(this, e, point);
point.plotX = plotX;
point.plotY = plotY;
 
if (this.cross) {
this.cross
.addClass('highcharts-coloraxis-marker')
.add(this.legendGroup);
 
 
this.cross.attr({
fill: this.crosshair.color
});
 
 
}
}
},
getPlotLinePath: function(a, b, c, d, pos) {
// crosshairs only
return isNumber(pos) ? // pos can be 0 (#3969)
(
this.horiz ? [
'M',
pos - 4, this.top - 6,
'L',
pos + 4, this.top - 6,
pos, this.top,
'Z'
] : [
'M',
this.left, pos,
'L',
this.left - 6, pos + 6,
this.left - 6, pos - 6,
'Z'
]
) :
Axis.prototype.getPlotLinePath.call(this, a, b, c, d);
},
 
update: function(newOptions, redraw) {
var chart = this.chart,
legend = chart.legend;
 
each(this.series, function(series) {
// Needed for Axis.update when choropleth colors change
series.isDirtyData = true;
});
 
// When updating data classes, destroy old items and make sure new ones
// are created (#3207)
if (newOptions.dataClasses && legend.allItems) {
each(legend.allItems, function(item) {
if (item.isDataClass && item.legendGroup) {
item.legendGroup.destroy();
}
});
chart.isDirtyLegend = true;
}
 
// Keep the options structure updated for export. Unlike xAxis and
// yAxis, the colorAxis is not an array. (#3207)
chart.options[this.coll] = merge(this.userOptions, newOptions);
 
Axis.prototype.update.call(this, newOptions, redraw);
if (this.legendItem) {
this.setLegendColor();
legend.colorizeItem(this, true);
}
},
 
/**
* Extend basic axis remove by also removing the legend item.
*/
remove: function() {
if (this.legendItem) {
this.chart.legend.destroyItem(this);
}
Axis.prototype.remove.call(this);
},
 
/**
* Get the legend item symbols for data classes
*/
getDataClassLegendSymbols: function() {
var axis = this,
chart = this.chart,
legendItems = this.legendItems,
legendOptions = chart.options.legend,
valueDecimals = legendOptions.valueDecimals,
valueSuffix = legendOptions.valueSuffix || '',
name;
 
if (!legendItems.length) {
each(this.dataClasses, function(dataClass, i) {
var vis = true,
from = dataClass.from,
to = dataClass.to;
 
// Assemble the default name. This can be overridden
// by legend.options.labelFormatter
name = '';
if (from === undefined) {
name = '< ';
} else if (to === undefined) {
name = '> ';
}
if (from !== undefined) {
name += H.numberFormat(from, valueDecimals) + valueSuffix;
}
if (from !== undefined && to !== undefined) {
name += ' - ';
}
if (to !== undefined) {
name += H.numberFormat(to, valueDecimals) + valueSuffix;
}
// Add a mock object to the legend items
legendItems.push(extend({
chart: chart,
name: name,
options: {},
drawLegendSymbol: LegendSymbolMixin.drawRectangle,
visible: true,
setState: noop,
isDataClass: true,
setVisible: function() {
vis = this.visible = !vis;
each(axis.series, function(series) {
each(series.points, function(point) {
if (point.dataClass === i) {
point.setVisible(vis);
}
});
});
 
chart.legend.colorizeItem(this, vis);
}
}, dataClass));
});
}
return legendItems;
},
name: '' // Prevents 'undefined' in legend in IE8
});
 
/**
* Handle animation of the color attributes directly
*/
each(['fill', 'stroke'], function(prop) {
H.Fx.prototype[prop + 'Setter'] = function() {
this.elem.attr(
prop,
color(this.start).tweenTo(
color(this.end),
this.pos
),
null,
true
);
};
});
 
/**
* Extend the chart getAxes method to also get the color axis
*/
wrap(Chart.prototype, 'getAxes', function(proceed) {
 
var options = this.options,
colorAxisOptions = options.colorAxis;
 
proceed.call(this);
 
this.colorAxis = [];
if (colorAxisOptions) {
new ColorAxis(this, colorAxisOptions); // eslint-disable-line no-new
}
});
 
 
/**
* Wrap the legend getAllItems method to add the color axis. This also removes
* the axis' own series to prevent them from showing up individually.
*/
wrap(Legend.prototype, 'getAllItems', function(proceed) {
var allItems = [],
colorAxis = this.chart.colorAxis[0];
 
if (colorAxis && colorAxis.options) {
if (colorAxis.options.showInLegend) {
// Data classes
if (colorAxis.options.dataClasses) {
allItems = allItems.concat(
colorAxis.getDataClassLegendSymbols()
);
// Gradient legend
} else {
// Add this axis on top
allItems.push(colorAxis);
}
}
 
// Don't add the color axis' series
each(colorAxis.series, function(series) {
series.options.showInLegend = false;
});
}
 
return allItems.concat(proceed.call(this));
});
 
wrap(Legend.prototype, 'colorizeItem', function(proceed, item, visible) {
proceed.call(this, item, visible);
if (visible && item.legendColor) {
item.legendSymbol.attr({
fill: item.legendColor
});
}
});
 
// Updates in the legend need to be reflected in the color axis (6888)
wrap(Legend.prototype, 'update', function(proceed) {
proceed.apply(this, [].slice.call(arguments, 1));
 
if (this.chart.colorAxis[0]) {
this.chart.colorAxis[0].update({}, arguments[2]);
}
});
 
}(Highcharts));
(function(H) {
/**
* (c) 2010-2017 Torstein Honsi
*
* License: www.highcharts.com/license
*/
var defined = H.defined,
each = H.each,
noop = H.noop,
seriesTypes = H.seriesTypes;
 
/**
* Mixin for maps and heatmaps
*/
H.colorPointMixin = {
/**
* Color points have a value option that determines whether or not it is
* a null point
*/
isValid: function() {
return this.value !== null;
},
 
/**
* Set the visibility of a single point
*/
setVisible: function(vis) {
var point = this,
method = vis ? 'show' : 'hide';
 
// Show and hide associated elements
each(['graphic', 'dataLabel'], function(key) {
if (point[key]) {
point[key][method]();
}
});
},
setState: function(state) {
H.Point.prototype.setState.call(this, state);
if (this.graphic) {
this.graphic.attr({
zIndex: state === 'hover' ? 1 : 0
});
}
}
};
 
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
*/
translateColors: function() {
var series = this,
nullColor = this.options.nullColor,
colorAxis = this.colorAxis,
colorKey = this.colorKey;
 
each(this.data, 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
*/
colorAttribs: function(point) {
var ret = {};
if (defined(point.color)) {
ret[this.colorProp || 'fill'] = point.color;
}
return ret;
}
};
 
}(Highcharts));
(function(H) {
/**
* (c) 2010-2017 Torstein Honsi
*
* License: www.highcharts.com/license
*/
var addEvent = H.addEvent,
Chart = H.Chart,
doc = H.doc,
each = H.each,
extend = H.extend,
merge = H.merge,
pick = H.pick,
wrap = H.wrap;
 
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.
* @param {Chart} chart The Chart instance.
*/
function MapNavigation(chart) {
this.init(chart);
}
 
/**
* Initiator function.
* @param {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: {} })`.
* @param {Object} 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
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')
.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.
* @param {Object} 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.
*
* @private
*/
fitToBox: function(inner, outer) {
each([
['x', 'width'],
['y', 'height']
], function(dim) {
var pos = dim[0],
size = dim[1];
 
if (inner[pos] + inner[size] > outer[pos] + outer[size]) { // right overflow
if (inner[size] > outer[size]) { // the general size is greater, fit fully to outer
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.
*
* @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) {
/*if (this.isMapZooming) {
this.mapZoomQueue = arguments;
return;
}*/
 
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
*/
wrap(Chart.prototype, 'render', function(proceed) {
// 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();
 
proceed.call(this);
});
 
}(Highcharts));
(function(H) {
/**
* (c) 2010-2017 Torstein Honsi
*
* License: www.highcharts.com/license
*/
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
);
}
});
 
}(Highcharts));
(function(H) {
/**
* (c) 2010-2017 Torstein Honsi
*
* License: www.highcharts.com/license
*/
var colorPointMixin = H.colorPointMixin,
colorSeriesMixin = H.colorSeriesMixin,
doc = H.doc,
each = H.each,
extend = H.extend,
isNumber = H.isNumber,
LegendSymbolMixin = H.LegendSymbolMixin,
map = H.map,
merge = H.merge,
noop = H.noop,
pick = H.pick,
isArray = H.isArray,
Point = H.Point,
Series = H.Series,
seriesType = H.seriesType,
seriesTypes = H.seriesTypes,
splat = H.splat;
 
// The vector-effect attribute is not supported in IE <= 11 (at least), so we need
// diffent logic (#3218)
var supportsVectorEffect = doc.documentElement.style.vectorEffect !== undefined;
 
 
// Add the map series type
/**
* @extends {plotOptions.scatter}
* @optionparent plotOptions.map
*/
seriesType('map', 'scatter', {
 
/**
*/
allAreas: true,
 
 
/**
*/
animation: false, // makes the complex shapes slow
 
/**
* The color to apply to null points.
*
* In [styled mode](http://www.highcharts.com/docs/chart-design-and-
* style/style-by-css), the null point fill is set in the `.highcharts-
* null-point` class.
*
* @type {Color}
* @sample {highmaps} maps/demo/all-areas-as-null/ Null color
* @default #f7f7f7
* @product highmaps
*/
nullColor: '#f7f7f7',
 
/**
*/
borderColor: '#cccccc',
 
/**
*/
borderWidth: 1,
 
/**
*/
marker: null,
 
/**
*/
stickyTracking: false,
 
/**
*/
joinBy: 'hc-key',
 
/**
*/
dataLabels: {
 
/**
*/
formatter: function() { // #2945
return this.point.value;
},
 
/**
*/
inside: true, // for the color
 
/**
*/
verticalAlign: 'middle',
 
/**
*/
crop: false,
 
/**
*/
overflow: false,
 
/**
*/
padding: 0
},
 
/**
*/
turboThreshold: 0,
 
/**
*/
tooltip: {
 
/**
*/
followPointer: true,
 
/**
*/
pointFormat: '{point.name}: {point.value}<br/>'
},
 
/**
*/
states: {
 
/**
*/
normal: {
 
/**
*/
animation: true
},
 
/**
*/
hover: {
 
/**
*/
brightness: 0.2,
 
/**
*/
halo: null
},
 
/**
*/
select: {
 
/**
*/
color: '#cccccc'
}
}
 
// Prototype members
}, merge(colorSeriesMixin, {
type: 'map',
getExtremesFromAll: true,
useMapGeometry: true, // get axis extremes from paths, not values
forceDL: true,
searchPoint: noop,
directTouch: true, // When tooltip is not shared, this series (and derivatives) requires direct touch/hover. KD-tree does not apply.
preserveAspectRatio: true, // X axis and Y axis must have same translation slope
pointArrayMap: ['value'],
/**
* Get the bounding box of all paths in the map combined.
*/
getBox: function(paths) {
var MAX_VALUE = Number.MAX_VALUE,
maxX = -MAX_VALUE,
minX = MAX_VALUE,
maxY = -MAX_VALUE,
minY = MAX_VALUE,
minRange = MAX_VALUE,
xAxis = this.xAxis,
yAxis = this.yAxis,
hasBox;
 
// Find the bounding box
each(paths || [], function(point) {
 
if (point.path) {
if (typeof point.path === 'string') {
point.path = H.splitPath(point.path);
}
 
var path = point.path || [],
i = path.length,
even = false, // while loop reads from the end
pointMaxX = -MAX_VALUE,
pointMinX = MAX_VALUE,
pointMaxY = -MAX_VALUE,
pointMinY = MAX_VALUE,
properties = point.properties;
 
// The first time a map point is used, analyze its box
if (!point._foundBox) {
while (i--) {
if (isNumber(path[i])) {
if (even) { // even = x
pointMaxX = Math.max(pointMaxX, path[i]);
pointMinX = Math.min(pointMinX, path[i]);
} else { // odd = Y
pointMaxY = Math.max(pointMaxY, path[i]);
pointMinY = Math.min(pointMinY, path[i]);
}
even = !even;
}
}
// Cache point bounding box for use to position data labels,
// bubbles etc
point._midX = pointMinX + (pointMaxX - pointMinX) * pick(
point.middleX,
properties && properties['hc-middle-x'],
0.5
);
point._midY = pointMinY + (pointMaxY - pointMinY) * pick(
point.middleY,
properties && properties['hc-middle-y'],
0.5
);
point._maxX = pointMaxX;
point._minX = pointMinX;
point._maxY = pointMaxY;
point._minY = pointMinY;
point.labelrank = pick(point.labelrank, (pointMaxX - pointMinX) * (pointMaxY - pointMinY));
point._foundBox = true;
}
 
maxX = Math.max(maxX, point._maxX);
minX = Math.min(minX, point._minX);
maxY = Math.max(maxY, point._maxY);
minY = Math.min(minY, point._minY);
minRange = Math.min(point._maxX - point._minX, point._maxY - point._minY, minRange);
hasBox = true;
}
});
 
// Set the box for the whole series
if (hasBox) {
this.minY = Math.min(minY, pick(this.minY, MAX_VALUE));
this.maxY = Math.max(maxY, pick(this.maxY, -MAX_VALUE));
this.minX = Math.min(minX, pick(this.minX, MAX_VALUE));
this.maxX = Math.max(maxX, pick(this.maxX, -MAX_VALUE));
 
// If no minRange option is set, set the default minimum zooming range to 5 times the
// size of the smallest element
if (xAxis && xAxis.options.minRange === undefined) {
xAxis.minRange = Math.min(5 * minRange, (this.maxX - this.minX) / 5, xAxis.minRange || MAX_VALUE);
}
if (yAxis && yAxis.options.minRange === undefined) {
yAxis.minRange = Math.min(5 * minRange, (this.maxY - this.minY) / 5, yAxis.minRange || MAX_VALUE);
}
}
},
 
getExtremes: function() {
// Get the actual value extremes for colors
Series.prototype.getExtremes.call(this, this.valueData);
 
// Recalculate box on updated data
if (this.chart.hasRendered && this.isDirtyData) {
this.getBox(this.options.data);
}
 
this.valueMin = this.dataMin;
this.valueMax = this.dataMax;
 
// Extremes for the mock Y axis
this.dataMin = this.minY;
this.dataMax = this.maxY;
},
 
/**
* Translate the path so that it automatically fits into the plot area box
* @param {Object} path
*/
translatePath: function(path) {
 
var series = this,
even = false, // while loop reads from the end
xAxis = series.xAxis,
yAxis = series.yAxis,
xMin = xAxis.min,
xTransA = xAxis.transA,
xMinPixelPadding = xAxis.minPixelPadding,
yMin = yAxis.min,
yTransA = yAxis.transA,
yMinPixelPadding = yAxis.minPixelPadding,
i,
ret = []; // Preserve the original
 
// Do the translation
if (path) {
i = path.length;
while (i--) {
if (isNumber(path[i])) {
ret[i] = even ?
(path[i] - xMin) * xTransA + xMinPixelPadding :
(path[i] - yMin) * yTransA + yMinPixelPadding;
even = !even;
} else {
ret[i] = path[i];
}
}
}
 
return ret;
},
 
/**
* Extend setData to join in mapData. If the allAreas option is true, all areas
* from the mapData are used, and those that don't correspond to a data value
* are given null values.
*/
setData: function(data, redraw, animation, updatePoints) {
var options = this.options,
chartOptions = this.chart.options.chart,
globalMapData = chartOptions && chartOptions.map,
mapData = options.mapData,
joinBy = options.joinBy,
joinByNull = joinBy === null,
pointArrayMap = options.keys || this.pointArrayMap,
dataUsed = [],
mapMap = {},
mapPoint,
mapTransforms = this.chart.mapTransforms,
props,
i;
 
// Collect mapData from chart options if not defined on series
if (!mapData && globalMapData) {
mapData = typeof globalMapData === 'string' ? H.maps[globalMapData] : globalMapData;
}
 
if (joinByNull) {
joinBy = '_i';
}
joinBy = this.joinBy = splat(joinBy);
if (!joinBy[1]) {
joinBy[1] = joinBy[0];
}
 
// Pick up numeric values, add index
// Convert Array point definitions to objects using pointArrayMap
if (data) {
each(data, function(val, i) {
var ix = 0;
if (isNumber(val)) {
data[i] = {
value: val
};
} else if (isArray(val)) {
data[i] = {};
// Automatically copy first item to hc-key if there is an extra leading string
if (!options.keys && val.length > pointArrayMap.length && typeof val[0] === 'string') {
data[i]['hc-key'] = val[0];
++ix;
}
// Run through pointArrayMap and what's left of the point data array in parallel, copying over the values
for (var j = 0; j < pointArrayMap.length; ++j, ++ix) {
if (pointArrayMap[j]) {
data[i][pointArrayMap[j]] = val[ix];
}
}
}
if (joinByNull) {
data[i]._i = i;
}
});
}
 
this.getBox(data);
 
// Pick up transform definitions for chart
this.chart.mapTransforms = mapTransforms = chartOptions && chartOptions.mapTransforms || mapData && mapData['hc-transform'] || mapTransforms;
 
// Cache cos/sin of transform rotation angle
if (mapTransforms) {
H.objectEach(mapTransforms, function(transform) {
if (transform.rotation) {
transform.cosAngle = Math.cos(transform.rotation);
transform.sinAngle = Math.sin(transform.rotation);
}
});
}
 
if (mapData) {
if (mapData.type === 'FeatureCollection') {
this.mapTitle = mapData.title;
mapData = H.geojson(mapData, this.type, this);
}
 
this.mapData = mapData;
this.mapMap = {};
 
for (i = 0; i < mapData.length; i++) {
mapPoint = mapData[i];
props = mapPoint.properties;
 
mapPoint._i = i;
// Copy the property over to root for faster access
if (joinBy[0] && props && props[joinBy[0]]) {
mapPoint[joinBy[0]] = props[joinBy[0]];
}
mapMap[mapPoint[joinBy[0]]] = mapPoint;
}
this.mapMap = mapMap;
 
// Registered the point codes that actually hold data
if (data && joinBy[1]) {
each(data, function(point) {
if (mapMap[point[joinBy[1]]]) {
dataUsed.push(mapMap[point[joinBy[1]]]);
}
});
}
 
if (options.allAreas) {
this.getBox(mapData);
data = data || [];
 
// Registered the point codes that actually hold data
if (joinBy[1]) {
each(data, function(point) {
dataUsed.push(point[joinBy[1]]);
});
}
 
// Add those map points that don't correspond to data, which will be drawn as null points
dataUsed = '|' + map(dataUsed, function(point) {
return point && point[joinBy[0]];
}).join('|') + '|'; // String search is faster than array.indexOf
 
each(mapData, function(mapPoint) {
if (!joinBy[0] || dataUsed.indexOf('|' + mapPoint[joinBy[0]] + '|') === -1) {
data.push(merge(mapPoint, {
value: null
}));
updatePoints = false; // #5050 - adding all areas causes the update optimization of setData to kick in, even though the point order has changed
}
});
} else {
this.getBox(dataUsed); // Issue #4784
}
}
Series.prototype.setData.call(this, data, redraw, animation, updatePoints);
},
 
 
/**
* No graph for the map series
*/
drawGraph: noop,
 
/**
* We need the points' bounding boxes in order to draw the data labels, so
* we skip it now and call it from drawPoints instead.
*/
drawDataLabels: noop,
 
/**
* Allow a quick redraw by just translating the area group. Used for zooming and panning
* in capable browsers.
*/
doFullTranslate: function() {
return this.isDirtyData || this.chart.isResizing || this.chart.renderer.isVML || !this.baseTrans;
},
 
/**
* Add the path option for data points. Find the max value for color calculation.
*/
translate: function() {
var series = this,
xAxis = series.xAxis,
yAxis = series.yAxis,
doFullTranslate = series.doFullTranslate();
 
series.generatePoints();
 
each(series.data, function(point) {
 
// Record the middle point (loosely based on centroid), determined
// by the middleX and middleY options.
point.plotX = xAxis.toPixels(point._midX, true);
point.plotY = yAxis.toPixels(point._midY, true);
 
if (doFullTranslate) {
 
point.shapeType = 'path';
point.shapeArgs = {
d: series.translatePath(point.path)
};
}
});
 
series.translateColors();
},
 
/**
* Get presentational attributes. In the maps series this runs in both
* styled and non-styled mode, because colors hold data when a colorAxis
* is used.
*/
pointAttribs: function(point, state) {
var attr;
 
attr = seriesTypes.column.prototype.pointAttribs.call(
this, point, state
);
 
 
// If vector-effect is not supported, we set the stroke-width on the group element
// and let all point graphics inherit. That way we don't have to iterate over all
// points to update the stroke-width on zooming. TODO: Check unstyled
if (supportsVectorEffect) {
attr['vector-effect'] = 'non-scaling-stroke';
} else {
attr['stroke-width'] = 'inherit';
}
 
return attr;
},
 
/**
* Use the drawPoints method of column, that is able to handle simple shapeArgs.
* Extend it by assigning the tooltip position.
*/
drawPoints: function() {
var series = this,
xAxis = series.xAxis,
yAxis = series.yAxis,
group = series.group,
chart = series.chart,
renderer = chart.renderer,
scaleX,
scaleY,
translateX,
translateY,
baseTrans = this.baseTrans,
transformGroup,
startTranslateX,
startTranslateY,
startScaleX,
startScaleY;
 
// Set a group that handles transform during zooming and panning in order to preserve clipping
// on series.group
if (!series.transformGroup) {
series.transformGroup = renderer.g()
.attr({
scaleX: 1,
scaleY: 1
})
.add(group);
series.transformGroup.survive = true;
}
 
// Draw the shapes again
if (series.doFullTranslate()) {
 
// Individual point actions. TODO: Check unstyled.
 
if (chart.hasRendered) {
each(series.points, function(point) {
 
// Restore state color on update/redraw (#3529)
if (point.shapeArgs) {
point.shapeArgs.fill = series.pointAttribs(point, point.state).fill;
}
});
}
 
 
// Draw them in transformGroup
series.group = series.transformGroup;
seriesTypes.column.prototype.drawPoints.apply(series);
series.group = group; // Reset
 
// Add class names
each(series.points, function(point) {
if (point.graphic) {
if (point.name) {
point.graphic.addClass('highcharts-name-' + point.name.replace(/ /g, '-').toLowerCase());
}
if (point.properties && point.properties['hc-key']) {
point.graphic.addClass('highcharts-key-' + point.properties['hc-key'].toLowerCase());
}
 
 
}
});
 
// Set the base for later scale-zooming. The originX and originY properties are the
// axis values in the plot area's upper left corner.
this.baseTrans = {
originX: xAxis.min - xAxis.minPixelPadding / xAxis.transA,
originY: yAxis.min - yAxis.minPixelPadding / yAxis.transA + (yAxis.reversed ? 0 : yAxis.len / yAxis.transA),
transAX: xAxis.transA,
transAY: yAxis.transA
};
 
// Reset transformation in case we're doing a full translate (#3789)
this.transformGroup.animate({
translateX: 0,
translateY: 0,
scaleX: 1,
scaleY: 1
});
 
// Just update the scale and transform for better performance
} else {
scaleX = xAxis.transA / baseTrans.transAX;
scaleY = yAxis.transA / baseTrans.transAY;
translateX = xAxis.toPixels(baseTrans.originX, true);
translateY = yAxis.toPixels(baseTrans.originY, true);
 
// Handle rounding errors in normal view (#3789)
if (scaleX > 0.99 && scaleX < 1.01 && scaleY > 0.99 && scaleY < 1.01) {
scaleX = 1;
scaleY = 1;
translateX = Math.round(translateX);
translateY = Math.round(translateY);
}
 
// Animate or move to the new zoom level. In order to prevent
// flickering as the different transform components are set out of
// sync (#5991), we run a fake animator attribute and set scale and
// translation synchronously in the same step.
// A possible improvement to the API would be to handle this in the
// renderer or animation engine itself, to ensure that when we are
// animating multiple properties, we make sure that each step for
// each property is performed in the same step. Also, for symbols
// and for transform properties, it should induce a single
// updateTransform and symbolAttr call.
transformGroup = this.transformGroup;
if (chart.renderer.globalAnimation) {
startTranslateX = transformGroup.attr('translateX');
startTranslateY = transformGroup.attr('translateY');
startScaleX = transformGroup.attr('scaleX');
startScaleY = transformGroup.attr('scaleY');
transformGroup
.attr({
animator: 0
})
.animate({
animator: 1
}, {
step: function(now, fx) {
transformGroup.attr({
translateX: startTranslateX +
(translateX - startTranslateX) * fx.pos,
translateY: startTranslateY +
(translateY - startTranslateY) * fx.pos,
scaleX: startScaleX +
(scaleX - startScaleX) * fx.pos,
scaleY: startScaleY +
(scaleY - startScaleY) * fx.pos
});
 
}
});
 
// When dragging, animation is off.
} else {
transformGroup.attr({
translateX: translateX,
translateY: translateY,
scaleX: scaleX,
scaleY: scaleY
});
}
 
}
 
// Set the stroke-width directly on the group element so the children inherit it. We need to use
// setAttribute directly, because the stroke-widthSetter method expects a stroke color also to be
// set.
if (!supportsVectorEffect) {
series.group.element.setAttribute(
'stroke-width',
series.options[
(series.pointAttrToOptions && series.pointAttrToOptions['stroke-width']) || 'borderWidth'
] / (scaleX || 1)
);
}
 
this.drawMapDataLabels();
 
 
},
 
/**
* Draw the data labels. Special for maps is the time that the data labels are drawn (after points),
* and the clipping of the dataLabelsGroup.
*/
drawMapDataLabels: function() {
 
Series.prototype.drawDataLabels.call(this);
if (this.dataLabelsGroup) {
this.dataLabelsGroup.clip(this.chart.clipRect);
}
},
 
/**
* Override render to throw in an async call in IE8. Otherwise it chokes on the US counties demo.
*/
render: function() {
var series = this,
render = Series.prototype.render;
 
// Give IE8 some time to breathe.
if (series.chart.renderer.isVML && series.data.length > 3000) {
setTimeout(function() {
render.call(series);
});
} else {
render.call(series);
}
},
 
/**
* The initial animation for the map series. By default, animation is disabled.
* Animation of map shapes is not at all supported in VML browsers.
*/
animate: function(init) {
var chart = this.chart,
animation = this.options.animation,
group = this.group,
xAxis = this.xAxis,
yAxis = this.yAxis,
left = xAxis.pos,
top = yAxis.pos;
 
if (chart.renderer.isSVG) {
 
if (animation === true) {
animation = {
duration: 1000
};
}
 
// Initialize the animation
if (init) {
 
// Scale down the group and place it in the center
group.attr({
translateX: left + xAxis.len / 2,
translateY: top + yAxis.len / 2,
scaleX: 0.001, // #1499
scaleY: 0.001
});
 
// Run the animation
} else {
group.animate({
translateX: left,
translateY: top,
scaleX: 1,
scaleY: 1
}, animation);
 
// Delete this function to allow it only once
this.animate = null;
}
}
},
 
/**
* Animate in the new series from the clicked point in the old series.
* Depends on the drilldown.js module
*/
animateDrilldown: function(init) {
var toBox = this.chart.plotBox,
level = this.chart.drilldownLevels[this.chart.drilldownLevels.length - 1],
fromBox = level.bBox,
animationOptions = this.chart.options.drilldown.animation,
scale;
 
if (!init) {
 
scale = Math.min(fromBox.width / toBox.width, fromBox.height / toBox.height);
level.shapeArgs = {
scaleX: scale,
scaleY: scale,
translateX: fromBox.x,
translateY: fromBox.y
};
 
each(this.points, function(point) {
if (point.graphic) {
point.graphic
.attr(level.shapeArgs)
.animate({
scaleX: 1,
scaleY: 1,
translateX: 0,
translateY: 0
}, animationOptions);
}
});
 
this.animate = null;
}
 
},
 
drawLegendSymbol: LegendSymbolMixin.drawRectangle,
 
/**
* When drilling up, pull out the individual point graphics from the lower series
* and animate them into the origin point in the upper series.
*/
animateDrillupFrom: function(level) {
seriesTypes.column.prototype.animateDrillupFrom.call(this, level);
},
 
 
/**
* When drilling up, keep the upper series invisible until the lower series has
* moved into place
*/
animateDrillupTo: function(init) {
seriesTypes.column.prototype.animateDrillupTo.call(this, init);
}
 
// Point class
}), extend({
/**
* Extend the Point object to split paths
*/
applyOptions: function(options, x) {
 
var point = Point.prototype.applyOptions.call(this, options, x),
series = this.series,
joinBy = series.joinBy,
mapPoint;
 
if (series.mapData) {
mapPoint = point[joinBy[1]] !== undefined && series.mapMap[point[joinBy[1]]];
if (mapPoint) {
// This applies only to bubbles
if (series.xyFromShape) {
point.x = mapPoint._midX;
point.y = mapPoint._midY;
}
extend(point, mapPoint); // copy over properties
} else {
point.value = point.value || null;
}
}
 
return point;
},
 
/**
* Stop the fade-out
*/
onMouseOver: function(e) {
clearTimeout(this.colorInterval);
if (this.value !== null || this.series.options.nullInteraction) {
Point.prototype.onMouseOver.call(this, e);
} else { //#3401 Tooltip doesn't hide when hovering over null points
this.series.onMouseOut(e);
}
},
 
/**
* Highmaps only. Zoom in on the point using the global animation.
*
* @function #zoomTo
* @memberOf Point
* @sample maps/members/point-zoomto/
* Zoom to points from butons
*/
zoomTo: function() {
var point = this,
series = point.series;
 
series.xAxis.setExtremes(
point._minX,
point._maxX,
false
);
series.yAxis.setExtremes(
point._minY,
point._maxY,
false
);
series.chart.redraw();
}
}, colorPointMixin));
 
}(Highcharts));
(function(H) {
/**
* (c) 2010-2017 Torstein Honsi
*
* License: www.highcharts.com/license
*/
var seriesType = H.seriesType,
seriesTypes = H.seriesTypes;
 
// The mapline series type
//
/**
* @extends {plotOptions.map}
* @optionparent plotOptions.mapline
*/
seriesType('mapline', 'map', {
 
 
/**
* The width of the map line.
*
* @type {Number}
* @default 1
* @product highmaps
*/
lineWidth: 1,
 
/**
* Fill color for the map line shapes
*
* @type {Color}
* @default none
* @product highmaps
*/
fillColor: 'none'
 
}, {
type: 'mapline',
colorProp: 'stroke',
 
pointAttrToOptions: {
'stroke': 'color',
'stroke-width': 'lineWidth'
},
/**
* Get presentational attributes
*/
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
});
 
}(Highcharts));
(function(H) {
/**
* (c) 2010-2017 Torstein Honsi
*
* License: www.highcharts.com/license
*/
var merge = H.merge,
Point = H.Point,
seriesType = H.seriesType;
 
// The mappoint series type
/**
* @extends plotOptions.scatter
* @optionparent plotOptions.mappoint
*/
seriesType('mappoint', 'scatter', {
 
/**
*/
dataLabels: {
 
/**
*/
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);
}
});
 
}(Highcharts));
(function(H) {
/**
* (c) 2010-2017 Torstein Honsi
*
* License: www.highcharts.com/license
*/
var arrayMax = H.arrayMax,
arrayMin = H.arrayMin,
Axis = H.Axis,
color = H.color,
each = H.each,
isNumber = H.isNumber,
noop = H.noop,
pick = H.pick,
pInt = H.pInt,
Point = H.Point,
Series = H.Series,
seriesType = H.seriesType,
seriesTypes = H.seriesTypes;
 
/* ****************************************************************************
* Start Bubble series code *
*****************************************************************************/
 
 
/**
* @extends plotOptions.scatter
* @optionparent plotOptions.bubble
*/
seriesType('bubble', 'scatter', {
 
/**
*/
dataLabels: {
 
/**
*/
formatter: function() { // #2945
return this.point.z;
},
 
/**
*/
inside: true,
 
/**
*/
verticalAlign: 'middle'
},
// displayNegative: true,
 
/**
* Options for the point markers of line-like series. Properties like
* `fillColor`, `lineColor` and `lineWidth` define the visual appearance
* of the markers. Other series types, like column series, don't have
* markers, but have visual options on the series level instead.
*
* In [styled mode](http://www.highcharts.com/docs/chart-design-and-
* style/style-by-css), the markers can be styled with the `.highcharts-
* point`, `.highcharts-point-hover` and `.highcharts-point-select`
* class names.
*
* @type {Object}
* @extends plotOptions.series.marker
* @excluding radius
* @product highcharts
*/
marker: {
 
// fillOpacity: 0.5,
 
/**
*/
lineColor: null, // inherit from series.color
 
/**
*/
lineWidth: 1,
 
// Avoid offset in Point.setState
 
/**
*/
radius: null,
 
/**
*/
states: {
 
/**
*/
hover: {
 
/**
*/
radiusPlus: 0
}
},
 
/**
* A predefined shape or symbol for the marker. Possible values are
* "circle", "square", "diamond", "triangle" and "triangle-down".
*
* Additionally, the URL to a graphic can be given on the form `url(graphic.
* png)`. Note that for the image to be applied to exported charts,
* its URL needs to be accessible by the export server.
*
* Custom callbacks for symbol path generation can also be added to
* `Highcharts.SVGRenderer.prototype.symbols`. The callback is then
* used by its method name, as shown in the demo.
*
* @validvalue ["circle", "square", "diamond", "triangle", "triangle-down"]
* @type {String}
* @sample {highcharts} highcharts/plotoptions/bubble-symbol/ Bubble chart with various symbols
* @sample {highcharts} highcharts/plotoptions/series-marker-symbol/ General chart with predefined, graphic and custom markers
* @default circle
* @since 5.0.11
* @product highcharts
*/
symbol: 'circle'
},
 
/**
* Minimum bubble size. Bubbles will automatically size between the
* `minSize` and `maxSize` to reflect the `z` value of each bubble.
* Can be either pixels (when no unit is given), or a percentage of
* the smallest one of the plot width and height.
*
* @type {String}
* @sample {highcharts} highcharts/plotoptions/bubble-size/ Bubble size
* @default 8
* @since 3.0
* @product highcharts
*/
minSize: 8,
 
/**
* Maximum bubble size. Bubbles will automatically size between the
* `minSize` and `maxSize` to reflect the `z` value of each bubble.
* Can be either pixels (when no unit is given), or a percentage of
* the smallest one of the plot width and height.
*
* @type {String}
* @sample {highcharts} highcharts/plotoptions/bubble-size/ Bubble size
* @default 20%
* @since 3.0
* @product highcharts
*/
maxSize: '20%',
// negativeColor: null,
// sizeBy: 'area'
 
/**
* When this is true, the series will not cause the Y axis to cross
* the zero plane (or [threshold](#plotOptions.series.threshold) option)
* unless the data actually crosses the plane.
*
* For example, if `softThreshold` is `false`, a series of 0, 1, 2,
* 3 will make the Y axis show negative values according to the `minPadding`
* option. If `softThreshold` is `true`, the Y axis starts at 0.
*
* @type {Boolean}
* @default false
* @since 4.1.9
* @product highcharts
*/
softThreshold: false,
 
/**
*/
states: {
 
/**
*/
hover: {
 
/**
*/
halo: {
 
/**
*/
size: 5
}
}
},
 
/**
*/
tooltip: {
 
/**
*/
pointFormat: '({point.x}, {point.y}), Size: {point.z}'
},
 
/**
*/
turboThreshold: 0,
 
/**
* When [displayNegative](#plotOptions.bubble.displayNegative) is `false`,
* bubbles with lower Z values are skipped. When `displayNegative`
* is `true` and a [negativeColor](#plotOptions.bubble.negativeColor)
* is given, points with lower Z is colored.
*
* @type {Number}
* @sample {highcharts} highcharts/plotoptions/bubble-negative/ Negative bubbles
* @default 0
* @since 3.0
* @product highcharts
*/
zThreshold: 0,
 
/**
*/
zoneAxis: 'z'
 
// Prototype members
}, {
pointArrayMap: ['y', 'z'],
parallelArrays: ['x', 'y', 'z'],
trackerGroups: ['group', 'dataLabelsGroup'],
specialGroup: 'group', // To allow clipping (#6296)
bubblePadding: true,
zoneAxis: 'z',
directTouch: true,
 
 
pointAttribs: function(point, state) {
var markerOptions = this.options.marker,
fillOpacity = pick(markerOptions.fillOpacity, 0.5),
attr = Series.prototype.pointAttribs.call(this, point, state);
 
if (fillOpacity !== 1) {
attr.fill = color(attr.fill).setOpacity(fillOpacity).get('rgba');
}
 
return attr;
},
 
 
/**
* Get the radius for each point based on the minSize, maxSize and each point's Z value. This
* must be done prior to Series.translate because the axis needs to add padding in
* accordance with the point sizes.
*/
getRadii: function(zMin, zMax, minSize, maxSize) {
var len,
i,
pos,
zData = this.zData,
radii = [],
options = this.options,
sizeByArea = options.sizeBy !== 'width',
zThreshold = options.zThreshold,
zRange = zMax - zMin,
value,
radius;
 
// Set the shape type and arguments to be picked up in drawPoints
for (i = 0, len = zData.length; i < len; i++) {
 
value = zData[i];
 
// When sizing by threshold, the absolute value of z determines the size
// of the bubble.
if (options.sizeByAbsoluteValue && value !== null) {
value = Math.abs(value - zThreshold);
zMax = Math.max(zMax - zThreshold, Math.abs(zMin - zThreshold));
zMin = 0;
}
 
if (value === null) {
radius = null;
// Issue #4419 - if value is less than zMin, push a radius that's always smaller than the minimum size
} else if (value < zMin) {
radius = minSize / 2 - 1;
} else {
// Relative size, a number between 0 and 1
pos = zRange > 0 ? (value - zMin) / zRange : 0.5;
 
if (sizeByArea && pos >= 0) {
pos = Math.sqrt(pos);
}
radius = Math.ceil(minSize + pos * (maxSize - minSize)) / 2;
}
radii.push(radius);
}
this.radii = radii;
},
 
/**
* Perform animation on the bubbles
*/
animate: function(init) {
var animation = this.options.animation;
 
if (!init) { // run the animation
each(this.points, function(point) {
var graphic = point.graphic,
animationTarget;
 
if (graphic && graphic.width) { // URL symbols don't have width
animationTarget = {
x: graphic.x,
y: graphic.y,
width: graphic.width,
height: graphic.height
};
 
// Start values
graphic.attr({
x: point.plotX,
y: point.plotY,
width: 1,
height: 1
});
 
// Run animation
graphic.animate(animationTarget, animation);
}
});
 
// delete this function to allow it only once
this.animate = null;
}
},
 
/**
* Extend the base translate method to handle bubble size
*/
translate: function() {
 
var i,
data = this.data,
point,
radius,
radii = this.radii;
 
// Run the parent method
seriesTypes.scatter.prototype.translate.call(this);
 
// Set the shape type and arguments to be picked up in drawPoints
i = data.length;
 
while (i--) {
point = data[i];
radius = radii ? radii[i] : 0; // #1737
 
if (isNumber(radius) && radius >= this.minPxSize / 2) {
// Shape arguments
point.marker = H.extend(point.marker, {
radius: radius,
width: 2 * radius,
height: 2 * radius
});
 
// Alignment box for the data label
point.dlBox = {
x: point.plotX - radius,
y: point.plotY - radius,
width: 2 * radius,
height: 2 * radius
};
} else { // below zThreshold
point.shapeArgs = point.plotY = point.dlBox = undefined; // #1691
}
}
},
 
alignDataLabel: seriesTypes.column.prototype.alignDataLabel,
buildKDTree: noop,
applyZones: noop
 
// Point class
}, {
haloPath: function(size) {
return Point.prototype.haloPath.call(
this,
size === 0 ? 0 : (this.marker ? this.marker.radius || 0 : 0) + size // #6067
);
},
ttBelow: false
});
 
/**
* Add logic to pad each axis with the amount of pixels
* necessary to avoid the bubbles to overflow.
*/
Axis.prototype.beforePadding = function() {
var axis = this,
axisLength = this.len,
chart = this.chart,
pxMin = 0,
pxMax = axisLength,
isXAxis = this.isXAxis,
dataKey = isXAxis ? 'xData' : 'yData',
min = this.min,
extremes = {},
smallestSize = Math.min(chart.plotWidth, chart.plotHeight),
zMin = Number.MAX_VALUE,
zMax = -Number.MAX_VALUE,
range = this.max - min,
transA = axisLength / range,
activeSeries = [];
 
// Handle padding on the second pass, or on redraw
each(this.series, function(series) {
 
var seriesOptions = series.options,
zData;
 
if (series.bubblePadding && (series.visible || !chart.options.chart.ignoreHiddenSeries)) {
 
// Correction for #1673
axis.allowZoomOutside = true;
 
// Cache it
activeSeries.push(series);
 
if (isXAxis) { // because X axis is evaluated first
 
// For each series, translate the size extremes to pixel values
each(['minSize', 'maxSize'], function(prop) {
var length = seriesOptions[prop],
isPercent = /%$/.test(length);
 
length = pInt(length);
extremes[prop] = isPercent ?
smallestSize * length / 100 :
length;
 
});
series.minPxSize = extremes.minSize;
// Prioritize min size if conflict to make sure bubbles are
// always visible. #5873
series.maxPxSize = Math.max(extremes.maxSize, extremes.minSize);
 
// Find the min and max Z
zData = series.zData;
if (zData.length) { // #1735
zMin = pick(seriesOptions.zMin, Math.min(
zMin,
Math.max(
arrayMin(zData),
seriesOptions.displayNegative === false ? seriesOptions.zThreshold : -Number.MAX_VALUE
)
));
zMax = pick(seriesOptions.zMax, Math.max(zMax, arrayMax(zData)));
}
}
}
});
 
each(activeSeries, function(series) {
 
var data = series[dataKey],
i = data.length,
radius;
 
if (isXAxis) {
series.getRadii(zMin, zMax, series.minPxSize, series.maxPxSize);
}
 
if (range > 0) {
while (i--) {
if (isNumber(data[i]) && axis.dataMin <= data[i] && data[i] <= axis.dataMax) {
radius = series.radii[i];
pxMin = Math.min(((data[i] - min) * transA) - radius, pxMin);
pxMax = Math.max(((data[i] - min) * transA) + radius, pxMax);
}
}
}
});
 
if (activeSeries.length && range > 0 && !this.isLog) {
pxMax -= axisLength;
transA *= (axisLength + pxMin - pxMax) / axisLength;
each([
['min', 'userMin', pxMin],
['max', 'userMax', pxMax]
], function(keys) {
if (pick(axis.options[keys[0]], axis[keys[1]]) === undefined) {
axis[keys[0]] += keys[2] / transA;
}
});
}
};
 
/* ****************************************************************************
* End Bubble series code *
*****************************************************************************/
 
}(Highcharts));
(function(H) {
/**
* (c) 2010-2017 Torstein Honsi
*
* License: www.highcharts.com/license
*/
var merge = H.merge,
Point = H.Point,
seriesType = H.seriesType,
seriesTypes = H.seriesTypes;
 
// The mapbubble series type
if (seriesTypes.bubble) {
 
/**
* @extends {plotOptions.bubble}
* @optionparent plotOptions.mapbubble
*/
seriesType('mapbubble', 'bubble', {
 
/**
*/
animationLimit: 500,
 
/**
*/
tooltip: {
 
/**
*/
pointFormat: '{point.name}: {point.z}'
}
 
// Prototype members
}, {
xyFromShape: true,
type: 'mapbubble',
pointArrayMap: ['z'], // If one single value is passed, it is interpreted as 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;
},
ttBelow: false
});
}
 
}(Highcharts));
(function(H) {
/**
* (c) 2010-2017 Torstein Honsi
*
* License: www.highcharts.com/license
*/
var colorPointMixin = H.colorPointMixin,
colorSeriesMixin = H.colorSeriesMixin,
each = H.each,
LegendSymbolMixin = H.LegendSymbolMixin,
merge = H.merge,
noop = H.noop,
pick = H.pick,
Series = H.Series,
seriesType = H.seriesType,
seriesTypes = H.seriesTypes;
 
// The Heatmap series type
 
/**
* @extends {plotOptions.scatter}
* @optionparent plotOptions.heatmap
*/
seriesType('heatmap', 'scatter', {
 
/**
*/
animation: false,
 
/**
*/
borderWidth: 0,
 
 
/**
*/
nullColor: '#f7f7f7',
 
 
/**
*/
dataLabels: {
 
/**
*/
formatter: function() { // #2945
return this.point.value;
},
 
/**
*/
inside: true,
 
/**
*/
verticalAlign: 'middle',
 
/**
*/
crop: false,
 
/**
*/
overflow: false,
 
/**
*/
padding: 0 // #3837
},
 
/**
*/
marker: null,
 
/**
*/
pointRange: null, // dynamically set to colsize by default
 
/**
*/
tooltip: {
 
/**
*/
pointFormat: '{point.x}, {point.y}: {point.value}<br/>'
},
 
/**
*/
states: {
 
/**
*/
normal: {
 
/**
*/
animation: true
},
 
/**
*/
hover: {
 
/**
*/
halo: false, // #3406, halo is not required on heatmaps
 
/**
*/
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.
*/
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);
this.yAxis.axisPointRange = options.rowsize || 1; // general point range
},
translate: function() {
var series = this,
options = series.options,
xAxis = series.xAxis,
yAxis = series.yAxis,
between = function(x, a, b) {
return Math.min(Math.max(a, x), b);
};
 
series.generatePoints();
 
each(series.points, 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)
), -xAxis.len, 2 * xAxis.len
),
x2 = between(
Math.round(
xAxis.len -
xAxis.translate(point.x + xPad, 0, 1, 0, 1)
), -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
);
 
// 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),
y: Math.min(y1, y2),
width: Math.abs(x2 - x1),
height: Math.abs(y2 - y1)
};
});
 
series.translateColors();
},
drawPoints: function() {
seriesTypes.column.prototype.drawPoints.call(this);
 
each(this.points, function(point) {
 
point.graphic.attr(this.colorAttribs(point));
 
}, this);
},
animate: noop,
getBox: noop,
drawLegendSymbol: LegendSymbolMixin.drawRectangle,
alignDataLabel: seriesTypes.column.prototype.alignDataLabel,
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);
}
 
}), colorPointMixin);
 
}(Highcharts));
(function(H) {
/**
* (c) 2010-2017 Torstein Honsi
*
* License: www.highcharts.com/license
*/
var Chart = H.Chart,
each = H.each,
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.
*
* @function transformFromLatLon
* @memberOf Chart.prototype
*
* @param {Object} latLon
* A latitude/longitude object.
* @param {Number} latLon.lat
* The latitude.
* @param {Number} latLon.lon
* The longitude.
* @param {Object} transform
* The transform definition to use as explained in the {@link
* https://www.highcharts.com/docs/maps/latlon|documentation}.
*
* @return {Object}
* An object with `x` and `y` properties.
*
* @sample maps/series/latlon-transform/
* Use specific transformation for lat/lon
*/
Chart.prototype.transformFromLatLon = function(latLon, transform) {
if (win.proj4 === undefined) {
H.error(21);
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`.
*
* @function transformToLatLon
* @memberOf Chart.prototype
*
* @param {Point|Object} point
* A `Point` instance, or 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 {Object}
* An object with `lat` and `lon` properties.
*
* @sample maps/series/latlon-transform/
* Use specific transformation for lat/lon
*
*/
Chart.prototype.transformToLatLon = function(point, transform) {
if (win.proj4 === undefined) {
H.error(21);
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`.
*
* @function fromPointToLatLon
* @memberOf Chart.prototype
*
* @param {Point|Object} point
* A `Point` instance or anything containing `x` and `y` properties
* with numeric values
* @return {Object}
* An object with `lat` and `lon` properties.
*
* @sample maps/demo/latlon-advanced/
* Advanced lat/lon demo
*/
Chart.prototype.fromPointToLatLon = function(point) {
var transforms = this.mapTransforms,
transform;
 
if (!transforms) {
H.error(22);
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`.
*
* @function fromLatLonToPoint
* @memberOf Chart.prototype
*
* @param {Object} latLon
* Coordinates.
* @param {Number} latLon.lat
* The latitude.
* @param {Number} latLon.lon
* The longitude.
*
* @sample maps/series/latlon-to-point/
* Find a point from lat/lon
*
* @return {Object}
* 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);
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.
*
* @function #geojson
* @memberOf Highcharts
*
* @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 {Object}
* An object ready for the `mapData` option.
*
* @sample samples/maps/demo/geojson/
* Simple areas
* @sample maps/demo/geojson-multiple-types/
* Multiple types
*
*/
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';
 
each(geojson.features, 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') {
each(coordinates, polygonToPath);
path.push('Z');
 
} else if (type === 'MultiPolygon') {
each(coordinates, function(items) {
each(items, polygonToPath);
});
path.push('Z');
}
 
if (path.length) {
point = {
path: path
};
}
 
} else if (hType === 'mapline') {
if (type === 'LineString') {
polygonToPath(coordinates);
} else if (type === 'MultiLineString') {
each(coordinates, 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.
*
* @name #properties
* @memberOf Point
* @type {Object}
*/
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
});
}
});
 
}(Highcharts));
(function(H) {
/**
* (c) 2010-2017 Torstein Honsi
*
* License: www.highcharts.com/license
*/
var Chart = H.Chart,
defaultOptions = H.defaultOptions,
each = H.each,
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
 
/**
* @products 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.
*
* @type {Object}
* @sample {highmaps} maps/mapnavigation/button-theme/ Theming the navigation buttons
* @product highmaps
*/
buttonOptions: {
 
/**
* What box to align the buttons to. Possible values are `plotBox`
* and `spacingBox`.
*
* @validvalue ["plotBox", "spacingBox"]
* @type {String}
* @default plotBox
* @product highmaps
*/
alignTo: 'plotBox',
 
/**
* The alignment of the navigation buttons.
*
* @validvalue ["left", "center", "right"]
* @type {String}
* @default left
* @product highmaps
*/
align: 'left',
 
/**
* The vertical alignment of the buttons. Individual alignment can
* be adjusted by each button's `y` offset.
*
* @validvalue ["top", "middle", "bottom"]
* @type {String}
* @default bottom
* @product highmaps
*/
verticalAlign: 'top',
 
/**
* The X offset of the buttons relative to its `align` setting.
*
* @type {Number}
* @default 0
* @product highmaps
*/
x: 0,
 
/**
* The width of the map navigation buttons.
*
* @type {Number}
* @default 18
* @product highmaps
*/
width: 18,
 
/**
* The pixel height of the map navigation buttons.
*
* @type {Number}
* @default 18
* @product highmaps
*/
height: 18,
 
/**
* Padding for the navigation buttons.
*
* @type {Number}
* @default 5
* @since 5.0.0
* @product highmaps
*/
padding: 5,
 
 
/**
* Text styles for the map navigation buttons. Defaults to
*
* <pre>{
* fontSize: '15px',
* fontWeight: 'bold',
* textAlign: 'center'
* }</pre>
*
* @type {CSSObject}
* @product highmaps
*/
style: {
 
/**
*/
fontSize: '15px',
 
/**
*/
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.
*
* @type {Object}
* @sample {highmaps} maps/mapnavigation/button-theme/ Themed navigation buttons
* @product highmaps
*/
theme: {
'stroke-width': 1,
 
/**
*/
'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.
*
* @type {Object}
* @product highmaps
*/
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.
*
* @type {Object}
* @extends mapNavigation.buttonOptions
* @product highmaps
*/
zoomIn: {
 
/**
* Click handler for the button. Defaults to:
*
* <pre>function () {
* this.mapZoom(0.5);
* }</pre>
*
* @type {Function}
* @product highmaps
*/
onclick: function() {
this.mapZoom(0.5);
},
 
/**
* The text for the button. The tooltip (title) is a language option
* given by [lang.zoomIn](#lang.zoomIn).
*
* @type {String}
* @default +
* @product highmaps
*/
text: '+',
 
/**
* The position of the zoomIn button relative to the vertical alignment.
*
* @type {Number}
* @default 0
* @product highmaps
*/
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.
*
* @type {Object}
* @extends mapNavigation.buttonOptions
* @product highmaps
*/
zoomOut: {
 
/**
* Click handler for the button. Defaults to:
*
* <pre>function () {
* this.mapZoom(2);
* }</pre>
*
* @type {Function}
* @product highmaps
*/
onclick: function() {
this.mapZoom(2);
},
 
/**
* The text for the button. The tooltip (title) is a language option
* given by [lang.zoomOut](#lang.zoomIn).
*
* @type {String}
* @default -
* @product highmaps
*/
text: '-',
 
/**
* The position of the zoomOut button relative to the vertical alignment.
*
* @type {Number}
* @default 28
* @product highmaps
*/
y: 28
}
},
 
/**
* Sensitivity of mouse wheel or trackpad scrolling. 1 is no sensitivity,
* while with 2, one mousewheel delta will zoom in 50%.
*
* @type {Number}
* @default 1.1
* @since 4.2.4
* @product highmaps
*/
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.
*/
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;
};
 
// A placeholder for map definitions
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) {
each(['topbutton', 'bottombutton'], function(shape) {
VMLRenderer.prototype.symbols[shape] = SVGRenderer.prototype.symbols[shape];
});
}
 
 
/**
* The factory function for creating new map charts. Creates a new {@link
* Chart|Chart} object with different default options than the basic Chart.
*
* @function #mapChart
* @memberOf Highcharts
*
* @param {String|HTMLDOMElement} renderTo
* The DOM element to render to, or its id.
* @param {Options} options
* The chart options structure as described in the {@link
* https://api.highcharts.com/highstock|options reference}.
* @param {Function} 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 {@link https://api.highcharts.com/highstock/chart.events.load|
* chart.event.load} handler is equivalent.
*
* @return {Chart}
* The chart object.
*/
H.Map = H.mapChart = function(a, b, c) {
 
var hasRenderToArg = typeof a === 'string' || a.nodeName,
options = arguments[hasRenderToArg ? 1 : 0],
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 = seriesOptions;
 
 
return hasRenderToArg ?
new Chart(a, options, c) :
new Chart(options, b);
};
 
}(Highcharts));
}));