highcharts-rails 5.0.14 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
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