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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.markdown +60 -0
  3. data/Rakefile +54 -5
  4. data/app/assets/images/highcharts/earth.svg +432 -0
  5. data/app/assets/javascripts/highcharts.js +5103 -3147
  6. data/app/assets/javascripts/highcharts/highcharts-3d.js +930 -277
  7. data/app/assets/javascripts/highcharts/highcharts-more.js +1374 -249
  8. data/app/assets/javascripts/highcharts/lib/canvg.js +3073 -0
  9. data/app/assets/javascripts/highcharts/lib/jspdf.js +16624 -0
  10. data/app/assets/javascripts/highcharts/lib/rgbcolor.js +299 -0
  11. data/app/assets/javascripts/highcharts/lib/svg2pdf.js +3488 -0
  12. data/app/assets/javascripts/highcharts/modules/accessibility.js +654 -212
  13. data/app/assets/javascripts/highcharts/modules/annotations.js +1552 -274
  14. data/app/assets/javascripts/highcharts/modules/boost-canvas.js +773 -0
  15. data/app/assets/javascripts/highcharts/modules/boost.js +636 -210
  16. data/app/assets/javascripts/highcharts/modules/broken-axis.js +2 -2
  17. data/app/assets/javascripts/highcharts/modules/bullet.js +364 -0
  18. data/app/assets/javascripts/highcharts/modules/data.js +766 -38
  19. data/app/assets/javascripts/highcharts/modules/drag-panes.js +588 -0
  20. data/app/assets/javascripts/highcharts/modules/drilldown.js +106 -36
  21. data/app/assets/javascripts/highcharts/modules/export-data.js +597 -0
  22. data/app/assets/javascripts/highcharts/modules/exporting.js +424 -162
  23. data/app/assets/javascripts/highcharts/modules/funnel.js +144 -22
  24. data/app/assets/javascripts/highcharts/modules/gantt.js +1154 -0
  25. data/app/assets/javascripts/highcharts/modules/grid-axis.js +1 -1
  26. data/app/assets/javascripts/highcharts/modules/heatmap.js +406 -80
  27. data/app/assets/javascripts/highcharts/modules/histogram-bellcurve.js +513 -0
  28. data/app/assets/javascripts/highcharts/modules/item-series.js +126 -0
  29. data/app/assets/javascripts/highcharts/modules/no-data-to-display.js +31 -13
  30. data/app/assets/javascripts/highcharts/modules/offline-exporting.js +179 -57
  31. data/app/assets/javascripts/highcharts/modules/oldie.js +1378 -0
  32. data/app/assets/javascripts/highcharts/modules/overlapping-datalabels.js +8 -6
  33. data/app/assets/javascripts/highcharts/modules/parallel-coordinates.js +494 -0
  34. data/app/assets/javascripts/highcharts/modules/pareto.js +275 -0
  35. data/app/assets/javascripts/highcharts/modules/sankey.js +641 -0
  36. data/app/assets/javascripts/highcharts/modules/series-label.js +355 -145
  37. data/app/assets/javascripts/highcharts/modules/solid-gauge.js +122 -1
  38. data/app/assets/javascripts/highcharts/modules/static-scale.js +64 -0
  39. data/app/assets/javascripts/highcharts/modules/stock.js +1944 -676
  40. data/app/assets/javascripts/highcharts/modules/streamgraph.js +139 -0
  41. data/app/assets/javascripts/highcharts/modules/sunburst.js +2403 -0
  42. data/app/assets/javascripts/highcharts/modules/tilemap.js +1199 -0
  43. data/app/assets/javascripts/highcharts/modules/treemap.js +538 -134
  44. data/app/assets/javascripts/highcharts/modules/variable-pie.js +490 -0
  45. data/app/assets/javascripts/highcharts/modules/variwide.js +283 -0
  46. data/app/assets/javascripts/highcharts/modules/vector.js +294 -0
  47. data/app/assets/javascripts/highcharts/modules/windbarb.js +490 -0
  48. data/app/assets/javascripts/highcharts/modules/wordcloud.js +681 -0
  49. data/app/assets/javascripts/highcharts/modules/xrange.js +615 -0
  50. data/app/assets/javascripts/highcharts/themes/avocado.js +54 -0
  51. data/app/assets/javascripts/highcharts/themes/dark-blue.js +6 -6
  52. data/app/assets/javascripts/highcharts/themes/dark-green.js +6 -6
  53. data/app/assets/javascripts/highcharts/themes/dark-unica.js +6 -6
  54. data/app/assets/javascripts/highcharts/themes/gray.js +14 -10
  55. data/app/assets/javascripts/highcharts/themes/grid-light.js +6 -6
  56. data/app/assets/javascripts/highcharts/themes/grid.js +7 -5
  57. data/app/assets/javascripts/highcharts/themes/sand-signika.js +8 -7
  58. data/app/assets/javascripts/highcharts/themes/skies.js +15 -9
  59. data/app/assets/javascripts/highcharts/themes/sunset.js +53 -0
  60. data/app/assets/stylesheets/highcharts/highcharts.css +802 -0
  61. data/app/assets/stylesheets/highcharts/highcharts.scss +665 -0
  62. data/lib/highcharts/version.rb +1 -1
  63. metadata +31 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Highcharts JS v5.0.14 (2017-07-28)
2
+ * @license Highcharts JS v6.0.0 (2017-10-04)
3
3
  * Boost module
4
4
  *
5
5
  * (c) 2010-2017 Highsoft AS
@@ -80,15 +80,50 @@
80
80
  * //Use pre-allocated buffers, much faster,
81
81
  * //but may cause rendering issues with some data sets
82
82
  * usePreallocated: boolean - default: false
83
- * //Output rendering time in console
84
- * timeRendering: boolean - default: false
85
- * //Output processing time in console
86
- * timeSeriesProcessing: boolean - default: false
87
- * //Output setup time in console
88
- * timeSetup: boolean - default: false
89
83
  * }
90
84
  */
91
85
 
86
+ /**
87
+ * Options for the Boost module. The Boost module allows certain series types
88
+ * to be rendered by WebGL instead of the default SVG. This allows hundreds of
89
+ * thousands of data points to be rendered in milliseconds. In addition to the
90
+ * WebGL rendering it saves time by skipping processing and inspection of the
91
+ * data wherever possible.
92
+ *
93
+ * In addition to the global `boost` option, each series has a
94
+ * [boostThreshold](#plotOptions.series.boostThreshold) that defines when the
95
+ * boost should kick in.
96
+ *
97
+ * Requires the `modules/boost.js` module.
98
+ *
99
+ * @sample {highstock} highcharts/boost/line-series-heavy-stock
100
+ * Stock chart
101
+ * @sample {highstock} highcharts/boost/line-series-heavy-dynamic
102
+ * Dynamic stock chart
103
+ * @sample highcharts/boost/line
104
+ * Line chart
105
+ * @sample highcharts/boost/line-series-heavy
106
+ * Line chart with hundreds of series
107
+ * @sample highcharts/boost/scatter
108
+ * Scatter chart
109
+ * @sample highcharts/boost/area
110
+ * Area chart
111
+ * @sample highcharts/boost/arearange
112
+ * Arearange chart
113
+ * @sample highcharts/boost/column
114
+ * Column chart
115
+ * @sample highcharts/boost/bubble
116
+ * Bubble chart
117
+ * @sample highcharts/boost/heatmap
118
+ * Heat map
119
+ * @sample highcharts/boost/treemap
120
+ * Tree map
121
+ *
122
+ * @product highcharts highstock
123
+ * @type {Object}
124
+ * @apioption boost
125
+ */
126
+
92
127
  /**
93
128
  * Set the series threshold for when the boost should kick in globally.
94
129
  *
@@ -98,22 +133,133 @@
98
133
  * a significant speed improvment in charts with a very high
99
134
  * amount of series.
100
135
  *
101
- * Note: only available when including the boost module.
102
- *
103
136
  * @default null
104
137
  * @apioption boost.seriesThreshold
105
138
  */
106
139
 
