highstock-rails 1.3.10 → 2.1.10

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/app/assets/images/highstock/meteogram-symbols-30px.png +0 -0
  4. data/app/assets/javascripts/highstock.js +418 -369
  5. data/app/assets/javascripts/highstock/adapters/standalone-framework.js +12 -12
  6. data/app/assets/javascripts/highstock/adapters/standalone-framework.src.js +635 -0
  7. data/app/assets/javascripts/highstock/highcharts-3d.js +48 -0
  8. data/app/assets/javascripts/highstock/highcharts-3d.src.js +1711 -0
  9. data/app/assets/javascripts/highstock/highcharts-more.js +49 -45
  10. data/app/assets/javascripts/highstock/highstock-all.js +637 -0
  11. data/app/assets/javascripts/highstock/modules/boost.js +12 -0
  12. data/app/assets/javascripts/highstock/modules/boost.src.js +591 -0
  13. data/app/assets/javascripts/highstock/modules/canvas-tools.js +9 -9
  14. data/app/assets/javascripts/highstock/modules/canvas-tools.src.js +3114 -0
  15. data/app/assets/javascripts/highstock/modules/data.js +20 -10
  16. data/app/assets/javascripts/highstock/modules/data.src.js +957 -0
  17. data/app/assets/javascripts/highstock/modules/drilldown.js +17 -14
  18. data/app/assets/javascripts/highstock/modules/drilldown.src.js +717 -0
  19. data/app/assets/javascripts/highstock/modules/exporting.js +17 -15
  20. data/app/assets/javascripts/highstock/modules/exporting.src.js +780 -0
  21. data/app/assets/javascripts/highstock/modules/funnel.js +5 -5
  22. data/app/assets/javascripts/highstock/modules/funnel.src.js +322 -0
  23. data/app/assets/javascripts/highstock/modules/heatmap.js +23 -2
  24. data/app/assets/javascripts/highstock/modules/heatmap.src.js +711 -0
  25. data/app/assets/javascripts/highstock/modules/no-data-to-display.js +4 -4
  26. data/app/assets/javascripts/highstock/modules/no-data-to-display.src.js +143 -0
  27. data/app/assets/javascripts/highstock/modules/offline-exporting.js +14 -0
  28. data/app/assets/javascripts/highstock/modules/offline-exporting.src.js +280 -0
  29. data/app/assets/javascripts/highstock/modules/solid-gauge.js +14 -0
  30. data/app/assets/javascripts/highstock/modules/solid-gauge.src.js +273 -0
  31. data/app/assets/javascripts/highstock/modules/treemap.js +30 -0
  32. data/app/assets/javascripts/highstock/modules/treemap.src.js +868 -0
  33. data/app/assets/javascripts/highstock/themes/dark-blue.js +1 -1
  34. data/app/assets/javascripts/highstock/themes/dark-green.js +1 -1
  35. data/app/assets/javascripts/highstock/themes/dark-unica.js +213 -0
  36. data/app/assets/javascripts/highstock/themes/gray.js +1 -1
  37. data/app/assets/javascripts/highstock/themes/grid-light.js +74 -0
  38. data/app/assets/javascripts/highstock/themes/sand-signika.js +104 -0
  39. data/lib/highstock/rails/version.rb +1 -1
  40. metadata +26 -7
  41. data/app/assets/javascripts/highstock/adapters/mootools-adapter.js +0 -13
  42. data/app/assets/javascripts/highstock/adapters/prototype-adapter.js +0 -15
  43. data/app/assets/javascripts/highstock/modules/annotations.js +0 -7
  44. data/app/assets/javascripts/highstock/modules/map.js +0 -41
