highcharts-rails 5.0.14 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.markdown +60 -0
- data/Rakefile +54 -5
- data/app/assets/images/highcharts/earth.svg +432 -0
- data/app/assets/javascripts/highcharts.js +5103 -3147
- data/app/assets/javascripts/highcharts/highcharts-3d.js +930 -277
- data/app/assets/javascripts/highcharts/highcharts-more.js +1374 -249
- data/app/assets/javascripts/highcharts/lib/canvg.js +3073 -0
- data/app/assets/javascripts/highcharts/lib/jspdf.js +16624 -0
- data/app/assets/javascripts/highcharts/lib/rgbcolor.js +299 -0
- data/app/assets/javascripts/highcharts/lib/svg2pdf.js +3488 -0
- data/app/assets/javascripts/highcharts/modules/accessibility.js +654 -212
- data/app/assets/javascripts/highcharts/modules/annotations.js +1552 -274
- data/app/assets/javascripts/highcharts/modules/boost-canvas.js +773 -0
- data/app/assets/javascripts/highcharts/modules/boost.js +636 -210
- data/app/assets/javascripts/highcharts/modules/broken-axis.js +2 -2
- data/app/assets/javascripts/highcharts/modules/bullet.js +364 -0
- data/app/assets/javascripts/highcharts/modules/data.js +766 -38
- data/app/assets/javascripts/highcharts/modules/drag-panes.js +588 -0
- data/app/assets/javascripts/highcharts/modules/drilldown.js +106 -36
- data/app/assets/javascripts/highcharts/modules/export-data.js +597 -0
- data/app/assets/javascripts/highcharts/modules/exporting.js +424 -162
- data/app/assets/javascripts/highcharts/modules/funnel.js +144 -22
- data/app/assets/javascripts/highcharts/modules/gantt.js +1154 -0
- data/app/assets/javascripts/highcharts/modules/grid-axis.js +1 -1
- data/app/assets/javascripts/highcharts/modules/heatmap.js +406 -80
- data/app/assets/javascripts/highcharts/modules/histogram-bellcurve.js +513 -0
- data/app/assets/javascripts/highcharts/modules/item-series.js +126 -0
- data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +31 -13
- data/app/assets/javascripts/highcharts/modules/offline-exporting.js +179 -57
- data/app/assets/javascripts/highcharts/modules/oldie.js +1378 -0
- data/app/assets/javascripts/highcharts/modules/overlapping-datalabels.js +8 -6
- data/app/assets/javascripts/highcharts/modules/parallel-coordinates.js +494 -0
- data/app/assets/javascripts/highcharts/modules/pareto.js +275 -0
- data/app/assets/javascripts/highcharts/modules/sankey.js +641 -0
- data/app/assets/javascripts/highcharts/modules/series-label.js +355 -145
- data/app/assets/javascripts/highcharts/modules/solid-gauge.js +122 -1
- data/app/assets/javascripts/highcharts/modules/static-scale.js +64 -0
- data/app/assets/javascripts/highcharts/modules/stock.js +1944 -676
- data/app/assets/javascripts/highcharts/modules/streamgraph.js +139 -0
- data/app/assets/javascripts/highcharts/modules/sunburst.js +2403 -0
- data/app/assets/javascripts/highcharts/modules/tilemap.js +1199 -0
- data/app/assets/javascripts/highcharts/modules/treemap.js +538 -134
- data/app/assets/javascripts/highcharts/modules/variable-pie.js +490 -0
- data/app/assets/javascripts/highcharts/modules/variwide.js +283 -0
- data/app/assets/javascripts/highcharts/modules/vector.js +294 -0
- data/app/assets/javascripts/highcharts/modules/windbarb.js +490 -0
- data/app/assets/javascripts/highcharts/modules/wordcloud.js +681 -0
- data/app/assets/javascripts/highcharts/modules/xrange.js +615 -0
- data/app/assets/javascripts/highcharts/themes/avocado.js +54 -0
- data/app/assets/javascripts/highcharts/themes/dark-blue.js +6 -6
- data/app/assets/javascripts/highcharts/themes/dark-green.js +6 -6
- data/app/assets/javascripts/highcharts/themes/dark-unica.js +6 -6
- data/app/assets/javascripts/highcharts/themes/gray.js +14 -10
- data/app/assets/javascripts/highcharts/themes/grid-light.js +6 -6
- data/app/assets/javascripts/highcharts/themes/grid.js +7 -5
- data/app/assets/javascripts/highcharts/themes/sand-signika.js +8 -7
- data/app/assets/javascripts/highcharts/themes/skies.js +15 -9
- data/app/assets/javascripts/highcharts/themes/sunset.js +53 -0
- data/app/assets/stylesheets/highcharts/highcharts.css +802 -0
- data/app/assets/stylesheets/highcharts/highcharts.scss +665 -0
- data/lib/highcharts/version.rb +1 -1
- metadata +31 -1
@@ -1,5 +1,5 @@
|
|
1
1
|
/**
|
2
|
-
* @license Highcharts JS
|
2
|
+
* @license Highcharts JS v6.0.0 (2017-10-04)
|
3
3
|
* Highcharts funnel module
|
4
4
|
*
|
5
5
|
* (c) 2010-2017 Torstein Honsi
|
@@ -40,11 +40,14 @@
|
|
40
40
|
*
|
41
41
|
* @sample highcharts/demo/funnel/ Funnel demo
|
42
42
|
* @extends {plotOptions.pie}
|
43
|
+
* @excluding size
|
44
|
+
* @product highcharts
|
43
45
|
* @optionparent plotOptions.funnel
|
44
46
|
*/
|
45
47
|
{
|
46
48
|
|
47
49
|
/**
|
50
|
+
* Initial animation is by default disabled for the funnel chart.
|
48
51
|
*/
|
49
52
|
animation: false,
|
50
53
|
|
@@ -117,42 +120,29 @@
|
|
117
120
|
*/
|
118
121
|
reversed: false,
|
119
122
|
|
120
|
-
/**
|
121
|
-
*/
|
123
|
+
/** @ignore */
|
122
124
|
size: true, // to avoid adapting to data label size in Pie.drawDataLabels
|
123
125
|
|
124
126
|
|
125
127
|
// Presentational
|
126
128
|
|
127
|
-
/**
|
128
|
-
*/
|
129
129
|
dataLabels: {
|
130
|
-
//position: 'right',
|
131
|
-
|
132
|
-
/**
|
133
|
-
*/
|
134
130
|
connectorWidth: 1
|
135
|
-
//connectorColor: null
|
136
131
|
},
|
137
132
|
|
138
133
|
/**
|
134
|
+
* Options for the series states.
|
135
|
+
*
|
136
|
+
* @optionparent plotOptions.funnel.states
|
139
137
|
*/
|
140
138
|
states: {
|
141
139
|
|
142
140
|
/**
|
141
|
+
* Options for a selected funnel item.
|
143
142
|
*/
|
144
143
|
select: {
|
145
|
-
|
146
|
-
/**
|
147
|
-
*/
|
148
144
|
color: '#cccccc',
|
149
|
-
|
150
|
-
/**
|
151
|
-
*/
|
152
145
|
borderColor: '#000000',
|
153
|
-
|
154
|
-
/**
|
155
|
-
*/
|
156
146
|
shadow: false
|
157
147
|
}
|
158
148
|
}
|
@@ -259,7 +249,6 @@
|
|
259
249
|
fraction = sum ? point.y / sum : 0;
|
260
250
|
y1 = centerY - height / 2 + cumulative * height;
|
261
251
|
y3 = y1 + fraction * height;
|
262
|
-
//tempWidth = neckWidth + (width - neckWidth) * ((height - neckHeight - y1) / (height - neckHeight));
|
263
252
|
tempWidth = getWidthAt(y1);
|
264
253
|
x1 = centerX - tempWidth / 2;
|
265
254
|
x2 = x1 + tempWidth;
|
@@ -391,22 +380,98 @@
|
|
391
380
|
|
392
381
|
});
|
393
382
|
|
383
|
+
|
384
|
+
/**
|
385
|
+
* A `funnel` series. If the [type](#series.funnel.type) option is
|
386
|
+
* not specified, it is inherited from [chart.type](#chart.type).
|
387
|
+
*
|
388
|
+
* For options that apply to multiple series, it is recommended to add
|
389
|
+
* them to the [plotOptions.series](#plotOptions.series) options structure.
|
390
|
+
* To apply to all series of this specific type, apply it to [plotOptions.
|
391
|
+
* funnel](#plotOptions.funnel).
|
392
|
+
*
|
393
|
+
* @type {Object}
|
394
|
+
* @extends series,plotOptions.funnel
|
395
|
+
* @excluding dataParser,dataURL,stack,xAxis,yAxis
|
396
|
+
* @product highcharts
|
397
|
+
* @apioption series.funnel
|
398
|
+
*/
|
399
|
+
|
400
|
+
/**
|
401
|
+
* An array of data points for the series. For the `funnel` series type,
|
402
|
+
* points can be given in the following ways:
|
403
|
+
*
|
404
|
+
* 1. An array of numerical values. In this case, the numerical values
|
405
|
+
* will be interpreted as `y` options. Example:
|
406
|
+
*
|
407
|
+
* ```js
|
408
|
+
* data: [0, 5, 3, 5]
|
409
|
+
* ```
|
410
|
+
*
|
411
|
+
* 2. An array of objects with named values. The objects are point
|
412
|
+
* configuration objects as seen below. If the total number of data
|
413
|
+
* points exceeds the series' [turboThreshold](#series.funnel.turboThreshold),
|
414
|
+
* this option is not available.
|
415
|
+
*
|
416
|
+
* ```js
|
417
|
+
* data: [{
|
418
|
+
* y: 3,
|
419
|
+
* name: "Point2",
|
420
|
+
* color: "#00FF00"
|
421
|
+
* }, {
|
422
|
+
* y: 1,
|
423
|
+
* name: "Point1",
|
424
|
+
* color: "#FF00FF"
|
425
|
+
* }]
|
426
|
+
* ```
|
427
|
+
*
|
428
|
+
* @type {Array<Object|Number>}
|
429
|
+
* @extends series.pie.data
|
430
|
+
* @excluding sliced
|
431
|
+
* @sample {highcharts} highcharts/chart/reflow-true/ Numerical values
|
432
|
+
* @sample {highcharts} highcharts/series/data-array-of-arrays/ Arrays of numeric x and y
|
433
|
+
* @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/ Arrays of datetime x and y
|
434
|
+
* @sample {highcharts} highcharts/series/data-array-of-name-value/ Arrays of point.name and y
|
435
|
+
* @sample {highcharts} highcharts/series/data-array-of-objects/ Config objects
|
436
|
+
* @product highcharts
|
437
|
+
* @apioption series.funnel.data
|
438
|
+
*/
|
439
|
+
|
394
440
|
/**
|
395
441
|
* Pyramid series type.
|
396
442
|
*/
|
397
443
|
seriesType('pyramid', 'funnel',
|
398
444
|
/**
|
399
|
-
* A pyramid series is a special type of funnel, without neck and reversed by
|
400
|
-
*
|
445
|
+
* A pyramid series is a special type of funnel, without neck and reversed by
|
446
|
+
* default.
|
447
|
+
*
|
448
|
+
* @sample highcharts/demo/pyramid/ Pyramid chart
|
449
|
+
*
|
450
|
+
* @extends plotOptions.funnel
|
451
|
+
* @product highcharts
|
401
452
|
* @optionparent plotOptions.pyramid
|
402
453
|
*/
|
403
454
|
{
|
404
455
|
|
405
456
|
/**
|
457
|
+
* The pyramid neck width is zero by default, as opposed to the funnel,
|
458
|
+
* which shares the same layout logic.
|
459
|
+
*
|
460
|
+
* @type String
|
461
|
+
* @default 0%
|
462
|
+
* @since 3.0.10
|
463
|
+
* @product highcharts
|
406
464
|
*/
|
407
465
|
neckWidth: '0%',
|
408
466
|
|
409
467
|
/**
|
468
|
+
* The pyramid neck width is zero by default, as opposed to the funnel,
|
469
|
+
* which shares the same layout logic.
|
470
|
+
*
|
471
|
+
* @type String
|
472
|
+
* @default 0%
|
473
|
+
* @since 3.0.10
|
474
|
+
* @product highcharts
|
410
475
|
*/
|
411
476
|
neckHeight: '0%',
|
412
477
|
|
@@ -422,5 +487,62 @@
|
|
422
487
|
reversed: true
|
423
488
|
});
|
424
489
|
|
490
|
+
/**
|
491
|
+
* A `pyramid` series. If the [type](#series.pyramid.type) option is
|
492
|
+
* not specified, it is inherited from [chart.type](#chart.type).
|
493
|
+
*
|
494
|
+
* For options that apply to multiple series, it is recommended to add
|
495
|
+
* them to the [plotOptions.series](#plotOptions.series) options structure.
|
496
|
+
* To apply to all series of this specific type, apply it to [plotOptions.
|
497
|
+
* pyramid](#plotOptions.pyramid).
|
498
|
+
*
|
499
|
+
* @type {Object}
|
500
|
+
* @extends series,plotOptions.pyramid
|
501
|
+
* @excluding dataParser,dataURL,stack,xAxis,yAxis
|
502
|
+
* @product highcharts
|
503
|
+
* @apioption series.pyramid
|
504
|
+
*/
|
505
|
+
|
506
|
+
/**
|
507
|
+
* An array of data points for the series. For the `pyramid` series
|
508
|
+
* type, points can be given in the following ways:
|
509
|
+
*
|
510
|
+
* 1. An array of numerical values. In this case, the numerical values
|
511
|
+
* will be interpreted as `y` options. Example:
|
512
|
+
*
|
513
|
+
* ```js
|
514
|
+
* data: [0, 5, 3, 5]
|
515
|
+
* ```
|
516
|
+
*
|
517
|
+
* 2. An array of objects with named values. The objects are point
|
518
|
+
* configuration objects as seen below. If the total number of data
|
519
|
+
* points exceeds the series' [turboThreshold](#series.pyramid.turboThreshold),
|
520
|
+
* this option is not available.
|
521
|
+
*
|
522
|
+
* ```js
|
523
|
+
* data: [{
|
524
|
+
* y: 9,
|
525
|
+
* name: "Point2",
|
526
|
+
* color: "#00FF00"
|
527
|
+
* }, {
|
528
|
+
* y: 6,
|
529
|
+
* name: "Point1",
|
530
|
+
* color: "#FF00FF"
|
531
|
+
* }]
|
532
|
+
* ```
|
533
|
+
*
|
534
|
+
* @type {Array<Object|Number>}
|
535
|
+
* @extends series.pie.data
|
536
|
+
* @excluding sliced
|
537
|
+
* @sample {highcharts} highcharts/chart/reflow-true/ Numerical values
|
538
|
+
* @sample {highcharts} highcharts/series/data-array-of-arrays/ Arrays of numeric x and y
|
539
|
+
* @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/ Arrays of datetime x and y
|
540
|
+
* @sample {highcharts} highcharts/series/data-array-of-name-value/ Arrays of point.name and y
|
541
|
+
* @sample {highcharts} highcharts/series/data-array-of-objects/ Config objects
|
542
|
+
* @product highcharts
|
543
|
+
* @apioption series.pyramid.data
|
544
|
+
*/
|
545
|
+
|
546
|
+
|
425
547
|
}(Highcharts));
|
426
548
|
}));
|
@@ -0,0 +1,1154 @@
|
|
1
|
+
/**
|
2
|
+
* @license Highcharts JS v6.0.0 (2017-10-04)
|
3
|
+
* Gantt series
|
4
|
+
*
|
5
|
+
* (c) 2016 Lars A. V. Cabrera
|
6
|
+
*
|
7
|
+
* --- WORK IN PROGRESS ---
|
8
|
+
*
|
9
|
+
* License: www.highcharts.com/license
|
10
|
+
*/
|
11
|
+
'use strict';
|
12
|
+
(function(factory) {
|
13
|
+
if (typeof module === 'object' && module.exports) {
|
14
|
+
module.exports = factory;
|
15
|
+
} else {
|
16
|
+
factory(Highcharts);
|
17
|
+
}
|
18
|
+
}(function(Highcharts) {
|
19
|
+
(function(H) {
|
20
|
+
/**
|
21
|
+
* (c) 2016 Highsoft AS
|
22
|
+
* Authors: Lars A. V. Cabrera
|
23
|
+
*
|
24
|
+
* License: www.highcharts.com/license
|
25
|
+
*/
|
26
|
+
|
27
|
+
var dateFormat = H.dateFormat,
|
28
|
+
each = H.each,
|
29
|
+
isObject = H.isObject,
|
30
|
+
pick = H.pick,
|
31
|
+
wrap = H.wrap,
|
32
|
+
Axis = H.Axis,
|
33
|
+
Chart = H.Chart,
|
34
|
+
Tick = H.Tick;
|
35
|
+
|
36
|
+
|
37
|
+
// Enum for which side the axis is on.
|
38
|
+
// Maps to axis.side
|
39
|
+
var axisSide = {
|
40
|
+
top: 0,
|
41
|
+
right: 1,
|
42
|
+
bottom: 2,
|
43
|
+
left: 3,
|
44
|
+
0: 'top',
|
45
|
+
1: 'right',
|
46
|
+
2: 'bottom',
|
47
|
+
3: 'left'
|
48
|
+
};
|
49
|
+
|
50
|
+
/**
|
51
|
+
* Checks if an axis is the outer axis in its dimension. Since
|
52
|
+
* axes are placed outwards in order, the axis with the highest
|
53
|
+
* index is the outermost axis.
|
54
|
+
*
|
55
|
+
* Example: If there are multiple x-axes at the top of the chart,
|
56
|
+
* this function returns true if the axis supplied is the last
|
57
|
+
* of the x-axes.
|
58
|
+
*
|
59
|
+
* @return true if the axis is the outermost axis in its dimension;
|
60
|
+
* false if not
|
61
|
+
*/
|
62
|
+
Axis.prototype.isOuterAxis = function() {
|
63
|
+
var axis = this,
|
64
|
+
thisIndex = -1,
|
65
|
+
isOuter = true;
|
66
|
+
|
67
|
+
each(this.chart.axes, function(otherAxis, index) {
|
68
|
+
if (otherAxis.side === axis.side) {
|
69
|
+
if (otherAxis === axis) {
|
70
|
+
// Get the index of the axis in question
|
71
|
+
thisIndex = index;
|
72
|
+
|
73
|
+
// Check thisIndex >= 0 in case thisIndex has
|
74
|
+
// not been found yet
|
75
|
+
} else if (thisIndex >= 0 && index > thisIndex) {
|
76
|
+
// There was an axis on the same side with a
|
77
|
+
// higher index. Exit the loop.
|
78
|
+
isOuter = false;
|
79
|
+
return;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
});
|
83
|
+
// There were either no other axes on the same side,
|
84
|
+
// or the other axes were not farther from the chart
|
85
|
+
return isOuter;
|
86
|
+
};
|
87
|
+
|
88
|
+
/**
|
89
|
+
* Shortcut function to Tick.label.getBBox().width.
|
90
|
+
*
|
91
|
+
* @return {number} width - the width of the tick label
|
92
|
+
*/
|
93
|
+
Tick.prototype.getLabelWidth = function() {
|
94
|
+
return this.label.getBBox().width;
|
95
|
+
};
|
96
|
+
|
97
|
+
/**
|
98
|
+
* Get the maximum label length.
|
99
|
+
* This function can be used in states where the axis.maxLabelLength has not
|
100
|
+
* been set.
|
101
|
+
*
|
102
|
+
* @param {boolean} force - Optional parameter to force a new calculation, even
|
103
|
+
* if a value has already been set
|
104
|
+
* @return {number} maxLabelLength - the maximum label length of the axis
|
105
|
+
*/
|
106
|
+
Axis.prototype.getMaxLabelLength = function(force) {
|
107
|
+
var tickPositions = this.tickPositions,
|
108
|
+
ticks = this.ticks,
|
109
|
+
maxLabelLength = 0;
|
110
|
+
|
111
|
+
if (!this.maxLabelLength || force) {
|
112
|
+
each(tickPositions, function(tick) {
|
113
|
+
tick = ticks[tick];
|
114
|
+
if (tick && tick.labelLength > maxLabelLength) {
|
115
|
+
maxLabelLength = tick.labelLength;
|
116
|
+
}
|
117
|
+
});
|
118
|
+
this.maxLabelLength = maxLabelLength;
|
119
|
+
}
|
120
|
+
return this.maxLabelLength;
|
121
|
+
};
|
122
|
+
|
123
|
+
/**
|
124
|
+
* Adds the axis defined in axis.options.title
|
125
|
+
*/
|
126
|
+
Axis.prototype.addTitle = function() {
|
127
|
+
var axis = this,
|
128
|
+
renderer = axis.chart.renderer,
|
129
|
+
axisParent = axis.axisParent,
|
130
|
+
horiz = axis.horiz,
|
131
|
+
opposite = axis.opposite,
|
132
|
+
options = axis.options,
|
133
|
+
axisTitleOptions = options.title,
|
134
|
+
hasData,
|
135
|
+
showAxis,
|
136
|
+
textAlign;
|
137
|
+
|
138
|
+
// For reuse in Axis.render
|
139
|
+
hasData = axis.hasData();
|
140
|
+
axis.showAxis = showAxis = hasData || pick(options.showEmpty, true);
|
141
|
+
|
142
|
+
// Disregard title generation in original Axis.getOffset()
|
143
|
+
options.title = '';
|
144
|
+
|
145
|
+
if (!axis.axisTitle) {
|
146
|
+
textAlign = axisTitleOptions.textAlign;
|
147
|
+
if (!textAlign) {
|
148
|
+
textAlign = (horiz ? {
|
149
|
+
low: 'left',
|
150
|
+
middle: 'center',
|
151
|
+
high: 'right'
|
152
|
+
} : {
|
153
|
+
low: opposite ? 'right' : 'left',
|
154
|
+
middle: 'center',
|
155
|
+
high: opposite ? 'left' : 'right'
|
156
|
+
})[axisTitleOptions.align];
|
157
|
+
}
|
158
|
+
axis.axisTitle = renderer.text(
|
159
|
+
axisTitleOptions.text,
|
160
|
+
0,
|
161
|
+
0,
|
162
|
+
axisTitleOptions.useHTML
|
163
|
+
)
|
164
|
+
.attr({
|
165
|
+
zIndex: 7,
|
166
|
+
rotation: axisTitleOptions.rotation || 0,
|
167
|
+
align: textAlign
|
168
|
+
})
|
169
|
+
.addClass('highcharts-axis-title')
|
170
|
+
|
171
|
+
.css(axisTitleOptions.style)
|
172
|
+
|
173
|
+
// Add to axisParent instead of axisGroup, to ignore the space
|
174
|
+
// it takes
|
175
|
+
.add(axisParent);
|
176
|
+
axis.axisTitle.isNew = true;
|
177
|
+
}
|
178
|
+
|
179
|
+
|
180
|
+
// hide or show the title depending on whether showEmpty is set
|
181
|
+
axis.axisTitle[showAxis ? 'show' : 'hide'](true);
|
182
|
+
};
|
183
|
+
|
184
|
+
/**
|
185
|
+
* Add custom date formats
|
186
|
+
*/
|
187
|
+
H.dateFormats = {
|
188
|
+
// Week number
|
189
|
+
W: function(timestamp) {
|
190
|
+
var date = new Date(timestamp),
|
191
|
+
day = date.getUTCDay() === 0 ? 7 : date.getUTCDay(),
|
192
|
+
time = date.getTime(),
|
193
|
+
startOfYear = new Date(date.getUTCFullYear(), 0, 1, -6),
|
194
|
+
dayNumber;
|
195
|
+
date.setDate(date.getUTCDate() + 4 - day);
|
196
|
+
dayNumber = Math.floor((time - startOfYear) / 86400000);
|
197
|
+
return 1 + Math.floor(dayNumber / 7);
|
198
|
+
},
|
199
|
+
// First letter of the day of the week, e.g. 'M' for 'Monday'.
|
200
|
+
E: function(timestamp) {
|
201
|
+
return dateFormat('%a', timestamp, true).charAt(0);
|
202
|
+
}
|
203
|
+
};
|
204
|
+
|
205
|
+
/**
|
206
|
+
* Prevents adding the last tick label if the axis is not a category axis.
|
207
|
+
*
|
208
|
+
* Since numeric labels are normally placed at starts and ends of a range of
|
209
|
+
* value, and this module makes the label point at the value, an "extra" label
|
210
|
+
* would appear.
|
211
|
+
*
|
212
|
+
* @param {function} proceed - the original function
|
213
|
+
*/
|
214
|
+
wrap(Tick.prototype, 'addLabel', function(proceed) {
|
215
|
+
var axis = this.axis,
|
216
|
+
isCategoryAxis = axis.options.categories !== undefined,
|
217
|
+
tickPositions = axis.tickPositions,
|
218
|
+
lastTick = tickPositions[tickPositions.length - 1],
|
219
|
+
isLastTick = this.pos !== lastTick;
|
220
|
+
|
221
|
+
if (!axis.options.grid || isCategoryAxis || isLastTick) {
|
222
|
+
proceed.apply(this);
|
223
|
+
}
|
224
|
+
});
|
225
|
+
|
226
|
+
/**
|
227
|
+
* Center tick labels vertically and horizontally between ticks
|
228
|
+
*
|
229
|
+
* @param {function} proceed - the original function
|
230
|
+
*
|
231
|
+
* @return {object} object - an object containing x and y positions
|
232
|
+
* for the tick
|
233
|
+
*/
|
234
|
+
wrap(Tick.prototype, 'getLabelPosition', function(proceed, x, y, label) {
|
235
|
+
var retVal = proceed.apply(this, Array.prototype.slice.call(arguments, 1)),
|
236
|
+
axis = this.axis,
|
237
|
+
options = axis.options,
|
238
|
+
tickInterval = options.tickInterval || 1,
|
239
|
+
newX,
|
240
|
+
newPos,
|
241
|
+
axisHeight,
|
242
|
+
fontSize,
|
243
|
+
labelMetrics,
|
244
|
+
lblB,
|
245
|
+
lblH,
|
246
|
+
labelCenter;
|
247
|
+
|
248
|
+
// Only center tick labels if axis has option grid: true
|
249
|
+
if (options.grid) {
|
250
|
+
fontSize = options.labels.style.fontSize;
|
251
|
+
labelMetrics = axis.chart.renderer.fontMetrics(fontSize, label);
|
252
|
+
lblB = labelMetrics.b;
|
253
|
+
lblH = labelMetrics.h;
|
254
|
+
|
255
|
+
if (axis.horiz && options.categories === undefined) {
|
256
|
+
// Center x position
|
257
|
+
axisHeight = axis.axisGroup.getBBox().height;
|
258
|
+
newPos = this.pos + tickInterval / 2;
|
259
|
+
retVal.x = axis.translate(newPos) + axis.left;
|
260
|
+
labelCenter = (axisHeight / 2) + (lblH / 2) - Math.abs(lblH - lblB);
|
261
|
+
|
262
|
+
// Center y position
|
263
|
+
if (axis.side === axisSide.top) {
|
264
|
+
retVal.y = y - labelCenter;
|
265
|
+
} else {
|
266
|
+
retVal.y = y + labelCenter;
|
267
|
+
}
|
268
|
+
} else {
|
269
|
+
// Center y position
|
270
|
+
if (options.categories === undefined) {
|
271
|
+
newPos = this.pos + (tickInterval / 2);
|
272
|
+
retVal.y = axis.translate(newPos) + axis.top + (lblB / 2);
|
273
|
+
}
|
274
|
+
|
275
|
+
// Center x position
|
276
|
+
newX = (this.getLabelWidth() / 2) - (axis.maxLabelLength / 2);
|
277
|
+
if (axis.side === axisSide.left) {
|
278
|
+
retVal.x += newX;
|
279
|
+
} else {
|
280
|
+
retVal.x -= newX;
|
281
|
+
}
|
282
|
+
}
|
283
|
+
}
|
284
|
+
return retVal;
|
285
|
+
});
|
286
|
+
|
287
|
+
|
288
|
+
/**
|
289
|
+
* Draw vertical ticks extra long to create cell floors and roofs.
|
290
|
+
* Overrides the tickLength for vertical axes.
|
291
|
+
*
|
292
|
+
* @param {function} proceed - the original function
|
293
|
+
* @returns {array} retVal -
|
294
|
+
*/
|
295
|
+
wrap(Axis.prototype, 'tickSize', function(proceed) {
|
296
|
+
var axis = this,
|
297
|
+
retVal = proceed.apply(axis, Array.prototype.slice.call(arguments, 1)),
|
298
|
+
labelPadding,
|
299
|
+
distance;
|
300
|
+
|
301
|
+
if (axis.options.grid && !axis.horiz) {
|
302
|
+
labelPadding = (Math.abs(axis.defaultLeftAxisOptions.labels.x) * 2);
|
303
|
+
if (!axis.maxLabelLength) {
|
304
|
+
axis.maxLabelLength = axis.getMaxLabelLength();
|
305
|
+
}
|
306
|
+
distance = axis.maxLabelLength + labelPadding;
|
307
|
+
|
308
|
+
retVal[0] = distance;
|
309
|
+
}
|
310
|
+
return retVal;
|
311
|
+
});
|
312
|
+
|
313
|
+
/**
|
314
|
+
* Disregards space required by axisTitle, by adding axisTitle to axisParent
|
315
|
+
* instead of axisGroup, and disregarding margins and offsets related to
|
316
|
+
* axisTitle.
|
317
|
+
*
|
318
|
+
* @param {function} proceed - the original function
|
319
|
+
*/
|
320
|
+
wrap(Axis.prototype, 'getOffset', function(proceed) {
|
321
|
+
var axis = this,
|
322
|
+
axisOffset = axis.chart.axisOffset,
|
323
|
+
side = axis.side,
|
324
|
+
axisHeight,
|
325
|
+
tickSize,
|
326
|
+
options = axis.options,
|
327
|
+
axisTitleOptions = options.title,
|
328
|
+
addTitle = axisTitleOptions &&
|
329
|
+
axisTitleOptions.text &&
|
330
|
+
axisTitleOptions.enabled !== false;
|
331
|
+
|
332
|
+
if (axis.options.grid && isObject(axis.options.title)) {
|
333
|
+
|
334
|
+
tickSize = axis.tickSize('tick')[0];
|
335
|
+
if (axisOffset[side] && tickSize) {
|
336
|
+
axisHeight = axisOffset[side] + tickSize;
|
337
|
+
}
|
338
|
+
|
339
|
+
if (addTitle) {
|
340
|
+
// Use the custom addTitle() to add it, while preventing making room
|
341
|
+
// for it
|
342
|
+
axis.addTitle();
|
343
|
+
}
|
344
|
+
|
345
|
+
proceed.apply(axis, Array.prototype.slice.call(arguments, 1));
|
346
|
+
|
347
|
+
axisOffset[side] = pick(axisHeight, axisOffset[side]);
|
348
|
+
|
349
|
+
|
350
|
+
// Put axis options back after original Axis.getOffset() has been called
|
351
|
+
options.title = axisTitleOptions;
|
352
|
+
|
353
|
+
} else {
|
354
|
+
proceed.apply(axis, Array.prototype.slice.call(arguments, 1));
|
355
|
+
}
|
356
|
+
});
|
357
|
+
|
358
|
+
/**
|
359
|
+
* Prevents rotation of labels when squished, as rotating them would not
|
360
|
+
* help.
|
361
|
+
*
|
362
|
+
* @param {function} proceed - the original function
|
363
|
+
*/
|
364
|
+
wrap(Axis.prototype, 'renderUnsquish', function(proceed) {
|
365
|
+
if (this.options.grid) {
|
366
|
+
this.labelRotation = 0;
|
367
|
+
this.options.labels.rotation = 0;
|
368
|
+
}
|
369
|
+
proceed.apply(this);
|
370
|
+
});
|
371
|
+
|
372
|
+
/**
|
373
|
+
* Places leftmost tick at the start of the axis, to create a left wall.
|
374
|
+
*
|
375
|
+
* @param {function} proceed - the original function
|
376
|
+
*/
|
377
|
+
wrap(Axis.prototype, 'setOptions', function(proceed, userOptions) {
|
378
|
+
var axis = this;
|
379
|
+
if (userOptions.grid && axis.horiz) {
|
380
|
+
userOptions.startOnTick = true;
|
381
|
+
userOptions.minPadding = 0;
|
382
|
+
userOptions.endOnTick = true;
|
383
|
+
}
|
384
|
+
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
|
385
|
+
});
|
386
|
+
|
387
|
+
/**
|
388
|
+
* Draw an extra line on the far side of the the axisLine,
|
389
|
+
* creating cell roofs of a grid.
|
390
|
+
*
|
391
|
+
* @param {function} proceed - the original function
|
392
|
+
*/
|
393
|
+
wrap(Axis.prototype, 'render', function(proceed) {
|
394
|
+
var axis = this,
|
395
|
+
options = axis.options,
|
396
|
+
labelPadding,
|
397
|
+
distance,
|
398
|
+
lineWidth,
|
399
|
+
linePath,
|
400
|
+
yStartIndex,
|
401
|
+
yEndIndex,
|
402
|
+
xStartIndex,
|
403
|
+
xEndIndex,
|
404
|
+
renderer = axis.chart.renderer,
|
405
|
+
axisGroupBox;
|
406
|
+
|
407
|
+
if (options.grid) {
|
408
|
+
labelPadding = (Math.abs(axis.defaultLeftAxisOptions.labels.x) * 2);
|
409
|
+
distance = axis.maxLabelLength + labelPadding;
|
410
|
+
lineWidth = options.lineWidth;
|
411
|
+
|
412
|
+
// Remove right wall before rendering
|
413
|
+
if (axis.rightWall) {
|
414
|
+
axis.rightWall.destroy();
|
415
|
+
}
|
416
|
+
|
417
|
+
// Call original Axis.render() to obtain axis.axisLine and
|
418
|
+
// axis.axisGroup
|
419
|
+
proceed.apply(axis);
|
420
|
+
|
421
|
+
axisGroupBox = axis.axisGroup.getBBox();
|
422
|
+
|
423
|
+
// Add right wall on horizontal axes
|
424
|
+
if (axis.horiz) {
|
425
|
+
axis.rightWall = renderer.path([
|
426
|
+
'M',
|
427
|
+
axisGroupBox.x + axis.width + 1, // account for left wall
|
428
|
+
axisGroupBox.y,
|
429
|
+
'L',
|
430
|
+
axisGroupBox.x + axis.width + 1, // account for left wall
|
431
|
+
axisGroupBox.y + axisGroupBox.height
|
432
|
+
])
|
433
|
+
.attr({
|
434
|
+
stroke: options.tickColor || '#ccd6eb',
|
435
|
+
'stroke-width': options.tickWidth || 1,
|
436
|
+
zIndex: 7,
|
437
|
+
class: 'grid-wall'
|
438
|
+
})
|
439
|
+
.add(axis.axisGroup);
|
440
|
+
}
|
441
|
+
|
442
|
+
if (axis.isOuterAxis() && axis.axisLine) {
|
443
|
+
if (axis.horiz) {
|
444
|
+
// -1 to avoid adding distance each time the chart updates
|
445
|
+
distance = axisGroupBox.height - 1;
|
446
|
+
}
|
447
|
+
|
448
|
+
if (lineWidth) {
|
449
|
+
linePath = axis.getLinePath(lineWidth);
|
450
|
+
xStartIndex = linePath.indexOf('M') + 1;
|
451
|
+
xEndIndex = linePath.indexOf('L') + 1;
|
452
|
+
yStartIndex = linePath.indexOf('M') + 2;
|
453
|
+
yEndIndex = linePath.indexOf('L') + 2;
|
454
|
+
|
455
|
+
// Negate distance if top or left axis
|
456
|
+
if (axis.side === axisSide.top || axis.side === axisSide.left) {
|
457
|
+
distance = -distance;
|
458
|
+
}
|
459
|
+
|
460
|
+
// If axis is horizontal, reposition line path vertically
|
461
|
+
if (axis.horiz) {
|
462
|
+
linePath[yStartIndex] = linePath[yStartIndex] + distance;
|
463
|
+
linePath[yEndIndex] = linePath[yEndIndex] + distance;
|
464
|
+
} else {
|
465
|
+
// If axis is vertical, reposition line path horizontally
|
466
|
+
linePath[xStartIndex] = linePath[xStartIndex] + distance;
|
467
|
+
linePath[xEndIndex] = linePath[xEndIndex] + distance;
|
468
|
+
}
|
469
|
+
|
470
|
+
if (!axis.axisLineExtra) {
|
471
|
+
axis.axisLineExtra = renderer.path(linePath)
|
472
|
+
.attr({
|
473
|
+
stroke: options.lineColor,
|
474
|
+
'stroke-width': lineWidth,
|
475
|
+
zIndex: 7
|
476
|
+
})
|
477
|
+
.add(axis.axisGroup);
|
478
|
+
} else {
|
479
|
+
axis.axisLineExtra.animate({
|
480
|
+
d: linePath
|
481
|
+
});
|
482
|
+
}
|
483
|
+
|
484
|
+
// show or hide the line depending on options.showEmpty
|
485
|
+
axis.axisLine[axis.showAxis ? 'show' : 'hide'](true);
|
486
|
+
}
|
487
|
+
}
|
488
|
+
} else {
|
489
|
+
proceed.apply(axis);
|
490
|
+
}
|
491
|
+
});
|
492
|
+
|
493
|
+
/**
|
494
|
+
* Wraps chart rendering with the following customizations:
|
495
|
+
* 1. Prohibit timespans of multitudes of a time unit
|
496
|
+
* 2. Draw cell walls on vertical axes
|
497
|
+
*
|
498
|
+
* @param {function} proceed - the original function
|
499
|
+
*/
|
500
|
+
wrap(Chart.prototype, 'render', function(proceed) {
|
501
|
+
// 25 is optimal height for default fontSize (11px)
|
502
|
+
// 25 / 11 ≈ 2.28
|
503
|
+
var fontSizeToCellHeightRatio = 25 / 11,
|
504
|
+
fontMetrics,
|
505
|
+
fontSize;
|
506
|
+
|
507
|
+
each(this.axes, function(axis) {
|
508
|
+
var options = axis.options;
|
509
|
+
if (options.grid) {
|
510
|
+
fontSize = options.labels.style.fontSize;
|
511
|
+
fontMetrics = axis.chart.renderer.fontMetrics(fontSize);
|
512
|
+
|
513
|
+
// Prohibit timespans of multitudes of a time unit,
|
514
|
+
// e.g. two days, three weeks, etc.
|
515
|
+
if (options.type === 'datetime') {
|
516
|
+
options.units = [
|
517
|
+
['millisecond', [1]],
|
518
|
+
['second', [1]],
|
519
|
+
['minute', [1]],
|
520
|
+
['hour', [1]],
|
521
|
+
['day', [1]],
|
522
|
+
['week', [1]],
|
523
|
+
['month', [1]],
|
524
|
+
['year', null]
|
525
|
+
];
|
526
|
+
}
|
527
|
+
|
528
|
+
// Make tick marks taller, creating cell walls of a grid.
|
529
|
+
// Use cellHeight axis option if set
|
530
|
+
if (axis.horiz) {
|
531
|
+
options.tickLength = options.cellHeight ||
|
532
|
+
fontMetrics.h * fontSizeToCellHeightRatio;
|
533
|
+
} else {
|
534
|
+
options.tickWidth = 1;
|
535
|
+
if (!options.lineWidth) {
|
536
|
+
options.lineWidth = 1;
|
537
|
+
}
|
538
|
+
}
|
539
|
+
}
|
540
|
+
});
|
541
|
+
|
542
|
+
// Call original Chart.render()
|
543
|
+
proceed.apply(this);
|
544
|
+
});
|
545
|
+
|
546
|
+
}(Highcharts));
|
547
|
+
(function(H) {
|
548
|
+
/**
|
549
|
+
* X-range series module
|
550
|
+
*
|
551
|
+
* (c) 2010-2017 Torstein Honsi, Lars A. V. Cabrera
|
552
|
+
*
|
553
|
+
* License: www.highcharts.com/license
|
554
|
+
*/
|
555
|
+
|
556
|
+
/**
|
557
|
+
* @todo
|
558
|
+
* - JSDoc
|
559
|
+
* - New series checklist
|
560
|
+
*/
|
561
|
+
|
562
|
+
|
563
|
+
var defined = H.defined,
|
564
|
+
color = H.Color,
|
565
|
+
columnType = H.seriesTypes.column,
|
566
|
+
each = H.each,
|
567
|
+
isNumber = H.isNumber,
|
568
|
+
isObject = H.isObject,
|
569
|
+
merge = H.merge,
|
570
|
+
pick = H.pick,
|
571
|
+
seriesType = H.seriesType,
|
572
|
+
seriesTypes = H.seriesTypes,
|
573
|
+
wrap = H.wrap,
|
574
|
+
Axis = H.Axis,
|
575
|
+
Point = H.Point,
|
576
|
+
Series = H.Series;
|
577
|
+
|
578
|
+
/**
|
579
|
+
* The X-range series displays ranges on the X axis, typically time intervals
|
580
|
+
* with a start and end date.
|
581
|
+
*
|
582
|
+
* @extends {plotOptions.column}
|
583
|
+
* @excluding boostThreshold,crisp,cropThreshold,depth,edgeColor,edgeWidth,
|
584
|
+
* findNearestPointBy,getExtremesFromAll,grouping,groupPadding,
|
585
|
+
* negativeColor,pointInterval,pointIntervalUnit,pointPlacement,
|
586
|
+
* pointRange,pointStart,softThreshold,stacking,threshold
|
587
|
+
* @product highcharts
|
588
|
+
* @sample {highcharts} highcharts/demo/x-range/
|
589
|
+
* X-range
|
590
|
+
* @sample {highcharts} highcharts/css/x-range/
|
591
|
+
* Styled mode X-range
|
592
|
+
* @sample {highcharts} highcharts/chart/inverted-xrange/
|
593
|
+
* Inverted X-range
|
594
|
+
* @since 6.0.0
|
595
|
+
* @optionparent plotOptions.xrange
|
596
|
+
*/
|
597
|
+
seriesType('xrange', 'column', {
|
598
|
+
/**
|
599
|
+
* In an X-range series, this option makes all points of the same Y-axis
|
600
|
+
* category the same color.
|
601
|
+
*/
|
602
|
+
colorByPoint: true,
|
603
|
+
dataLabels: {
|
604
|
+
verticalAlign: 'middle',
|
605
|
+
inside: true,
|
606
|
+
/**
|
607
|
+
* The default formatter for X-range data labels displays the percentage
|
608
|
+
* of the partial fill amount.
|
609
|
+
*/
|
610
|
+
formatter: function() {
|
611
|
+
var point = this.point,
|
612
|
+
amount = point.partialFill;
|
613
|
+
if (isObject(amount)) {
|
614
|
+
amount = amount.amount;
|
615
|
+
}
|
616
|
+
if (!defined(amount)) {
|
617
|
+
amount = 0;
|
618
|
+
}
|
619
|
+
return (amount * 100) + '%';
|
620
|
+
}
|
621
|
+
},
|
622
|
+
tooltip: {
|
623
|
+
headerFormat: '<span style="font-size: 0.85em">{point.x} - {point.x2}</span><br/>',
|
624
|
+
pointFormat: '<span style="color:{point.color}">\u25CF</span> {series.name}: <b>{point.yCategory}</b><br/>'
|
625
|
+
},
|
626
|
+
borderRadius: 3
|
627
|
+
/**
|
628
|
+
* A partial fill for each point, typically used to visualize how much of
|
629
|
+
* a task is performed. The partial fill object can be set either on series
|
630
|
+
* or point level.
|
631
|
+
*
|
632
|
+
* @sample {highcharts} highcharts/demo/x-range
|
633
|
+
* X-range with partial fill
|
634
|
+
* @type {Object}
|
635
|
+
* @product highcharts
|
636
|
+
* @apioption plotOptions.xrange.partialFill
|
637
|
+
*/
|
638
|
+
/**
|
639
|
+
* The fill color to be used for partial fills. Defaults to a darker shade
|
640
|
+
* of the point color.
|
641
|
+
*
|
642
|
+
* @type {Color}
|
643
|
+
* @product highcharts
|
644
|
+
* @apioption plotOptions.xrange.partialFill.fill
|
645
|
+
*/
|
646
|
+
|
647
|
+
}, {
|
648
|
+
type: 'xrange',
|
649
|
+
forceDL: true,
|
650
|
+
parallelArrays: ['x', 'x2', 'y'],
|
651
|
+
requireSorting: false,
|
652
|
+
animate: seriesTypes.line.prototype.animate,
|
653
|
+
cropShoulder: 1,
|
654
|
+
getExtremesFromAll: true,
|
655
|
+
|
656
|
+
/**
|
657
|
+
* Borrow the column series metrics, but with swapped axes. This gives free
|
658
|
+
* access to features like groupPadding, grouping, pointWidth etc.
|
659
|
+
*/
|
660
|
+
getColumnMetrics: function() {
|
661
|
+
var metrics,
|
662
|
+
chart = this.chart;
|
663
|
+
|
664
|
+
function swapAxes() {
|
665
|
+
each(chart.series, function(s) {
|
666
|
+
var xAxis = s.xAxis;
|
667
|
+
s.xAxis = s.yAxis;
|
668
|
+
s.yAxis = xAxis;
|
669
|
+
});
|
670
|
+
}
|
671
|
+
|
672
|
+
swapAxes();
|
673
|
+
|
674
|
+
metrics = columnType.prototype.getColumnMetrics.call(this);
|
675
|
+
|
676
|
+
swapAxes();
|
677
|
+
|
678
|
+
return metrics;
|
679
|
+
},
|
680
|
+
|
681
|
+
/**
|
682
|
+
* Override cropData to show a point where x or x2 is outside visible range,
|
683
|
+
* but one of them is inside.
|
684
|
+
*/
|
685
|
+
cropData: function(xData, yData, min, max) {
|
686
|
+
|
687
|
+
// Replace xData with x2Data to find the appropriate cropStart
|
688
|
+
var cropData = Series.prototype.cropData,
|
689
|
+
crop = cropData.call(this, this.x2Data, yData, min, max);
|
690
|
+
|
691
|
+
// Re-insert the cropped xData
|
692
|
+
crop.xData = xData.slice(crop.start, crop.end);
|
693
|
+
|
694
|
+
return crop;
|
695
|
+
},
|
696
|
+
|
697
|
+
translatePoint: function(point) {
|
698
|
+
var series = this,
|
699
|
+
xAxis = series.xAxis,
|
700
|
+
metrics = series.columnMetrics,
|
701
|
+
minPointLength = series.options.minPointLength || 0,
|
702
|
+
plotX = point.plotX,
|
703
|
+
posX = pick(point.x2, point.x + (point.len || 0)),
|
704
|
+
plotX2 = xAxis.translate(posX, 0, 0, 0, 1),
|
705
|
+
length = plotX2 - plotX,
|
706
|
+
widthDifference,
|
707
|
+
shapeArgs,
|
708
|
+
partialFill,
|
709
|
+
inverted = this.chart.inverted,
|
710
|
+
borderWidth = pick(series.options.borderWidth, 1),
|
711
|
+
crisper = borderWidth % 2 / 2;
|
712
|
+
|
713
|
+
if (minPointLength) {
|
714
|
+
widthDifference = minPointLength - length;
|
715
|
+
if (widthDifference < 0) {
|
716
|
+
widthDifference = 0;
|
717
|
+
}
|
718
|
+
plotX -= widthDifference / 2;
|
719
|
+
plotX2 += widthDifference / 2;
|
720
|
+
}
|
721
|
+
|
722
|
+
plotX = Math.max(plotX, -10);
|
723
|
+
plotX2 = Math.min(Math.max(plotX2, -10), xAxis.len + 10);
|
724
|
+
|
725
|
+
point.shapeArgs = {
|
726
|
+
x: Math.floor(Math.min(plotX, plotX2)) + crisper,
|
727
|
+
y: Math.floor(point.plotY + metrics.offset) + crisper,
|
728
|
+
width: Math.round(Math.abs(plotX2 - plotX)),
|
729
|
+
height: Math.round(metrics.width),
|
730
|
+
r: series.options.borderRadius
|
731
|
+
};
|
732
|
+
|
733
|
+
// Tooltip position
|
734
|
+
point.tooltipPos[0] += inverted ? 0 : length / 2;
|
735
|
+
point.tooltipPos[1] -= inverted ? length / 2 : metrics.width / 2;
|
736
|
+
|
737
|
+
// Add a partShapeArgs to the point, based on the shapeArgs property
|
738
|
+
partialFill = point.partialFill;
|
739
|
+
if (partialFill) {
|
740
|
+
// Get the partial fill amount
|
741
|
+
if (isObject(partialFill)) {
|
742
|
+
partialFill = partialFill.amount;
|
743
|
+
}
|
744
|
+
// If it was not a number, assume 0
|
745
|
+
if (!isNumber(partialFill)) {
|
746
|
+
partialFill = 0;
|
747
|
+
}
|
748
|
+
shapeArgs = point.shapeArgs;
|
749
|
+
point.partShapeArgs = {
|
750
|
+
x: shapeArgs.x,
|
751
|
+
y: shapeArgs.y,
|
752
|
+
width: shapeArgs.width,
|
753
|
+
height: shapeArgs.height,
|
754
|
+
r: series.options.borderRadius
|
755
|
+
};
|
756
|
+
point.clipRectArgs = {
|
757
|
+
x: shapeArgs.x,
|
758
|
+
y: shapeArgs.y,
|
759
|
+
width: Math.round(shapeArgs.width * partialFill),
|
760
|
+
height: shapeArgs.height
|
761
|
+
};
|
762
|
+
}
|
763
|
+
},
|
764
|
+
|
765
|
+
translate: function() {
|
766
|
+
columnType.prototype.translate.apply(this, arguments);
|
767
|
+
each(this.points, function(point) {
|
768
|
+
this.translatePoint(point);
|
769
|
+
}, this);
|
770
|
+
},
|
771
|
+
|
772
|
+
/**
|
773
|
+
* Aligns an individual dataLabel.
|
774
|
+
*
|
775
|
+
* TODO: Do we need this for inside datalabels? Seems to work.
|
776
|
+
*
|
777
|
+
* @param {Object} point the point belonging to the dataLabel
|
778
|
+
* @param {Object} dataLabel the dataLabel configuration object
|
779
|
+
* @param {Object} options dataLabel options for the series
|
780
|
+
* @param {Object} alignTo
|
781
|
+
* @param {Boolean} isNew Wheter the label is new or already existed
|
782
|
+
* @return {void}
|
783
|
+
* /
|
784
|
+
alignDataLabel: function (point, dataLabel, options, alignTo, isNew) {
|
785
|
+
var chart = this.chart,
|
786
|
+
align = options.align,
|
787
|
+
inverted = chart.inverted,
|
788
|
+
plotX = pick(point.plotX, -9999),
|
789
|
+
plotY = pick(point.plotY, -9999),
|
790
|
+
verticalAlign = options.verticalAlign,
|
791
|
+
inside = options.inside,
|
792
|
+
pointBox = point.shapeArgs,
|
793
|
+
labelBox = dataLabel.getBBox(),
|
794
|
+
labelTextBox = dataLabel.text.getBBox(),
|
795
|
+
attr = {},
|
796
|
+
visible =
|
797
|
+
this.visible &&
|
798
|
+
(
|
799
|
+
labelTextBox.width <= pointBox.width &&
|
800
|
+
labelTextBox.height <= pointBox.height
|
801
|
+
) &&
|
802
|
+
(
|
803
|
+
this.forceDL ||
|
804
|
+
chart.isInsidePlot(plotX, Math.round(plotY), inverted)
|
805
|
+
);
|
806
|
+
|
807
|
+
if (visible) {
|
808
|
+
if (align === 'right') {
|
809
|
+
if (inside) {
|
810
|
+
attr.x = pointBox.x + pointBox.width - labelBox.width;
|
811
|
+
} else {
|
812
|
+
attr.x = pointBox.x - labelBox.width;
|
813
|
+
}
|
814
|
+
} else if (align === 'left') {
|
815
|
+
if (inside) {
|
816
|
+
attr.x = pointBox.x;
|
817
|
+
} else {
|
818
|
+
attr.x = pointBox.x + pointBox.width + labelBox.x;
|
819
|
+
}
|
820
|
+
} else { // Center
|
821
|
+
attr.x = pointBox.x + pointBox.width / 2 - labelBox.width / 2;
|
822
|
+
}
|
823
|
+
|
824
|
+
if (verticalAlign === 'bottom') {
|
825
|
+
if (inside) {
|
826
|
+
attr.y = pointBox.y + pointBox.height - labelBox.height;
|
827
|
+
} else {
|
828
|
+
attr.y = pointBox.y - labelBox.height;
|
829
|
+
}
|
830
|
+
} else if (verticalAlign === 'top') {
|
831
|
+
if (inside) {
|
832
|
+
attr.y = pointBox.y;
|
833
|
+
} else {
|
834
|
+
attr.y = pointBox.y + pointBox.height;
|
835
|
+
}
|
836
|
+
} else { // Middle
|
837
|
+
attr.y = pointBox.y + pointBox.height / 2 - labelBox.height / 2;
|
838
|
+
}
|
839
|
+
|
840
|
+
dataLabel[isNew ? 'attr' : 'animate'](attr);
|
841
|
+
}
|
842
|
+
},
|
843
|
+
*/
|
844
|
+
/**
|
845
|
+
* Draws a single point in the series. Needed for partial fill.
|
846
|
+
*
|
847
|
+
* This override turns point.graphic into a group containing the original
|
848
|
+
* graphic and an overlay displaying the partial fill.
|
849
|
+
*
|
850
|
+
* @param {Object} point an instance of Point in the series
|
851
|
+
* @param {string} verb 'animate' (animates changes) or 'attr' (sets
|
852
|
+
* options)
|
853
|
+
* @returns {void}
|
854
|
+
*/
|
855
|
+
drawPoint: function(point, verb) {
|
856
|
+
var series = this,
|
857
|
+
seriesOpts = series.options,
|
858
|
+
renderer = series.chart.renderer,
|
859
|
+
graphic = point.graphic,
|
860
|
+
type = point.shapeType,
|
861
|
+
shapeArgs = point.shapeArgs,
|
862
|
+
partShapeArgs = point.partShapeArgs,
|
863
|
+
clipRectArgs = point.clipRectArgs,
|
864
|
+
pfOptions = point.partialFill,
|
865
|
+
fill,
|
866
|
+
state = point.selected && 'select',
|
867
|
+
cutOff = seriesOpts.stacking && !seriesOpts.borderRadius;
|
868
|
+
|
869
|
+
if (!point.isNull) {
|
870
|
+
|
871
|
+
// Original graphic
|
872
|
+
if (graphic) { // update
|
873
|
+
point.graphicOriginal[verb](
|
874
|
+
merge(shapeArgs)
|
875
|
+
);
|
876
|
+
|
877
|
+
} else {
|
878
|
+
point.graphic = graphic = renderer.g('point')
|
879
|
+
.addClass(point.getClassName())
|
880
|
+
.add(point.group || series.group);
|
881
|
+
|
882
|
+
point.graphicOriginal = renderer[type](shapeArgs)
|
883
|
+
.addClass(point.getClassName())
|
884
|
+
.addClass('highcharts-partfill-original')
|
885
|
+
.add(graphic);
|
886
|
+
}
|
887
|
+
|
888
|
+
// Partial fill graphic
|
889
|
+
if (partShapeArgs) {
|
890
|
+
if (point.graphicOverlay) {
|
891
|
+
point.graphicOverlay[verb](
|
892
|
+
merge(partShapeArgs)
|
893
|
+
);
|
894
|
+
point.clipRect.animate(
|
895
|
+
merge(clipRectArgs)
|
896
|
+
);
|
897
|
+
|
898
|
+
} else {
|
899
|
+
|
900
|
+
point.clipRect = renderer.clipRect(
|
901
|
+
clipRectArgs.x,
|
902
|
+
clipRectArgs.y,
|
903
|
+
clipRectArgs.width,
|
904
|
+
clipRectArgs.height
|
905
|
+
);
|
906
|
+
|
907
|
+
point.graphicOverlay = renderer[type](partShapeArgs)
|
908
|
+
.addClass('highcharts-partfill-overlay')
|
909
|
+
.add(graphic)
|
910
|
+
.clip(point.clipRect);
|
911
|
+
}
|
912
|
+
}
|
913
|
+
|
914
|
+
|
915
|
+
|
916
|
+
// Presentational
|
917
|
+
point.graphicOriginal
|
918
|
+
.attr(series.pointAttribs(point, state))
|
919
|
+
.shadow(seriesOpts.shadow, null, cutOff);
|
920
|
+
if (partShapeArgs) {
|
921
|
+
// Ensure pfOptions is an object
|
922
|
+
if (!isObject(pfOptions)) {
|
923
|
+
pfOptions = {};
|
924
|
+
}
|
925
|
+
if (isObject(seriesOpts.partialFill)) {
|
926
|
+
pfOptions = merge(pfOptions, seriesOpts.partialFill);
|
927
|
+
}
|
928
|
+
|
929
|
+
fill = (
|
930
|
+
pfOptions.fill ||
|
931
|
+
color(point.color || series.color).brighten(-0.3).get()
|
932
|
+
);
|
933
|
+
|
934
|
+
point.graphicOverlay
|
935
|
+
.attr(series.pointAttribs(point, state))
|
936
|
+
.attr({
|
937
|
+
'fill': fill
|
938
|
+
})
|
939
|
+
.shadow(seriesOpts.shadow, null, cutOff);
|
940
|
+
}
|
941
|
+
|
942
|
+
|
943
|
+
} else if (graphic) {
|
944
|
+
point.graphic = graphic.destroy(); // #1269
|
945
|
+
}
|
946
|
+
},
|
947
|
+
|
948
|
+
drawPoints: function() {
|
949
|
+
var series = this,
|
950
|
+
chart = this.chart,
|
951
|
+
options = series.options,
|
952
|
+
animationLimit = options.animationLimit || 250,
|
953
|
+
verb = chart.pointCount < animationLimit ? 'animate' : 'attr';
|
954
|
+
|
955
|
+
// draw the columns
|
956
|
+
each(series.points, function(point) {
|
957
|
+
series.drawPoint(point, verb);
|
958
|
+
});
|
959
|
+
}
|
960
|
+
|
961
|
+
/**
|
962
|
+
* Override to remove stroke from points.
|
963
|
+
* For partial fill.
|
964
|
+
* /
|
965
|
+
pointAttribs: function () {
|
966
|
+
var series = this,
|
967
|
+
retVal = columnType.prototype.pointAttribs.apply(series, arguments);
|
968
|
+
|
969
|
+
//retVal['stroke-width'] = 0;
|
970
|
+
return retVal;
|
971
|
+
}
|
972
|
+
*/
|
973
|
+
|
974
|
+
// Point class properties
|
975
|
+
}, {
|
976
|
+
|
977
|
+
/**
|
978
|
+
* Extend init so that `colorByPoint` for x-range means that one color is
|
979
|
+
* applied per Y axis category.
|
980
|
+
*/
|
981
|
+
init: function() {
|
982
|
+
|
983
|
+
Point.prototype.init.apply(this, arguments);
|
984
|
+
|
985
|
+
var colors,
|
986
|
+
series = this.series,
|
987
|
+
colorCount = series.chart.options.chart.colorCount;
|
988
|
+
|
989
|
+
if (!this.y) {
|
990
|
+
this.y = 0;
|
991
|
+
}
|
992
|
+
|
993
|
+
|
994
|
+
if (series.options.colorByPoint) {
|
995
|
+
colors = series.options.colors || series.chart.options.colors;
|
996
|
+
colorCount = colors.length;
|
997
|
+
|
998
|
+
if (!this.options.color && colors[this.y % colorCount]) {
|
999
|
+
this.color = colors[this.y % colorCount];
|
1000
|
+
}
|
1001
|
+
}
|
1002
|
+
|
1003
|
+
this.colorIndex = this.y % colorCount;
|
1004
|
+
|
1005
|
+
return this;
|
1006
|
+
},
|
1007
|
+
|
1008
|
+
// Add x2 and yCategory to the available properties for tooltip formats
|
1009
|
+
getLabelConfig: function() {
|
1010
|
+
var point = this,
|
1011
|
+
cfg = Point.prototype.getLabelConfig.call(point),
|
1012
|
+
yCats = point.series.yAxis.categories;
|
1013
|
+
|
1014
|
+
cfg.x2 = point.x2;
|
1015
|
+
cfg.yCategory = point.yCategory = yCats && yCats[point.y];
|
1016
|
+
return cfg;
|
1017
|
+
},
|
1018
|
+
tooltipDateKeys: ['x', 'x2'],
|
1019
|
+
|
1020
|
+
isValid: function() {
|
1021
|
+
return typeof this.x === 'number' &&
|
1022
|
+
typeof this.x2 === 'number';
|
1023
|
+
}
|
1024
|
+
});
|
1025
|
+
|
1026
|
+
/**
|
1027
|
+
* Max x2 should be considered in xAxis extremes
|
1028
|
+
*/
|
1029
|
+
wrap(Axis.prototype, 'getSeriesExtremes', function(proceed) {
|
1030
|
+
var axis = this,
|
1031
|
+
axisSeries = axis.series,
|
1032
|
+
dataMax,
|
1033
|
+
modMax;
|
1034
|
+
proceed.call(axis);
|
1035
|
+
if (axis.isXAxis) {
|
1036
|
+
dataMax = pick(axis.dataMax, -Number.MAX_VALUE);
|
1037
|
+
each(axisSeries, function(series) {
|
1038
|
+
if (series.x2Data) {
|
1039
|
+
each(series.x2Data, function(val) {
|
1040
|
+
if (val > dataMax) {
|
1041
|
+
dataMax = val;
|
1042
|
+
modMax = true;
|
1043
|
+
}
|
1044
|
+
});
|
1045
|
+
}
|
1046
|
+
});
|
1047
|
+
if (modMax) {
|
1048
|
+
axis.dataMax = dataMax;
|
1049
|
+
}
|
1050
|
+
}
|
1051
|
+
});
|
1052
|
+
|
1053
|
+
|
1054
|
+
/**
|
1055
|
+
* An `xrange` series. If the [type](#series.xrange.type) option is not
|
1056
|
+
* specified, it is inherited from [chart.type](#chart.type).
|
1057
|
+
*
|
1058
|
+
* For options that apply to multiple series, it is recommended to add
|
1059
|
+
* them to the [plotOptions.series](#plotOptions.series) options structure.
|
1060
|
+
* To apply to all series of this specific type, apply it to [plotOptions.
|
1061
|
+
* xrange](#plotOptions.xrange).
|
1062
|
+
*
|
1063
|
+
* @type {Object}
|
1064
|
+
* @extends series,plotOptions.xrange
|
1065
|
+
* @product highcharts highstock
|
1066
|
+
* @apioption series.xrange
|
1067
|
+
*/
|
1068
|
+
|
1069
|
+
/**
|
1070
|
+
* An array of data points for the series. For the `xrange` series type,
|
1071
|
+
* points can be given in the following ways:
|
1072
|
+
*
|
1073
|
+
* 1. An array of objects with named values. The objects are point
|
1074
|
+
* configuration objects as seen below.
|
1075
|
+
*
|
1076
|
+
* ```js
|
1077
|
+
* data: [{
|
1078
|
+
* x: Date.UTC(2017, 0, 1),
|
1079
|
+
* x2: Date.UTC(2017, 0, 3),
|
1080
|
+
* name: "Test",
|
1081
|
+
* y: 0,
|
1082
|
+
* color: "#00FF00"
|
1083
|
+
* }, {
|
1084
|
+
* x: Date.UTC(2017, 0, 4),
|
1085
|
+
* x2: Date.UTC(2017, 0, 5),
|
1086
|
+
* name: "Deploy",
|
1087
|
+
* y: 1,
|
1088
|
+
* color: "#FF0000"
|
1089
|
+
* }]
|
1090
|
+
* ```
|
1091
|
+
*
|
1092
|
+
* @type {Array<Object|Array|Number>}
|
1093
|
+
* @extends series.line.data
|
1094
|
+
* @sample {highcharts} highcharts/chart/reflow-true/ Numerical values
|
1095
|
+
* @sample {highcharts} highcharts/series/data-array-of-arrays/ Arrays of numeric x and y
|
1096
|
+
* @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/ Arrays of datetime x and y
|
1097
|
+
* @sample {highcharts} highcharts/series/data-array-of-name-value/ Arrays of point.name and y
|
1098
|
+
* @sample {highcharts} highcharts/series/data-array-of-objects/ Config objects
|
1099
|
+
* @product highcharts highstock
|
1100
|
+
* @apioption series.xrange.data
|
1101
|
+
*/
|
1102
|
+
|
1103
|
+
|
1104
|
+
/**
|
1105
|
+
* The ending X value of the range point.
|
1106
|
+
*
|
1107
|
+
* @sample {highcharts} highcharts/demo/x-range
|
1108
|
+
* X-range
|
1109
|
+
* @type {Number}
|
1110
|
+
* @product highcharts
|
1111
|
+
* @apioption plotOptions.xrange.data.x2
|
1112
|
+
*/
|
1113
|
+
|
1114
|
+
/**
|
1115
|
+
* A partial fill for each point, typically used to visualize how much of
|
1116
|
+
* a task is performed. The partial fill object can be set either on series
|
1117
|
+
* or point level.
|
1118
|
+
*
|
1119
|
+
* @sample {highcharts} highcharts/demo/x-range
|
1120
|
+
* X-range with partial fill
|
1121
|
+
* @type {Object|Number}
|
1122
|
+
* @product highcharts
|
1123
|
+
* @apioption plotOptions.xrange.data.partialFill
|
1124
|
+
*/
|
1125
|
+
|
1126
|
+
/**
|
1127
|
+
* The amount of the X-range point to be filled. Values can be 0-1 and are
|
1128
|
+
* converted to percentages in the default data label formatter.
|
1129
|
+
*
|
1130
|
+
* @type {Number}
|
1131
|
+
* @product highcharts
|
1132
|
+
* @apioption plotOptions.xrange.data.partialFill.amount
|
1133
|
+
*/
|
1134
|
+
|
1135
|
+
/**
|
1136
|
+
* The fill color to be used for partial fills. Defaults to a darker shade
|
1137
|
+
* of the point color.
|
1138
|
+
*
|
1139
|
+
* @type {Color}
|
1140
|
+
* @product highcharts
|
1141
|
+
* @apioption plotOptions.xrange.data.partialFill.fill
|
1142
|
+
*/
|
1143
|
+
|
1144
|
+
}(Highcharts));
|
1145
|
+
(function(H) {
|
1146
|
+
/**
|
1147
|
+
* (c) 2016 Highsoft AS
|
1148
|
+
* Authors: Lars A. V. Cabrera
|
1149
|
+
*
|
1150
|
+
* License: www.highcharts.com/license
|
1151
|
+
*/
|
1152
|
+
//
|
1153
|
+
}(Highcharts));
|
1154
|
+
}));
|