pghero 3.1.0 → 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/app/assets/javascripts/pghero/Chart.bundle.js +23379 -19766
  4. data/app/assets/javascripts/pghero/application.js +13 -12
  5. data/app/assets/javascripts/pghero/chartkick.js +834 -764
  6. data/app/assets/javascripts/pghero/highlight.min.js +440 -0
  7. data/app/assets/javascripts/pghero/jquery.js +318 -197
  8. data/app/assets/javascripts/pghero/nouislider.js +676 -1066
  9. data/app/assets/stylesheets/pghero/application.css +8 -2
  10. data/app/assets/stylesheets/pghero/nouislider.css +4 -10
  11. data/app/controllers/pg_hero/home_controller.rb +31 -9
  12. data/app/helpers/pg_hero/home_helper.rb +2 -2
  13. data/app/views/layouts/pg_hero/application.html.erb +1 -1
  14. data/app/views/pg_hero/home/_query_stats_slider.html.erb +6 -6
  15. data/app/views/pg_hero/home/connections.html.erb +6 -6
  16. data/app/views/pg_hero/home/index.html.erb +3 -1
  17. data/app/views/pg_hero/home/queries.html.erb +4 -2
  18. data/app/views/pg_hero/home/relation_space.html.erb +1 -1
  19. data/app/views/pg_hero/home/show_query.html.erb +16 -12
  20. data/app/views/pg_hero/home/space.html.erb +44 -40
  21. data/app/views/pg_hero/home/system.html.erb +6 -6
  22. data/lib/generators/pghero/query_stats_generator.rb +1 -0
  23. data/lib/generators/pghero/space_stats_generator.rb +1 -0
  24. data/lib/pghero/engine.rb +1 -1
  25. data/lib/pghero/methods/basic.rb +5 -8
  26. data/lib/pghero/methods/connections.rb +4 -4
  27. data/lib/pghero/methods/constraints.rb +1 -1
  28. data/lib/pghero/methods/indexes.rb +8 -8
  29. data/lib/pghero/methods/kill.rb +1 -1
  30. data/lib/pghero/methods/maintenance.rb +3 -3
  31. data/lib/pghero/methods/queries.rb +2 -2
  32. data/lib/pghero/methods/query_stats.rb +19 -19
  33. data/lib/pghero/methods/replication.rb +2 -2
  34. data/lib/pghero/methods/sequences.rb +2 -2
  35. data/lib/pghero/methods/space.rb +18 -12
  36. data/lib/pghero/methods/suggested_indexes.rb +10 -6
  37. data/lib/pghero/methods/tables.rb +4 -5
  38. data/lib/pghero/version.rb +1 -1
  39. data/lib/pghero.rb +28 -26
  40. data/lib/tasks/pghero.rake +11 -1
  41. data/licenses/LICENSE-chart.js.txt +1 -1
  42. data/licenses/LICENSE-date-fns.txt +21 -20
  43. data/licenses/LICENSE-kurkle-color.txt +9 -0
  44. metadata +5 -4
  45. data/app/assets/javascripts/pghero/highlight.pack.js +0 -2
@@ -1,8 +1,7 @@
1
1
  /*!
2
- * Chartkick.js
2
+ * Chartkick.js v5.0.1
3
3
  * Create beautiful charts with one line of JavaScript
4
4
  * https://github.com/ankane/chartkick.js
5
- * v4.0.2
6
5
  * MIT License
7
6
  */
8
7
 
@@ -10,7 +9,7 @@
10
9
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
11
10
  typeof define === 'function' && define.amd ? define(factory) :