@@ -0,0 +1,12 @@
1
+ (function(c){typeof module==="object"&&module.exports?module.exports=c:c(Highcharts)})(function(c){function u(a,b,d,e,f){f=f||0;e=e||v;k(a.slice(f,f+e),b);f+e<a.length?setTimeout(function(){u(a,b,d,e,f+e)}):d&&d()}var L=function(){},M=c.Color,j=c.Series,h=c.seriesTypes,k=c.each,p=c.extend,N=c.addEvent,O=c.fireEvent,P=c.merge,Q=c.pick,g=c.wrap,n=c.getOptions().plotOptions,v=5E4;k(["area","arearange","column","line","scatter"],function(a){if(n[a])n[a].boostThreshold=5E3});k(["translate","generatePoints",
2
+ "drawTracker","drawPoints","render"],function(a){function b(b){var e=this.options.stacking&&(a==="translate"||a==="generatePoints");if((this.processedXData||this.options.data).length<(this.options.boostThreshold||Number.MAX_VALUE)||e){if(a==="render"&&this.image)this.image.attr({href:""}),this.animate=null;b.call(this)}else if(this[a+"Canvas"])this[a+"Canvas"]()}g(j.prototype,a,b);a==="translate"&&(h.column&&g(h.column.prototype,a,b),h.arearange&&g(h.arearange.prototype,a,b))});g(j.prototype,"getExtremes",
3
+ function(a){this.hasExtremes()||a.apply(this,Array.prototype.slice.call(arguments,1))});g(j.prototype,"setData",function(a){this.hasExtremes(!0)||a.apply(this,Array.prototype.slice.call(arguments,1))});g(j.prototype,"processData",function(a){this.hasExtremes(!0)||a.apply(this,Array.prototype.slice.call(arguments,1))});c.extend(j.prototype,{pointRange:0,hasExtremes:function(a){var b=this.options,d=this.xAxis&&this.xAxis.options,e=this.yAxis&&this.yAxis.options;return b.data.length>(b.boostThreshold||
4
+ Number.MAX_VALUE)&&typeof e.min==="number"&&typeof e.max==="number"&&(!a||typeof d.min==="number"&&typeof d.max==="number")},destroyGraphics:function(){var a=this,b=this.points,d,e;if(b)for(e=0;e<b.length;e+=1)if((d=b[e])&&d.graphic)d.graphic=d.graphic.destroy();k(["graph","area","tracker"],function(b){a[b]&&(a[b]=a[b].destroy())})},getContext:function(){var a=this.chart,b=a.plotWidth,d=a.plotHeight,e=this.ctx,f=function(a,b,d,e,f,c,i){a.call(this,d,b,e,f,c,i)};this.canvas?e.clearRect(0,0,b,d):(this.canvas=
5
+ document.createElement("canvas"),this.image=a.renderer.image("",0,0,b,d).add(this.group),this.ctx=e=this.canvas.getContext("2d"),a.inverted&&k(["moveTo","lineTo","rect","arc"],function(a){g(e,a,f)}));this.canvas.setAttribute("width",b);this.canvas.setAttribute("height",d);this.image.attr({width:b,height:d});return e},canvasToSVG:function(){this.image.attr({href:this.canvas.toDataURL("image/png")})},cvsLineTo:function(a,b,d){a.lineTo(b,d)},renderCanvas:function(){var a=this,b=a.options,d=a.chart,e=
6
+ this.xAxis,f=this.yAxis,c,h,g=0,j=a.processedXData,k=a.processedYData,n=b.data,i=e.getExtremes(),R=i.min,S=i.max,i=f.getExtremes(),T=i.min,U=i.max,w={},q,V=!!a.sampling,x,y=b.marker&&b.marker.radius,z=this.cvsDrawPoint,A=b.lineWidth?this.cvsLineTo:!1,B=y<=1?this.cvsMarkerSquare:this.cvsMarkerCircle,W=b.enableMouseTracking!==!1,C,i=b.threshold,l=f.getThreshold(i),D=typeof i==="number",E=l,X=this.fill,F=a.pointArrayMap&&a.pointArrayMap.join(",")==="low,high",G=!!b.stacking,Y=a.cropStart||0,i=d.options.loading,
7
+ Z=a.requireSorting,H,$=b.connectNulls,I=!j,r,s,m,o,aa=a.fillOpacity?(new M(a.color)).setOpacity(Q(b.fillOpacity,0.75)).get():a.color,J=function(){X?(c.fillStyle=aa,c.fill()):(c.strokeStyle=a.color,c.lineWidth=b.lineWidth,c.stroke())},K=function(a,b,d){g===0&&c.beginPath();H?c.moveTo(a,b):z?z(c,a,b,d,C):A?A(c,a,b):B&&B(c,a,b,y);g+=1;g===1E3&&(J(),g=0);C={clientX:a,plotY:b,yBottom:d}},t=function(a,b,c){W&&!w[a+","+b]&&(w[a+","+b]=!0,d.inverted&&(a=e.len-a,b=f.len-b),x.push({clientX:a,plotX:a,plotY:b,
8
+ i:Y+c}))};(this.points||this.graph)&&this.destroyGraphics();a.plotGroup("group","series",a.visible?"visible":"hidden",b.zIndex,d.seriesGroup);a.getAttribs();a.markerGroup=a.group;N(a,"destroy",function(){a.markerGroup=null});x=this.points=[];c=this.getContext();a.buildKDTree=L;if(n.length>99999)d.options.loading=P(i,{labelStyle:{backgroundColor:"rgba(255,255,255,0.75)",padding:"1em",borderRadius:"0.5em"},style:{backgroundColor:"none",opacity:1}}),d.showLoading("Drawing..."),d.options.loading=i,d.loadingShown===
9
+ !0?d.loadingShown=1:d.loadingShown+=1;h=0;u(G?a.data:j||n,function(b){var d,c,g,i=!0;I?(d=b[0],c=b[1]):(d=b,c=k[h]);if(F)I&&(c=b.slice(1,3)),g=c[0],c=c[1];else if(G)d=b.x,c=b.stackY,g=c-b.y;b=c===null;Z||(i=c>=T&&c<=U);if(!b&&d>=R&&d<=S&&i)if(d=Math.round(e.toPixels(d,!0)),V){if(m===void 0||d===q){F||(g=c);if(o===void 0||c>s)s=c,o=h;if(m===void 0||g<r)r=g,m=h}d!==q&&(m!==void 0&&(c=f.toPixels(s,!0),l=f.toPixels(r,!0),K(d,D?Math.min(c,E):c,D?Math.max(l,E):l),t(d,c,o),l!==c&&t(d,l,m)),m=o=void 0,q=
10
+ d)}else c=Math.round(f.toPixels(c,!0)),K(d,c,l),t(d,c,h);H=b&&!$;h+=1;h%v===0&&a.canvasToSVG()},function(){var b=d.loadingDiv,c=+d.loadingShown;J();a.canvasToSVG();O(a,"renderedCanvas");if(c===1)p(b.style,{transition:"opacity 250ms",opacity:0}),d.loadingShown=!1,setTimeout(function(){b.parentNode&&b.parentNode.removeChild(b);d.loadingDiv=d.loadingSpan=null},250);if(c)d.loadingShown=c-1;a.directTouch=!1;a.options.stickyTracking=!0;delete a.buildKDTree;a.buildKDTree()},d.renderer.forExport?Number.MAX_VALUE:
11
+ void 0)}});h.scatter.prototype.cvsMarkerCircle=function(a,b,d,c){a.moveTo(b,d);a.arc(b,d,c,0,2*Math.PI,!1)};h.scatter.prototype.cvsMarkerSquare=function(a,b,d,c){a.moveTo(b,d);a.rect(b-c,d-c,c*2,c*2)};h.scatter.prototype.fill=!0;p(h.area.prototype,{cvsDrawPoint:function(a,b,d,c,f){f&&b!==f.clientX&&(a.moveTo(f.clientX,f.yBottom),a.lineTo(f.clientX,f.plotY),a.lineTo(b,d),a.lineTo(b,c))},fill:!0,fillOpacity:!0,sampling:!0});p(h.column.prototype,{cvsDrawPoint:function(a,b,c,e){a.rect(b-1,c,1,e-c)},fill:!0,
12
+ sampling:!0});j.prototype.getPoint=function(a){var b=a;if(a&&!(a instanceof this.pointClass))b=(new this.pointClass).init(this,this.options.data[a.i]),b.dist=a.dist,b.category=b.x,b.plotX=a.plotX,b.plotY=a.plotY;return b};g(j.prototype,"searchPoint",function(a){return this.getPoint(a.apply(this,[].slice.call(arguments,1)))})});
@@ -0,0 +1,591 @@
1
+ /**
2
+ * This is an experimental Highcharts module that draws long data series on a canvas
3
+ * in order to increase performance of the initial load time and tooltip responsiveness.
4
+ *
5
+ * Compatible with HTML5 canvas compatible browsers (not IE < 9).
6
+ *
7
+ * Author: Torstein Honsi
8
+ *
9
+ *
10
+ * Development plan
11
+ * - Column range.
12
+ * - Heatmap.
13
+ * - Treemap.
14
+ * - Check how it works with Highstock and data grouping.
15
+ * - Check inverted charts.
16
+ * - Check reversed axes.
17
+ * - Chart callback should be async after last series is drawn. (But not necessarily, we don't do
18
+ that with initial series animation).
19
+ * - Cache full-size image so we don't have to redraw on hide/show and zoom up. But k-d-tree still
20
+ * needs to be built.
21
+ * - Test IE9 and IE10.
22
+ * - Stacking is not perhaps not correct since it doesn't use the translation given in
23
+ * the translate method. If this gets to complicated, a possible way out would be to
24
+ * have a simplified renderCanvas method that simply draws the areaPath on a canvas.
25
+ *
26
+ * If this module is taken in as part of the core
27
+ * - All the loading logic should be merged with core. Update styles in the core.
28
+ * - Most of the method wraps should probably be added directly in parent methods.
29
+ *
30
+ * Notes for boost mode
31
+ * - Area lines are not drawn
32
+ * - Point markers are not drawn
33
+ * - Zones and negativeColor don't work
34
+ * - Columns are always one pixel wide. Don't set the threshold too low.
35
+ *
36
+ * Optimizing tips for users
37
+ * - For scatter plots, use a marker.radius of 1 or less. It results in a rectangle being drawn, which is
38
+ * considerably faster than a circle.
39
+ * - Set extremes (min, max) explicitly on the axes in order for Highcharts to avoid computing extremes.
40
+ * - Set enableMouseTracking to false on the series to improve total rendering time.
41
+ * - The default threshold is set based on one series. If you have multiple, dense series, the combined
42
+ * number of points drawn gets higher, and you may want to set the threshold lower in order to
43
+ * use optimizations.
44
+ */
45
+
46
+ /* eslint indent: [2, 4] */
47
+ (function (factory) {
48
+ if (typeof module === 'object' && module.exports) {
49
+ module.exports = factory;
50
+ } else {
51
+ factory(Highcharts);
52
+ }
53
+ }(function (H) {
54
+
55
+ 'use strict';
56
+
57
+ var noop = function () {},
58
+ Color = H.Color,
59
+ Series = H.Series,
60
+ seriesTypes = H.seriesTypes,
61
+ each = H.each,
62
+ extend = H.extend,
63
+ addEvent = H.addEvent,
64
+ fireEvent = H.fireEvent,
65
+ merge = H.merge,
66
+ pick = H.pick,
67
+ wrap = H.wrap,
68
+ plotOptions = H.getOptions().plotOptions,
69
+ CHUNK_SIZE = 50000;
70
+
71
+ function eachAsync(arr, fn, finalFunc, chunkSize, i) {
72
+ i = i || 0;
73
+ chunkSize = chunkSize || CHUNK_SIZE;
74
+ each(arr.slice(i, i + chunkSize), fn);
75
+ if (i + chunkSize < arr.length) {
76
+ setTimeout(function () {
77
+ eachAsync(arr, fn, finalFunc, chunkSize, i + chunkSize);
78
+ });
79
+ } else if (finalFunc) {
80
+ finalFunc();
81
+ }
82
+ }
83
+
84
+ // Set default options
85
+ each(['area', 'arearange', 'column', 'line', 'scatter'], function (type) {
86
+ if (plotOptions[type]) {
87
+ plotOptions[type].boostThreshold = 5000;
88
+ }
89
+ });
90
+
91
+ /**
92
+ * Override a bunch of methods the same way. If the number of points is below the threshold,
93
+ * run the original method. If not, check for a canvas version or do nothing.
94
+ */
95
+ each(['translate', 'generatePoints', 'drawTracker', 'drawPoints', 'render'], function (method) {
96
+ function branch(proceed) {
97
+ var letItPass = this.options.stacking && (method === 'translate' || method === 'generatePoints');
98
+ if ((this.processedXData || this.options.data).length < (this.options.boostThreshold || Number.MAX_VALUE) ||
99
+ letItPass) {
100
+
101
+ // Clear image
102
+ if (method === 'render' && this.image) {
103
+ this.image.attr({ href: '' });
104
+ this.animate = null; // We're zooming in, don't run animation
105
+ }
106
+
107
+ proceed.call(this);
108
+
109
+ // If a canvas version of the method exists, like renderCanvas(), run
110
+ } else if (this[method + 'Canvas']) {
111
+
112
+ this[method + 'Canvas']();
113
+ }
114
+ }
115
+ wrap(Series.prototype, method, branch);
116
+
117
+ // A special case for some types - its translate method is already wrapped
118
+ if (method === 'translate') {
119
+ if (seriesTypes.column) {
120
+ wrap(seriesTypes.column.prototype, method, branch);
121
+ }
122
+ if (seriesTypes.arearange) {
123
+ wrap(seriesTypes.arearange.prototype, method, branch);
124
+ }
125
+ }
126
+ });
127
+
128
+ /**
129
+ * Do not compute extremes when min and max are set.
130
+ * If we use this in the core, we can add the hook to hasExtremes to the methods directly.
131
+ */
132
+ wrap(Series.prototype, 'getExtremes', function (proceed) {
133
+ if (!this.hasExtremes()) {
134
+ proceed.apply(this, Array.prototype.slice.call(arguments, 1));
135
+ }
136
+ });
137
+ wrap(Series.prototype, 'setData', function (proceed) {
138
+ if (!this.hasExtremes(true)) {
139
+ proceed.apply(this, Array.prototype.slice.call(arguments, 1));
140
+ }
141
+ });
142
+ wrap(Series.prototype, 'processData', function (proceed) {
143
+ if (!this.hasExtremes(true)) {
144
+ proceed.apply(this, Array.prototype.slice.call(arguments, 1));
145
+ }
146
+ });
147
+
148
+
149
+ H.extend(Series.prototype, {
150
+ pointRange: 0,
151
+
152
+ hasExtremes: function (checkX) {
153
+ var options = this.options,
154
+ data = options.data,
155
+ xAxis = this.xAxis && this.xAxis.options,
156
+ yAxis = this.yAxis && this.yAxis.options;
157
+ return data.length > (options.boostThreshold || Number.MAX_VALUE) && typeof yAxis.min === 'number' && typeof yAxis.max === 'number' &&
158
+ (!checkX || (typeof xAxis.min === 'number' && typeof xAxis.max === 'number'));
159
+ },
160
+
161
+ /**
162
+ * If implemented in the core, parts of this can probably be shared with other similar
163
+ * methods in Highcharts.
164
+ */
165
+ destroyGraphics: function () {
166
+ var series = this,
167
+ points = this.points,
168
+ point,
169
+ i;
170
+
171
+ if (points) {
172
+ for (i = 0; i < points.length; i = i + 1) {
173
+ point = points[i];
174
+ if (point && point.graphic) {
175
+ point.graphic = point.graphic.destroy();
176
+ }
177
+ }
178
+ }
179
+
180
+ each(['graph', 'area', 'tracker'], function (prop) {
181
+ if (series[prop]) {
182
+ series[prop] = series[prop].destroy();
183
+ }
184
+ });
185
+ },
186
+
187
+ /**
188
+ * Create a hidden canvas to draw the graph on. The contents is later copied over
189
+ * to an SVG image element.
190
+ */
191
+ getContext: function () {
192
+ var chart = this.chart,
193
+ width = chart.plotWidth,
194
+ height = chart.plotHeight,
195
+ ctx = this.ctx,
196
+ swapXY = function (proceed, x, y, a, b, c, d) {
197
+ proceed.call(this, y, x, a, b, c, d);
198
+ };
199
+
200
+ if (!this.canvas) {
201
+ this.canvas = document.createElement('canvas');
202
+ this.image = chart.renderer.image('', 0, 0, width, height).add(this.group);
203
+ this.ctx = ctx = this.canvas.getContext('2d');
204
+ if (chart.inverted) {
205
+ each(['moveTo', 'lineTo', 'rect', 'arc'], function (fn) {
206
+ wrap(ctx, fn, swapXY);
207
+ });
208
+ }
209
+ } else {
210
+ ctx.clearRect(0, 0, width, height);
211
+ }
212
+
213
+ this.canvas.setAttribute('width', width);
214
+ this.canvas.setAttribute('height', height);
215
+ this.image.attr({
216
+ width: width,
217
+ height: height
218
+ });
219
+
220
+ return ctx;
221
+ },
222
+
223
+ /**
224
+ * Draw the canvas image inside an SVG image
225
+ */
226
+ canvasToSVG: function () {
227
+ this.image.attr({ href: this.canvas.toDataURL('image/png') });
228
+ },
229
+
230
+ cvsLineTo: function (ctx, clientX, plotY) {
231
+ ctx.lineTo(clientX, plotY);
232
+ },
233
+
234
+ renderCanvas: function () {
235
+ var series = this,
236
+ options = series.options,
237
+ chart = series.chart,
238
+ xAxis = this.xAxis,
239
+ yAxis = this.yAxis,
240
+ ctx,
241
+ i,
242
+ c = 0,
243
+ xData = series.processedXData,
244
+ yData = series.processedYData,
245
+ rawData = options.data,
246
+ xExtremes = xAxis.getExtremes(),
247
+ xMin = xExtremes.min,
248
+ xMax = xExtremes.max,
249
+ yExtremes = yAxis.getExtremes(),
250
+ yMin = yExtremes.min,
251
+ yMax = yExtremes.max,
252
+ pointTaken = {},
253
+ lastClientX,
254
+ sampling = !!series.sampling,
255
+ points,
256
+ r = options.marker && options.marker.radius,
257
+ cvsDrawPoint = this.cvsDrawPoint,
258
+ cvsLineTo = options.lineWidth ? this.cvsLineTo : false,
259
+ cvsMarker = r <= 1 ? this.cvsMarkerSquare : this.cvsMarkerCircle,
260
+ enableMouseTracking = options.enableMouseTracking !== false,
261
+ lastPoint,
262
+ threshold = options.threshold,
263
+ yBottom = yAxis.getThreshold(threshold),
264
+ hasThreshold = typeof threshold === 'number',
265
+ translatedThreshold = yBottom,
266
+ doFill = this.fill,
267
+ isRange = series.pointArrayMap && series.pointArrayMap.join(',') === 'low,high',
268
+ isStacked = !!options.stacking,
269
+ cropStart = series.cropStart || 0,
270
+ loadingOptions = chart.options.loading,
271
+ requireSorting = series.requireSorting,
272
+ wasNull,
273
+ connectNulls = options.connectNulls,
274
+ useRaw = !xData,
275
+ minVal,
276
+ maxVal,
277
+ minI,
278
+ maxI,
279
+ fillColor = series.fillOpacity ?
280
+ new Color(series.color).setOpacity(pick(options.fillOpacity, 0.75)).get() :
281
+ series.color,
282
+ stroke = function () {
283
+ if (doFill) {
284
+ ctx.fillStyle = fillColor;
285
+ ctx.fill();
286
+ } else {
287
+ ctx.strokeStyle = series.color;
288
+ ctx.lineWidth = options.lineWidth;
289
+ ctx.stroke();
290
+ }
291
+ },
292
+ drawPoint = function (clientX, plotY, yBottom) {
293
+ if (c === 0) {
294
+ ctx.beginPath();
295
+ }
296
+
297
+ if (wasNull) {
298
+ ctx.moveTo(clientX, plotY);
299
+ } else {
300
+ if (cvsDrawPoint) {
301
+ cvsDrawPoint(ctx, clientX, plotY, yBottom, lastPoint);
302
+ } else if (cvsLineTo) {
303
+ cvsLineTo(ctx, clientX, plotY);
304
+ } else if (cvsMarker) {
305
+ cvsMarker(ctx, clientX, plotY, r);
306
+ }
307
+ }
308
+
309
+ // We need to stroke the line for every 1000 pixels. It will crash the browser
310
+ // memory use if we stroke too infrequently.
311
+ c = c + 1;
312
+ if (c === 1000) {
313
+ stroke();
314
+ c = 0;
315
+ }
316
+
317
+ // Area charts need to keep track of the last point
318
+ lastPoint = {
319
+ clientX: clientX,
320
+ plotY: plotY,
321
+ yBottom: yBottom
322
+ };
323
+ },
324
+
325
+ addKDPoint = function (clientX, plotY, i) {
326
+
327
+ // The k-d tree requires series points. Reduce the amount of points, since the time to build the
328
+ // tree increases exponentially.
329
+ if (enableMouseTracking && !pointTaken[clientX + ',' + plotY]) {
330
+ pointTaken[clientX + ',' + plotY] = true;
331
+
332
+ if (chart.inverted) {
333
+ clientX = xAxis.len - clientX;
334
+ plotY = yAxis.len - plotY;
335
+ }
336
+
337
+ points.push({
338
+ clientX: clientX,
339
+ plotX: clientX,
340
+ plotY: plotY,
341
+ i: cropStart + i
342
+ });
343
+ }
344
+ };
345
+
346
+ // If we are zooming out from SVG mode, destroy the graphics
347
+ if (this.points || this.graph) {
348
+ this.destroyGraphics();
349
+ }
350
+
351
+ // The group
352
+ series.plotGroup(
353
+ 'group',
354
+ 'series',
355
+ series.visible ? 'visible' : 'hidden',
356
+ options.zIndex,
357
+ chart.seriesGroup
358
+ );
359
+
360
+ series.getAttribs();
361
+ series.markerGroup = series.group;
362
+ addEvent(series, 'destroy', function () {
363
+ series.markerGroup = null;
364
+ });
365
+
366
+ points = this.points = [];
367
+ ctx = this.getContext();
368
+ series.buildKDTree = noop; // Do not start building while drawing
369
+
370
+ // Display a loading indicator
371
+ if (rawData.length > 99999) {
372
+ chart.options.loading = merge(loadingOptions, {
373
+ labelStyle: {
374
+ backgroundColor: 'rgba(255,255,255,0.75)',
375
+ padding: '1em',
376
+ borderRadius: '0.5em'
377
+ },
378
+ style: {
379
+ backgroundColor: 'none',
380
+ opacity: 1
381
+ }
382
+ });
383
+ chart.showLoading('Drawing...');
384
+ chart.options.loading = loadingOptions; // reset
385
+ if (chart.loadingShown === true) {
386
+ chart.loadingShown = 1;
387
+ } else {
388
+ chart.loadingShown = chart.loadingShown + 1;
389
+ }
390
+ }
391
+
392
+ // Loop over the points
393
+ i = 0;
394
+ eachAsync(isStacked ? series.data : (xData || rawData), function (d) {
395
+
396
+ var x,
397
+ y,
398
+ clientX,
399
+ plotY,
400
+ isNull,
401
+ low,
402
+ isYInside = true;
403
+
404
+ if (useRaw) {
405
+ x = d[0];
406
+ y = d[1];
407
+ } else {
408
+ x = d;
409
+ y = yData[i];
410
+ }
411
+
412
+ // Resolve low and high for range series
413
+ if (isRange) {
414
+ if (useRaw) {
415
+ y = d.slice(1, 3);
416
+ }
417
+ low = y[0];
418
+ y = y[1];
419
+ } else if (isStacked) {
420
+ x = d.x;
421
+ y = d.stackY;
422
+ low = y - d.y;
423
+ }
424
+
425
+ isNull = y === null;
426
+
427
+ // Optimize for scatter zooming
428
+ if (!requireSorting) {
429
+ isYInside = y >= yMin && y <= yMax;
430
+ }
431
+
432
+ if (!isNull && x >= xMin && x <= xMax && isYInside) {
433
+
434
+ clientX = Math.round(xAxis.toPixels(x, true));
435
+
436
+ if (sampling) {
437
+ if (minI === undefined || clientX === lastClientX) {
438
+ if (!isRange) {
439
+ low = y;
440
+ }
441
+ if (maxI === undefined || y > maxVal) {
442
+ maxVal = y;
443
+ maxI = i;
444
+ }
445
+ if (minI === undefined || low < minVal) {
446
+ minVal = low;
447
+ minI = i;
448
+ }
449
+
450
+ }
451
+ if (clientX !== lastClientX) { // Add points and reset
452
+ if (minI !== undefined) { // then maxI is also a number
453
+ plotY = yAxis.toPixels(maxVal, true);
454
+ yBottom = yAxis.toPixels(minVal, true);
455
+ drawPoint(
456
+ clientX,
457
+ hasThreshold ? Math.min(plotY, translatedThreshold) : plotY,
458
+ hasThreshold ? Math.max(yBottom, translatedThreshold) : yBottom
459
+ );
460
+ addKDPoint(clientX, plotY, maxI);
461
+ if (yBottom !== plotY) {
462
+ addKDPoint(clientX, yBottom, minI);
463
+ }
464
+ }
465
+
466
+
467
+ minI = maxI = undefined;
468
+ lastClientX = clientX;
469
+ }
470
+ } else {
471
+ plotY = Math.round(yAxis.toPixels(y, true));
472
+ drawPoint(clientX, plotY, yBottom);
473
+ addKDPoint(clientX, plotY, i);
474
+ }
475
+ }
476
+ wasNull = isNull && !connectNulls;
477
+
478
+ i = i + 1;
479
+
480
+ if (i % CHUNK_SIZE === 0) {
481
+ series.canvasToSVG();
482
+ }
483
+
484
+ }, function () {
485
+
486
+ var loadingDiv = chart.loadingDiv,
487
+ loadingShown = +chart.loadingShown;
488
+
489
+ stroke();
490
+ series.canvasToSVG();
491
+
492
+ fireEvent(series, 'renderedCanvas');
493
+
494
+ // Do not use chart.hideLoading, as it runs JS animation and will be blocked by buildKDTree.
495
+ // CSS animation looks good, but then it must be deleted in timeout. If we add the module to core,
496
+ // change hideLoading so we can skip this block.
497
+ if (loadingShown === 1) {
498
+ extend(loadingDiv.style, {
499
+ transition: 'opacity 250ms',
500
+ opacity: 0
501
+ });
502
+
503
+ chart.loadingShown = false;
504
+ setTimeout(function () {
505
+ if (loadingDiv.parentNode) { // In exporting it is falsy
506
+ loadingDiv.parentNode.removeChild(loadingDiv);
507
+ }
508
+ chart.loadingDiv = chart.loadingSpan = null;
509
+ }, 250);
510
+ }
511
+ if (loadingShown) {
512
+ chart.loadingShown = loadingShown - 1;
513
+ }
514
+
515
+ // Pass tests in Pointer.
516
+ // Replace this with a single property, and replace when zooming in
517
+ // below boostThreshold.
518
+ series.directTouch = false;
519
+ series.options.stickyTracking = true;
520
+
521
+ delete series.buildKDTree; // Go back to prototype, ready to build
522
+ series.buildKDTree();
523
+
524
+ // Don't do async on export, the exportChart, getSVGForExport and getSVG methods are not chained for it.
525
+ }, chart.renderer.forExport ? Number.MAX_VALUE : undefined);
526
+ }
527
+ });
528
+
529
+ seriesTypes.scatter.prototype.cvsMarkerCircle = function (ctx, clientX, plotY, r) {
530
+ ctx.moveTo(clientX, plotY);
531
+ ctx.arc(clientX, plotY, r, 0, 2 * Math.PI, false);
532
+ };
533
+
534
+ // Rect is twice as fast as arc, should be used for small markers
535
+ seriesTypes.scatter.prototype.cvsMarkerSquare = function (ctx, clientX, plotY, r) {
536
+ ctx.moveTo(clientX, plotY);
537
+ ctx.rect(clientX - r, plotY - r, r * 2, r * 2);
538
+ };
539
+ seriesTypes.scatter.prototype.fill = true;
540
+
541
+ extend(seriesTypes.area.prototype, {
542
+ cvsDrawPoint: function (ctx, clientX, plotY, yBottom, lastPoint) {
543
+ if (lastPoint && clientX !== lastPoint.clientX) {
544
+ ctx.moveTo(lastPoint.clientX, lastPoint.yBottom);
545
+ ctx.lineTo(lastPoint.clientX, lastPoint.plotY);
546
+ ctx.lineTo(clientX, plotY);
547
+ ctx.lineTo(clientX, yBottom);
548
+ }
549
+ },
550
+ fill: true,
551
+ fillOpacity: true,
552
+ sampling: true
553
+ });
554
+
555
+ extend(seriesTypes.column.prototype, {
556
+ cvsDrawPoint: function (ctx, clientX, plotY, yBottom) {
557
+ ctx.rect(clientX - 1, plotY, 1, yBottom - plotY);
558
+ },
559
+ fill: true,
560
+ sampling: true
561
+ });
562
+
563
+ /**
564
+ * Return a full Point object based on the index. The boost module uses stripped point objects
565
+ * for performance reasons.
566
+ * @param {Number} boostPoint A stripped-down point object
567
+ * @returns {Object} A Point object as per http://api.highcharts.com/highcharts#Point
568
+ */
569
+ Series.prototype.getPoint = function (boostPoint) {
570
+ var point = boostPoint;
571
+
572
+ if (boostPoint && !(boostPoint instanceof this.pointClass)) {
573
+ point = (new this.pointClass()).init(this, this.options.data[boostPoint.i]);
574
+ point.dist = boostPoint.dist;
575
+ point.category = point.x;
576
+ point.plotX = boostPoint.plotX;
577
+ point.plotY = boostPoint.plotY;
578
+ }
579
+
580
+ return point;
581
+ };
582
+
583
+ /**
584
+ * Return a point instance from the k-d-tree
585
+ */
586
+ wrap(Series.prototype, 'searchPoint', function (proceed) {
587
+ return this.getPoint(
588
+ proceed.apply(this, [].slice.call(arguments, 1))
589
+ );
590
+ });
591
+ }));