140
+ /**
141
+ * Enable or disable boost on a chart.
142
+ *
143
+ * @type {Boolean}
144
+ * @default true
145
+ * @apioption boost.enabled
146
+ */
147
+
148
+ /**
149
+ * Debugging options for boost.
150
+ * Useful for benchmarking, and general timing.
151
+ *
152
+ * @type {Object}
153
+ * @apioption boost.debug
154
+ */
155
+
156
+ /**
157
+ * Time the series rendering.
158
+ *
159
+ * This outputs the time spent on actual rendering in the console when
160
+ * set to true.
161
+ *
162
+ * @type {Boolean}
163
+ * @default false
164
+ * @apioption boost.debug.timeRendering
165
+ */
166
+
167
+ /**
168
+ * Time the series processing.
169
+ *
170
+ * This outputs the time spent on transforming the series data to
171
+ * vertex buffers when set to true.
172
+ *
173
+ * @type {Boolean}
174
+ * @default false
175
+ * @apioption boost.debug.timeSeriesProcessing
176
+ */
177
+
178
+ /**
179
+ * Time the the WebGL setup.
180
+ *
181
+ * This outputs the time spent on setting up the WebGL context,
182
+ * creating shaders, and textures.
183
+ *
184
+ * @type {Boolean}
185
+ * @default false
186
+ * @apioption boost.debug.timeSetup
187
+ */
188
+
189
+ /**
190
+ * Time the building of the k-d tree.
191
+ *
192
+ * This outputs the time spent building the k-d tree used for
193
+ * markers etc.
194
+ *
195
+ * Note that the k-d tree is built async, and runs post-rendering.
196
+ * Following, it does not affect the performance of the rendering itself.
197
+ *
198
+ * @type {Boolean}
199
+ * @default false
200
+ * @apioption boost.debug.timeKDTree
201
+ */
202
+
203
+ /**
204
+ * Show the number of points skipped through culling.
205
+ *
206
+ * When set to true, the number of points skipped in series processing
207
+ * is outputted. Points are skipped if they are closer than 1 pixel from
208
+ * each other.
209
+ *
210
+ * @type {Boolean}
211
+ * @default false
212
+ * @apioption boost.debug.showSkipSummary
213
+ */
214
+
215
+ /**
216
+ * Time the WebGL to SVG buffer copy
217
+ *
218
+ * After rendering, the result is copied to an image which is injected
219
+ * into the SVG.
220
+ *
221
+ * If this property is set to true, the time it takes for the buffer copy
222
+ * to complete is outputted.
223
+ *
224
+ * @type {Boolean}
225
+ * @default false
226
+ * @apioption boost.debug.timeBufferCopy
227
+ */
228
+
229
+ /**
230
+ * Enable or disable GPU translations. GPU translations are faster than doing
231
+ * the translation in JavaScript.
232
+ *
233
+ * This option may cause rendering issues with certain datasets.
234
+ * Namely, if your dataset has large numbers with small increments (such as
235
+ * timestamps), it won't work correctly. This is due to floating point
236
+ * precission.
237
+ *
238
+ * @type {Boolean}
239
+ * @default false
240
+ * @apioption boost.useGPUTranslations
241
+ */
242
+
107
243
  /**
108
244
  * Set the point threshold for when a series should enter boost mode.
109
245
  *
110
246
  * Setting it to e.g. 2000 will cause the series to enter boost mode
111
247
  * when there are 2000 or more points in the series.
112
248
  *
113
- * Note: only available when including the boost module.
249
+ * Requires `modules/boost.js`.
250
+ *
251
+ * @type {Number}
252
+ * @default 5000
253
+ * @apioption plotOptions.series.boostThreshold
254
+ */
255
+
256
+ /**
257
+ * If set to true, the whole chart will be boosted if one of the series
258
+ * crosses its threshold, and all the series can be boosted.
114
259
  *
115
- * @default 5000
116
- * @apioption series.boostThreshold
260
+ * @type {Boolean}
261
+ * @default true
262
+ * @apioption boost.allowForce
117
263
  */
118
264
 
119
265
  /* global Float32Array */
@@ -135,8 +281,25 @@
135
281
  pick = H.pick,
136
282
  wrap = H.wrap,
137
283
  plotOptions = H.getOptions().plotOptions,
138
- CHUNK_SIZE = 50000,
139
- index;
284
+ CHUNK_SIZE = 30000,
285
+ mainCanvas = doc.createElement('canvas'),
286
+ index,
287
+ boostable = [
288
+ 'area',
289
+ 'arearange',
290
+ 'column',
291
+ 'bar',
292
+ 'line',
293
+ 'scatter',
294
+ 'heatmap',
295
+ 'bubble',
296
+ 'treemap'
297
+ ],
298
+ boostableMap = {};
299
+
300
+ each(boostable, function(item) {
301
+ boostableMap[item] = 1;
302
+ });
140
303
 
141
304
  // Register color names since GL can't render those directly.