12
11
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Chartkick = factory());
13
- }(this, (function () { 'use strict';
12
+ })(this, (function () { 'use strict';
14
13
 
15
14
  function isArray(variable) {
16
15
  return Object.prototype.toString.call(variable) === "[object Array]";
@@ -27,8 +26,7 @@
27
26
 
28
27
  // https://github.com/madrobby/zepto/blob/master/src/zepto.js
29
28
  function extend(target, source) {
30
- var key;
31
- for (key in source) {
29
+ for (var key in source) {
32
30
  // protect against prototype pollution, defense 1
33
31
  if (key === "__proto__") { continue; }
34
32
 
@@ -53,13 +51,12 @@
53
51
  return target;
54
52
  }
55
53
 
56
- var DATE_PATTERN = /^(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)$/i;
54
+ var DATE_PATTERN = /^(\d\d\d\d)(?:-)?(\d\d)(?:-)?(\d\d)$/i;
57
55
 
58
56
  function negativeValues(series) {
59
- var i, j, data;
60
- for (i = 0; i < series.length; i++) {
61
- data = series[i].data;
62
- for (j = 0; j < data.length; j++) {
57
+ for (var i = 0; i < series.length; i++) {
58
+ var data = series[i].data;
59
+ for (var j = 0; j < data.length; j++) {
63
60
  if (data[j][1] < 0) {
64
61
  return true;
65
62
  }
@@ -68,49 +65,49 @@
68
65
  return false;
69
66
  }
70
67
 
71
- function toStr(n) {
72
- return "" + n;
68
+ function toStr(obj) {
69
+ return "" + obj;
73
70
  }
74
71
 
75
- function toFloat(n) {
76
- return parseFloat(n);
72
+ function toFloat(obj) {
73
+ return parseFloat(obj);
77
74
  }
78
75
 
79
- function toDate(n) {
80
- var matches, year, month, day;
81
- if (typeof n !== "object") {
82
- if (typeof n === "number") {
83
- n = new Date(n * 1000); // ms
76
+ function toDate(obj) {
77
+ if (obj instanceof Date) {
78
+ return obj;
79
+ } else if (typeof obj === "number") {
80
+ return new Date(obj * 1000); // ms
81
+ } else {
82
+ var s = toStr(obj);
83
+ var matches = s.match(DATE_PATTERN);
84
+ if (matches) {
85
+ var year = parseInt(matches[1], 10);
86
+ var month = parseInt(matches[2], 10) - 1;
87
+ var day = parseInt(matches[3], 10);
88
+ return new Date(year, month, day);
84
89
  } else {
85
- n = toStr(n);
86
- if ((matches = n.match(DATE_PATTERN))) {
87
- year = parseInt(matches[1], 10);
88
- month = parseInt(matches[3], 10) - 1;
89
- day = parseInt(matches[5], 10);
90
- return new Date(year, month, day);
91
- } else {
92
- // try our best to get the str into iso8601
93
- // TODO be smarter about this
94
- var str = n.replace(/ /, "T").replace(" ", "").replace("UTC", "Z");
95
- // Date.parse returns milliseconds if valid and NaN if invalid
96
- n = new Date(Date.parse(str) || n);
97
- }
90
+ // try our best to get the str into iso8601
91
+ // TODO be smarter about this
92
+ var str = s.replace(/ /, "T").replace(" ", "").replace("UTC", "Z");
93
+ // Date.parse returns milliseconds if valid and NaN if invalid
94
+ return new Date(Date.parse(str) || s);
98
95
  }
99
96
  }
100
- return n;
101
97
  }
102
98
 
103
- function toArr(n) {
104
- if (!isArray(n)) {
105
- var arr = [], i;
106
- for (i in n) {
107
- if (n.hasOwnProperty(i)) {
108
- arr.push([i, n[i]]);
99
+ function toArr(obj) {
100
+ if (isArray(obj)) {
101
+ return obj;
102
+ } else {
103
+ var arr = [];
104
+ for (var i in obj) {
105
+ if (Object.prototype.hasOwnProperty.call(obj, i)) {
106
+ arr.push([i, obj[i]]);
109
107
  }
110
108
  }
111
- n = arr;
109
+ return arr;
112
110
  }
113
- return n;
114
111
  }
115
112
 
116
113
  function jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle) {
@@ -170,32 +167,63 @@
170
167
  return a[0] - b[0];
171
168
  }
172
169
 
170
+ // needed since sort() without arguments does string comparison
173
171
  function sortByNumber(a, b) {
174
172
  return a - b;
175
173
  }
176
174
 
177
- function isMinute(d) {
178
- return d.getMilliseconds() === 0 && d.getSeconds() === 0;
175
+ function every(values, fn) {
176
+ for (var i = 0; i < values.length; i++) {
177
+ if (!fn(values[i])) {
178
+ return false;
179
+ }
180
+ }
181
+ return true;
179
182
  }
180
183
 
181
- function isHour(d) {
182
- return isMinute(d) && d.getMinutes() === 0;
184
+ function isDay(timeUnit) {
185
+ return timeUnit === "day" || timeUnit === "week" || timeUnit === "month" || timeUnit === "year";
183
186
  }
184
187
 
185
- function isDay(d) {
186
- return isHour(d) && d.getHours() === 0;
187
- }
188
+ function calculateTimeUnit(values, maxDay) {
189
+ if ( maxDay === void 0 ) maxDay = false;
188
190
 
189
- function isWeek(d, dayOfWeek) {
190
- return isDay(d) && d.getDay() === dayOfWeek;
191
- }
191
+ if (values.length === 0) {
192
+ return null;
193
+ }
192
194
 
193
- function isMonth(d) {
194
- return isDay(d) && d.getDate() === 1;
195
- }
195
+ var minute = every(values, function (d) { return d.getMilliseconds() === 0 && d.getSeconds() === 0; });
196
+ if (!minute) {
197
+ return null;
198
+ }
199
+
200
+ var hour = every(values, function (d) { return d.getMinutes() === 0; });
201
+ if (!hour) {
202
+ return "minute";
203
+ }
204
+
205
+ var day = every(values, function (d) { return d.getHours() === 0; });
206
+ if (!day) {
207
+ return "hour";
208
+ }
196
209
 
197
- function isYear(d) {
198
- return isMonth(d) && d.getMonth() === 0;
210
+ if (maxDay) {
211
+ return "day";
212
+ }
213
+
214
+ var month = every(values, function (d) { return d.getDate() === 1; });
215
+ if (!month) {
216
+ var dayOfWeek = values[0].getDay();
217
+ var week = every(values, function (d) { return d.getDay() === dayOfWeek; });
218
+ return (week ? "week" : "day");
219
+ }
220
+
221
+ var year = every(values, function (d) { return d.getMonth() === 0; });
222
+ if (!year) {
223
+ return "month";
224
+ }
225
+
226
+ return "year";
199
227
  }
200
228
 
201
229
  function isDate(obj) {
@@ -223,9 +251,14 @@
223
251
  var round = options.round;
224
252
 
225
253
  if (options.byteScale) {
226
- var suffixIdx;
254
+ var positive = value >= 0;
255
+ if (!positive) {
256
+ value *= -1;
257
+ }
258
+
227
259
  var baseValue = axis ? options.byteScale : value;
228
260
 
261
+ var suffixIdx;
229
262
  if (baseValue >= 1152921504606846976) {
230
263
  value /= 1152921504606846976;
231
264
  suffixIdx = 6;
@@ -259,6 +292,11 @@
259
292
  precision = value >= 1000 ? 4 : 3;
260
293
  }
261
294
  suffix = " " + byteSuffixes[suffixIdx];
295
+
296
+ // flip value back
297
+ if (!positive) {
298
+ value *= -1;
299
+ }
262
300
  }
263
301
 
264
302
  if (precision !== undefined && round !== undefined) {
@@ -310,19 +348,6 @@
310
348
  return null;
311
349
  }
312
350
 
313
- function allZeros(data) {
314
- var i, j, d;
315
- for (i = 0; i < data.length; i++) {
316
- d = data[i].data;
317
- for (j = 0; j < d.length; j++) {
318
- if (d[j][1] != 0) {
319
- return false;
320
- }
321
- }
322
- }
323
- return true;
324
- }
325
-
326
351
  var baseOptions = {
327
352
  maintainAspectRatio: false,
328
353
  animation: false,
@@ -379,7 +404,7 @@
379
404
  "#6633CC", "#E67300", "#8B0707", "#329262", "#5574A6", "#651067"
380
405
  ];
381
406
 
382
- var hideLegend$2 = function (options, legend, hideLegend) {
407
+ function hideLegend$2(options, legend, hideLegend) {
383
408
  if (legend !== undefined) {
384
409
  options.plugins.legend.display = !!legend;
385
410
  if (legend && legend !== true) {
@@ -388,61 +413,59 @@
388
413
  } else if (hideLegend) {
389
414
  options.plugins.legend.display = false;
390
415
  }
391
- };
416
+ }
392
417
 
393
- var setTitle$2 = function (options, title) {
418
+ function setTitle$2(options, title) {
394
419
  options.plugins.title.display = true;
395
420
  options.plugins.title.text = title;
396
- };
421
+ }
397
422
 
398
- var setMin$2 = function (options, min) {
423
+ function setMin$2(options, min) {
399
424
  if (min !== null) {
400
425
  options.scales.y.min = toFloat(min);
401
426
  }
402
- };
427
+ }
403
428
 
404
- var setMax$2 = function (options, max) {
429
+ function setMax$2(options, max) {
405
430
  options.scales.y.max = toFloat(max);
406
- };
431
+ }
407
432
 
408
- var setBarMin$1 = function (options, min) {
433
+ function setBarMin$1(options, min) {
409
434
  if (min !== null) {
410
435
  options.scales.x.min = toFloat(min);
411
436
  }
412
- };
437
+ }
413
438
 
414
- var setBarMax$1 = function (options, max) {
439
+ function setBarMax$1(options, max) {
415
440
  options.scales.x.max = toFloat(max);
416
- };
441
+ }
417
442
 
418
- var setStacked$2 = function (options, stacked) {
443
+ function setStacked$2(options, stacked) {
419
444
  options.scales.x.stacked = !!stacked;
420
445
  options.scales.y.stacked = !!stacked;
421
- };
446
+ }
422
447
 
423
- var setXtitle$2 = function (options, title) {
448
+ function setXtitle$2(options, title) {
424
449
  options.scales.x.title.display = true;
425
450
  options.scales.x.title.text = title;
426
- };
451
+ }
427
452
 
428
- var setYtitle$2 = function (options, title) {
453
+ function setYtitle$2(options, title) {
429
454
  options.scales.y.title.display = true;
430
455
  options.scales.y.title.text = title;
431
- };
456
+ }
432
457
 
433
458
  // https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
434
- var addOpacity = function (hex, opacity) {
459
+ function addOpacity(hex, opacity) {
435
460
  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
436
461
  return result ? "rgba(" + parseInt(result[1], 16) + ", " + parseInt(result[2], 16) + ", " + parseInt(result[3], 16) + ", " + opacity + ")" : hex;
437
- };
462
+ }
438
463
 
439
- // check if not null or undefined
440
- // https://stackoverflow.com/a/27757708/1177228
441
- var notnull = function (x) {
442
- return x != null;
443
- };
464
+ function notnull(x) {
465
+ return x !== null && x !== undefined;
466
+ }
444
467
 
445
- var setLabelSize = function (chart, data, options) {
468
+ function setLabelSize(chart, data, options) {
446
469
  var maxLabelSize = Math.ceil(chart.element.offsetWidth / 4.0 / data.labels.length);
447
470
  if (maxLabelSize > 25) {
448
471
  maxLabelSize = 25;
@@ -459,18 +482,33 @@
459
482
  }
460
483
  };
461
484
  }
462
- };
485
+ }
463
486
 
464
- var setFormatOptions$1 = function (chart, options, chartType) {
465
- var formatOptions = {
487
+ function calculateScale(series) {
488
+ var scale = 1;
489
+ var max = maxAbsY(series);
490
+ while (max >= 1024) {
491
+ scale *= 1024;
492
+ max /= 1024;
493
+ }
494
+ return scale;
495
+ }
496
+
497
+ function setFormatOptions$1(chart, options, chartType) {
498
+ // options to apply to x and r values for scatter and bubble
499
+ var numericOptions = {
500
+ thousands: chart.options.thousands,
501
+ decimal: chart.options.decimal
502
+ };
503
+
504
+ // options to apply to y value
505
+ var formatOptions = merge({
466
506
  prefix: chart.options.prefix,
467
507
  suffix: chart.options.suffix,
468
- thousands: chart.options.thousands,
469
- decimal: chart.options.decimal,
470
508
  precision: chart.options.precision,
471
509
  round: chart.options.round,
472
510
  zeros: chart.options.zeros
473
- };
511
+ }, numericOptions);
474
512
 
475
513
  if (chart.options.bytes) {
476
514
  var series = chart.data;
@@ -478,26 +516,8 @@
478
516
  series = [{data: series}];
479
517
  }
480
518
 
481
- // calculate max
482
- var max = 0;
483
- for (var i = 0; i < series.length; i++) {
484
- var s = series[i];
485
- for (var j = 0; j < s.data.length; j++) {
486
- if (s.data[j][1] > max) {
487
- max = s.data[j][1];
488
- }
489
- }
490
- }
491
-
492
- // calculate scale
493
- var scale = 1;
494
- while (max >= 1024) {
495
- scale *= 1024;
496
- max /= 1024;
497
- }
498
-
499
519
  // set step size
500
- formatOptions.byteScale = scale;
520
+ formatOptions.byteScale = calculateScale(series);
501
521
  }
502
522
 
503
523
  if (chartType !== "pie") {
@@ -520,6 +540,12 @@
520
540
  return formatValue("", value, formatOptions, true);
521
541
  };
522
542
  }
543
+
544
+ if ((chartType === "scatter" || chartType === "bubble") && !options.scales.x.ticks.callback) {
545
+ options.scales.x.ticks.callback = function (value) {
546
+ return formatValue("", value, numericOptions, true);
547
+ };
548
+ }
523
549
  }
524
550
 
525
551
  if (!options.plugins.tooltip.callbacks.label) {
@@ -529,7 +555,9 @@
529
555
  if (label) {
530
556
  label += ': ';
531
557
  }
532
- return label + '(' + context.label + ', ' + context.formattedValue + ')';
558
+
559
+ var dataPoint = context.parsed;
560
+ return label + '(' + formatValue('', dataPoint.x, numericOptions) + ', ' + formatValue('', dataPoint.y, formatOptions) + ')';
533
561
  };
534
562
  } else if (chartType === "bubble") {
535
563
  options.plugins.tooltip.callbacks.label = function (context) {
@@ -538,28 +566,21 @@
538
566
  label += ': ';
539
567
  }
540
568
  var dataPoint = context.raw;
541
- return label + '(' + dataPoint.x + ', ' + dataPoint.y + ', ' + dataPoint.v + ')';
569
+ return label + '(' + formatValue('', dataPoint.x, numericOptions) + ', ' + formatValue('', dataPoint.y, formatOptions) + ', ' + formatValue('', dataPoint.v, numericOptions) + ')';
542
570
  };
543
571
  } else if (chartType === "pie") {
544
572
  // need to use separate label for pie charts
545
573
  options.plugins.tooltip.callbacks.label = function (context) {
546
- var dataLabel = context.label;
547
- var value = ': ';
548
-
549
- if (isArray(dataLabel)) {
550
- // show value on first line of multiline label
551
- // need to clone because we are changing the value
552
- dataLabel = dataLabel.slice();
553
- dataLabel[0] += value;
554
- } else {
555
- dataLabel += value;
556
- }
557
-
558
- return formatValue(dataLabel, context.parsed, formatOptions);
574
+ return formatValue('', context.parsed, formatOptions);
559
575
  };
560
576
  } else {
561
577
  var valueLabel = chartType === "bar" ? "x" : "y";
562
578
  options.plugins.tooltip.callbacks.label = function (context) {
579
+ // don't show null values for stacked charts
580
+ if (context.parsed[valueLabel] === null) {
581
+ return;
582
+ }
583
+
563
584
  var label = context.dataset.label || '';
564
585
  if (label) {
565
586
  label += ': ';
@@ -568,124 +589,187 @@
568
589
  };
569
590
  }
570
591
  }
571
- };
572
-
573
- var jsOptions$2 = jsOptionsFunc(merge(baseOptions, defaultOptions$2), hideLegend$2, setTitle$2, setMin$2, setMax$2, setStacked$2, setXtitle$2, setYtitle$2);
574
-
575
- var createDataTable = function (chart, options, chartType) {
576
- var datasets = [];
577
- var labels = [];
578
592
 
579
- var colors = chart.options.colors || defaultColors;
593
+ // avoid formatting x-axis labels
594
+ // by default, Chart.js applies locale
595
+ if ((chartType === "line" || chartType === "area") && chart.xtype === "number") {
596
+ if (!options.scales.x.ticks.callback) {
597
+ options.scales.x.ticks.callback = function (value) {
598
+ return toStr(value);
599
+ };
600
+ }
580
601
 
581
- var day = true;
582
- var week = true;
583
- var dayOfWeek;
584
- var month = true;
585
- var year = true;
586
- var hour = true;
587
- var minute = true;
602
+ if (!options.plugins.tooltip.callbacks.title) {
603
+ options.plugins.tooltip.callbacks.title = function (context) {
604
+ return toStr(context[0].parsed.x);
605
+ };
606
+ }
607
+ }
608
+ }
588
609
 
589
- var series = chart.data;
610
+ function maxAbsY(series) {
611
+ var max = 0;
612
+ for (var i = 0; i < series.length; i++) {
613
+ var data = series[i].data;
614
+ for (var j = 0; j < data.length; j++) {
615
+ var v = Math.abs(data[j][1]);
616
+ if (v > max) {
617
+ max = v;
618
+ }
619
+ }
620
+ }
621
+ return max;
622
+ }
590
623
 
624
+ function maxR(series) {
625
+ // start at zero since radius must be positive
591
626
  var max = 0;
592
- if (chartType === "bubble") {
593
- for (var i$1 = 0; i$1 < series.length; i$1++) {
594
- var s$1 = series[i$1];
595
- for (var j$1 = 0; j$1 < s$1.data.length; j$1++) {
596
- if (s$1.data[j$1][2] > max) {
597
- max = s$1.data[j$1][2];
598
- }
627
+ for (var i = 0; i < series.length; i++) {
628
+ var data = series[i].data;
629
+ for (var j = 0; j < data.length; j++) {
630
+ var v = data[j][2];
631
+ if (v > max) {
632
+ max = v;
599
633
  }
600
634
  }
601
635
  }
636
+ return max;
637
+ }
602
638
 
603
- var i, j, s, d, key, rows = [], rows2 = [];
639
+ var jsOptions$2 = jsOptionsFunc(merge(baseOptions, defaultOptions$2), hideLegend$2, setTitle$2, setMin$2, setMax$2, setStacked$2, setXtitle$2, setYtitle$2);
604
640
 
605
- if (chartType === "bar" || chartType === "column" || (chart.xtype !== "number" && chart.xtype !== "bubble")) {
606
- var sortedLabels = [];
641
+ function prepareDefaultData(chart) {
642
+ var series = chart.data;
643
+ var rows = {};
644
+ var keys = [];
645
+ var labels = [];
646
+ var values = [];
607
647
 
608
- for (i = 0; i < series.length; i++) {
609
- s = series[i];
648
+ for (var i = 0; i < series.length; i++) {
649
+ var data = series[i].data;
610
650
 
611
- for (j = 0; j < s.data.length; j++) {
612
- d = s.data[j];
613
- key = chart.xtype == "datetime" ? d[0].getTime() : d[0];
614
- if (!rows[key]) {
615
- rows[key] = new Array(series.length);
616
- }
617
- rows[key][i] = toFloat(d[1]);
618
- if (sortedLabels.indexOf(key) === -1) {
619
- sortedLabels.push(key);
620
- }
651
+ for (var j = 0; j < data.length; j++) {
652
+ var d = data[j];
653
+ var key = chart.xtype === "datetime" ? d[0].getTime() : d[0];
654
+ if (!rows[key]) {
655
+ rows[key] = new Array(series.length);
656
+ keys.push(key);
621
657
  }
658
+ rows[key][i] = d[1];
622
659
  }
660
+ }
661
+
662
+ if (chart.xtype === "datetime" || chart.xtype === "number") {
663
+ keys.sort(sortByNumber);
664
+ }
665
+
666
+ for (var i$1 = 0; i$1 < series.length; i$1++) {
667
+ values.push([]);
668
+ }
669
+
670
+ for (var i$2 = 0; i$2 < keys.length; i$2++) {
671
+ var key$1 = keys[i$2];
623
672
 
624
- if (chart.xtype === "datetime" || chart.xtype === "number") {
625
- sortedLabels.sort(sortByNumber);
673
+ var label = chart.xtype === "datetime" ? new Date(key$1) : key$1;
674
+ labels.push(label);
675
+
676
+ var row = rows[key$1];
677
+ for (var j$1 = 0; j$1 < series.length; j$1++) {
678
+ var v = row[j$1];
679
+ // Chart.js doesn't like undefined
680
+ values[j$1].push(v === undefined ? null : v);
626
681
  }
682
+ }
683
+
684
+ return {
685
+ labels: labels,
686
+ values: values
687
+ };
688
+ }
627
689
 
628
- for (j = 0; j < series.length; j++) {
629
- rows2.push([]);
690
+ function prepareBubbleData(chart) {
691
+ var series = chart.data;
692
+ var values = [];
693
+ var max = maxR(series);
694
+
695
+ for (var i = 0; i < series.length; i++) {
696
+ var data = series[i].data;
697
+ var points = [];
698
+ for (var j = 0; j < data.length; j++) {
699
+ var v = data[j];
700
+ points.push({
701
+ x: v[0],
702
+ y: v[1],
703
+ r: v[2] * 20 / max,
704
+ // custom attribute, for tooltip
705
+ v: v[2]
706
+ });
630
707
  }
708
+ values.push(points);
709
+ }
631
710
 
632
- var value;
633
- var k;
634
- for (k = 0; k < sortedLabels.length; k++) {
635
- i = sortedLabels[k];
636
- if (chart.xtype === "datetime") {
637
- value = new Date(toFloat(i));
638
- // TODO make this efficient
639
- day = day && isDay(value);
640
- if (!dayOfWeek) {
641
- dayOfWeek = value.getDay();
642
- }
643
- week = week && isWeek(value, dayOfWeek);
644
- month = month && isMonth(value);
645
- year = year && isYear(value);
646
- hour = hour && isHour(value);
647
- minute = minute && isMinute(value);
648
- } else {
649
- value = i;
650
- }
651
- labels.push(value);
652
- for (j = 0; j < series.length; j++) {
653
- // Chart.js doesn't like undefined
654
- rows2[j].push(rows[i][j] === undefined ? null : rows[i][j]);
655
- }
711
+ return {
712
+ labels: [],
713
+ values: values
714
+ };
715
+ }
716
+
717
+ // scatter or numeric line/area
718
+ function prepareNumberData(chart) {
719
+ var series = chart.data;
720
+ var values = [];
721
+
722
+ for (var i = 0; i < series.length; i++) {
723
+ var data = series[i].data;
724
+
725
+ data.sort(sortByNumberSeries);
726
+
727
+ var points = [];
728
+ for (var j = 0; j < data.length; j++) {
729
+ var v = data[j];
730
+ points.push({
731
+ x: v[0],
732
+ y: v[1]
733
+ });
656
734
  }
735
+ values.push(points);
736
+ }
737
+
738
+ return {
739
+ labels: [],
740
+ values: values
741
+ };
742
+ }
743
+
744
+ function prepareData(chart, chartType) {
745
+ if (chartType === "bubble") {
746
+ return prepareBubbleData(chart);
747
+ } else if (chart.xtype === "number" && chartType !== "bar" && chartType !== "column") {
748
+ return prepareNumberData(chart);
657
749
  } else {
658
- for (var i$2 = 0; i$2 < series.length; i$2++) {
659
- var s$2 = series[i$2];
660
- var d$1 = [];
661
- for (var j$2 = 0; j$2 < s$2.data.length; j$2++) {
662
- var point = {
663
- x: toFloat(s$2.data[j$2][0]),
664
- y: toFloat(s$2.data[j$2][1])
665
- };
666
- if (chartType === "bubble") {
667
- point.r = toFloat(s$2.data[j$2][2]) * 20 / max;
668
- // custom attribute, for tooltip
669
- point.v = s$2.data[j$2][2];
670
- }
671
- d$1.push(point);
672
- }
673
- rows2.push(d$1);
674
- }
750
+ return prepareDefaultData(chart);
675
751
  }
752
+ }
676
753
 
677
- var color;
678
- var backgroundColor;
754
+ function createDataTable(chart, options, chartType) {
755
+ var ref = prepareData(chart, chartType);
756
+ var labels = ref.labels;
757
+ var values = ref.values;
679
758
 
680
- for (i = 0; i < series.length; i++) {
681
- s = series[i];
759
+ var series = chart.data;
760
+ var datasets = [];
761
+ var colors = chart.options.colors || defaultColors;
762
+ for (var i = 0; i < series.length; i++) {
763
+ var s = series[i];
682
764
 
683
765
  // use colors for each bar for single series format
684
- if (chart.options.colors && chart.singleSeriesFormat && (chartType === "bar" || chartType === "column") && !s.color) {
766
+ var color = (void 0);
767
+ var backgroundColor = (void 0);
768
+ if (chart.options.colors && chart.singleSeriesFormat && (chartType === "bar" || chartType === "column") && !s.color && isArray(chart.options.colors) && !isArray(chart.options.colors[0])) {
685
769
  color = colors;
686
770
  backgroundColor = [];
687
- for (var j$3 = 0; j$3 < colors.length; j$3++) {
688
- backgroundColor[j$3] = addOpacity(color[j$3], 0.5);
771
+ for (var j = 0; j < colors.length; j++) {
772
+ backgroundColor[j] = addOpacity(color[j], 0.5);
689
773
  }
690
774
  } else {
691
775
  color = s.color || colors[i];
@@ -694,7 +778,7 @@
694
778
 
695
779
  var dataset = {
696
780
  label: s.name || "",
697
- data: rows2[i],
781
+ data: values[i],
698
782
  fill: chartType === "area",
699
783
  borderColor: color,
700
784
  backgroundColor: backgroundColor,
@@ -743,100 +827,104 @@
743
827
 
744
828
  if (chart.xtype === "datetime") {
745
829
  if (notnull(xmin)) {
746
- options.scales.x.ticks.min = toDate(xmin).getTime();
830
+ options.scales.x.min = toDate(xmin).getTime();
747
831
  }
748
832
  if (notnull(xmax)) {
749
- options.scales.x.ticks.max = toDate(xmax).getTime();
833
+ options.scales.x.max = toDate(xmax).getTime();
750
834
  }
751
835
  } else if (chart.xtype === "number") {
752
836
  if (notnull(xmin)) {
753
- options.scales.x.ticks.min = xmin;
754
- }
755
- if (notnull(xmax)) {
756
- options.scales.x.ticks.max = xmax;
757
- }
758
- }
759
-
760
- // for empty datetime chart
761
- if (chart.xtype === "datetime" && labels.length === 0) {
762
- if (notnull(xmin)) {
763
- labels.push(toDate(xmin));
837
+ options.scales.x.min = xmin;
764
838
  }
765
839
  if (notnull(xmax)) {
766
- labels.push(toDate(xmax));
840
+ options.scales.x.max = xmax;
767
841
  }
768
- day = false;
769
- week = false;
770
- month = false;
771
- year = false;
772
- hour = false;
773
- minute = false;
774
842
  }
775
843
 
776
- if (chart.xtype === "datetime" && labels.length > 0) {
777
- var minTime = (notnull(xmin) ? toDate(xmin) : labels[0]).getTime();
778
- var maxTime = (notnull(xmax) ? toDate(xmax) : labels[0]).getTime();
844
+ if (chart.xtype === "datetime") {
845
+ var timeUnit = calculateTimeUnit(labels);
779
846
 
780
- for (i = 1; i < labels.length; i++) {
781
- var value$1 = labels[i].getTime();
782
- if (value$1 < minTime) {
783
- minTime = value$1;
847
+ // for empty datetime chart
848
+ if (labels.length === 0) {
849
+ if (notnull(xmin)) {
850
+ labels.push(toDate(xmin));
784
851
  }
785
- if (value$1 > maxTime) {
786
- maxTime = value$1;
852
+ if (notnull(xmax)) {
853
+ labels.push(toDate(xmax));
787
854
  }
788
855
  }
789
856
 
790
- var timeDiff = (maxTime - minTime) / (86400 * 1000.0);
791
-
792
- if (!options.scales.x.time.unit) {
793
- var step;
794
- if (year || timeDiff > 365 * 10) {
795
- options.scales.x.time.unit = "year";
796
- step = 365;
797
- } else if (month || timeDiff > 30 * 10) {
798
- options.scales.x.time.unit = "month";
799
- step = 30;
800
- } else if (day || timeDiff > 10) {
801
- options.scales.x.time.unit = "day";
802
- step = 1;
803
- } else if (hour || timeDiff > 0.5) {
804
- options.scales.x.time.displayFormats = {hour: "MMM d, h a"};
805
- options.scales.x.time.unit = "hour";
806
- step = 1 / 24.0;
807
- } else if (minute) {
808
- options.scales.x.time.displayFormats = {minute: "h:mm a"};
809
- options.scales.x.time.unit = "minute";
810
- step = 1 / 24.0 / 60.0;
857
+ if (labels.length > 0) {
858
+ var minTime = (notnull(xmin) ? toDate(xmin) : labels[0]).getTime();
859
+ var maxTime = (notnull(xmax) ? toDate(xmax) : labels[0]).getTime();
860
+
861
+ for (var i$1 = 1; i$1 < labels.length; i$1++) {
862
+ var value = labels[i$1].getTime();
863
+ if (value < minTime) {
864
+ minTime = value;
865
+ }
866
+ if (value > maxTime) {
867
+ maxTime = value;
868
+ }
811
869
  }
812
870
 
813
- if (step && timeDiff > 0) {
814
- var unitStepSize = Math.ceil(timeDiff / step / (chart.element.offsetWidth / 100.0));
815
- if (week && step === 1) {
816
- unitStepSize = Math.ceil(unitStepSize / 7.0) * 7;
871
+ var timeDiff = (maxTime - minTime) / (86400 * 1000.0);
872
+
873
+ if (!options.scales.x.time.unit) {
874
+ var step;
875
+ if (timeUnit === "year" || timeDiff > 365 * 10) {
876
+ options.scales.x.time.unit = "year";
877
+ step = 365;
878
+ } else if (timeUnit === "month" || timeDiff > 30 * 10) {
879
+ options.scales.x.time.unit = "month";
880
+ step = 30;
881
+ } else if (timeUnit === "week" || timeUnit === "day" || timeDiff > 10) {
882
+ options.scales.x.time.unit = "day";
883
+ step = 1;
884
+ } else if (timeUnit === "hour" || timeDiff > 0.5) {
885
+ options.scales.x.time.displayFormats = {hour: "MMM d, h a"};
886
+ options.scales.x.time.unit = "hour";
887
+ step = 1 / 24.0;
888
+ } else if (timeUnit === "minute") {
889
+ options.scales.x.time.displayFormats = {minute: "h:mm a"};
890
+ options.scales.x.time.unit = "minute";
891
+ step = 1 / 24.0 / 60.0;
892
+ }
893
+
894
+ if (step && timeDiff > 0) {
895
+ // width not available for hidden elements
896
+ var width = chart.element.offsetWidth;
897
+ if (width > 0) {
898
+ var unitStepSize = Math.ceil(timeDiff / step / (width / 100.0));
899
+ if (timeUnit === "week" && step === 1) {
900
+ unitStepSize = Math.ceil(unitStepSize / 7.0) * 7;
901
+ }
902
+ options.scales.x.ticks.stepSize = unitStepSize;
903
+ }
817
904
  }
818
- options.scales.x.time.stepSize = unitStepSize;
819
905
  }
820
- }
821
906
 
822
- if (!options.scales.x.time.tooltipFormat) {
823
- if (day) {
824
- options.scales.x.time.tooltipFormat = "PP";
825
- } else if (hour) {
826
- options.scales.x.time.tooltipFormat = "MMM d, h a";
827
- } else if (minute) {
828
- options.scales.x.time.tooltipFormat = "h:mm a";
907
+ if (!options.scales.x.time.tooltipFormat) {
908
+ if (timeUnit === "year") {
909
+ options.scales.x.time.tooltipFormat = "yyyy";
910
+ } else if (timeUnit === "month") {
911
+ options.scales.x.time.tooltipFormat = "MMM yyyy";
912
+ } else if (timeUnit === "week" || timeUnit === "day") {
913
+ options.scales.x.time.tooltipFormat = "PP";
914
+ } else if (timeUnit === "hour") {
915
+ options.scales.x.time.tooltipFormat = "MMM d, h a";
916
+ } else if (timeUnit === "minute") {
917
+ options.scales.x.time.tooltipFormat = "h:mm a";
918
+ }
829
919
  }
830
920
  }
831
921
  }
832
922
 
833
- var data = {
923
+ return {
834
924
  labels: labels,
835
925
  datasets: datasets
836
926
  };
837
-
838
- return data;
839
- };
927
+ }
840
928
 
841
929
  var defaultExport$2 = function defaultExport(library) {
842
930
  this.name = "chartjs";
@@ -844,20 +932,20 @@
844
932
  };
845
933
 
846
934
  defaultExport$2.prototype.renderLineChart = function renderLineChart (chart, chartType) {
847
- var chartOptions = {};
848
- // fix for https://github.com/chartjs/Chart.js/issues/2441
849
- if (!chart.options.max && allZeros(chart.data)) {
850
- chartOptions.max = 1;
935
+ if (!chartType) {
936
+ chartType = "line";
851
937
  }
852
938
 
939
+ var chartOptions = {};
940
+
853
941
  var options = jsOptions$2(chart, merge(chartOptions, chart.options));
854
942
  setFormatOptions$1(chart, options, chartType);
855
943
 
856
- var data = createDataTable(chart, options, chartType || "line");
944
+ var data = createDataTable(chart, options, chartType);
857
945
 
858
946
  if (chart.xtype === "number") {
859
- options.scales.x.type = "linear";
860
- options.scales.x.position = "bottom";
947
+ options.scales.x.type = options.scales.x.type || "linear";
948
+ options.scales.x.position = options.scales.x.position || "bottom";
861
949
  } else {
862
950
  options.scales.x.type = chart.xtype === "string" ? "category" : "time";
863
951
  }
@@ -924,6 +1012,9 @@
924
1012
  if (chartType !== "bar") {
925
1013
  setLabelSize(chart, data, options);
926
1014
  }
1015
+ if (!("mode" in options.interaction)) {
1016
+ options.interaction.mode = "index";
1017
+ }
927
1018
  this.drawChart(chart, "bar", data, options);
928
1019
  };
929
1020
 
@@ -947,8 +1038,8 @@
947
1038
 
948
1039
  var data = createDataTable(chart, options, chartType);
949
1040
 
950
- options.scales.x.type = "linear";
951
- options.scales.x.position = "bottom";
1041
+ options.scales.x.type = options.scales.x.type || "linear";
1042
+ options.scales.x.position = options.scales.x.position || "bottom";
952
1043
 
953
1044
  // prevent grouping hover and tooltips
954
1045
  if (!("mode" in options.interaction)) {
@@ -1035,7 +1126,7 @@
1035
1126
  }
1036
1127
  };
1037
1128
 
1038
- var hideLegend$1 = function (options, legend, hideLegend) {
1129
+ function hideLegend$1(options, legend, hideLegend) {
1039
1130
  if (legend !== undefined) {
1040
1131
  options.legend.enabled = !!legend;
1041
1132
  if (legend && legend !== true) {
@@ -1050,38 +1141,38 @@
1050
1141
  } else if (hideLegend) {
1051
1142
  options.legend.enabled = false;
1052
1143
  }
1053
- };
1144
+ }
1054
1145
 
1055
- var setTitle$1 = function (options, title) {
1146
+ function setTitle$1(options, title) {
1056
1147
  options.title.text = title;
1057
- };
1148
+ }
1058
1149
 
1059
- var setMin$1 = function (options, min) {
1150
+ function setMin$1(options, min) {
1060
1151
  options.yAxis.min = min;
1061
- };
1152
+ }
1062
1153
 
1063
- var setMax$1 = function (options, max) {
1154
+ function setMax$1(options, max) {
1064
1155
  options.yAxis.max = max;
1065
- };
1156
+ }
1066
1157
 
1067
- var setStacked$1 = function (options, stacked) {
1158
+ function setStacked$1(options, stacked) {
1068
1159
  var stackedValue = stacked ? (stacked === true ? "normal" : stacked) : null;
1069
1160
  options.plotOptions.series.stacking = stackedValue;
1070
1161
  options.plotOptions.area.stacking = stackedValue;
1071
1162
  options.plotOptions.areaspline.stacking = stackedValue;
1072
- };
1163
+ }
1073
1164
 
1074
- var setXtitle$1 = function (options, title) {
1165
+ function setXtitle$1(options, title) {
1075
1166
  options.xAxis.title.text = title;
1076
- };
1167
+ }
1077
1168
 
1078
- var setYtitle$1 = function (options, title) {
1169
+ function setYtitle$1(options, title) {
1079
1170
  options.yAxis.title.text = title;
1080
- };
1171
+ }
1081
1172
 
1082
1173
  var jsOptions$1 = jsOptionsFunc(defaultOptions$1, hideLegend$1, setTitle$1, setMin$1, setMax$1, setStacked$1, setXtitle$1, setYtitle$1);
1083
1174
 
1084
- var setFormatOptions = function(chart, options, chartType) {
1175
+ function setFormatOptions(chart, options, chartType) {
1085
1176
  var formatOptions = {
1086
1177
  prefix: chart.options.prefix,
1087
1178
  suffix: chart.options.suffix,
@@ -1092,18 +1183,19 @@
1092
1183
  zeros: chart.options.zeros
1093
1184
  };
1094
1185
 
1095
- if (chartType !== "pie" && !options.yAxis.labels.formatter) {
1186
+ // skip when axis is an array (like with min/max)
1187
+ if (chartType !== "pie" && !isArray(options.yAxis) && !options.yAxis.labels.formatter) {
1096
1188
  options.yAxis.labels.formatter = function () {
1097
1189
  return formatValue("", this.value, formatOptions);
1098
1190
  };
1099
1191
  }
1100
1192
 
1101
- if (!options.tooltip.pointFormatter) {
1193
+ if (!options.tooltip.pointFormatter && !options.tooltip.pointFormat) {
1102
1194
  options.tooltip.pointFormatter = function () {
1103
1195
  return '<span style="color:' + this.color + '">\u25CF</span> ' + formatValue(this.series.name + ': <b>', this.y, formatOptions) + '</b><br/>';
1104
1196
  };
1105
1197
  }
1106
- };
1198
+ }
1107
1199
 
1108
1200
  var defaultExport$1 = function defaultExport(library) {
1109
1201
  this.name = "highcharts";
@@ -1139,21 +1231,27 @@
1139
1231
  }
1140
1232
  }
1141
1233
 
1142
- var options = jsOptions$1(chart, chart.options, chartOptions), data, i, j;
1143
- options.xAxis.type = chart.xtype === "string" ? "category" : (chart.xtype === "number" ? "linear" : "datetime");
1234
+ var options = jsOptions$1(chart, chart.options, chartOptions);
1235
+ if (chart.xtype === "number") {
1236
+ options.xAxis.type = options.xAxis.type || "linear";
1237
+ } else {
1238
+ options.xAxis.type = chart.xtype === "string" ? "category" : "datetime";
1239
+ }
1144
1240
  if (!options.chart.type) {
1145
1241
  options.chart.type = chartType;
1146
1242
  }
1147
1243
  setFormatOptions(chart, options, chartType);
1148
1244
 
1149
1245
  var series = chart.data;
1150
- for (i = 0; i < series.length; i++) {
1246
+ for (var i = 0; i < series.length; i++) {
1151
1247
  series[i].name = series[i].name || "Value";
1152
- data = series[i].data;
1248
+ var data = series[i].data;
1153
1249
  if (chart.xtype === "datetime") {
1154
- for (j = 0; j < data.length; j++) {
1250
+ for (var j = 0; j < data.length; j++) {
1155
1251
  data[j][0] = data[j][0].getTime();
1156
1252
  }
1253
+ } else if (chart.xtype === "number") {
1254
+ data.sort(sortByNumberSeries);
1157
1255
  }
1158
1256
  series[i].marker = {symbol: "circle"};
1159
1257
  if (chart.options.points === false) {
@@ -1202,15 +1300,17 @@
1202
1300
  defaultExport$1.prototype.renderColumnChart = function renderColumnChart (chart, chartType) {
1203
1301
  chartType = chartType || "column";
1204
1302
  var series = chart.data;
1205
- var options = jsOptions$1(chart, chart.options), i, j, s, d, rows = [], categories = [];
1303
+ var options = jsOptions$1(chart, chart.options);
1304
+ var rows = [];
1305
+ var categories = [];
1206
1306
  options.chart.type = chartType;
1207
1307
  setFormatOptions(chart, options, chartType);
1208
1308
 
1209
- for (i = 0; i < series.length; i++) {
1210
- s = series[i];
1309
+ for (var i = 0; i < series.length; i++) {
1310
+ var s = series[i];
1211
1311
 
1212
- for (j = 0; j < s.data.length; j++) {
1213
- d = s.data[j];
1312
+ for (var j = 0; j < s.data.length; j++) {
1313
+ var d = s.data[j];
1214
1314
  if (!rows[d[0]]) {
1215
1315
  rows[d[0]] = new Array(series.length);
1216
1316
  categories.push(d[0]);
@@ -1225,19 +1325,19 @@
1225
1325
 
1226
1326
  options.xAxis.categories = categories;
1227
1327
 
1228
- var newSeries = [], d2;
1229
- for (i = 0; i < series.length; i++) {
1230
- d = [];
1231
- for (j = 0; j < categories.length; j++) {
1232
- d.push(rows[categories[j]][i] || 0);
1328
+ var newSeries = [];
1329
+ for (var i$1 = 0; i$1 < series.length; i$1++) {
1330
+ var d$1 = [];
1331
+ for (var j$1 = 0; j$1 < categories.length; j$1++) {
1332
+ d$1.push(rows[categories[j$1]][i$1] || 0);
1233
1333
  }
1234
1334
 
1235
- d2 = {
1236
- name: series[i].name || "Value",
1237
- data: d
1335
+ var d2 = {
1336
+ name: series[i$1].name || "Value",
1337
+ data: d$1
1238
1338
  };
1239
- if (series[i].stack) {
1240
- d2.stack = series[i].stack;
1339
+ if (series[i$1].stack) {
1340
+ d2.stack = series[i$1].stack;
1241
1341
  }
1242
1342
 
1243
1343
  newSeries.push(d2);
@@ -1320,7 +1420,7 @@
1320
1420
  }
1321
1421
  };
1322
1422
 
1323
- var hideLegend = function (options, legend, hideLegend) {
1423
+ function hideLegend(options, legend, hideLegend) {
1324
1424
  if (legend !== undefined) {
1325
1425
  var position;
1326
1426
  if (!legend) {
@@ -1334,53 +1434,53 @@
1334
1434
  } else if (hideLegend) {
1335
1435
  options.legend.position = "none";
1336
1436
  }
1337
- };
1437
+ }
1338
1438
 
1339
- var setTitle = function (options, title) {
1439
+ function setTitle(options, title) {
1340
1440
  options.title = title;
1341
1441
  options.titleTextStyle = {color: "#333", fontSize: "20px"};
1342
- };
1442
+ }
1343
1443
 
1344
- var setMin = function (options, min) {
1444
+ function setMin(options, min) {
1345
1445
  options.vAxis.viewWindow.min = min;
1346
- };
1446
+ }
1347
1447
 
1348
- var setMax = function (options, max) {
1448
+ function setMax(options, max) {
1349
1449
  options.vAxis.viewWindow.max = max;
1350
- };
1450
+ }
1351
1451
 
1352
- var setBarMin = function (options, min) {
1452
+ function setBarMin(options, min) {
1353
1453
  options.hAxis.viewWindow.min = min;
1354
- };
1454
+ }
1355
1455
 
1356
- var setBarMax = function (options, max) {
1456
+ function setBarMax(options, max) {
1357
1457
  options.hAxis.viewWindow.max = max;
1358
- };
1458
+ }
1359
1459
 
1360
- var setStacked = function (options, stacked) {
1361
- options.isStacked = stacked ? stacked : false;
1362
- };
1460
+ function setStacked(options, stacked) {
1461
+ options.isStacked = stacked || false;
1462
+ }
1363
1463
 
1364
- var setXtitle = function (options, title) {
1464
+ function setXtitle(options, title) {
1365
1465
  options.hAxis.title = title;
1366
1466
  options.hAxis.titleTextStyle.italic = false;
1367
- };
1467
+ }
1368
1468
 
1369
- var setYtitle = function (options, title) {
1469
+ function setYtitle(options, title) {
1370
1470
  options.vAxis.title = title;
1371
1471
  options.vAxis.titleTextStyle.italic = false;
1372
- };
1472
+ }
1373
1473
 
1374
1474
  var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
1375
1475
 
1376
- var resize = function (callback) {
1476
+ function resize(callback) {
1377
1477
  if (window.attachEvent) {
1378
1478
  window.attachEvent("onresize", callback);
1379
1479
  } else if (window.addEventListener) {
1380
1480
  window.addEventListener("resize", callback, true);
1381
1481
  }
1382
1482
  callback();
1383
- };
1483
+ }
1384
1484
 
1385
1485
  var defaultExport = function defaultExport(library) {
1386
1486
  this.name = "google";
@@ -1388,7 +1488,7 @@
1388
1488
  };
1389
1489
 
1390
1490
  defaultExport.prototype.renderLineChart = function renderLineChart (chart) {
1391
- var this$1 = this;
1491
+ var this$1$1 = this;
1392
1492
 
1393
1493
  this.waitForLoaded(chart, function () {
1394
1494
  var chartOptions = {};
@@ -1402,14 +1502,14 @@
1402
1502
  }
1403
1503
 
1404
1504
  var options = jsOptions(chart, chart.options, chartOptions);
1405
- var data = this$1.createDataTable(chart.data, chart.xtype);
1505
+ var data = this$1$1.createDataTable(chart.data, chart.xtype);
1406
1506
 
1407
- this$1.drawChart(chart, "LineChart", data, options);
1507
+ this$1$1.drawChart(chart, "LineChart", data, options);
1408
1508
  });
1409
1509
  };
1410
1510
 
1411
1511
  defaultExport.prototype.renderPieChart = function renderPieChart (chart) {
1412
- var this$1 = this;
1512
+ var this$1$1 = this;
1413
1513
 
1414
1514
  this.waitForLoaded(chart, function () {
1415
1515
  var chartOptions = {
@@ -1433,28 +1533,28 @@
1433
1533
  }
1434
1534
  var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
1435
1535
 
1436
- var data = new this$1.library.visualization.DataTable();
1536
+ var data = new this$1$1.library.visualization.DataTable();
1437
1537
  data.addColumn("string", "");
1438
1538
  data.addColumn("number", "Value");
1439
1539
  data.addRows(chart.data);
1440
1540
 
1441
- this$1.drawChart(chart, "PieChart", data, options);
1541
+ this$1$1.drawChart(chart, "PieChart", data, options);
1442
1542
  });
1443
1543
  };
1444
1544
 
1445
1545
  defaultExport.prototype.renderColumnChart = function renderColumnChart (chart) {
1446
- var this$1 = this;
1546
+ var this$1$1 = this;
1447
1547
 
1448
1548
  this.waitForLoaded(chart, function () {
1449
1549
  var options = jsOptions(chart, chart.options);
1450
- var data = this$1.createDataTable(chart.data, chart.xtype);
1550
+ var data = this$1$1.createDataTable(chart.data, chart.xtype);
1451
1551
 
1452
- this$1.drawChart(chart, "ColumnChart", data, options);
1552
+ this$1$1.drawChart(chart, "ColumnChart", data, options);
1453
1553
  });
1454
1554
  };
1455
1555
 
1456
1556
  defaultExport.prototype.renderBarChart = function renderBarChart (chart) {
1457
- var this$1 = this;
1557
+ var this$1$1 = this;
1458
1558
 
1459
1559
  this.waitForLoaded(chart, function () {
1460
1560
  var chartOptions = {
@@ -1465,14 +1565,14 @@
1465
1565
  }
1466
1566
  };
1467
1567
  var options = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart, chart.options, chartOptions);
1468
- var data = this$1.createDataTable(chart.data, chart.xtype);
1568
+ var data = this$1$1.createDataTable(chart.data, chart.xtype);
1469
1569
 
1470
- this$1.drawChart(chart, "BarChart", data, options);
1570
+ this$1$1.drawChart(chart, "BarChart", data, options);
1471
1571
  });
1472
1572
  };
1473
1573
 
1474
1574
  defaultExport.prototype.renderAreaChart = function renderAreaChart (chart) {
1475
- var this$1 = this;
1575
+ var this$1$1 = this;
1476
1576
 
1477
1577
  this.waitForLoaded(chart, function () {
1478
1578
  var chartOptions = {
@@ -1482,14 +1582,14 @@
1482
1582
  };
1483
1583
 
1484
1584
  var options = jsOptions(chart, chart.options, chartOptions);
1485
- var data = this$1.createDataTable(chart.data, chart.xtype);
1585
+ var data = this$1$1.createDataTable(chart.data, chart.xtype);
1486
1586
 
1487
- this$1.drawChart(chart, "AreaChart", data, options);
1587
+ this$1$1.drawChart(chart, "AreaChart", data, options);
1488
1588
  });
1489
1589
  };
1490
1590
 
1491
1591
  defaultExport.prototype.renderGeoChart = function renderGeoChart (chart) {
1492
- var this$1 = this;
1592
+ var this$1$1 = this;
1493
1593
 
1494
1594
  this.waitForLoaded(chart, "geochart", function () {
1495
1595
  var chartOptions = {
@@ -1500,27 +1600,28 @@
1500
1600
  };
1501
1601
  var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
1502
1602
 
1503
- var data = new this$1.library.visualization.DataTable();
1603
+ var data = new this$1$1.library.visualization.DataTable();
1504
1604
  data.addColumn("string", "");
1505
1605
  data.addColumn("number", chart.options.label || "Value");
1506
1606
  data.addRows(chart.data);
1507
1607
 
1508
- this$1.drawChart(chart, "GeoChart", data, options);
1608
+ this$1$1.drawChart(chart, "GeoChart", data, options);
1509
1609
  });
1510
1610
  };
1511
1611
 
1512
1612
  defaultExport.prototype.renderScatterChart = function renderScatterChart (chart) {
1513
- var this$1 = this;
1613
+ var this$1$1 = this;
1514
1614
 
1515
1615
  this.waitForLoaded(chart, function () {
1516
1616
  var chartOptions = {};
1517
1617
  var options = jsOptions(chart, chart.options, chartOptions);
1518
1618
 
1519
- var series = chart.data, rows2 = [], i, j, data, d;
1520
- for (i = 0; i < series.length; i++) {
1619
+ var series = chart.data;
1620
+ var rows2 = [];
1621
+ for (var i = 0; i < series.length; i++) {
1521
1622
  series[i].name = series[i].name || "Value";
1522
- d = series[i].data;
1523
- for (j = 0; j < d.length; j++) {
1623
+ var d = series[i].data;
1624
+ for (var j = 0; j < d.length; j++) {
1524
1625
  var row = new Array(series.length + 1);
1525
1626
  row[0] = d[j][0];
1526
1627
  row[i + 1] = d[j][1];
@@ -1528,19 +1629,19 @@
1528
1629
  }
1529
1630
  }
1530
1631
 
1531
- data = new this$1.library.visualization.DataTable();
1632
+ var data = new this$1$1.library.visualization.DataTable();
1532
1633
  data.addColumn("number", "");
1533
- for (i = 0; i < series.length; i++) {
1534
- data.addColumn("number", series[i].name);
1634
+ for (var i$1 = 0; i$1 < series.length; i$1++) {
1635
+ data.addColumn("number", series[i$1].name);
1535
1636
  }
1536
1637
  data.addRows(rows2);
1537
1638
 
1538
- this$1.drawChart(chart, "ScatterChart", data, options);
1639
+ this$1$1.drawChart(chart, "ScatterChart", data, options);
1539
1640
  });
1540
1641
  };
1541
1642
 
1542
1643
  defaultExport.prototype.renderTimeline = function renderTimeline (chart) {
1543
- var this$1 = this;
1644
+ var this$1$1 = this;
1544
1645
 
1545
1646
  this.waitForLoaded(chart, "timeline", function () {
1546
1647
  var chartOptions = {
@@ -1552,7 +1653,7 @@
1552
1653
  }
1553
1654
  var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
1554
1655
 
1555
- var data = new this$1.library.visualization.DataTable();
1656
+ var data = new this$1$1.library.visualization.DataTable();
1556
1657
  data.addColumn({type: "string", id: "Name"});
1557
1658
  data.addColumn({type: "date", id: "Start"});
1558
1659
  data.addColumn({type: "date", id: "End"});
@@ -1560,7 +1661,7 @@
1560
1661
 
1561
1662
  chart.element.style.lineHeight = "normal";
1562
1663
 
1563
- this$1.drawChart(chart, "Timeline", data, options);
1664
+ this$1$1.drawChart(chart, "Timeline", data, options);
1564
1665
  });
1565
1666
  };
1566
1667
 
@@ -1586,7 +1687,7 @@
1586
1687
  };
1587
1688
 
1588
1689
  defaultExport.prototype.waitForLoaded = function waitForLoaded (chart, pack, callback) {
1589
- var this$1 = this;
1690
+ var this$1$1 = this;
1590
1691
 
1591
1692
  if (!callback) {
1592
1693
  callback = pack;
@@ -1603,7 +1704,7 @@
1603
1704
  // https://groups.google.com/forum/#!topic/google-visualization-api/fMKJcyA2yyI
1604
1705
  var loadOptions = {
1605
1706
  packages: [pack],
1606
- callback: function () { this$1.runCallbacks(); }
1707
+ callback: function () { this$1$1.runCallbacks(); }
1607
1708
  };
1608
1709
  var config = chart.__config();
1609
1710
  if (config.language) {
@@ -1618,10 +1719,9 @@
1618
1719
  };
1619
1720
 
1620
1721
  defaultExport.prototype.runCallbacks = function runCallbacks () {
1621
- var cb, call;
1622
1722
  for (var i = 0; i < callbacks.length; i++) {
1623
- cb = callbacks[i];
1624
- call = this.library.visualization && ((cb.pack === "corechart" && this.library.visualization.LineChart) || (cb.pack === "timeline" && this.library.visualization.Timeline) || (cb.pack === "geochart" && this.library.visualization.GeoChart));
1723
+ var cb = callbacks[i];
1724
+ var call = this.library.visualization && ((cb.pack === "corechart" && this.library.visualization.LineChart) || (cb.pack === "timeline" && this.library.visualization.Timeline) || (cb.pack === "geochart" && this.library.visualization.GeoChart));
1625
1725
  if (call) {
1626
1726
  cb.callback();
1627
1727
  callbacks.splice(i, 1);
@@ -1632,44 +1732,48 @@
1632
1732
 
1633
1733
  // cant use object as key
1634
1734
  defaultExport.prototype.createDataTable = function createDataTable (series, columnType) {
1635
- var i, j, s, d, key, rows = [], sortedLabels = [];
1636
- for (i = 0; i < series.length; i++) {
1637
- s = series[i];
1735
+ var rows = [];
1736
+ var sortedLabels = [];
1737
+ for (var i = 0; i < series.length; i++) {
1738
+ var s = series[i];
1638
1739
  series[i].name = series[i].name || "Value";
1639
1740
 
1640
- for (j = 0; j < s.data.length; j++) {
1641
- d = s.data[j];
1642
- key = (columnType === "datetime") ? d[0].getTime() : d[0];
1741
+ for (var j = 0; j < s.data.length; j++) {
1742
+ var d = s.data[j];
1743
+ var key = columnType === "datetime" ? d[0].getTime() : d[0];
1643
1744
  if (!rows[key]) {
1644
1745
  rows[key] = new Array(series.length);
1645
1746
  sortedLabels.push(key);
1646
1747
  }
1647
- rows[key][i] = toFloat(d[1]);
1748
+ rows[key][i] = d[1];
1648
1749
  }
1649
1750
  }
1650
1751
 
1651
1752
  var rows2 = [];
1652
- var day = true;
1653
- var value;
1654
- for (j = 0; j < sortedLabels.length; j++) {
1655
- i = sortedLabels[j];
1753
+ var values = [];
1754
+ for (var j$1 = 0; j$1 < sortedLabels.length; j$1++) {
1755
+ var i$1 = sortedLabels[j$1];
1756
+ var value = (void 0);
1656
1757
  if (columnType === "datetime") {
1657
- value = new Date(toFloat(i));
1658
- day = day && isDay(value);
1659
- } else if (columnType === "number") {
1660
- value = toFloat(i);
1758
+ value = new Date(i$1);
1759
+ values.push(value);
1661
1760
  } else {
1662
- value = i;
1761
+ value = i$1;
1663
1762
  }
1664
- rows2.push([value].concat(rows[i]));
1763
+ rows2.push([value].concat(rows[i$1]));
1665
1764
  }
1765
+
1766
+ var day = true;
1666
1767
  if (columnType === "datetime") {
1667
1768
  rows2.sort(sortByTime);
1769
+
1770
+ var timeUnit = calculateTimeUnit(values, true);
1771
+ day = isDay(timeUnit);
1668
1772
  } else if (columnType === "number") {
1669
1773
  rows2.sort(sortByNumberSeries);
1670
1774
 
1671
- for (i = 0; i < rows2.length; i++) {
1672
- rows2[i][0] = toStr(rows2[i][0]);
1775
+ for (var i$2 = 0; i$2 < rows2.length; i$2++) {
1776
+ rows2[i$2][0] = toStr(rows2[i$2][0]);
1673
1777
  }
1674
1778
 
1675
1779
  columnType = "string";
@@ -1679,232 +1783,39 @@
1679
1783
  var data = new this.library.visualization.DataTable();
1680
1784
  columnType = columnType === "datetime" && day ? "date" : columnType;
1681
1785
  data.addColumn(columnType, "");
1682
- for (i = 0; i < series.length; i++) {
1683
- data.addColumn("number", series[i].name);
1786
+ for (var i$3 = 0; i$3 < series.length; i$3++) {
1787
+ data.addColumn("number", series[i$3].name);
1684
1788
  }
1685
1789
  data.addRows(rows2);
1686
1790
 
1687
1791
  return data;
1688
1792
  };
1689
1793
 
1690
- var pendingRequests = [], runningRequests = 0, maxRequests = 4;
1691
-
1692
- function pushRequest(url, success, error) {
1693
- pendingRequests.push([url, success, error]);
1694
- runNext();
1695
- }
1794
+ var adapters = [];
1696
1795
 
1697
- function runNext() {
1698
- if (runningRequests < maxRequests) {
1699
- var request = pendingRequests.shift();
1700
- if (request) {
1701
- runningRequests++;
1702
- getJSON(request[0], request[1], request[2]);
1703
- runNext();
1796
+ function getAdapterType(library) {
1797
+ if (library) {
1798
+ if (library.product === "Highcharts") {
1799
+ return defaultExport$1;
1800
+ } else if (library.charts) {
1801
+ return defaultExport;
1802
+ } else if (isFunction(library)) {
1803
+ return defaultExport$2;
1704
1804
  }
1705
1805
  }
1706
- }
1707
-
1708
- function requestComplete() {
1709
- runningRequests--;
1710
- runNext();
1711
- }
1712
-
1713
- function getJSON(url, success, error) {
1714
- ajaxCall(url, success, function (jqXHR, textStatus, errorThrown) {
1715
- var message = (typeof errorThrown === "string") ? errorThrown : errorThrown.message;
1716
- error(message);
1717
- });
1718
- }
1719
-
1720
- function ajaxCall(url, success, error) {
1721
- var $ = window.jQuery || window.Zepto || window.$;
1722
-
1723
- if ($ && $.ajax) {
1724
- $.ajax({
1725
- dataType: "json",
1726
- url: url,
1727
- success: success,
1728
- error: error,
1729
- complete: requestComplete
1730
- });
1731
- } else {
1732
- var xhr = new XMLHttpRequest();
1733
- xhr.open("GET", url, true);
1734
- xhr.setRequestHeader("Content-Type", "application/json");
1735
- xhr.onload = function () {
1736
- requestComplete();
1737
- if (xhr.status === 200) {
1738
- success(JSON.parse(xhr.responseText), xhr.statusText, xhr);
1739
- } else {
1740
- error(xhr, "error", xhr.statusText);
1741
- }
1742
- };
1743
- xhr.send();
1744
- }
1745
- }
1746
-
1747
- var config = {};
1748
- var adapters = [];
1749
-
1750
- // helpers
1751
-
1752
- function setText(element, text) {
1753
- if (document.body.innerText) {
1754
- element.innerText = text;
1755
- } else {
1756
- element.textContent = text;
1757
- }
1758
- }
1759
-
1760
- // TODO remove prefix for all messages
1761
- function chartError(element, message, noPrefix) {
1762
- if (!noPrefix) {
1763
- message = "Error Loading Chart: " + message;
1764
- }
1765
- setText(element, message);
1766
- element.style.color = "#ff0000";
1767
- }
1768
-
1769
- function errorCatcher(chart) {
1770
- try {
1771
- chart.__render();
1772
- } catch (err) {
1773
- chartError(chart.element, err.message);
1774
- throw err;
1775
- }
1776
- }
1777
-
1778
- function fetchDataSource(chart, dataSource, showLoading) {
1779
- // only show loading message for urls and callbacks
1780
- if (showLoading && chart.options.loading && (typeof dataSource === "string" || typeof dataSource === "function")) {
1781
- setText(chart.element, chart.options.loading);
1782
- }
1783
-
1784
- if (typeof dataSource === "string") {
1785
- pushRequest(dataSource, function (data) {
1786
- chart.rawData = data;
1787
- errorCatcher(chart);
1788
- }, function (message) {
1789
- chartError(chart.element, message);
1790
- });
1791
- } else if (typeof dataSource === "function") {
1792
- try {
1793
- dataSource(function (data) {
1794
- chart.rawData = data;
1795
- errorCatcher(chart);
1796
- }, function (message) {
1797
- chartError(chart.element, message, true);
1798
- });
1799
- } catch (err) {
1800
- chartError(chart.element, err, true);
1801
- }
1802
- } else {
1803
- chart.rawData = dataSource;
1804
- errorCatcher(chart);
1805
- }
1806
- }
1807
-
1808
- function addDownloadButton(chart) {
1809
- var element = chart.element;
1810
- var link = document.createElement("a");
1811
-
1812
- var download = chart.options.download;
1813
- if (download === true) {
1814
- download = {};
1815
- } else if (typeof download === "string") {
1816
- download = {filename: download};
1817
- }
1818
- link.download = download.filename || "chart.png"; // https://caniuse.com/download
1819
-
1820
- link.style.position = "absolute";
1821
- link.style.top = "20px";
1822
- link.style.right = "20px";
1823
- link.style.zIndex = 1000;
1824
- link.style.lineHeight = "20px";
1825
- link.target = "_blank"; // for safari
1826
- var image = document.createElement("img");
1827
- image.alt = "Download";
1828
- image.style.border = "none";
1829
- // icon from font-awesome
1830
- // http://fa2png.io/
1831
- image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAABCFBMVEUAAADMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMywEsqxAAAAV3RSTlMAAQIDBggJCgsMDQ4PERQaHB0eISIjJCouLzE0OTo/QUJHSUpLTU5PUllhYmltcHh5foWLjI+SlaCio6atr7S1t7m6vsHHyM7R2tze5Obo7fHz9ff5+/1hlxK2AAAA30lEQVQYGUXBhVYCQQBA0TdYWAt2d3d3YWAHyur7/z9xgD16Lw0DW+XKx+1GgX+FRzM3HWQWrHl5N/oapW5RPe0PkBu+UYeICvozTWZVK23Ao04B79oJrOsJDOoxkZoQPWgX29pHpCZEk7rEvQYiNSFq1UMqvlCjJkRBS1R8hb00Vb/TajtBL7nTHE1X1vyMQF732dQhyF2o6SAwrzP06iUQzvwsArlnzcOdrgBhJyHa1QOgO9U1GsKuvjUTjavliZYQ8nNPapG6sap/3nrIdJ6bOWzmX/fy0XVpfzZP3S8OJT3g9EEiJwAAAABJRU5ErkJggg==";
1832
- link.appendChild(image);
1833
- element.style.position = "relative";
1834
-
1835
- chart.__downloadAttached = true;
1836
-
1837
- // mouseenter
1838
- chart.__enterEvent = addEvent(element, "mouseover", function(e) {
1839
- var related = e.relatedTarget;
1840
- // check download option again to ensure it wasn't changed
1841
- if ((!related || (related !== this && !childOf(this, related))) && chart.options.download) {
1842
- link.href = chart.toImage(download);
1843
- element.appendChild(link);
1844
- }
1845
- });
1846
-
1847
- // mouseleave
1848
- chart.__leaveEvent = addEvent(element, "mouseout", function(e) {
1849
- var related = e.relatedTarget;
1850
- if (!related || (related !== this && !childOf(this, related))) {
1851
- if (link.parentNode) {
1852
- link.parentNode.removeChild(link);
1853
- }
1854
- }
1855
- });
1856
- }
1857
-
1858
- // https://stackoverflow.com/questions/10149963/adding-event-listener-cross-browser
1859
- function addEvent(elem, event, fn) {
1860
- if (elem.addEventListener) {
1861
- elem.addEventListener(event, fn, false);
1862
- return fn;
1863
- } else {
1864
- var fn2 = function() {
1865
- // set the this pointer same as addEventListener when fn is called
1866
- return(fn.call(elem, window.event));
1867
- };
1868
- elem.attachEvent("on" + event, fn2);
1869
- return fn2;
1870
- }
1871
- }
1872
-
1873
- function removeEvent(elem, event, fn) {
1874
- if (elem.removeEventListener) {
1875
- elem.removeEventListener(event, fn, false);
1876
- } else {
1877
- elem.detachEvent("on" + event, fn);
1878
- }
1879
- }
1880
-
1881
- // https://gist.github.com/shawnbot/4166283
1882
- function childOf(p, c) {
1883
- if (p === c) { return false; }
1884
- while (c && c !== p) { c = c.parentNode; }
1885
- return c === p;
1886
- }
1887
-
1888
- function getAdapterType(library) {
1889
- if (library) {
1890
- if (library.product === "Highcharts") {
1891
- return defaultExport$1;
1892
- } else if (library.charts) {
1893
- return defaultExport;
1894
- } else if (isFunction(library)) {
1895
- return defaultExport$2;
1896
- }
1897
- }
1898
- throw new Error("Unknown adapter");
1806
+ throw new Error("Unknown adapter");
1899
1807
  }
1900
1808
 
1901
1809
  function addAdapter(library) {
1902
1810
  var adapterType = getAdapterType(library);
1903
- var adapter = new adapterType(library);
1904
1811
 
1905
- if (adapters.indexOf(adapter) === -1) {
1906
- adapters.push(adapter);
1812
+ for (var i = 0; i < adapters.length; i++) {
1813
+ if (adapters[i].library === library) {
1814
+ return;
1815
+ }
1907
1816
  }
1817
+
1818
+ adapters.push(new adapterType(library));
1908
1819
  }
1909
1820
 
1910
1821
  function loadAdapters() {
@@ -1921,42 +1832,16 @@
1921
1832
  }
1922
1833
  }
1923
1834
 
1924
- function dataEmpty(data, chartType) {
1925
- if (chartType === "PieChart" || chartType === "GeoChart" || chartType === "Timeline") {
1926
- return data.length === 0;
1927
- } else {
1928
- for (var i = 0; i < data.length; i++) {
1929
- if (data[i].data.length > 0) {
1930
- return false;
1931
- }
1932
- }
1933
- return true;
1934
- }
1935
- }
1936
-
1937
- function renderChart(chartType, chart) {
1938
- if (dataEmpty(chart.data, chartType)) {
1939
- var message = chart.options.empty || (chart.options.messages && chart.options.messages.empty) || "No data";
1940
- setText(chart.element, message);
1941
- } else {
1942
- callAdapter(chartType, chart);
1943
- if (chart.options.download && !chart.__downloadAttached && chart.adapter === "chartjs") {
1944
- addDownloadButton(chart);
1945
- }
1946
- }
1947
- }
1948
-
1949
1835
  // TODO remove chartType if cross-browser way
1950
1836
  // to get the name of the chart class
1951
1837
  function callAdapter(chartType, chart) {
1952
- var i, adapter, fnName, adapterName;
1953
- fnName = "render" + chartType;
1954
- adapterName = chart.options.adapter;
1838
+ var fnName = "render" + chartType;
1839
+ var adapterName = chart.options.adapter;
1955
1840
 
1956
1841
  loadAdapters();
1957
1842
 
1958
- for (i = 0; i < adapters.length; i++) {
1959
- adapter = adapters[i];
1843
+ for (var i = 0; i < adapters.length; i++) {
1844
+ var adapter = adapters[i];
1960
1845
  if ((!adapterName || adapterName === adapter.name) && isFunction(adapter[fnName])) {
1961
1846
  chart.adapter = adapter.name;
1962
1847
  chart.__adapterObject = adapter;
@@ -1971,36 +1856,73 @@
1971
1856
  }
1972
1857
  }
1973
1858
 
1974
- // process data
1859
+ var Chartkick = {
1860
+ charts: {},
1861
+ configure: function (options) {
1862
+ for (var key in options) {
1863
+ if (Object.prototype.hasOwnProperty.call(options, key)) {
1864
+ Chartkick.config[key] = options[key];
1865
+ }
1866
+ }
1867
+ },
1868
+ setDefaultOptions: function (opts) {
1869
+ Chartkick.options = opts;
1870
+ },
1871
+ eachChart: function (callback) {
1872
+ for (var chartId in Chartkick.charts) {
1873
+ if (Object.prototype.hasOwnProperty.call(Chartkick.charts, chartId)) {
1874
+ callback(Chartkick.charts[chartId]);
1875
+ }
1876
+ }
1877
+ },
1878
+ destroyAll: function () {
1879
+ for (var chartId in Chartkick.charts) {
1880
+ if (Object.prototype.hasOwnProperty.call(Chartkick.charts, chartId)) {
1881
+ Chartkick.charts[chartId].destroy();
1882
+ delete Chartkick.charts[chartId];
1883
+ }
1884
+ }
1885
+ },
1886
+ config: {},
1887
+ options: {},
1888
+ adapters: adapters,
1889
+ addAdapter: addAdapter,
1890
+ use: function (adapter) {
1891
+ addAdapter(adapter);
1892
+ return Chartkick;
1893
+ }
1894
+ };
1895
+
1896
+ function formatSeriesBubble(data) {
1897
+ var r = [];
1898
+ for (var i = 0; i < data.length; i++) {
1899
+ r.push([toFloat(data[i][0]), toFloat(data[i][1]), toFloat(data[i][2])]);
1900
+ }
1901
+ return r;
1902
+ }
1903
+
1904
+ // casts data to proper type
1905
+ // sorting is left to adapters
1906
+ function formatSeriesData(data, keyType) {
1907
+ if (keyType === "bubble") {
1908
+ return formatSeriesBubble(data);
1909
+ }
1975
1910
 
1976
- var toFormattedKey = function (key, keyType) {
1911
+ var keyFunc;
1977
1912
  if (keyType === "number") {
1978
- key = toFloat(key);
1913
+ keyFunc = toFloat;
1979
1914
  } else if (keyType === "datetime") {
1980
- key = toDate(key);
1915
+ keyFunc = toDate;
1981
1916
  } else {
1982
- key = toStr(key);
1917
+ keyFunc = toStr;
1983
1918
  }
1984
- return key;
1985
- };
1986
1919
 
1987
- var formatSeriesData = function (data, keyType) {
1988
- var r = [], key, j;
1989
- for (j = 0; j < data.length; j++) {
1990
- if (keyType === "bubble") {
1991
- r.push([toFloat(data[j][0]), toFloat(data[j][1]), toFloat(data[j][2])]);
1992
- } else {
1993
- key = toFormattedKey(data[j][0], keyType);
1994
- r.push([key, toFloat(data[j][1])]);
1995
- }
1996
- }
1997
- if (keyType === "datetime") {
1998
- r.sort(sortByTime);
1999
- } else if (keyType === "number") {
2000
- r.sort(sortByNumberSeries);
1920
+ var r = [];
1921
+ for (var i = 0; i < data.length; i++) {
1922
+ r.push([keyFunc(data[i][0]), toFloat(data[i][1])]);
2001
1923
  }
2002
1924
  return r;
2003
- };
1925
+ }
2004
1926
 
2005
1927
  function detectXType(series, noDatetime, options) {
2006
1928
  if (dataEmpty(series)) {
@@ -2019,10 +1941,9 @@
2019
1941
  }
2020
1942
 
2021
1943
  function detectXTypeWithFunction(series, func) {
2022
- var i, j, data;
2023
- for (i = 0; i < series.length; i++) {
2024
- data = toArr(series[i].data);
2025
- for (j = 0; j < data.length; j++) {
1944
+ for (var i = 0; i < series.length; i++) {
1945
+ var data = toArr(series[i].data);
1946
+ for (var j = 0; j < data.length; j++) {
2026
1947
  if (!func(data[j][0])) {
2027
1948
  return false;
2028
1949
  }
@@ -2034,11 +1955,11 @@
2034
1955
  // creates a shallow copy of each element of the array
2035
1956
  // elements are expected to be objects
2036
1957
  function copySeries(series) {
2037
- var newSeries = [], i, j;
2038
- for (i = 0; i < series.length; i++) {
1958
+ var newSeries = [];
1959
+ for (var i = 0; i < series.length; i++) {
2039
1960
  var copy = {};
2040
- for (j in series[i]) {
2041
- if (series[i].hasOwnProperty(j)) {
1961
+ for (var j in series[i]) {
1962
+ if (Object.prototype.hasOwnProperty.call(series[i], j)) {
2042
1963
  copy[j] = series[i][j];
2043
1964
  }
2044
1965
  }
@@ -2048,60 +1969,235 @@
2048
1969
  }
2049
1970
 
2050
1971
  function processSeries(chart, keyType, noDatetime) {
2051
- var i;
2052
-
2053
1972
  var opts = chart.options;
2054
1973
  var series = chart.rawData;
2055
1974
 
2056
1975
  // see if one series or multiple
2057
- if (!isArray(series) || typeof series[0] !== "object" || isArray(series[0])) {
1976
+ chart.singleSeriesFormat = !isArray(series) || !isPlainObject(series[0]);
1977
+ if (chart.singleSeriesFormat) {
2058
1978
  series = [{name: opts.label, data: series}];
2059
- chart.singleSeriesFormat = true;
2060
- } else {
2061
- chart.singleSeriesFormat = false;
2062
1979
  }
2063
1980
 
2064
1981
  // convert to array
2065
1982
  // must come before dataEmpty check
2066
1983
  series = copySeries(series);
2067
- for (i = 0; i < series.length; i++) {
1984
+ for (var i = 0; i < series.length; i++) {
2068
1985
  series[i].data = toArr(series[i].data);
2069
1986
  }
2070
1987
 
2071
- chart.xtype = keyType ? keyType : (opts.discrete ? "string" : detectXType(series, noDatetime, opts));
1988
+ chart.xtype = keyType || (opts.discrete ? "string" : detectXType(series, noDatetime, opts));
2072
1989
 
2073
1990
  // right format
2074
- for (i = 0; i < series.length; i++) {
2075
- series[i].data = formatSeriesData(series[i].data, chart.xtype);
1991
+ for (var i$1 = 0; i$1 < series.length; i$1++) {
1992
+ series[i$1].data = formatSeriesData(series[i$1].data, chart.xtype);
2076
1993
  }
2077
1994
 
2078
1995
  return series;
2079
1996
  }
2080
1997
 
2081
1998
  function processSimple(chart) {
2082
- var perfectData = toArr(chart.rawData), i;
2083
- for (i = 0; i < perfectData.length; i++) {
1999
+ var perfectData = toArr(chart.rawData);
2000
+ for (var i = 0; i < perfectData.length; i++) {
2084
2001
  perfectData[i] = [toStr(perfectData[i][0]), toFloat(perfectData[i][1])];
2085
2002
  }
2086
2003
  return perfectData;
2087
2004
  }
2088
2005
 
2089
- // define classes
2006
+ function dataEmpty(data, chartType) {
2007
+ if (chartType === "PieChart" || chartType === "GeoChart" || chartType === "Timeline") {
2008
+ return data.length === 0;
2009
+ } else {
2010
+ for (var i = 0; i < data.length; i++) {
2011
+ if (data[i].data.length > 0) {
2012
+ return false;
2013
+ }
2014
+ }
2015
+ return true;
2016
+ }
2017
+ }
2090
2018
 
2091
- var Chart = function Chart(element, dataSource, options) {
2092
- var elementId;
2019
+ function addDownloadButton(chart) {
2020
+ var download = chart.options.download;
2021
+ if (download === true) {
2022
+ download = {};
2023
+ } else if (typeof download === "string") {
2024
+ download = {filename: download};
2025
+ }
2026
+
2027
+ var link = document.createElement("a");
2028
+ link.download = download.filename || "chart.png";
2029
+ link.style.position = "absolute";
2030
+ link.style.top = "20px";
2031
+ link.style.right = "20px";
2032
+ link.style.zIndex = 1000;
2033
+ link.style.lineHeight = "20px";
2034
+ link.target = "_blank"; // for safari
2035
+
2036
+ var image = document.createElement("img");
2037
+ // icon from Font Awesome, modified to set fill color
2038
+ var svg = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --><path fill=\"#CCCCCC\" d=\"M344 240h-56L287.1 152c0-13.25-10.75-24-24-24h-16C234.7 128 223.1 138.8 223.1 152L224 240h-56c-9.531 0-18.16 5.656-22 14.38C142.2 263.1 143.9 273.3 150.4 280.3l88.75 96C243.7 381.2 250.1 384 256.8 384c7.781-.3125 13.25-2.875 17.75-7.844l87.25-96c6.406-7.031 8.031-17.19 4.188-25.88S353.5 240 344 240zM256 0C114.6 0 0 114.6 0 256s114.6 256 256 256s256-114.6 256-256S397.4 0 256 0zM256 464c-114.7 0-208-93.31-208-208S141.3 48 256 48s208 93.31 208 208S370.7 464 256 464z\"/></svg>";
2039
+ image.src = "data:image/svg+xml;utf8," + (encodeURIComponent(svg));
2040
+ image.alt = "Download";
2041
+ image.style.width = "20px";
2042
+ image.style.height = "20px";
2043
+ image.style.border = "none";
2044
+ link.appendChild(image);
2045
+
2046
+ var element = chart.element;
2047
+ element.style.position = "relative";
2048
+
2049
+ chart.__downloadAttached = true;
2050
+
2051
+ // mouseenter
2052
+ chart.__enterEvent = element.addEventListener("mouseover", function (e) {
2053
+ var related = e.relatedTarget;
2054
+ // check download option again to ensure it wasn't changed
2055
+ if ((!related || (related !== this && !this.contains(related))) && chart.options.download) {
2056
+ link.href = chart.toImage(download);
2057
+ element.appendChild(link);
2058
+ }
2059
+ });
2060
+
2061
+ // mouseleave
2062
+ chart.__leaveEvent = element.addEventListener("mouseout", function (e) {
2063
+ var related = e.relatedTarget;
2064
+ if (!related || (related !== this && !this.contains(related))) {
2065
+ if (link.parentNode) {
2066
+ link.parentNode.removeChild(link);
2067
+ }
2068
+ }
2069
+ });
2070
+ }
2071
+
2072
+ var pendingRequests = [];
2073
+ var runningRequests = 0;
2074
+ var maxRequests = 4;
2075
+
2076
+ function pushRequest(url, success, error) {
2077
+ pendingRequests.push([url, success, error]);
2078
+ runNext();
2079
+ }
2080
+
2081
+ function runNext() {
2082
+ if (runningRequests < maxRequests) {
2083
+ var request = pendingRequests.shift();
2084
+ if (request) {
2085
+ runningRequests++;
2086
+ getJSON(request[0], request[1], request[2]);
2087
+ runNext();
2088
+ }
2089
+ }
2090
+ }
2091
+
2092
+ function requestComplete() {
2093
+ runningRequests--;
2094
+ runNext();
2095
+ }
2096
+
2097
+ function getJSON(url, success, error) {
2098
+ var xhr = new XMLHttpRequest();
2099
+ xhr.open("GET", url, true);
2100
+ xhr.setRequestHeader("Content-Type", "application/json");
2101
+ xhr.onload = function () {
2102
+ requestComplete();
2103
+ if (xhr.status === 200) {
2104
+ success(JSON.parse(xhr.responseText));
2105
+ } else {
2106
+ error(xhr.statusText);
2107
+ }
2108
+ };
2109
+ xhr.send();
2110
+ }
2111
+
2112
+ // helpers
2113
+
2114
+ function setText(element, text) {
2115
+ element.textContent = text;
2116
+ }
2117
+
2118
+ // TODO remove prefix for all messages
2119
+ function chartError(element, message, noPrefix) {
2120
+ if (!noPrefix) {
2121
+ message = "Error Loading Chart: " + message;
2122
+ }
2123
+ setText(element, message);
2124
+ element.style.color = "#ff0000";
2125
+ }
2126
+
2127
+ function errorCatcher(chart) {
2128
+ try {
2129
+ chart.__render();
2130
+ } catch (err) {
2131
+ chartError(chart.element, err.message);
2132
+ throw err;
2133
+ }
2134
+ }
2135
+
2136
+ function fetchDataSource(chart, dataSource, showLoading) {
2137
+ // only show loading message for urls and callbacks
2138
+ if (showLoading && chart.options.loading && (typeof dataSource === "string" || typeof dataSource === "function")) {
2139
+ setText(chart.element, chart.options.loading);
2140
+ }
2141
+
2142
+ if (typeof dataSource === "string") {
2143
+ pushRequest(dataSource, function (data) {
2144
+ chart.rawData = data;
2145
+ errorCatcher(chart);
2146
+ }, function (message) {
2147
+ chartError(chart.element, message);
2148
+ });
2149
+ } else if (typeof dataSource === "function") {
2150
+ try {
2151
+ dataSource(function (data) {
2152
+ chart.rawData = data;
2153
+ errorCatcher(chart);
2154
+ }, function (message) {
2155
+ chartError(chart.element, message, true);
2156
+ });
2157
+ } catch (err) {
2158
+ chartError(chart.element, err, true);
2159
+ }
2160
+ } else {
2161
+ chart.rawData = dataSource;
2162
+ errorCatcher(chart);
2163
+ }
2164
+ }
2165
+
2166
+ function renderChart(chartType, chart) {
2167
+ if (dataEmpty(chart.data, chartType)) {
2168
+ var message = chart.options.empty || (chart.options.messages && chart.options.messages.empty) || "No data";
2169
+ setText(chart.element, message);
2170
+ } else {
2171
+ callAdapter(chartType, chart);
2172
+ // TODO add downloadSupported method to adapter
2173
+ if (chart.options.download && !chart.__downloadAttached && chart.adapter === "chartjs") {
2174
+ addDownloadButton(chart);
2175
+ }
2176
+ }
2177
+ }
2178
+
2179
+ function getElement(element) {
2093
2180
  if (typeof element === "string") {
2094
- elementId = element;
2181
+ var elementId = element;
2095
2182
  element = document.getElementById(element);
2096
2183
  if (!element) {
2097
2184
  throw new Error("No element with id " + elementId);
2098
2185
  }
2099
2186
  }
2100
- this.element = element;
2187
+ return element;
2188
+ }
2189
+
2190
+ // define classes
2191
+
2192
+ var Chart = function Chart(element, dataSource, options) {
2193
+ this.element = getElement(element);
2101
2194
  this.options = merge(Chartkick.options, options || {});
2102
2195
  this.dataSource = dataSource;
2103
2196
 
2104
- Chartkick.charts[element.id] = this;
2197
+ // TODO handle charts without an id for eachChart and destroyAll
2198
+ if (this.element.id) {
2199
+ Chartkick.charts[this.element.id] = this;
2200
+ }
2105
2201
 
2106
2202
  fetchDataSource(this, dataSource, true);
2107
2203
 
@@ -2163,7 +2259,7 @@
2163
2259
  };
2164
2260
 
2165
2261
  Chart.prototype.startRefresh = function startRefresh () {
2166
- var this$1 = this;
2262
+ var this$1$1 = this;
2167
2263
 
2168
2264
  var refresh = this.options.refresh;
2169
2265
 
@@ -2173,8 +2269,8 @@
2173
2269
 
2174
2270
  if (!this.intervalId) {
2175
2271
  if (refresh) {
2176
- this.intervalId = setInterval( function () {
2177
- this$1.refreshData();
2272
+ this.intervalId = setInterval(function () {
2273
+ this$1$1.refreshData();
2178
2274
  }, refresh * 1000);
2179
2275
  } else {
2180
2276
  throw new Error("No refresh interval");
@@ -2190,11 +2286,12 @@
2190
2286
  };
2191
2287
 
2192
2288
  Chart.prototype.toImage = function toImage (download) {
2289
+ // TODO move logic to adapter
2193
2290
  if (this.adapter === "chartjs") {
2194
2291
  if (download && download.background && download.background !== "transparent") {
2195
2292
  // https://stackoverflow.com/questions/30464750/chartjs-line-chart-set-background-color
2196
- var canvas = this.chart.chart.canvas;
2197
- var ctx = this.chart.chart.ctx;
2293
+ var canvas = this.chart.canvas;
2294
+ var ctx = this.chart.ctx;
2198
2295
  var tmpCanvas = document.createElement("canvas");
2199
2296
  var tmpCtx = tmpCanvas.getContext("2d");
2200
2297
  tmpCanvas.width = ctx.canvas.width;
@@ -2220,11 +2317,11 @@
2220
2317
  }
2221
2318
 
2222
2319
  if (this.__enterEvent) {
2223
- removeEvent(this.element, "mouseover", this.__enterEvent);
2320
+ this.element.removeEventListener("mouseover", this.__enterEvent);
2224
2321
  }
2225
2322
 
2226
2323
  if (this.__leaveEvent) {
2227
- removeEvent(this.element, "mouseout", this.__leaveEvent);
2324
+ this.element.removeEventListener("mouseout", this.__leaveEvent);
2228
2325
  }
2229
2326
  };
2230
2327
 
@@ -2243,7 +2340,7 @@
2243
2340
  };
2244
2341
 
2245
2342
  Chart.prototype.__config = function __config () {
2246
- return config;
2343
+ return Chartkick.config;
2247
2344
  };
2248
2345
 
2249
2346
  var LineChart = /*@__PURE__*/(function (Chart) {
@@ -2416,8 +2513,8 @@
2416
2513
  Timeline.prototype.constructor = Timeline;
2417
2514
 
2418
2515
  Timeline.prototype.__processData = function __processData () {
2419
- var i, data = this.rawData;
2420
- for (i = 0; i < data.length; i++) {
2516
+ var data = this.rawData;
2517
+ for (var i = 0; i < data.length; i++) {
2421
2518
  data[i][1] = toDate(data[i][1]);
2422
2519
  data[i][2] = toDate(data[i][2]);
2423
2520
  }
@@ -2431,63 +2528,36 @@
2431
2528
  return Timeline;
2432
2529
  }(Chart));
2433
2530
 
2434
- var Chartkick = {
2435
- LineChart: LineChart,
2436
- PieChart: PieChart,
2437
- ColumnChart: ColumnChart,
2438
- BarChart: BarChart,
2439
- AreaChart: AreaChart,
2440
- GeoChart: GeoChart,
2441
- ScatterChart: ScatterChart,
2442
- BubbleChart: BubbleChart,
2443
- Timeline: Timeline,
2444
- charts: {},
2445
- configure: function (options) {
2446
- for (var key in options) {
2447
- if (options.hasOwnProperty(key)) {
2448
- config[key] = options[key];
2449
- }
2450
- }
2451
- },
2452
- setDefaultOptions: function (opts) {
2453
- Chartkick.options = opts;
2454
- },
2455
- eachChart: function (callback) {
2456
- for (var chartId in Chartkick.charts) {
2457
- if (Chartkick.charts.hasOwnProperty(chartId)) {
2458
- callback(Chartkick.charts[chartId]);
2459
- }
2460
- }
2461
- },
2462
- destroyAll: function() {
2463
- for (var chartId in Chartkick.charts) {
2464
- if (Chartkick.charts.hasOwnProperty(chartId)) {
2465
- Chartkick.charts[chartId].destroy();
2466
- delete Chartkick.charts[chartId];
2467
- }
2468
- }
2469
- },
2470
- config: config,
2471
- options: {},
2472
- adapters: adapters,
2473
- addAdapter: addAdapter,
2474
- use: function(adapter) {
2475
- addAdapter(adapter);
2476
- return Chartkick;
2477
- }
2478
- };
2531
+ Chartkick.LineChart = LineChart;
2532
+ Chartkick.PieChart = PieChart;
2533
+ Chartkick.ColumnChart = ColumnChart;
2534
+ Chartkick.BarChart = BarChart;
2535
+ Chartkick.AreaChart = AreaChart;
2536
+ Chartkick.GeoChart = GeoChart;
2537
+ Chartkick.ScatterChart = ScatterChart;
2538
+ Chartkick.BubbleChart = BubbleChart;
2539
+ Chartkick.Timeline = Timeline;
2479
2540
 
2480
2541
  // not ideal, but allows for simpler integration
2481
2542
  if (typeof window !== "undefined" && !window.Chartkick) {
2482
2543
  window.Chartkick = Chartkick;
2483
2544
 
2484
2545
  // clean up previous charts before Turbolinks loads new page
2485
- document.addEventListener("turbolinks:before-render", function() {
2486
- Chartkick.destroyAll();
2546
+ document.addEventListener("turbolinks:before-render", function () {
2547
+ if (Chartkick.config.autoDestroy !== false) {
2548
+ Chartkick.destroyAll();
2549
+ }
2550
+ });
2551
+
2552
+ // clean up previous charts before Turbo loads new page
2553
+ document.addEventListener("turbo:before-render", function () {
2554
+ if (Chartkick.config.autoDestroy !== false) {
2555
+ Chartkick.destroyAll();
2556
+ }
2487
2557
  });
2488
2558
 
2489
2559
  // use setTimeout so charting library can come later in same JS file
2490
- setTimeout(function() {
2560
+ setTimeout(function () {
2491
2561
  window.dispatchEvent(new Event("chartkick:load"));
2492
2562
  }, 0);
2493
2563
  }
@@ -2497,4 +2567,4 @@
2497
2567
 
2498
2568
  return Chartkick;
2499
2569
 
2500
- })));
2570
+ }));