UNPKG

28.9 kBJavaScriptView Raw
1/**
2 * @license Highcharts JS v5.0.2 (2016-10-26)
3 *
4 * (c) 2009-2016 Torstein Honsi
5 *
6 * License: www.highcharts.com/license
7 */
8(function(factory) {
9 if (typeof module === 'object' && module.exports) {
10 module.exports = factory;
11 } else {
12 factory(Highcharts);
13 }
14}(function(Highcharts) {
15 (function(H) {
16 /**
17 * (c) 2010-2016 Torstein Honsi
18 *
19 * License: www.highcharts.com/license
20 */
21 'use strict';
22 var Axis = H.Axis,
23 Chart = H.Chart,
24 color = H.color,
25 ColorAxis,
26 each = H.each,
27 extend = H.extend,
28 isNumber = H.isNumber,
29 Legend = H.Legend,
30 LegendSymbolMixin = H.LegendSymbolMixin,
31 noop = H.noop,
32 merge = H.merge,
33 pick = H.pick,
34 wrap = H.wrap;
35
36 /**
37 * The ColorAxis object for inclusion in gradient legends
38 */
39 ColorAxis = H.ColorAxis = function() {
40 this.init.apply(this, arguments);
41 };
42 extend(ColorAxis.prototype, Axis.prototype);
43 extend(ColorAxis.prototype, {
44 defaultColorAxisOptions: {
45 lineWidth: 0,
46 minPadding: 0,
47 maxPadding: 0,
48 gridLineWidth: 1,
49 tickPixelInterval: 72,
50 startOnTick: true,
51 endOnTick: true,
52 offset: 0,
53 marker: {
54 animation: {
55 duration: 50
56 },
57 width: 0.01,
58
59 color: '#999999'
60
61 },
62 labels: {
63 overflow: 'justify'
64 },
65 minColor: '#e6ebf5',
66 maxColor: '#003399',
67 tickLength: 5,
68 showInLegend: true
69 },
70 init: function(chart, userOptions) {
71 var horiz = chart.options.legend.layout !== 'vertical',
72 options;
73
74 this.coll = 'colorAxis';
75
76 // Build the options
77 options = merge(this.defaultColorAxisOptions, {
78 side: horiz ? 2 : 1,
79 reversed: !horiz
80 }, userOptions, {
81 opposite: !horiz,
82 showEmpty: false,
83 title: null
84 });
85
86 Axis.prototype.init.call(this, chart, options);
87
88 // Base init() pushes it to the xAxis array, now pop it again
89 //chart[this.isXAxis ? 'xAxis' : 'yAxis'].pop();
90
91 // Prepare data classes
92 if (userOptions.dataClasses) {
93 this.initDataClasses(userOptions);
94 }
95 this.initStops(userOptions);
96
97 // Override original axis properties
98 this.horiz = horiz;
99 this.zoomEnabled = false;
100
101 // Add default values
102 this.defaultLegendLength = 200;
103 },
104
105 /*
106 * Return an intermediate color between two colors, according to pos where 0
107 * is the from color and 1 is the to color.
108 * NOTE: Changes here should be copied
109 * to the same function in drilldown.src.js and solid-gauge-src.js.
110 */
111 tweenColors: function(from, to, pos) {
112 // Check for has alpha, because rgba colors perform worse due to lack of
113 // support in WebKit.
114 var hasAlpha,
115 ret;
116
117 // Unsupported color, return to-color (#3920)
118 if (!to.rgba.length || !from.rgba.length) {
119 ret = to.input || 'none';
120
121 // Interpolate
122 } else {
123 from = from.rgba;
124 to = to.rgba;
125 hasAlpha = (to[3] !== 1 || from[3] !== 1);
126 ret = (hasAlpha ? 'rgba(' : 'rgb(') +
127 Math.round(to[0] + (from[0] - to[0]) * (1 - pos)) + ',' +
128 Math.round(to[1] + (from[1] - to[1]) * (1 - pos)) + ',' +
129 Math.round(to[2] + (from[2] - to[2]) * (1 - pos)) +
130 (hasAlpha ? (',' + (to[3] + (from[3] - to[3]) * (1 - pos))) : '') + ')';
131 }
132 return ret;
133 },
134
135 initDataClasses: function(userOptions) {
136 var axis = this,
137 chart = this.chart,
138 dataClasses,
139 colorCounter = 0,
140 colorCount = chart.options.chart.colorCount,
141 options = this.options,
142 len = userOptions.dataClasses.length;
143 this.dataClasses = dataClasses = [];
144 this.legendItems = [];
145
146 each(userOptions.dataClasses, function(dataClass, i) {
147 var colors;
148
149 dataClass = merge(dataClass);
150 dataClasses.push(dataClass);
151 if (!dataClass.color) {
152 if (options.dataClassColor === 'category') {
153
154 colors = chart.options.colors;
155 colorCount = colors.length;
156 dataClass.color = colors[colorCounter];
157
158 dataClass.colorIndex = colorCounter;
159
160 // increase and loop back to zero
161 colorCounter++;
162 if (colorCounter === colorCount) {
163 colorCounter = 0;
164 }
165 } else {
166 dataClass.color = axis.tweenColors(
167 color(options.minColor),
168 color(options.maxColor),
169 len < 2 ? 0.5 : i / (len - 1) // #3219
170 );
171 }
172 }
173 });
174 },
175
176 initStops: function(userOptions) {
177 this.stops = userOptions.stops || [
178 [0, this.options.minColor],
179 [1, this.options.maxColor]
180 ];
181 each(this.stops, function(stop) {
182 stop.color = color(stop[1]);
183 });
184 },
185
186 /**
187 * Extend the setOptions method to process extreme colors and color
188 * stops.
189 */
190 setOptions: function(userOptions) {
191 Axis.prototype.setOptions.call(this, userOptions);
192
193 this.options.crosshair = this.options.marker;
194 },
195
196 setAxisSize: function() {
197 var symbol = this.legendSymbol,
198 chart = this.chart,
199 legendOptions = chart.options.legend || {},
200 x,
201 y,
202 width,
203 height;
204
205 if (symbol) {
206 this.left = x = symbol.attr('x');
207 this.top = y = symbol.attr('y');
208 this.width = width = symbol.attr('width');
209 this.height = height = symbol.attr('height');
210 this.right = chart.chartWidth - x - width;
211 this.bottom = chart.chartHeight - y - height;
212
213 this.len = this.horiz ? width : height;
214 this.pos = this.horiz ? x : y;
215 } else {
216 // Fake length for disabled legend to avoid tick issues and such (#5205)
217 this.len = (this.horiz ? legendOptions.symbolWidth : legendOptions.symbolHeight) || this.defaultLegendLength;
218 }
219 },
220
221 /**
222 * Translate from a value to a color
223 */
224 toColor: function(value, point) {
225 var pos,
226 stops = this.stops,
227 from,
228 to,
229 color,
230 dataClasses = this.dataClasses,
231 dataClass,
232 i;
233
234 if (dataClasses) {
235 i = dataClasses.length;
236 while (i--) {
237 dataClass = dataClasses[i];
238 from = dataClass.from;
239 to = dataClass.to;
240 if ((from === undefined || value >= from) && (to === undefined || value <= to)) {
241 color = dataClass.color;
242 if (point) {
243 point.dataClass = i;
244 point.colorIndex = dataClass.colorIndex;
245 }
246 break;
247 }
248 }
249
250 } else {
251
252 if (this.isLog) {
253 value = this.val2lin(value);
254 }
255 pos = 1 - ((this.max - value) / ((this.max - this.min) || 1));
256 i = stops.length;
257 while (i--) {
258 if (pos > stops[i][0]) {
259 break;
260 }
261 }
262 from = stops[i] || stops[i + 1];
263 to = stops[i + 1] || from;
264
265 // The position within the gradient
266 pos = 1 - (to[0] - pos) / ((to[0] - from[0]) || 1);
267
268 color = this.tweenColors(
269 from.color,
270 to.color,
271 pos
272 );
273 }
274 return color;
275 },
276
277 /**
278 * Override the getOffset method to add the whole axis groups inside the legend.
279 */
280 getOffset: function() {
281 var group = this.legendGroup,
282 sideOffset = this.chart.axisOffset[this.side];
283
284 if (group) {
285
286 // Hook for the getOffset method to add groups to this parent group
287 this.axisParent = group;
288
289 // Call the base
290 Axis.prototype.getOffset.call(this);
291
292 // First time only
293 if (!this.added) {
294
295 this.added = true;
296
297 this.labelLeft = 0;
298 this.labelRight = this.width;
299 }
300 // Reset it to avoid color axis reserving space
301 this.chart.axisOffset[this.side] = sideOffset;
302 }
303 },
304
305 /**
306 * Create the color gradient
307 */
308 setLegendColor: function() {
309 var grad,
310 horiz = this.horiz,
311 options = this.options,
312 reversed = this.reversed,
313 one = reversed ? 1 : 0,
314 zero = reversed ? 0 : 1;
315
316 grad = horiz ? [one, 0, zero, 0] : [0, zero, 0, one]; // #3190
317 this.legendColor = {
318 linearGradient: {
319 x1: grad[0],
320 y1: grad[1],
321 x2: grad[2],
322 y2: grad[3]
323 },
324 stops: options.stops || [
325 [0, options.minColor],
326 [1, options.maxColor]
327 ]
328 };
329 },
330
331 /**
332 * The color axis appears inside the legend and has its own legend symbol
333 */
334 drawLegendSymbol: function(legend, item) {
335 var padding = legend.padding,
336 legendOptions = legend.options,
337 horiz = this.horiz,
338 width = pick(legendOptions.symbolWidth, horiz ? this.defaultLegendLength : 12),
339 height = pick(legendOptions.symbolHeight, horiz ? 12 : this.defaultLegendLength),
340 labelPadding = pick(legendOptions.labelPadding, horiz ? 16 : 30),
341 itemDistance = pick(legendOptions.itemDistance, 10);
342
343 this.setLegendColor();
344
345 // Create the gradient
346 item.legendSymbol = this.chart.renderer.rect(
347 0,
348 legend.baseline - 11,
349 width,
350 height
351 ).attr({
352 zIndex: 1
353 }).add(item.legendGroup);
354
355 // Set how much space this legend item takes up
356 this.legendItemWidth = width + padding + (horiz ? itemDistance : labelPadding);
357 this.legendItemHeight = height + padding + (horiz ? labelPadding : 0);
358 },
359 /**
360 * Fool the legend
361 */
362 setState: noop,
363 visible: true,
364 setVisible: noop,
365 getSeriesExtremes: function() {
366 var series;
367 if (this.series.length) {
368 series = this.series[0];
369 this.dataMin = series.valueMin;
370 this.dataMax = series.valueMax;
371 }
372 },
373 drawCrosshair: function(e, point) {
374 var plotX = point && point.plotX,
375 plotY = point && point.plotY,
376 crossPos,
377 axisPos = this.pos,
378 axisLen = this.len;
379
380 if (point) {
381 crossPos = this.toPixels(point[point.series.colorKey]);
382 if (crossPos < axisPos) {
383 crossPos = axisPos - 2;
384 } else if (crossPos > axisPos + axisLen) {
385 crossPos = axisPos + axisLen + 2;
386 }
387
388 point.plotX = crossPos;
389 point.plotY = this.len - crossPos;
390 Axis.prototype.drawCrosshair.call(this, e, point);
391 point.plotX = plotX;
392 point.plotY = plotY;
393
394 if (this.cross) {
395 this.cross
396 .addClass('highcharts-coloraxis-marker')
397 .add(this.legendGroup);
398
399
400 this.cross.attr({
401 fill: this.crosshair.color
402 });
403
404
405 }
406 }
407 },
408 getPlotLinePath: function(a, b, c, d, pos) {
409 return isNumber(pos) ? // crosshairs only // #3969 pos can be 0 !!
410 (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']) :
411 Axis.prototype.getPlotLinePath.call(this, a, b, c, d);
412 },
413
414 update: function(newOptions, redraw) {
415 var chart = this.chart,
416 legend = chart.legend;
417
418 each(this.series, function(series) {
419 series.isDirtyData = true; // Needed for Axis.update when choropleth colors change
420 });
421
422 // When updating data classes, destroy old items and make sure new ones are created (#3207)
423 if (newOptions.dataClasses && legend.allItems) {
424 each(legend.allItems, function(item) {
425 if (item.isDataClass) {
426 item.legendGroup.destroy();
427 }
428 });
429 chart.isDirtyLegend = true;
430 }
431
432 // Keep the options structure updated for export. Unlike xAxis and yAxis, the colorAxis is
433 // not an array. (#3207)
434 chart.options[this.coll] = merge(this.userOptions, newOptions);
435
436 Axis.prototype.update.call(this, newOptions, redraw);
437 if (this.legendItem) {
438 this.setLegendColor();
439 legend.colorizeItem(this, true);
440 }
441 },
442
443 /**
444 * Get the legend item symbols for data classes
445 */
446 getDataClassLegendSymbols: function() {
447 var axis = this,
448 chart = this.chart,
449 legendItems = this.legendItems,
450 legendOptions = chart.options.legend,
451 valueDecimals = legendOptions.valueDecimals,
452 valueSuffix = legendOptions.valueSuffix || '',
453 name;
454
455 if (!legendItems.length) {
456 each(this.dataClasses, function(dataClass, i) {
457 var vis = true,
458 from = dataClass.from,
459 to = dataClass.to;
460
461 // Assemble the default name. This can be overridden by legend.options.labelFormatter
462 name = '';
463 if (from === undefined) {
464 name = '< ';
465 } else if (to === undefined) {
466 name = '> ';
467 }
468 if (from !== undefined) {
469 name += H.numberFormat(from, valueDecimals) + valueSuffix;
470 }
471 if (from !== undefined && to !== undefined) {
472 name += ' - ';
473 }
474 if (to !== undefined) {
475 name += H.numberFormat(to, valueDecimals) + valueSuffix;
476 }
477 // Add a mock object to the legend items
478 legendItems.push(extend({
479 chart: chart,
480 name: name,
481 options: {},
482 drawLegendSymbol: LegendSymbolMixin.drawRectangle,
483 visible: true,
484 setState: noop,
485 isDataClass: true,
486 setVisible: function() {
487 vis = this.visible = !vis;
488 each(axis.series, function(series) {
489 each(series.points, function(point) {
490 if (point.dataClass === i) {
491 point.setVisible(vis);
492 }
493 });
494 });
495
496 chart.legend.colorizeItem(this, vis);
497 }
498 }, dataClass));
499 });
500 }
501 return legendItems;
502 },
503 name: '' // Prevents 'undefined' in legend in IE8
504 });
505
506 /**
507 * Handle animation of the color attributes directly
508 */
509 each(['fill', 'stroke'], function(prop) {
510 H.Fx.prototype[prop + 'Setter'] = function() {
511 this.elem.attr(prop, ColorAxis.prototype.tweenColors(color(this.start), color(this.end), this.pos));
512 };
513 });
514
515 /**
516 * Extend the chart getAxes method to also get the color axis
517 */
518 wrap(Chart.prototype, 'getAxes', function(proceed) {
519
520 var options = this.options,
521 colorAxisOptions = options.colorAxis;
522
523 proceed.call(this);
524
525 this.colorAxis = [];
526 if (colorAxisOptions) {
527 new ColorAxis(this, colorAxisOptions); // eslint-disable-line no-new
528 }
529 });
530
531
532 /**
533 * Wrap the legend getAllItems method to add the color axis. This also removes the
534 * axis' own series to prevent them from showing up individually.
535 */
536 wrap(Legend.prototype, 'getAllItems', function(proceed) {
537 var allItems = [],
538 colorAxis = this.chart.colorAxis[0];
539
540 if (colorAxis && colorAxis.options) {
541 if (colorAxis.options.showInLegend) {
542 // Data classes
543 if (colorAxis.options.dataClasses) {
544 allItems = allItems.concat(colorAxis.getDataClassLegendSymbols());
545 // Gradient legend
546 } else {
547 // Add this axis on top
548 allItems.push(colorAxis);
549 }
550 }
551
552 // Don't add the color axis' series
553 each(colorAxis.series, function(series) {
554 series.options.showInLegend = false;
555 });
556 }
557
558 return allItems.concat(proceed.call(this));
559 });
560
561 wrap(Legend.prototype, 'colorizeItem', function(proceed, item, visible) {
562 proceed.call(this, item, visible);
563 if (visible && item.legendColor) {
564 item.legendSymbol.attr({
565 fill: item.legendColor
566 });
567 }
568 });
569
570 }(Highcharts));
571 (function(H) {
572 /**
573 * (c) 2010-2016 Torstein Honsi
574 *
575 * License: www.highcharts.com/license
576 */
577 'use strict';
578 var defined = H.defined,
579 each = H.each,
580 noop = H.noop,
581 seriesTypes = H.seriesTypes;
582
583 /**
584 * Mixin for maps and heatmaps
585 */
586 H.colorPointMixin = {
587 /**
588 * Color points have a value option that determines whether or not it is a null point
589 */
590 isValid: function() {
591 return this.value !== null;
592 },
593
594 /**
595 * Set the visibility of a single point
596 */
597 setVisible: function(vis) {
598 var point = this,
599 method = vis ? 'show' : 'hide';
600
601 // Show and hide associated elements
602 each(['graphic', 'dataLabel'], function(key) {
603 if (point[key]) {
604 point[key][method]();
605 }
606 });
607 }
608 };
609
610 H.colorSeriesMixin = {
611 pointArrayMap: ['value'],
612 axisTypes: ['xAxis', 'yAxis', 'colorAxis'],
613 optionalAxis: 'colorAxis',
614 trackerGroups: ['group', 'markerGroup', 'dataLabelsGroup'],
615 getSymbol: noop,
616 parallelArrays: ['x', 'y', 'value'],
617 colorKey: 'value',
618
619
620 pointAttribs: seriesTypes.column.prototype.pointAttribs,
621
622
623 /**
624 * In choropleth maps, the color is a result of the value, so this needs translation too
625 */
626 translateColors: function() {
627 var series = this,
628 nullColor = this.options.nullColor,
629 colorAxis = this.colorAxis,
630 colorKey = this.colorKey;
631
632 each(this.data, function(point) {
633 var value = point[colorKey],
634 color;
635
636 color = point.options.color ||
637 (point.isNull ? nullColor : (colorAxis && value !== undefined) ? colorAxis.toColor(value, point) : point.color || series.color);
638
639 if (color) {
640 point.color = color;
641 }
642 });
643 },
644
645 /**
646 * Get the color attibutes to apply on the graphic
647 */
648 colorAttribs: function(point) {
649 var ret = {};
650 if (defined(point.color)) {
651 ret[this.colorProp || 'fill'] = point.color;
652 }
653 return ret;
654 }
655 };
656
657 }(Highcharts));
658 (function(H) {
659 /**
660 * (c) 2010-2016 Torstein Honsi
661 *
662 * License: www.highcharts.com/license
663 */
664 'use strict';
665 var colorPointMixin = H.colorPointMixin,
666 colorSeriesMixin = H.colorSeriesMixin,
667 each = H.each,
668 LegendSymbolMixin = H.LegendSymbolMixin,
669 merge = H.merge,
670 noop = H.noop,
671 pick = H.pick,
672 Series = H.Series,
673 seriesType = H.seriesType,
674 seriesTypes = H.seriesTypes;
675
676 // The Heatmap series type
677 seriesType('heatmap', 'scatter', {
678 animation: false,
679 borderWidth: 0,
680
681 nullColor: '#f7f7f7',
682
683 dataLabels: {
684 formatter: function() { // #2945
685 return this.point.value;
686 },
687 inside: true,
688 verticalAlign: 'middle',
689 crop: false,
690 overflow: false,
691 padding: 0 // #3837
692 },
693 marker: null,
694 pointRange: null, // dynamically set to colsize by default
695 tooltip: {
696 pointFormat: '{point.x}, {point.y}: {point.value}<br/>'
697 },
698 states: {
699 normal: {
700 animation: true
701 },
702 hover: {
703 halo: false, // #3406, halo is not required on heatmaps
704 brightness: 0.2
705 }
706 }
707 }, merge(colorSeriesMixin, {
708 pointArrayMap: ['y', 'value'],
709 hasPointSpecificOptions: true,
710 supportsDrilldown: true,
711 getExtremesFromAll: true,
712 directTouch: true,
713
714 /**
715 * Override the init method to add point ranges on both axes.
716 */
717 init: function() {
718 var options;
719 seriesTypes.scatter.prototype.init.apply(this, arguments);
720
721 options = this.options;
722 options.pointRange = pick(options.pointRange, options.colsize || 1); // #3758, prevent resetting in setData
723 this.yAxis.axisPointRange = options.rowsize || 1; // general point range
724 },
725 translate: function() {
726 var series = this,
727 options = series.options,
728 xAxis = series.xAxis,
729 yAxis = series.yAxis,
730 between = function(x, a, b) {
731 return Math.min(Math.max(a, x), b);
732 };
733
734 series.generatePoints();
735
736 each(series.points, function(point) {
737 var xPad = (options.colsize || 1) / 2,
738 yPad = (options.rowsize || 1) / 2,
739 x1 = between(Math.round(xAxis.len - xAxis.translate(point.x - xPad, 0, 1, 0, 1)), -xAxis.len, 2 * xAxis.len),
740 x2 = between(Math.round(xAxis.len - xAxis.translate(point.x + xPad, 0, 1, 0, 1)), -xAxis.len, 2 * xAxis.len),
741 y1 = between(Math.round(yAxis.translate(point.y - yPad, 0, 1, 0, 1)), -yAxis.len, 2 * yAxis.len),
742 y2 = between(Math.round(yAxis.translate(point.y + yPad, 0, 1, 0, 1)), -yAxis.len, 2 * yAxis.len);
743
744 // Set plotX and plotY for use in K-D-Tree and more
745 point.plotX = point.clientX = (x1 + x2) / 2;
746 point.plotY = (y1 + y2) / 2;
747
748 point.shapeType = 'rect';
749 point.shapeArgs = {
750 x: Math.min(x1, x2),
751 y: Math.min(y1, y2),
752 width: Math.abs(x2 - x1),
753 height: Math.abs(y2 - y1)
754 };
755 });
756
757 series.translateColors();
758 },
759 drawPoints: function() {
760 seriesTypes.column.prototype.drawPoints.call(this);
761
762 each(this.points, function(point) {
763 point.graphic.attr(this.colorAttribs(point, point.state));
764 }, this);
765 },
766 animate: noop,
767 getBox: noop,
768 drawLegendSymbol: LegendSymbolMixin.drawRectangle,
769 alignDataLabel: seriesTypes.column.prototype.alignDataLabel,
770 getExtremes: function() {
771 // Get the extremes from the value data
772 Series.prototype.getExtremes.call(this, this.valueData);
773 this.valueMin = this.dataMin;
774 this.valueMax = this.dataMax;
775
776 // Get the extremes from the y data
777 Series.prototype.getExtremes.call(this);
778 }
779
780 }), colorPointMixin);
781
782 }(Highcharts));
783}));