142
305
  Color.prototype.names = {
@@ -295,7 +458,7 @@
295
458
 
296
459
  each(args, function(t) {
297
460
  if (typeof t !== 'undefined' && typeof t.length !== 'undefined') {
298
- //r = r < t.length ? t.length : r;
461
+ // r = r < t.length ? t.length : r;
299
462
  if (t.length > 0) {
300
463
  r = t.length;
301
464
  return true;
@@ -308,27 +471,54 @@
308
471
 
309
472
  /*
310
473
  * Returns true if we should force chart series boosting
474
+ * The result of this is cached in chart.boostForceChartBoost.
475
+ * It's re-fetched on redraw.
476
+ *
477
+ * We do this because there's a lot of overhead involved when dealing
478
+ * with a lot of series.
479
+ *
311
480
  */
312
481
  function shouldForceChartSeriesBoosting(chart) {
313
482
  // If there are more than five series currently boosting,
314
483
  // we should boost the whole chart to avoid running out of webgl contexts.
315
484
  var sboostCount = 0,
485
+ canBoostCount = 0,
486
+ allowBoostForce = true,
316
487
  series;
317
488
 
489
+ if (typeof chart.boostForceChartBoost !== 'undefined') {
490
+ return chart.boostForceChartBoost;
491
+ }
492
+
493
+ allowBoostForce = chart.options.boost ?
494
+ (typeof chart.options.boost.allowForce !== 'undefined' ?
495
+ chart.options.boost.allowForce : allowBoostForce) :
496
+ allowBoostForce;
497
+
318
498
  if (chart.series.length > 1) {
319
499
  for (var i = 0; i < chart.series.length; i++) {
500
+
320
501
  series = chart.series[i];
502
+
503
+ if (boostableMap[series.type]) {
504
+ ++canBoostCount;
505
+ }
506
+
321
507
  if (patientMax(
322
508
  series.processedXData,
323
509
  series.options.data,
510
+ // series.xData,
324
511
  series.points
325
512
  ) >= (series.options.boostThreshold || Number.MAX_VALUE)) {
326
- sboostCount++;
513
+ ++sboostCount;
327
514
  }
328
515
  }
329
516
  }
330
517
 
331
- return sboostCount > 5;
518
+ chart.boostForceChartBoost = (allowBoostForce && canBoostCount === chart.series.length && sboostCount > 0) ||
519
+ sboostCount > 5;
520
+
521
+ return chart.boostForceChartBoost;
332
522
  }
333
523
 
334
524
  /*
@@ -337,10 +527,13 @@
337
527
  * @returns {Boolean} - true if the chart is in series boost mode
338
528
  */
339
529
  function isChartSeriesBoosting(chart) {
340
- return shouldForceChartSeriesBoosting(chart) || chart.series.length >= pick(
341
- chart.options.boost && chart.options.boost.seriesThreshold,
342
- 50
343
- );
530
+ var threshold = 50;
531
+
532
+ threshold = chart.options.boost && typeof chart.options.boost.seriesThreshold !== 'undefined' ?
533
+ chart.options.boost.seriesThreshold : threshold;
534
+
535
+ return threshold <= chart.series.length ||
536
+ shouldForceChartSeriesBoosting(chart);
344
537
  }
345
538
 
346
539
  /*
@@ -348,16 +541,15 @@
348
541
  * @param series {Highchart.Series} - the series to check
349
542
  * @returns {boolean} - true if the series is in boost mode
350
543
  */
351
- function isSeriesBoosting(series) {
544
+ function isSeriesBoosting(series, overrideThreshold) {
352
545
  return isChartSeriesBoosting(series.chart) ||
353
546
  patientMax(
354
547
  series.processedXData,
355
548
  series.options.data,
356
549
  series.points
357
- ) >= (series.options.boostThreshold || Number.MAX_VALUE);
550
+ ) >= (overrideThreshold || series.options.boostThreshold || Number.MAX_VALUE);
358
551
  }
359
552
 
360
- ////////////////////////////////////////////////////////////////////////////////
361
553
  // START OF WEBGL ABSTRACTIONS
362
554
 
363
555
  /*
@@ -384,6 +576,8 @@
384
576
 
385
577
  'uniform bool skipTranslation;',
386
578
 
579
+ 'uniform float plotHeight;',
580
+
387
581
  'uniform float xAxisTrans;',
388
582
  'uniform float xAxisMin;',
389
583
  'uniform float xAxisMinPad;',
@@ -479,6 +673,9 @@
479
673
  'v = value;// + yAxisPos;',
480
674
  '} else {',
481
675
  'v = translate(value, 0.0, yAxisTrans, yAxisMin, yAxisMinPad, yAxisPointRange, yAxisLen, yAxisCVSCoord);// + yAxisPos;',
676
+ 'if (v > plotHeight) {',
677
+ 'v = plotHeight;',
678
+ '}',
482
679
  '}',
483
680
  'if (checkTreshold > 0.0 && hasThreshold) {',
484
681
  'v = min(v, translatedThreshold);',
@@ -504,7 +701,7 @@
504
701
  '}'
505
702
  /* eslint-enable */
506
703
  ].join('\n'),
507
- //Fragment shader source
704
+ // Fragment shader source
508
705
  fragShade = [
509
706
  /* eslint-disable */
510
707
  'precision highp float;',
@@ -521,13 +718,20 @@
521
718
 
522
719
  'void main(void) {',
523
720
  'vec4 col = fillColor;',
721
+ 'vec4 tcol;',
524
722
 
525
723
  'if (hasColor) {',
526
724
  'col = vColor;',
527
725
  '}',
528
726
 
529
727
  'if (isCircle) {',
530
- 'gl_FragColor = col * texture2D(uSampler, gl_PointCoord.st);',
728
+ 'tcol = texture2D(uSampler, gl_PointCoord.st);',
729
+ 'col *= tcol;',
730
+ 'if (tcol.r < 0.0) {',
731
+ 'discard;',
732
+ '} else {',
733
+ 'gl_FragColor = col;',
734
+ '}',
531
735
  '} else {',
532
736
  'gl_FragColor = col;',
533
737
  '}',
@@ -535,26 +739,27 @@
535
739
  /* eslint-enable */
536
740
  ].join('\n'),
537
741
  uLocations = {},
538
- //The shader program
742
+ // The shader program
539
743
  shaderProgram,
540
- //Uniform handle to the perspective matrix
744
+ // Uniform handle to the perspective matrix
541
745
  pUniform,
542
- //Uniform for point size
746
+ // Uniform for point size
543
747
  psUniform,
544
- //Uniform for fill color
748
+ // Uniform for fill color
545
749
  fillColorUniform,
546
- //Uniform for isBubble
750
+ // Uniform for isBubble
547
751
  isBubbleUniform,
548
- //Uniform for bubble abs sizing
752
+ // Uniform for bubble abs sizing
549
753
  bubbleSizeAbsUniform,
550
754
  bubbleSizeAreaUniform,
551
- //Skip translation uniform
755
+ // Skip translation uniform
552
756
  skipTranslationUniform,
553
- //Set to 1 if circle
757
+ // Set to 1 if circle
554
758
  isCircleUniform,
555
- //Uniform for invertion
759
+ // Uniform for invertion
556
760
  isInverted,
557
- //Texture uniform
761
+ plotHeightUniform,
762
+ // Texture uniform
558
763
  uSamplerUniform;
559
764
 
560
765
  /* String to shader program
@@ -570,7 +775,7 @@
570
775
  gl.compileShader(shader);
571
776
 
572
777
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
573
- //console.error('shader error:', gl.getShaderInfoLog(shader));
778
+ // console.error('shader error:', gl.getShaderInfoLog(shader));
574
779
  return false;
575
780
  }
576
781
  return shader;
@@ -586,7 +791,7 @@
586
791
 
587
792
  if (!v || !f) {
588
793
  shaderProgram = false;
589
- //console.error('error creating shader program');
794
+ // console.error('error creating shader program');
590
795
  return false;
591
796
  }
592
797
 
@@ -614,7 +819,7 @@
614
819
  skipTranslationUniform = uloc('skipTranslation');
615
820
  isCircleUniform = uloc('isCircle');
616
821
  isInverted = uloc('isInverted');
617
-
822
+ plotHeightUniform = uloc('plotHeight');
618
823
  return true;
619
824
  }
620
825
 
@@ -622,8 +827,11 @@
622
827
  * Destroy the shader
623
828
  */
624
829
  function destroy() {
625
- if (gl && shaderProgram) {
626
- gl.deleteProgram(shaderProgram);
830
+ if (gl) {
831
+ if (shaderProgram) {
832
+ gl.deleteProgram(shaderProgram);
833
+ shaderProgram = false;
834
+ }
627
835
  }
628
836
  }
629
837
 
@@ -664,8 +872,6 @@
664
872
  gl.uniform1i(isInverted, flag);
665
873
  }
666
874
 
667
- ////////////////////////////////////////////////////////////////////////////
668
-
669
875
  /*
670
876
  * Enable/disable circle drawing
671
877
  */
@@ -673,6 +879,10 @@
673
879
  gl.uniform1i(isCircleUniform, flag ? 1 : 0);
674
880
  }
675
881
 
882
+ function setPlotHeight(n) {
883
+ gl.uniform1f(plotHeightUniform, n);
884
+ }
885
+
676
886
  /*
677
887
  * Flush
678
888
  */
@@ -774,6 +984,7 @@
774
984
  fillColorUniform: function() {
775
985
  return fillColorUniform;
776
986
  },
987
+ setPlotHeight: setPlotHeight,
777
988
  setBubbleUniforms: setBubbleUniforms,
778
989
  bind: bind,
779
990
  program: getProgram,
@@ -798,12 +1009,13 @@
798
1009
  * @param gl {WebGLContext} - the context in which to create the buffer
799
1010
  * @param shader {GLShader} - the shader to use
800
1011
  */
801
- function GLVertexBuffer(gl, shader, dataComponents /*, type */ ) {
1012
+ function GLVertexBuffer(gl, shader, dataComponents /* , type */ ) {
802
1013
  var buffer = false,
803
1014
  vertAttribute = false,
804
1015
  components = dataComponents || 2,
805
1016
  preAllocated = false,
806
1017
  iterator = 0,
1018
+ // farray = false,
807
1019
  data;
808
1020
 
809
1021
  // type = type || 'float';
@@ -811,7 +1023,13 @@
811
1023
  function destroy() {
812
1024
  if (buffer) {
813
1025
  gl.deleteBuffer(buffer);
1026
+ buffer = false;
1027
+ vertAttribute = false;
814
1028
  }
1029
+
1030
+ iterator = 0;
1031
+ components = dataComponents || 2;
1032
+ data = [];
815
1033
  }
816
1034
 
817
1035
  /*
@@ -821,12 +1039,13 @@
821
1039
  * @param dataComponents {Integer} - the number of components per. indice
822
1040
  */
823
1041
  function build(dataIn, attrib, dataComponents) {
1042
+ var farray;
824
1043
 
825
1044
  data = dataIn || [];
826
1045
 
827
1046
  if ((!data || data.length === 0) && !preAllocated) {
828
- //console.error('trying to render empty vbuffer');
829
- buffer = false;
1047
+ // console.error('trying to render empty vbuffer');
1048
+ destroy();
830
1049
  return false;
831
1050
  }
832
1051
 
@@ -836,11 +1055,15 @@
836
1055
  gl.deleteBuffer(buffer);
837
1056
  }
838
1057
 
1058
+ if (!preAllocated) {
1059
+ farray = new Float32Array(data);
1060
+ }
1061
+
839
1062
  buffer = gl.createBuffer();
840
1063
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
841
1064
  gl.bufferData(
842
1065
  gl.ARRAY_BUFFER,
843
- preAllocated || new Float32Array(data),
1066
+ preAllocated || farray,
844
1067
  gl.STATIC_DRAW
845
1068
  );
846
1069
 
@@ -848,6 +1071,9 @@
848
1071
  vertAttribute = gl.getAttribLocation(shader.program(), attrib);
849
1072
  gl.enableVertexAttribArray(vertAttribute);
850
1073
 
1074
+ // Trigger cleanup
1075
+ farray = false;
1076
+
851
1077
  return true;
852
1078
  }
853
1079
 
@@ -860,10 +1086,10 @@
860
1086
  }
861
1087
 
862
1088
  // gl.bindAttribLocation(shader.program(), 0, 'aVertexPosition');
863
- //gl.enableVertexAttribArray(vertAttribute);
864
- //gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
1089
+ // gl.enableVertexAttribArray(vertAttribute);
1090
+ // gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
865
1091
  gl.vertexAttribPointer(vertAttribute, components, gl.FLOAT, false, 0, 0);
866
- //gl.enableVertexAttribArray(vertAttribute);
1092
+ // gl.enableVertexAttribArray(vertAttribute);
867
1093
  }
868
1094
 
869
1095
  /*
@@ -919,12 +1145,12 @@
919
1145
  size *= 4;
920
1146
  iterator = -1;
921
1147
 
922
- //if (!preAllocated || (preAllocated && preAllocated.length !== size)) {
1148
+ // if (!preAllocated || (preAllocated && preAllocated.length !== size)) {
923
1149
  preAllocated = new Float32Array(size);
924
- //}
1150
+ // }
925
1151
  }
926
1152
 
927
- ////////////////////////////////////////////////////////////////////////////
1153
+ // /////////////////////////////////////////////////////////////////////////
928
1154
  return {
929
1155
  destroy: destroy,
930
1156
  bind: bind,
@@ -974,26 +1200,32 @@
974
1200
  // Things to draw as "rectangles" (i.e lines)
975
1201
  asBar = {
976
1202
  'column': true,
1203
+ 'bar': true,
977
1204
  'area': true
978
1205
  },
979
1206
  asCircle = {
980
1207
  'scatter': true,
981
1208
  'bubble': true
982
1209
  },
983
- //Render settings
1210
+ // Render settings
984
1211
  settings = {
985
1212
  pointSize: 1,
986
- lineWidth: 3,
1213
+ lineWidth: 1,
987
1214
  fillColor: '#AA00AA',
988
1215
  useAlpha: true,
989
1216
  usePreallocated: false,
990
1217
  useGPUTranslations: false,
991
- timeRendering: false,
992
- timeSeriesProcessing: false,
993
- timeSetup: false
1218
+ debug: {
1219
+ timeRendering: false,
1220
+ timeSeriesProcessing: false,
1221
+ timeSetup: false,
1222
+ timeBufferCopy: false,
1223
+ timeKDTree: false,
1224
+ showSkipSummary: false
1225
+ }
994
1226
  };
995
1227
 
996
- ////////////////////////////////////////////////////////////////////////////
1228
+ // /////////////////////////////////////////////////////////////////////////
997
1229
 
998
1230
  function setOptions(options) {
999
1231
  merge(true, settings, options);
@@ -1108,6 +1340,7 @@
1108
1340
  zData = series.zData || options.zData || series.processedZData,
1109
1341
  yAxis = series.yAxis,
1110
1342
  xAxis = series.xAxis,
1343
+ plotHeight = series.chart.plotHeight,
1111
1344
  useRaw = !xData || xData.length === 0,
1112
1345
  // threshold = options.threshold,
1113
1346
  // yBottom = chart.yAxis[0].getThreshold(threshold),
@@ -1120,9 +1353,10 @@
1120
1353
  // caxis,
1121
1354
  // connectNulls = options.connectNulls,
1122
1355
  // For some reason eslint doesn't pick up that this is actually used
1123
- maxVal, //eslint-disable-line no-unused-vars
1356
+ maxVal, // eslint-disable-line no-unused-vars
1124
1357
  points = series.points || false,
1125
1358
  lastX = false,
1359
+ lastY = false,
1126
1360
  minVal,
1127
1361
  color,
1128
1362
  scolor,
@@ -1134,7 +1368,30 @@
1134
1368
  closestRight = {
1135
1369
  x: Number.MIN_VALUE,
1136
1370
  y: 0
1137
- };
1371
+ },
1372
+
1373
+ skipped = 0,
1374
+
1375
+ cullXThreshold = 1,
1376
+ cullYThreshold = 1,
1377
+
1378
+ // The following are used in the builder while loop
1379
+ x,
1380
+ y,
1381
+ d,
1382
+ z,
1383
+ i = -1,
1384
+ px = false,
1385
+ nx = false,
1386
+ // This is in fact used.
1387
+ low, // eslint-disable-line no-unused-vars
1388
+ chartDestroyed = typeof chart.index === 'undefined',
1389
+ nextInside = false,
1390
+ prevInside = false,
1391
+ pcolor = false,
1392
+ drawAsBar = asBar[series.type],
1393
+ isXInside = false,
1394
+ isYInside = true;
1138
1395
 
1139
1396
  if (options.boostData && options.boostData.length > 0) {
1140
1397
  return;
@@ -1152,7 +1409,7 @@
1152
1409
  }
1153
1410
  }
1154
1411
 
1155
- //Push a vertice to the data buffer
1412
+ // Push a vertice to the data buffer
1156
1413
  function vertice(x, y, checkTreshold, pointSize, color) {
1157
1414
  pushColor(color);
1158
1415
  if (settings.usePreallocated) {
@@ -1233,7 +1490,7 @@
1233
1490
  // better color interpolation.
1234
1491
 
1235
1492
  // If there's stroking, we do an additional rect
1236
- //if (pointAttr.stroke !== 'none' && swidth && swidth > 0) {
1493
+ // if (pointAttr.stroke !== 'none' && swidth && swidth > 0) {
1237
1494
  if (series.type === 'treemap') {
1238
1495
  swidth = swidth || 1;
1239
1496
  scolor = H.color(pointAttr.stroke).rgba;
@@ -1288,24 +1545,16 @@
1288
1545
  // }
1289
1546
  // });
1290
1547
 
1291
- each(sdata, function(d, i) {
1292
- var x,
1293
- y,
1294
- z,
1295
- px = false,
1296
- nx = false,
1297
- // This is in fact used.
1298
- low, //eslint-disable-line no-unused-vars
1299
- chartDestroyed = typeof chart.index === 'undefined',
1300
- nextInside = false,
1301
- prevInside = false,
1302
- pcolor = false,
1303
- drawAsBar = asBar[series.type],
1304
- isXInside = false,
1305
- isYInside = true;
1548
+ while (i < sdata.length - 1) {
1549
+ d = sdata[++i];
1550
+
1551
+ // px = x = y = z = nx = low = false;
1552
+ // chartDestroyed = typeof chart.index === 'undefined';
1553
+ // nextInside = prevInside = pcolor = isXInside = isYInside = false;
1554
+ // drawAsBar = asBar[series.type];
1306
1555
 
1307
1556
  if (chartDestroyed) {
1308
- return false;
1557
+ break;
1309
1558
  }
1310
1559
 
1311
1560
  // Uncomment this to enable color by point.
@@ -1406,7 +1655,7 @@
1406
1655
  }
1407
1656
 
1408
1657
  if (y !== 0 && (!y || !isYInside)) {
1409
- return;
1658
+ continue;
1410
1659
  }
1411
1660
 
1412
1661
  if (x >= xMin && x <= xMax) {
@@ -1414,7 +1663,7 @@
1414
1663
  }
1415
1664
 
1416
1665
  if (!isXInside && !nextInside && !prevInside) {
1417
- return;
1666
+ continue;
1418
1667
  }
1419
1668
 
1420
1669
  // Skip translations - temporary floating point fix
@@ -1422,6 +1671,12 @@
1422
1671
  inst.skipTranslation = true;
1423
1672
  x = xAxis.toPixels(x, true);
1424
1673
  y = yAxis.toPixels(y, true);
1674
+
1675
+ // Make sure we're not drawing outside of the chart area.
1676
+ // See #6594.
1677
+ if (y > plotHeight) {
1678
+ y = plotHeight;
1679
+ }
1425
1680
  }
1426
1681
 
1427
1682
  if (drawAsBar) {
@@ -1466,6 +1721,35 @@
1466
1721
  }
1467
1722
  }
1468
1723
 
1724
+ // If the last _drawn_ point is closer to this point than the
1725
+ // threshold, skip it. Shaves off 20-100ms in processing.
1726
+
1727
+ if (!settings.useGPUTranslations &&
1728
+ !settings.usePreallocated &&
1729
+ (lastX && x - lastX < cullXThreshold) &&
1730
+ (lastY && Math.abs(y - lastY) < cullYThreshold)
1731
+ ) {
1732
+ if (settings.debug.showSkipSummary) {
1733
+ ++skipped;
1734
+ }
1735
+
1736
+ continue;
1737
+ }
1738
+
1739
+ // Do step line if enabled.
1740
+ // Draws an additional point at the old Y at the new X.
1741
+ // See #6976.
1742
+
1743
+ if (options.step) {
1744
+ vertice(
1745
+ x,
1746
+ lastY,
1747
+ 0,
1748
+ 2,
1749
+ pcolor
1750
+ );
1751
+ }
1752
+
1469
1753
  vertice(
1470
1754
  x,
1471
1755
  y,
@@ -1485,9 +1769,12 @@
1485
1769
  // }
1486
1770
 
1487
1771
  lastX = x;
1772
+ lastY = y;
1773
+ }
1488
1774
 
1489
- //return true;
1490
- });
1775
+ if (settings.debug.showSkipSummary) {
1776
+ console.log('skipped points:', skipped); // eslint-disable-line no-console
1777
+ }
1491
1778
 
1492
1779
  function pushSupplementPoint(point) {
1493
1780
  if (!settings.useGPUTranslations) {
@@ -1527,8 +1814,8 @@
1527
1814
  }
1528
1815
  }
1529
1816
 
1530
- if (settings.timeSeriesProcessing) {
1531
- console.time('building ' + s.type + ' series'); //eslint-disable-line no-console
1817
+ if (settings.debug.timeSeriesProcessing) {
1818
+ console.time('building ' + s.type + ' series'); // eslint-disable-line no-console
1532
1819
  }
1533
1820
 
1534
1821
  series.push({
@@ -1548,6 +1835,7 @@
1548
1835
  'arearange': 'lines',
1549
1836
  'areaspline': 'line_strip',
1550
1837
  'column': 'lines',
1838
+ 'bar': 'lines',
1551
1839
  'line': 'line_strip',
1552
1840
  'scatter': 'points',
1553
1841
  'heatmap': 'triangles',
@@ -1559,8 +1847,8 @@
1559
1847
  // Add the series data to our buffer(s)
1560
1848
  pushSeriesData(s, series[series.length - 1]);
1561
1849
 
1562
- if (settings.timeSeriesProcessing) {
1563
- console.timeEnd('building ' + s.type + ' series'); //eslint-disable-line no-console
1850
+ if (settings.debug.timeSeriesProcessing) {
1851
+ console.timeEnd('building ' + s.type + ' series'); // eslint-disable-line no-console
1564
1852
  }
1565
1853
  }
1566
1854
 
@@ -1573,6 +1861,10 @@
1573
1861
  series = [];
1574
1862
  exports.data = data = [];
1575
1863
  markerData = [];
1864
+
1865
+ if (vbuffer) {
1866
+ vbuffer.destroy();
1867
+ }
1576
1868
  }
1577
1869
 
1578
1870
  /*
@@ -1629,7 +1921,7 @@
1629
1921
 
1630
1922
  if (chart) {
1631
1923
  if (!chart.chartHeight || !chart.chartWidth) {
1632
- //chart.setChartSize();
1924
+ // chart.setChartSize();
1633
1925
  }
1634
1926
 
1635
1927
  width = chart.chartWidth || 800;
@@ -1642,14 +1934,19 @@
1642
1934
  return false;
1643
1935
  }
1644
1936
 
1645
- if (settings.timeRendering) {
1646
- console.time('gl rendering'); //eslint-disable-line no-console
1937
+ if (settings.debug.timeRendering) {
1938
+ console.time('gl rendering'); // eslint-disable-line no-console
1647
1939
  }
1648
1940
 
1941
+ gl.canvas.width = width;
1942
+ gl.canvas.height = height;
1943
+
1649
1944
  shader.bind();
1650
1945
 
1946
+
1651
1947
  gl.viewport(0, 0, width, height);
1652
1948
  shader.setPMatrix(orthoMatrix(width, height));
1949
+ shader.setPlotHeight(chart.plotHeight);
1653
1950
 
1654
1951
  if (settings.lineWidth > 1 && !H.isMS) {
1655
1952
  gl.lineWidth(settings.lineWidth);
@@ -1663,7 +1960,8 @@
1663
1960
  shader.setTexture(circleTextureHandle);
1664
1961
  }
1665
1962
 
1666
- shader.setInverted(chart.options.chart ? chart.options.chart.inverted : false);
1963
+ shader.setInverted(chart.inverted); // chart.options.chart ? chart.options.chart.inverted : false);
1964
+
1667
1965
 
1668
1966
  // Render the series
1669
1967
  each(series, function(s, si) {
@@ -1683,14 +1981,16 @@
1683
1981
  10
1684
1982
  ) || 10)
1685
1983
  ),
1686
- fillColor = s.series.fillOpacity ?
1687
- new Color(s.series.color).setOpacity(
1688
- pick(options.fillOpacity, 0.85)
1689
- ).get() :
1984
+ fillColor =
1985
+ (s.series.pointAttribs && s.series.pointAttribs().fill) ||
1690
1986
  s.series.color,
1691
1987
  color;
1692
1988
 
1693
- vbuffer.bind();
1989
+ if (s.series.fillOpacity && options.fillOpacity) {
1990
+ fillColor = new Color(fillColor).setOpacity(
1991
+ pick(options.fillOpacity, 1.0)
1992
+ ).get();
1993
+ }
1694
1994
 
1695
1995
  if (options.colorByPoint) {
1696
1996
  fillColor = s.series.chart.options.colors[si];
@@ -1702,7 +2002,12 @@
1702
2002
  color[3] = 1.0;
1703
2003
  }
1704
2004
 
1705
- //Blending
2005
+ // This is very much temporary
2006
+ if (s.drawMode === 'lines' && settings.useAlpha && color[3] < 1) {
2007
+ color[3] /= 10;
2008
+ }
2009
+
2010
+ // Blending
1706
2011
  if (options.boostBlending === 'add') {
1707
2012
  gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
1708
2013
  gl.blendEquation(gl.FUNC_ADD);
@@ -1715,8 +2020,8 @@
1715
2020
  gl.blendEquation(gl.FUNC_MIN);
1716
2021
 
1717
2022
  } else {
1718
- //gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);//, gl.ONE, gl.ZERO);
1719
- //gl.blendEquation(gl.FUNC_ADD);
2023
+ // gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);//, gl.ONE, gl.ZERO);
2024
+ // gl.blendEquation(gl.FUNC_ADD);
1720
2025
  gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
1721
2026
  }
1722
2027
 
@@ -1725,7 +2030,7 @@
1725
2030
  // If there are entries in the colorData buffer, build and bind it.
1726
2031
  if (s.colorData.length > 0) {
1727
2032
  shader.setUniform('hasColor', 1.0);
1728
- cbuffer = GLVertexBuffer(gl, shader); //eslint-disable-line new-cap
2033
+ cbuffer = GLVertexBuffer(gl, shader); // eslint-disable-line new-cap
1729
2034
  cbuffer.build(s.colorData, 'aColor', 4);
1730
2035
  cbuffer.bind();
1731
2036
  }
@@ -1768,17 +2073,15 @@
1768
2073
  }
1769
2074
  });
1770
2075
 
1771
- vbuffer.destroy();
1772
-
1773
- if (settings.timeRendering) {
1774
- console.timeEnd('gl rendering'); //eslint-disable-line no-console
2076
+ if (settings.debug.timeRendering) {
2077
+ console.timeEnd('gl rendering'); // eslint-disable-line no-console
1775
2078
  }
1776
2079
 
1777
- flush();
1778
-
1779
2080
  if (postRenderCallback) {
1780
2081
  postRenderCallback();
1781
2082
  }
2083
+
2084
+ flush();
1782
2085
  }
1783
2086
 
1784
2087
  /*
@@ -1838,12 +2141,14 @@
1838
2141
  return false;
1839
2142
  }
1840
2143
 
1841
- if (settings.timeSetup) {
1842
- console.time('gl setup'); //eslint-disable-line no-console
2144
+ if (settings.debug.timeSetup) {
2145
+ console.time('gl setup'); // eslint-disable-line no-console
1843
2146
  }
1844
2147
 
1845
2148
  for (; i < contexts.length; i++) {
1846
- gl = canvas.getContext(contexts[i]);
2149
+ gl = canvas.getContext(contexts[i], {
2150
+ // premultipliedAlpha: false
2151
+ });
1847
2152
  if (gl) {
1848
2153
  break;
1849
2154
  }
@@ -1861,10 +2166,11 @@
1861
2166
  // gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
1862
2167
  gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
1863
2168
  gl.disable(gl.DEPTH_TEST);
1864
- gl.depthMask(gl.FALSE);
2169
+ // gl.depthMask(gl.FALSE);
2170
+ gl.depthFunc(gl.LESS);
1865
2171
 
1866
- shader = GLShader(gl); //eslint-disable-line new-cap
1867
- vbuffer = GLVertexBuffer(gl, shader); //eslint-disable-line new-cap
2172
+ shader = GLShader(gl); // eslint-disable-line new-cap
2173
+ vbuffer = GLVertexBuffer(gl, shader); // eslint-disable-line new-cap
1868
2174
 
1869
2175
  textureIsReady = false;
1870
2176
 
@@ -1875,14 +2181,23 @@
1875
2181
  circleTexture.width = 512;
1876
2182
  circleTexture.height = 512;
1877
2183
 
2184
+ circleCtx.mozImageSmoothingEnabled = false;
2185
+ circleCtx.webkitImageSmoothingEnabled = false;
2186
+ circleCtx.msImageSmoothingEnabled = false;
2187
+ circleCtx.imageSmoothingEnabled = false;
2188
+
2189
+ circleCtx.strokeStyle = 'rgba(255, 255, 255, 0)';
1878
2190
  circleCtx.fillStyle = '#FFF';
2191
+
1879
2192
  circleCtx.beginPath();
1880
2193
  circleCtx.arc(256, 256, 256, 0, 2 * Math.PI);
2194
+ circleCtx.stroke();
1881
2195
  circleCtx.fill();
1882
2196
 
1883
2197
  try {
1884
2198
 
1885
2199
  gl.bindTexture(gl.TEXTURE_2D, circleTextureHandle);
2200
+ // gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
1886
2201
 
1887
2202
  gl.texImage2D(
1888
2203
  gl.TEXTURE_2D,
@@ -1896,9 +2211,9 @@
1896
2211
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
1897
2212
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1898
2213
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
1899
- gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
2214
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
1900
2215
 
1901
- gl.generateMipmap(gl.TEXTURE_2D);
2216
+ // gl.generateMipmap(gl.TEXTURE_2D);
1902
2217
 
1903
2218
  gl.bindTexture(gl.TEXTURE_2D, null);
1904
2219
 
@@ -1907,8 +2222,8 @@
1907
2222
 
1908
2223
  isInited = true;
1909
2224
 
1910
- if (settings.timeSetup) {
1911
- console.timeEnd('gl setup'); //eslint-disable-line no-console
2225
+ if (settings.debug.timeSetup) {
2226
+ console.timeEnd('gl setup'); // eslint-disable-line no-console
1912
2227
  }
1913
2228
 
1914
2229
  return true;
@@ -1931,6 +2246,7 @@
1931
2246
  }
1932
2247
 
1933
2248
  function destroy() {
2249
+ flush();
1934
2250
  vbuffer.destroy();
1935
2251
  shader.destroy();
1936
2252
  if (gl) {
@@ -1942,7 +2258,7 @@
1942
2258
  }
1943
2259
  }
1944
2260
 
1945
- ////////////////////////////////////////////////////////////////////////////
2261
+ // /////////////////////////////////////////////////////////////////////////
1946
2262
  exports = {
1947
2263
  allocateBufferForSingleSeries: allocateBufferForSingleSeries,
1948
2264
  pushSeries: pushSeries,
@@ -1968,7 +2284,7 @@
1968
2284
  }
1969
2285
 
1970
2286
  // END OF WEBGL ABSTRACTIONS
1971
- ////////////////////////////////////////////////////////////////////////////////
2287
+ // /////////////////////////////////////////////////////////////////////////////
1972
2288
 
1973
2289
  /*
1974
2290
  * Create a canvas + context and attach it to the target
@@ -1979,7 +2295,12 @@
1979
2295
  var width = chart.chartWidth,
1980
2296
  height = chart.chartHeight,
1981
2297
  target = chart,
1982
- targetGroup = chart.seriesGroup || series.group;
2298
+ targetGroup = chart.seriesGroup || series.group,
2299
+ alpha = 1,
2300
+ foSupported = doc.implementation.hasFeature(
2301
+ 'www.http://w3.org/TR/SVG11/feature#Extensibility',
2302
+ '1.1'
2303
+ );
1983
2304
 
1984
2305
  if (isChartSeriesBoosting(chart)) {
1985
2306
  target = chart;
@@ -1987,20 +2308,78 @@
1987
2308
  target = series;
1988
2309
  }
1989
2310
 
1990
- if (target.ogl) {
1991
- //target.ogl.destroy();
1992
- }
2311
+ // Support for foreignObject is flimsy as best.
2312
+ // IE does not support it, and Chrome has a bug which messes up
2313
+ // the canvas draw order.
2314
+ // As such, we force the Image fallback for now, but leaving the
2315
+ // actual Canvas path in-place in case this changes in the future.
2316
+ foSupported = false;
1993
2317
 
1994
- if (!target.image) {
1995
- target.canvas = doc.createElement('canvas');
2318
+ if (!target.renderTarget) {
2319
+ target.canvas = mainCanvas;
1996
2320
 
1997
- target.image = chart.renderer.image(
1998
- '',
1999
- 0,
2000
- 0,
2001
- width,
2002
- height
2003
- ).add(targetGroup);
2321
+ // Fall back to image tag if foreignObject isn't supported,
2322
+ // or if we're exporting.
2323
+ if (chart.renderer.forExport || !foSupported) {
2324
+ target.renderTarget = chart.renderer.image(
2325
+ '',
2326
+ 0,
2327
+ 0,
2328
+ width,
2329
+ height
2330
+ ).add(targetGroup);
2331
+
2332
+ target.boostClear = function() {
2333
+ target.renderTarget.attr({
2334
+ href: ''
2335
+ });
2336
+ };
2337
+
2338
+ target.boostCopy = function() {
2339
+ target.boostResizeTarget();
2340
+ target.renderTarget.attr({
2341
+ href: target.canvas.toDataURL('image/png')
2342
+ });
2343
+ };
2344
+
2345
+ } else {
2346
+ target.renderTargetFo = chart.renderer.createElement('foreignObject')
2347
+ .add(targetGroup);
2348
+
2349
+ target.renderTarget = doc.createElement('canvas');
2350
+ target.renderTargetCtx = target.renderTarget.getContext('2d');
2351
+
2352
+ target.renderTargetFo.element.appendChild(target.renderTarget);
2353
+
2354
+ target.boostClear = function() {
2355
+ target.renderTarget.width = target.canvas.width;
2356
+ target.renderTarget.height = target.canvas.height;
2357
+ };
2358
+
2359
+ target.boostCopy = function() {
2360
+ target.renderTarget.width = target.canvas.width;
2361
+ target.renderTarget.height = target.canvas.height;
2362
+
2363
+ target.renderTargetCtx.drawImage(target.canvas, 0, 0);
2364
+ };
2365
+ }
2366
+
2367
+ target.boostResizeTarget = function() {
2368
+ width = chart.chartWidth;
2369
+ height = chart.chartHeight;
2370
+
2371
+ (target.renderTargetFo || target.renderTarget).attr({
2372
+ x: 0,
2373
+ y: 0,
2374
+ width: width,
2375
+ height: height,
2376
+ style: 'pointer-events: none; mix-blend-mode: normal; opacity:' + alpha
2377
+ });
2378
+
2379
+ if (target instanceof H.Chart) {
2380
+ target.markerGroup.translate(series.xAxis.pos, series.yAxis.pos);
2381
+ }
2382
+ };
2004
2383
 
2005
2384
  target.boostClipRect = chart.renderer.clipRect(
2006
2385
  chart.plotLeft,
@@ -2009,7 +2388,7 @@
2009
2388
  chart.chartHeight
2010
2389
  );
2011
2390
 
2012
- target.image.clip(target.boostClipRect);
2391
+ (target.renderTargetFo || target.renderTarget).clip(target.boostClipRect);
2013
2392
 
2014
2393
  if (target instanceof H.Chart) {
2015
2394
  target.markerGroup = target.renderer.g().add(targetGroup);
@@ -2021,14 +2400,6 @@
2021
2400
  target.canvas.width = width;
2022
2401
  target.canvas.height = height;
2023
2402
 
2024
- target.image.attr({
2025
- x: 0,
2026
- y: 0,
2027
- width: width,
2028
- height: height,
2029
- style: 'pointer-events: none'
2030
- });
2031
-
2032
2403
  target.boostClipRect.attr({
2033
2404
  x: chart.plotLeft,
2034
2405
  y: chart.plotTop,
@@ -2036,18 +2407,22 @@
2036
2407
  height: chart.chartHeight
2037
2408
  });
2038
2409
 
2410
+ target.boostResizeTarget();
2411
+ target.boostClear();
2412
+
2039
2413
  if (!target.ogl) {
2414
+ target.ogl = GLRenderer(function() { // eslint-disable-line new-cap
2415
+ if (target.ogl.settings.debug.timeBufferCopy) {
2416
+ console.time('buffer copy'); // eslint-disable-line no-console
2417
+ }
2040
2418
 
2419
+ target.boostCopy();
2041
2420
 
2042
- target.ogl = GLRenderer(function() { // eslint-disable-line new-cap
2043
- target.image.attr({
2044
- href: target.canvas.toDataURL('image/png')
2045
- });
2421
+ if (target.ogl.settings.debug.timeBufferCopy) {
2422
+ console.timeEnd('buffer copy'); // eslint-disable-line no-console
2423
+ }
2046
2424
 
2047
- // Destroy gl context when we're done with it
2048
- target.ogl.destroy();
2049
- target.ogl = false;
2050
- }); //eslint-disable-line new-cap
2425
+ }); // eslint-disable-line new-cap
2051
2426
 
2052
2427
  target.ogl.init(target.canvas);
2053
2428
  // target.ogl.clear();
@@ -2071,7 +2446,7 @@
2071
2446
  */
2072
2447
  function renderIfNotSeriesBoosting(renderer, series, chart) {
2073
2448
  if (renderer &&
2074
- series.image &&
2449
+ series.renderTarget &&
2075
2450
  series.canvas &&
2076
2451
  !isChartSeriesBoosting(chart || series.chart)
2077
2452
  ) {
@@ -2081,7 +2456,7 @@
2081
2456
 
2082
2457
  function allocateIfNotSeriesBoosting(renderer, series) {
2083
2458
  if (renderer &&
2084
- series.image &&
2459
+ series.renderTarget &&
2085
2460
  series.canvas &&
2086
2461
  !isChartSeriesBoosting(series.chart)
2087
2462
  ) {
@@ -2110,13 +2485,14 @@
2110
2485
  proceed = fn(arr[i], i);
2111
2486
  ++i;
2112
2487
  }
2488
+
2113
2489
  if (proceed) {
2114
2490
  if (i < arr.length) {
2115
2491
 
2116
2492
  if (noTimeout) {
2117
2493
  eachAsync(arr, fn, finalFunc, chunkSize, i, noTimeout);
2118
2494
  } else if (win.requestAnimationFrame) {
2119
- //If available, do requestAnimationFrame - shaves off a few ms
2495
+ // If available, do requestAnimationFrame - shaves off a few ms
2120
2496
  win.requestAnimationFrame(function() {
2121
2497
  eachAsync(arr, fn, finalFunc, chunkSize, i);
2122
2498
  });
@@ -2132,7 +2508,7 @@
2132
2508
  }
2133
2509
  }
2134
2510
 
2135
- ////////////////////////////////////////////////////////////////////////////////
2511
+ // /////////////////////////////////////////////////////////////////////////////
2136
2512
  // Following is the parts of the boost that's common between OGL/Legacy
2137
2513
 
2138
2514
  /**
@@ -2211,21 +2587,13 @@
2211
2587
  });
2212
2588
 
2213
2589
  // Set default options
2214
- each([
2215
- 'area',
2216
- 'arearange',
2217
- 'column',
2218
- 'line',
2219
- 'scatter',
2220
- 'heatmap',
2221
- 'bubble',
2222
- 'treemap',
2223
- 'heatmap'
2224
- ],
2590
+ each(boostable,
2225
2591
  function(type) {
2226
2592
  if (plotOptions[type]) {
2227
2593
  plotOptions[type].boostThreshold = 5000;
2228
2594
  plotOptions[type].boostData = [];
2595
+
2596
+ seriesTypes[type].prototype.fillOpacity = true;
2229
2597
  }
2230
2598
  }
2231
2599
  );
@@ -2246,20 +2614,44 @@
2246
2614
  ], function(method) {
2247
2615
  function branch(proceed) {
2248
2616
  var letItPass = this.options.stacking &&
2249
- (method === 'translate' || method === 'generatePoints');
2617
+ (method === 'translate' || method === 'generatePoints'),
2618
+ enabled = true;
2619
+
2620
+ if (this.chart && this.chart.options && this.chart.options.boost) {
2621
+ enabled = typeof this.chart.options.boost.enabled === 'undefined' ?
2622
+ true :
2623
+ this.chart.options.boost.enabled;
2624
+ }
2250
2625
 
2251
2626
  if (!isSeriesBoosting(this) ||
2252
2627
  letItPass ||
2628
+ !enabled ||
2253
2629
  this.type === 'heatmap' ||
2254
2630
  this.type === 'treemap'
2255
2631
  ) {
2256
2632
 
2257
2633
  // Clear image
2258
- if (method === 'render' && this.image && !isChartSeriesBoosting(this.chart)) {
2259
- this.image.attr({
2260
- href: ''
2261
- });
2262
- this.animate = null; // We're zooming in, don't run animation
2634
+ if (method === 'render') {
2635
+ this.stickyTracking = (this.options || {}).stickyTracking;
2636
+
2637
+ if (this.boostClear) {
2638
+ this.boostClear();
2639
+ this.animate = null; // We're zooming in, don't run animation
2640
+ }
2641
+ }
2642
+
2643
+ if (!this.options.stacking && method === 'translate' &&
2644
+ this.type !== 'treemap' &&
2645
+ this.type !== 'heatmap') {
2646
+ // We call generate points and check if we're now boosting
2647
+ // so that we don't have to call series.translate
2648
+ // when zooming out from SVG mode (which is very, very expensive)
2649
+
2650
+ this.generatePoints();
2651
+
2652
+ if (isSeriesBoosting(this)) {
2653
+ return;
2654
+ }
2263
2655
  }
2264
2656
 
2265
2657
  proceed.call(this);
@@ -2278,6 +2670,10 @@
2278
2670
  wrap(seriesTypes.column.prototype, method, branch);
2279
2671
  }
2280
2672
 
2673
+ if (seriesTypes.bar) {
2674
+ wrap(seriesTypes.bar.prototype, method, branch);
2675
+ }
2676
+
2281
2677
  if (seriesTypes.arearange) {
2282
2678
  wrap(seriesTypes.arearange.prototype, method, branch);
2283
2679
  }
@@ -2321,12 +2717,23 @@
2321
2717
 
2322
2718
  /* Used for treemap|heatmap.drawPoints */
2323
2719
  function pointDrawHandler(proceed) {
2324
- if (!isSeriesBoosting(this)) {
2720
+ var enabled = true,
2721
+ renderer;
2722
+
2723
+ if (this.chart.options && this.chart.options.boost) {
2724
+ enabled = typeof this.chart.options.boost.enabled === 'undefined' ?
2725
+ true :
2726
+ this.chart.options.boost.enabled;
2727
+ }
2728
+
2729
+ if (!enabled || !isSeriesBoosting(this)) {
2325
2730
  return proceed.call(this);
2326
2731
  }
2327
2732
 
2328
- //Make sure we have a valid OGL context
2329
- var renderer = createAndAttachRenderer(this.chart, this);
2733
+ this.chart.isBoosting = true;
2734
+
2735
+ // Make sure we have a valid OGL context
2736
+ renderer = createAndAttachRenderer(this.chart, this);
2330
2737
 
2331
2738
  if (renderer) {
2332
2739
  allocateIfNotSeriesBoosting(renderer, this);
@@ -2336,7 +2743,7 @@
2336
2743
  renderIfNotSeriesBoosting(renderer, this);
2337
2744
  }
2338
2745
 
2339
- ////////////////////////////////////////////////////////////////////////////////
2746
+ // /////////////////////////////////////////////////////////////////////////////
2340
2747
  // We're wrapped in a closure, so just return if there's no webgl support
2341
2748
 
2342
2749
  if (!hasWebGLSupport()) {
@@ -2348,7 +2755,7 @@
2348
2755
  }
2349
2756
  } else {
2350
2757
 
2351
- ////////////////////////////////////////////////////////////////////////////
2758
+ // /////////////////////////////////////////////////////////////////////////
2352
2759
  // GL-SPECIFIC WRAPPINGS FOLLOWS
2353
2760
 
2354
2761
  /** If the series is a heatmap or treemap, or if the series is not boosting
@@ -2416,11 +2823,8 @@
2416
2823
  chart = series.chart,
2417
2824
  xAxis = this.xAxis,
2418
2825
  yAxis = this.yAxis,
2419
- //ctx,
2420
- //c = 0,
2421
2826
  xData = options.xData || series.processedXData,
2422
2827
  yData = options.yData || series.processedYData,
2423
-
2424
2828
  rawData = options.data,
2425
2829
  xExtremes = xAxis.getExtremes(),
2426
2830
  xMin = xExtremes.min,
@@ -2445,9 +2849,12 @@
2445
2849
  maxVal,
2446
2850
  minI,
2447
2851
  maxI,
2852
+ boostOptions,
2853
+
2854
+ xDataFull = this.xData || this.options.xData || this.processedXData || false,
2448
2855
 
2449
2856
  addKDPoint = function(clientX, plotY, i) {
2450
- //Shaves off about 60ms compared to repeated concatination
2857
+ // Shaves off about 60ms compared to repeated concatination
2451
2858
  index = clientX + ',' + plotY;
2452
2859
 
2453
2860
  // The k-d tree requires series points.
@@ -2462,6 +2869,7 @@
2462
2869
  }
2463
2870
 
2464
2871
  points.push({
2872
+ x: xDataFull ? xDataFull[cropStart + i] : false,
2465
2873
  clientX: clientX,
2466
2874
  plotX: clientX,
2467
2875
  plotY: plotY,
@@ -2473,18 +2881,21 @@
2473
2881
  // Get or create the renderer
2474
2882
  renderer = createAndAttachRenderer(chart, series);
2475
2883
 
2884
+ chart.isBoosting = true;
2885
+
2886
+ boostOptions = renderer.settings;
2887
+
2888
+ // Force sticky tracking
2889
+ this.stickyTracking = true;
2890
+
2476
2891
  if (!this.visible) {
2477
- if (!isChartSeriesBoosting(chart) && renderer) {
2478
- renderer.clear();
2479
- this.image.attr({
2480
- href: ''
2481
- });
2482
- }
2483
2892
  return;
2484
2893
  }
2485
2894
 
2486
2895
  // If we are zooming out from SVG mode, destroy the graphics
2487
2896
  if (this.points || this.graph) {
2897
+
2898
+ this.animate = null;
2488
2899
  this.destroyGraphics();
2489
2900
  }
2490
2901
 
@@ -2499,7 +2910,7 @@
2499
2910
  chart.seriesGroup
2500
2911
  );
2501
2912
  } else {
2502
- //Use a single group for the markers
2913
+ // Use a single group for the markers
2503
2914
  this.markerGroup = chart.markerGroup;
2504
2915
  }
2505
2916
 
@@ -2513,7 +2924,7 @@
2513
2924
  renderer.pushSeries(series);
2514
2925
  // Perform the actual renderer if we're on series level
2515
2926
  renderIfNotSeriesBoosting(renderer, this, chart);
2516
- //console.log(series, chart);
2927
+ // console.log(series, chart);
2517
2928
  }
2518
2929
 
2519
2930
  /* This builds the KD-tree */
@@ -2612,15 +3023,24 @@
2612
3023
  // Go back to prototype, ready to build
2613
3024
  delete series.buildKDTree;
2614
3025
  series.buildKDTree();
3026
+
3027
+ if (boostOptions.debug.timeKDTree) {
3028
+ console.timeEnd('kd tree building'); // eslint-disable-line no-console
3029
+ }
2615
3030
  }
2616
3031
 
2617
- // Loop over the points to build the k-d tree
2618
- eachAsync(
2619
- isStacked ? series.data : (xData || rawData),
2620
- processPoint,
2621
- doneProcessing,
2622
- chart.renderer.forExport ? Number.MAX_VALUE : undefined
2623
- );
3032
+ // Loop over the points to build the k-d tree - skip this if exporting
3033
+ if (!chart.renderer.forExport) {
3034
+ if (boostOptions.debug.timeKDTree) {
3035
+ console.time('kd tree building'); // eslint-disable-line no-console
3036
+ }
3037
+
3038
+ eachAsync(
3039
+ isStacked ? series.data : (xData || rawData),
3040
+ processPoint,
3041
+ doneProcessing
3042
+ );
3043
+ }
2624
3044
  }
2625
3045
  });
2626
3046
 
@@ -2667,20 +3087,19 @@
2667
3087
  sampling: true
2668
3088
  });
2669
3089
 
3090
+
2670
3091
  extend(seriesTypes.column.prototype, {
2671
3092
  fill: true,
2672
3093
  sampling: true
2673
3094
  });
2674
3095
 
2675
- wrap(Series.prototype, 'setVisible', function(proceed, vis) {
2676
- proceed.call(this, vis, false);
2677
- if (this.visible === false && this.ogl && this.canvas && this.image) {
2678
- this.ogl.clear();
2679
- this.image.attr({
2680
- href: ''
2681
- });
2682
- } else {
2683
- this.chart.redraw();
3096
+ wrap(Series.prototype, 'setVisible', function(proceed, vis, redraw) {
3097
+ proceed.call(this, vis, redraw);
3098
+ if (this.visible === false && this.canvas && this.renderTarget) {
3099
+ if (this.ogl) {
3100
+ this.ogl.clear();
3101
+ }
3102
+ this.boostClear();
2684
3103
  }
2685
3104
  });
2686
3105
 
@@ -2698,15 +3117,18 @@
2698
3117
 
2699
3118
  /* Clear chart-level canvas */
2700
3119
  function preRender() {
3120
+ // Reset force state
3121
+ chart.boostForceChartBoost = undefined;
3122
+ chart.boostForceChartBoost = shouldForceChartSeriesBoosting(chart);
3123
+ chart.isBoosting = false;
2701
3124
 
2702
3125
  if (!isChartSeriesBoosting(chart) && chart.didBoost) {
2703
3126
  chart.didBoost = false;
2704
- // Clear the canvas
2705
- if (chart.image) {
2706
- chart.image.attr({
2707
- href: ''
2708
- });
2709
- }
3127
+ }
3128
+
3129
+ // Clear the canvas
3130
+ if (chart.boostClear) {
3131
+ chart.boostClear();
2710
3132
  }
2711
3133
 
2712
3134
  if (chart.canvas && chart.ogl && isChartSeriesBoosting(chart)) {
@@ -2716,18 +3138,22 @@
2716
3138
  chart.ogl.allocateBuffer(chart);
2717
3139
  }
2718
3140
 
2719
- //see #6518 + #6739
3141
+ // see #6518 + #6739
2720
3142
  if (chart.markerGroup && chart.xAxis && chart.xAxis.length > 0 && chart.yAxis && chart.yAxis.length > 0) {
2721
3143
  chart.markerGroup.translate(
2722
3144
  chart.xAxis[0].pos,
2723
3145
  chart.yAxis[0].pos
2724
3146
  );
2725
3147
  }
2726
-
2727
3148
  }
2728
3149
 
2729
3150
  addEvent(chart, 'predraw', preRender);
2730
3151
  addEvent(chart, 'render', canvasToSVG);
3152
+
3153
+ // addEvent(chart, 'zoom', function () {
3154
+ // chart.boostForceChartBoost = shouldForceChartSeriesBoosting(chart);
3155
+ // });
3156
+
2731
3157
  });
2732
3158
  } // if hasCanvasSupport
2733
3159