chartkick 3.4.1 → 4.0.3

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.
@@ -1,15 +1,15 @@
1
- /*
1
+ /*!
2
2
  * Chartkick.js
3
3
  * Create beautiful charts with one line of JavaScript
4
4
  * https://github.com/ankane/chartkick.js
5
- * v3.2.1
5
+ * v4.0.3
6
6
  * MIT License
7
7
  */
8
8
 
9
9
  (function (global, factory) {
10
10
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
11
11
  typeof define === 'function' && define.amd ? define(factory) :
12
- (global = global || self, global.Chartkick = factory());
12
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Chartkick = factory());
13
13
  }(this, (function () { 'use strict';
14
14
 
15
15
  function isArray(variable) {
@@ -55,42 +55,6 @@
55
55
 
56
56
  var DATE_PATTERN = /^(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)$/i;
57
57
 
58
- // https://github.com/Do/iso8601.js
59
- var ISO8601_PATTERN = /(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)(T)?(\d\d)(:)?(\d\d)?(:)?(\d\d)?([.,]\d+)?($|Z|([+-])(\d\d)(:)?(\d\d)?)/i;
60
- var DECIMAL_SEPARATOR = String(1.5).charAt(1);
61
-
62
- function parseISO8601(input) {
63
- var day, hour, matches, milliseconds, minutes, month, offset, result, seconds, type, year;
64
- type = Object.prototype.toString.call(input);
65
- if (type === "[object Date]") {
66
- return input;
67
- }
68
- if (type !== "[object String]") {
69
- return;
70
- }
71
- matches = input.match(ISO8601_PATTERN);
72
- if (matches) {
73
- year = parseInt(matches[1], 10);
74
- month = parseInt(matches[3], 10) - 1;
75
- day = parseInt(matches[5], 10);
76
- hour = parseInt(matches[7], 10);
77
- minutes = matches[9] ? parseInt(matches[9], 10) : 0;
78
- seconds = matches[11] ? parseInt(matches[11], 10) : 0;
79
- milliseconds = matches[12] ? parseFloat(DECIMAL_SEPARATOR + matches[12].slice(1)) * 1000 : 0;
80
- result = Date.UTC(year, month, day, hour, minutes, seconds, milliseconds);
81
- if (matches[13] && matches[14]) {
82
- offset = matches[15] * 60;
83
- if (matches[17]) {
84
- offset += parseInt(matches[17], 10);
85
- }
86
- offset *= matches[14] === "-" ? -1 : 1;
87
- result -= offset * 60 * 1000;
88
- }
89
- return new Date(result);
90
- }
91
- }
92
- // end iso8601.js
93
-
94
58
  function negativeValues(series) {
95
59
  var i, j, data;
96
60
  for (i = 0; i < series.length; i++) {
@@ -120,15 +84,16 @@
120
84
  } else {
121
85
  n = toStr(n);
122
86
  if ((matches = n.match(DATE_PATTERN))) {
123
- year = parseInt(matches[1], 10);
124
- month = parseInt(matches[3], 10) - 1;
125
- day = parseInt(matches[5], 10);
126
- return new Date(year, month, day);
127
- } else { // str
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 {
128
92
  // try our best to get the str into iso8601
129
93
  // TODO be smarter about this
130
94
  var str = n.replace(/ /, "T").replace(" ", "").replace("UTC", "Z");
131
- n = parseISO8601(str) || new Date(n);
95
+ // Date.parse returns milliseconds if valid and NaN if invalid
96
+ n = new Date(Date.parse(str) || n);
132
97
  }
133
98
  }
134
99
  }
@@ -154,8 +119,8 @@
154
119
  var options = merge({}, defaultOptions);
155
120
  options = merge(options, chartOptions || {});
156
121
 
157
- if (chart.hideLegend || "legend" in opts) {
158
- hideLegend(options, opts.legend, chart.hideLegend);
122
+ if (chart.singleSeriesFormat || "legend" in opts) {
123
+ hideLegend(options, opts.legend, chart.singleSeriesFormat);
159
124
  }
160
125
 
161
126
  if (opts.title) {
@@ -361,42 +326,49 @@
361
326
  var baseOptions = {
362
327
  maintainAspectRatio: false,
363
328
  animation: false,
364
- tooltips: {
365
- displayColors: false,
366
- callbacks: {}
329
+ plugins: {
330
+ legend: {},
331
+ tooltip: {
332
+ displayColors: false,
333
+ callbacks: {}
334
+ },
335
+ title: {
336
+ font: {
337
+ size: 20
338
+ },
339
+ color: "#333"
340
+ }
367
341
  },
368
- legend: {},
369
- title: {fontSize: 20, fontColor: "#333"}
342
+ interaction: {}
370
343
  };
371
344
 
372
- var defaultOptions = {
345
+ var defaultOptions$2 = {
373
346
  scales: {
374
- yAxes: [
375
- {
376
- ticks: {
377
- maxTicksLimit: 4
378
- },
379
- scaleLabel: {
380
- fontSize: 16,
381
- // fontStyle: "bold",
382
- fontColor: "#333"
383
- }
384
- }
385
- ],
386
- xAxes: [
387
- {
388
- gridLines: {
389
- drawOnChartArea: false
347
+ y: {
348
+ ticks: {
349
+ maxTicksLimit: 4
350
+ },
351
+ title: {
352
+ font: {
353
+ size: 16
390
354
  },
391
- scaleLabel: {
392
- fontSize: 16,
393
- // fontStyle: "bold",
394
- fontColor: "#333"
355
+ color: "#333"
356
+ },
357
+ grid: {}
358
+ },
359
+ x: {
360
+ grid: {
361
+ drawOnChartArea: false
362
+ },
363
+ title: {
364
+ font: {
365
+ size: 16
395
366
  },
396
- time: {},
397
- ticks: {}
398
- }
399
- ]
367
+ color: "#333"
368
+ },
369
+ time: {},
370
+ ticks: {}
371
+ }
400
372
  }
401
373
  };
402
374
 
@@ -407,66 +379,66 @@
407
379
  "#6633CC", "#E67300", "#8B0707", "#329262", "#5574A6", "#651067"
408
380
  ];
409
381
 
410
- var hideLegend = function (options, legend, hideLegend) {
382
+ var hideLegend$2 = function (options, legend, hideLegend) {
411
383
  if (legend !== undefined) {
412
- options.legend.display = !!legend;
384
+ options.plugins.legend.display = !!legend;
413
385
  if (legend && legend !== true) {
414
- options.legend.position = legend;
386
+ options.plugins.legend.position = legend;
415
387
  }
416
388
  } else if (hideLegend) {
417
- options.legend.display = false;
389
+ options.plugins.legend.display = false;
418
390
  }
419
391
  };
420
392
 
421
- var setTitle = function (options, title) {
422
- options.title.display = true;
423
- options.title.text = title;
393
+ var setTitle$2 = function (options, title) {
394
+ options.plugins.title.display = true;
395
+ options.plugins.title.text = title;
424
396
  };
425
397
 
426
- var setMin = function (options, min) {
398
+ var setMin$2 = function (options, min) {
427
399
  if (min !== null) {
428
- options.scales.yAxes[0].ticks.min = toFloat(min);
400
+ options.scales.y.min = toFloat(min);
429
401
  }
430
402
  };
431
403
 
432
- var setMax = function (options, max) {
433
- options.scales.yAxes[0].ticks.max = toFloat(max);
404
+ var setMax$2 = function (options, max) {
405
+ options.scales.y.max = toFloat(max);
434
406
  };
435
407
 
436
- var setBarMin = function (options, min) {
408
+ var setBarMin$1 = function (options, min) {
437
409
  if (min !== null) {
438
- options.scales.xAxes[0].ticks.min = toFloat(min);
410
+ options.scales.x.min = toFloat(min);
439
411
  }
440
412
  };
441
413
 
442
- var setBarMax = function (options, max) {
443
- options.scales.xAxes[0].ticks.max = toFloat(max);
414
+ var setBarMax$1 = function (options, max) {
415
+ options.scales.x.max = toFloat(max);
444
416
  };
445
417
 
446
- var setStacked = function (options, stacked) {
447
- options.scales.xAxes[0].stacked = !!stacked;
448
- options.scales.yAxes[0].stacked = !!stacked;
418
+ var setStacked$2 = function (options, stacked) {
419
+ options.scales.x.stacked = !!stacked;
420
+ options.scales.y.stacked = !!stacked;
449
421
  };
450
422
 
451
- var setXtitle = function (options, title) {
452
- options.scales.xAxes[0].scaleLabel.display = true;
453
- options.scales.xAxes[0].scaleLabel.labelString = title;
423
+ var setXtitle$2 = function (options, title) {
424
+ options.scales.x.title.display = true;
425
+ options.scales.x.title.text = title;
454
426
  };
455
427
 
456
- var setYtitle = function (options, title) {
457
- options.scales.yAxes[0].scaleLabel.display = true;
458
- options.scales.yAxes[0].scaleLabel.labelString = title;
428
+ var setYtitle$2 = function (options, title) {
429
+ options.scales.y.title.display = true;
430
+ options.scales.y.title.text = title;
459
431
  };
460
432
 
461
433
  // https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
462
- var addOpacity = function(hex, opacity) {
434
+ var addOpacity = function (hex, opacity) {
463
435
  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
464
436
  return result ? "rgba(" + parseInt(result[1], 16) + ", " + parseInt(result[2], 16) + ", " + parseInt(result[3], 16) + ", " + opacity + ")" : hex;
465
437
  };
466
438
 
467
439
  // check if not null or undefined
468
440
  // https://stackoverflow.com/a/27757708/1177228
469
- var notnull = function(x) {
441
+ var notnull = function (x) {
470
442
  return x != null;
471
443
  };
472
444
 
@@ -477,9 +449,9 @@
477
449
  } else if (maxLabelSize < 10) {
478
450
  maxLabelSize = 10;
479
451
  }
480
- if (!options.scales.xAxes[0].ticks.callback) {
481
- options.scales.xAxes[0].ticks.callback = function (value) {
482
- value = toStr(value);
452
+ if (!options.scales.x.ticks.callback) {
453
+ options.scales.x.ticks.callback = function (value) {
454
+ value = toStr(this.getLabelForValue(value));
483
455
  if (value.length > maxLabelSize) {
484
456
  return value.substring(0, maxLabelSize - 2) + "...";
485
457
  } else {
@@ -489,7 +461,7 @@
489
461
  }
490
462
  };
491
463
 
492
- var setFormatOptions = function(chart, options, chartType) {
464
+ var setFormatOptions$1 = function (chart, options, chartType) {
493
465
  var formatOptions = {
494
466
  prefix: chart.options.prefix,
495
467
  suffix: chart.options.suffix,
@@ -529,49 +501,49 @@
529
501
  }
530
502
 
531
503
  if (chartType !== "pie") {
532
- var myAxes = options.scales.yAxes;
504
+ var axis = options.scales.y;
533
505
  if (chartType === "bar") {
534
- myAxes = options.scales.xAxes;
506
+ axis = options.scales.x;
535
507
  }
536
508
 
537
509
  if (formatOptions.byteScale) {
538
- if (!myAxes[0].ticks.stepSize) {
539
- myAxes[0].ticks.stepSize = formatOptions.byteScale / 2;
510
+ if (!axis.ticks.stepSize) {
511
+ axis.ticks.stepSize = formatOptions.byteScale / 2;
540
512
  }
541
- if (!myAxes[0].ticks.maxTicksLimit) {
542
- myAxes[0].ticks.maxTicksLimit = 4;
513
+ if (!axis.ticks.maxTicksLimit) {
514
+ axis.ticks.maxTicksLimit = 4;
543
515
  }
544
516
  }
545
517
 
546
- if (!myAxes[0].ticks.callback) {
547
- myAxes[0].ticks.callback = function (value) {
518
+ if (!axis.ticks.callback) {
519
+ axis.ticks.callback = function (value) {
548
520
  return formatValue("", value, formatOptions, true);
549
521
  };
550
522
  }
551
523
  }
552
524
 
553
- if (!options.tooltips.callbacks.label) {
525
+ if (!options.plugins.tooltip.callbacks.label) {
554
526
  if (chartType === "scatter") {
555
- options.tooltips.callbacks.label = function (item, data) {
556
- var label = data.datasets[item.datasetIndex].label || '';
527
+ options.plugins.tooltip.callbacks.label = function (context) {
528
+ var label = context.dataset.label || '';
557
529
  if (label) {
558
530
  label += ': ';
559
531
  }
560
- return label + '(' + item.xLabel + ', ' + item.yLabel + ')';
532
+ return label + '(' + context.label + ', ' + context.formattedValue + ')';
561
533
  };
562
534
  } else if (chartType === "bubble") {
563
- options.tooltips.callbacks.label = function (item, data) {
564
- var label = data.datasets[item.datasetIndex].label || '';
535
+ options.plugins.tooltip.callbacks.label = function (context) {
536
+ var label = context.dataset.label || '';
565
537
  if (label) {
566
538
  label += ': ';
567
539
  }
568
- var dataPoint = data.datasets[item.datasetIndex].data[item.index];
569
- return label + '(' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.v + ')';
540
+ var dataPoint = context.raw;
541
+ return label + '(' + dataPoint.x + ', ' + dataPoint.y + ', ' + dataPoint.v + ')';
570
542
  };
571
543
  } else if (chartType === "pie") {
572
544
  // need to use separate label for pie charts
573
- options.tooltips.callbacks.label = function (tooltipItem, data) {
574
- var dataLabel = data.labels[tooltipItem.index];
545
+ options.plugins.tooltip.callbacks.label = function (context) {
546
+ var dataLabel = context.label;
575
547
  var value = ': ';
576
548
 
577
549
  if (isArray(dataLabel)) {
@@ -583,24 +555,29 @@
583
555
  dataLabel += value;
584
556
  }
585
557
 
586
- return formatValue(dataLabel, data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index], formatOptions);
558
+ return formatValue(dataLabel, context.parsed, formatOptions);
587
559
  };
588
560
  } else {
589
- var valueLabel = chartType === "bar" ? "xLabel" : "yLabel";
590
- options.tooltips.callbacks.label = function (tooltipItem, data) {
591
- var label = data.datasets[tooltipItem.datasetIndex].label || '';
561
+ var valueLabel = chartType === "bar" ? "x" : "y";
562
+ options.plugins.tooltip.callbacks.label = function (context) {
563
+ // don't show null values for stacked charts
564
+ if (context.parsed[valueLabel] === null) {
565
+ return;
566
+ }
567
+
568
+ var label = context.dataset.label || '';
592
569
  if (label) {
593
570
  label += ': ';
594
571
  }
595
- return formatValue(label, tooltipItem[valueLabel], formatOptions);
572
+ return formatValue(label, context.parsed[valueLabel], formatOptions);
596
573
  };
597
574
  }
598
575
  }
599
576
  };
600
577
 
601
- var jsOptions = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
578
+ var jsOptions$2 = jsOptionsFunc(merge(baseOptions, defaultOptions$2), hideLegend$2, setTitle$2, setMin$2, setMax$2, setStacked$2, setXtitle$2, setYtitle$2);
602
579
 
603
- var createDataTable = function (chart, options, chartType, library) {
580
+ var createDataTable = function (chart, options, chartType) {
604
581
  var datasets = [];
605
582
  var labels = [];
606
583
 
@@ -702,11 +679,23 @@
702
679
  }
703
680
  }
704
681
 
682
+ var color;
683
+ var backgroundColor;
684
+
705
685
  for (i = 0; i < series.length; i++) {
706
686
  s = series[i];
707
687
 
708
- var color = s.color || colors[i];
709
- var backgroundColor = chartType !== "line" ? addOpacity(color, 0.5) : color;
688
+ // use colors for each bar for single series format
689
+ if (chart.options.colors && chart.singleSeriesFormat && (chartType === "bar" || chartType === "column") && !s.color && isArray(chart.options.colors) && !isArray(chart.options.colors[0])) {
690
+ color = colors;
691
+ backgroundColor = [];
692
+ for (var j$3 = 0; j$3 < colors.length; j$3++) {
693
+ backgroundColor[j$3] = addOpacity(color[j$3], 0.5);
694
+ }
695
+ } else {
696
+ color = s.color || colors[i];
697
+ backgroundColor = chartType !== "line" ? addOpacity(color, 0.5) : color;
698
+ }
710
699
 
711
700
  var dataset = {
712
701
  label: s.name || "",
@@ -714,24 +703,37 @@
714
703
  fill: chartType === "area",
715
704
  borderColor: color,
716
705
  backgroundColor: backgroundColor,
717
- pointBackgroundColor: color,
718
- borderWidth: 2,
719
- pointHoverBackgroundColor: color
706
+ borderWidth: 2
720
707
  };
721
708
 
709
+ var pointChart = chartType === "line" || chartType === "area" || chartType === "scatter" || chartType === "bubble";
710
+ if (pointChart) {
711
+ dataset.pointBackgroundColor = color;
712
+ dataset.pointHoverBackgroundColor = color;
713
+ dataset.pointHitRadius = 50;
714
+ }
715
+
716
+ if (chartType === "bubble") {
717
+ dataset.pointBackgroundColor = backgroundColor;
718
+ dataset.pointHoverBackgroundColor = backgroundColor;
719
+ dataset.pointHoverBorderWidth = 2;
720
+ }
721
+
722
722
  if (s.stack) {
723
723
  dataset.stack = s.stack;
724
724
  }
725
725
 
726
726
  var curve = seriesOption(chart, s, "curve");
727
727
  if (curve === false) {
728
- dataset.lineTension = 0;
728
+ dataset.tension = 0;
729
+ } else if (pointChart) {
730
+ dataset.tension = 0.4;
729
731
  }
730
732
 
731
733
  var points = seriesOption(chart, s, "points");
732
734
  if (points === false) {
733
735
  dataset.pointRadius = 0;
734
- dataset.pointHitRadius = 5;
736
+ dataset.pointHoverRadius = 0;
735
737
  }
736
738
 
737
739
  dataset = merge(dataset, chart.options.dataset || {});
@@ -745,22 +747,18 @@
745
747
  var xmax = chart.options.xmax;
746
748
 
747
749
  if (chart.xtype === "datetime") {
748
- // hacky check for Chart.js >= 2.9.0
749
- // https://github.com/chartjs/Chart.js/compare/v2.8.0...v2.9.0
750
- var gte29 = "math" in library.helpers;
751
- var ticksKey = gte29 ? "ticks" : "time";
752
750
  if (notnull(xmin)) {
753
- options.scales.xAxes[0][ticksKey].min = toDate(xmin).getTime();
751
+ options.scales.x.ticks.min = toDate(xmin).getTime();
754
752
  }
755
753
  if (notnull(xmax)) {
756
- options.scales.xAxes[0][ticksKey].max = toDate(xmax).getTime();
754
+ options.scales.x.ticks.max = toDate(xmax).getTime();
757
755
  }
758
756
  } else if (chart.xtype === "number") {
759
757
  if (notnull(xmin)) {
760
- options.scales.xAxes[0].ticks.min = xmin;
758
+ options.scales.x.ticks.min = xmin;
761
759
  }
762
760
  if (notnull(xmax)) {
763
- options.scales.xAxes[0].ticks.max = xmax;
761
+ options.scales.x.ticks.max = xmax;
764
762
  }
765
763
  }
766
764
 
@@ -796,24 +794,24 @@
796
794
 
797
795
  var timeDiff = (maxTime - minTime) / (86400 * 1000.0);
798
796
 
799
- if (!options.scales.xAxes[0].time.unit) {
797
+ if (!options.scales.x.time.unit) {
800
798
  var step;
801
799
  if (year || timeDiff > 365 * 10) {
802
- options.scales.xAxes[0].time.unit = "year";
800
+ options.scales.x.time.unit = "year";
803
801
  step = 365;
804
802
  } else if (month || timeDiff > 30 * 10) {
805
- options.scales.xAxes[0].time.unit = "month";
803
+ options.scales.x.time.unit = "month";
806
804
  step = 30;
807
805
  } else if (day || timeDiff > 10) {
808
- options.scales.xAxes[0].time.unit = "day";
806
+ options.scales.x.time.unit = "day";
809
807
  step = 1;
810
808
  } else if (hour || timeDiff > 0.5) {
811
- options.scales.xAxes[0].time.displayFormats = {hour: "MMM D, h a"};
812
- options.scales.xAxes[0].time.unit = "hour";
809
+ options.scales.x.time.displayFormats = {hour: "MMM d, h a"};
810
+ options.scales.x.time.unit = "hour";
813
811
  step = 1 / 24.0;
814
812
  } else if (minute) {
815
- options.scales.xAxes[0].time.displayFormats = {minute: "h:mm a"};
816
- options.scales.xAxes[0].time.unit = "minute";
813
+ options.scales.x.time.displayFormats = {minute: "h:mm a"};
814
+ options.scales.x.time.unit = "minute";
817
815
  step = 1 / 24.0 / 60.0;
818
816
  }
819
817
 
@@ -822,17 +820,17 @@
822
820
  if (week && step === 1) {
823
821
  unitStepSize = Math.ceil(unitStepSize / 7.0) * 7;
824
822
  }
825
- options.scales.xAxes[0].time.unitStepSize = unitStepSize;
823
+ options.scales.x.time.stepSize = unitStepSize;
826
824
  }
827
825
  }
828
826
 
829
- if (!options.scales.xAxes[0].time.tooltipFormat) {
827
+ if (!options.scales.x.time.tooltipFormat) {
830
828
  if (day) {
831
- options.scales.xAxes[0].time.tooltipFormat = "ll";
829
+ options.scales.x.time.tooltipFormat = "PP";
832
830
  } else if (hour) {
833
- options.scales.xAxes[0].time.tooltipFormat = "MMM D, h a";
831
+ options.scales.x.time.tooltipFormat = "MMM d, h a";
834
832
  } else if (minute) {
835
- options.scales.xAxes[0].time.tooltipFormat = "h:mm a";
833
+ options.scales.x.time.tooltipFormat = "h:mm a";
836
834
  }
837
835
  }
838
836
  }
@@ -845,49 +843,49 @@
845
843
  return data;
846
844
  };
847
845
 
848
- var defaultExport = function defaultExport(library) {
846
+ var defaultExport$2 = function defaultExport(library) {
849
847
  this.name = "chartjs";
850
848
  this.library = library;
851
849
  };
852
850
 
853
- defaultExport.prototype.renderLineChart = function renderLineChart (chart, chartType) {
851
+ defaultExport$2.prototype.renderLineChart = function renderLineChart (chart, chartType) {
854
852
  var chartOptions = {};
855
853
  // fix for https://github.com/chartjs/Chart.js/issues/2441
856
854
  if (!chart.options.max && allZeros(chart.data)) {
857
855
  chartOptions.max = 1;
858
856
  }
859
857
 
860
- var options = jsOptions(chart, merge(chartOptions, chart.options));
861
- setFormatOptions(chart, options, chartType);
858
+ var options = jsOptions$2(chart, merge(chartOptions, chart.options));
859
+ setFormatOptions$1(chart, options, chartType);
862
860
 
863
- var data = createDataTable(chart, options, chartType || "line", this.library);
861
+ var data = createDataTable(chart, options, chartType || "line");
864
862
 
865
863
  if (chart.xtype === "number") {
866
- options.scales.xAxes[0].type = "linear";
867
- options.scales.xAxes[0].position = "bottom";
864
+ options.scales.x.type = "linear";
865
+ options.scales.x.position = "bottom";
868
866
  } else {
869
- options.scales.xAxes[0].type = chart.xtype === "string" ? "category" : "time";
867
+ options.scales.x.type = chart.xtype === "string" ? "category" : "time";
870
868
  }
871
869
 
872
870
  this.drawChart(chart, "line", data, options);
873
871
  };
874
872
 
875
- defaultExport.prototype.renderPieChart = function renderPieChart (chart) {
873
+ defaultExport$2.prototype.renderPieChart = function renderPieChart (chart) {
876
874
  var options = merge({}, baseOptions);
877
875
  if (chart.options.donut) {
878
- options.cutoutPercentage = 50;
876
+ options.cutout = "50%";
879
877
  }
880
878
 
881
879
  if ("legend" in chart.options) {
882
- hideLegend(options, chart.options.legend);
880
+ hideLegend$2(options, chart.options.legend);
883
881
  }
884
882
 
885
883
  if (chart.options.title) {
886
- setTitle(options, chart.options.title);
884
+ setTitle$2(options, chart.options.title);
887
885
  }
888
886
 
889
887
  options = merge(options, chart.options.library || {});
890
- setFormatOptions(chart, options, "pie");
888
+ setFormatOptions$1(chart, options, "pie");
891
889
 
892
890
  var labels = [];
893
891
  var values = [];
@@ -911,61 +909,73 @@
911
909
  this.drawChart(chart, "pie", data, options);
912
910
  };
913
911
 
914
- defaultExport.prototype.renderColumnChart = function renderColumnChart (chart, chartType) {
912
+ defaultExport$2.prototype.renderColumnChart = function renderColumnChart (chart, chartType) {
915
913
  var options;
916
914
  if (chartType === "bar") {
917
- var barOptions = merge(baseOptions, defaultOptions);
918
- delete barOptions.scales.yAxes[0].ticks.maxTicksLimit;
919
- options = jsOptionsFunc(barOptions, hideLegend, setTitle, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart, chart.options);
915
+ var barOptions = merge(baseOptions, defaultOptions$2);
916
+ barOptions.indexAxis = "y";
917
+
918
+ // ensure gridlines have proper orientation
919
+ barOptions.scales.x.grid.drawOnChartArea = true;
920
+ barOptions.scales.y.grid.drawOnChartArea = false;
921
+ delete barOptions.scales.y.ticks.maxTicksLimit;
922
+
923
+ options = jsOptionsFunc(barOptions, hideLegend$2, setTitle$2, setBarMin$1, setBarMax$1, setStacked$2, setXtitle$2, setYtitle$2)(chart, chart.options);
920
924
  } else {
921
- options = jsOptions(chart, chart.options);
925
+ options = jsOptions$2(chart, chart.options);
922
926
  }
923
- setFormatOptions(chart, options, chartType);
924
- var data = createDataTable(chart, options, "column", this.library);
927
+ setFormatOptions$1(chart, options, chartType);
928
+ var data = createDataTable(chart, options, "column");
925
929
  if (chartType !== "bar") {
926
930
  setLabelSize(chart, data, options);
927
931
  }
928
- this.drawChart(chart, (chartType === "bar" ? "horizontalBar" : "bar"), data, options);
932
+ this.drawChart(chart, "bar", data, options);
929
933
  };
930
934
 
931
- defaultExport.prototype.renderAreaChart = function renderAreaChart (chart) {
935
+ defaultExport$2.prototype.renderAreaChart = function renderAreaChart (chart) {
932
936
  this.renderLineChart(chart, "area");
933
937
  };
934
938
 
935
- defaultExport.prototype.renderBarChart = function renderBarChart (chart) {
939
+ defaultExport$2.prototype.renderBarChart = function renderBarChart (chart) {
936
940
  this.renderColumnChart(chart, "bar");
937
941
  };
938
942
 
939
- defaultExport.prototype.renderScatterChart = function renderScatterChart (chart, chartType) {
943
+ defaultExport$2.prototype.renderScatterChart = function renderScatterChart (chart, chartType) {
940
944
  chartType = chartType || "scatter";
941
945
 
942
- var options = jsOptions(chart, chart.options);
943
- setFormatOptions(chart, options, chartType);
946
+ var options = jsOptions$2(chart, chart.options);
947
+ setFormatOptions$1(chart, options, chartType);
944
948
 
945
- if (!("showLines" in options)) {
946
- options.showLines = false;
949
+ if (!("showLine" in options)) {
950
+ options.showLine = false;
947
951
  }
948
952
 
949
- var data = createDataTable(chart, options, chartType, this.library);
953
+ var data = createDataTable(chart, options, chartType);
950
954
 
951
- options.scales.xAxes[0].type = "linear";
952
- options.scales.xAxes[0].position = "bottom";
955
+ options.scales.x.type = "linear";
956
+ options.scales.x.position = "bottom";
957
+
958
+ // prevent grouping hover and tooltips
959
+ if (!("mode" in options.interaction)) {
960
+ options.interaction.mode = "nearest";
961
+ }
953
962
 
954
963
  this.drawChart(chart, chartType, data, options);
955
964
  };
956
965
 
957
- defaultExport.prototype.renderBubbleChart = function renderBubbleChart (chart) {
966
+ defaultExport$2.prototype.renderBubbleChart = function renderBubbleChart (chart) {
958
967
  this.renderScatterChart(chart, "bubble");
959
968
  };
960
969
 
961
- defaultExport.prototype.destroy = function destroy (chart) {
970
+ defaultExport$2.prototype.destroy = function destroy (chart) {
962
971
  if (chart.chart) {
963
972
  chart.chart.destroy();
964
973
  }
965
974
  };
966
975
 
967
- defaultExport.prototype.drawChart = function drawChart (chart, type, data, options) {
976
+ defaultExport$2.prototype.drawChart = function drawChart (chart, type, data, options) {
968
977
  this.destroy(chart);
978
+ if (chart.destroyed) { return; }
969
979
 
970
980
  var chartOptions = {
971
981
  type: type,
@@ -1024,6 +1034,9 @@
1024
1034
  series: {
1025
1035
  marker: {}
1026
1036
  }
1037
+ },
1038
+ time: {
1039
+ useUTC: false
1027
1040
  }
1028
1041
  };
1029
1042
 
@@ -1073,7 +1086,7 @@
1073
1086
 
1074
1087
  var jsOptions$1 = jsOptionsFunc(defaultOptions$1, hideLegend$1, setTitle$1, setMin$1, setMax$1, setStacked$1, setXtitle$1, setYtitle$1);
1075
1088
 
1076
- var setFormatOptions$1 = function(chart, options, chartType) {
1089
+ var setFormatOptions = function(chart, options, chartType) {
1077
1090
  var formatOptions = {
1078
1091
  prefix: chart.options.prefix,
1079
1092
  suffix: chart.options.suffix,
@@ -1136,7 +1149,7 @@
1136
1149
  if (!options.chart.type) {
1137
1150
  options.chart.type = chartType;
1138
1151
  }
1139
- setFormatOptions$1(chart, options, chartType);
1152
+ setFormatOptions(chart, options, chartType);
1140
1153
 
1141
1154
  var series = chart.data;
1142
1155
  for (i = 0; i < series.length; i++) {
@@ -1181,7 +1194,7 @@
1181
1194
  }
1182
1195
 
1183
1196
  var options = merge(chartOptions, chart.options.library || {});
1184
- setFormatOptions$1(chart, options, "pie");
1197
+ setFormatOptions(chart, options, "pie");
1185
1198
  var series = [{
1186
1199
  type: "pie",
1187
1200
  name: chart.options.label || "Value",
@@ -1196,7 +1209,7 @@
1196
1209
  var series = chart.data;
1197
1210
  var options = jsOptions$1(chart, chart.options), i, j, s, d, rows = [], categories = [];
1198
1211
  options.chart.type = chartType;
1199
- setFormatOptions$1(chart, options, chartType);
1212
+ setFormatOptions(chart, options, chartType);
1200
1213
 
1201
1214
  for (i = 0; i < series.length; i++) {
1202
1215
  s = series[i];
@@ -1254,6 +1267,7 @@
1254
1267
 
1255
1268
  defaultExport$1.prototype.drawChart = function drawChart (chart, data, options) {
1256
1269
  this.destroy(chart);
1270
+ if (chart.destroyed) { return; }
1257
1271
 
1258
1272
  options.chart.renderTo = chart.element.id;
1259
1273
  options.series = data;
@@ -1269,7 +1283,7 @@
1269
1283
  var callbacks = [];
1270
1284
 
1271
1285
  // Set chart options
1272
- var defaultOptions$2 = {
1286
+ var defaultOptions = {
1273
1287
  chartArea: {},
1274
1288
  fontName: "'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif",
1275
1289
  pointSize: 6,
@@ -1311,7 +1325,7 @@
1311
1325
  }
1312
1326
  };
1313
1327
 
1314
- var hideLegend$2 = function (options, legend, hideLegend) {
1328
+ var hideLegend = function (options, legend, hideLegend) {
1315
1329
  if (legend !== undefined) {
1316
1330
  var position;
1317
1331
  if (!legend) {
@@ -1327,42 +1341,42 @@
1327
1341
  }
1328
1342
  };
1329
1343
 
1330
- var setTitle$2 = function (options, title) {
1344
+ var setTitle = function (options, title) {
1331
1345
  options.title = title;
1332
1346
  options.titleTextStyle = {color: "#333", fontSize: "20px"};
1333
1347
  };
1334
1348
 
1335
- var setMin$2 = function (options, min) {
1349
+ var setMin = function (options, min) {
1336
1350
  options.vAxis.viewWindow.min = min;
1337
1351
  };
1338
1352
 
1339
- var setMax$2 = function (options, max) {
1353
+ var setMax = function (options, max) {
1340
1354
  options.vAxis.viewWindow.max = max;
1341
1355
  };
1342
1356
 
1343
- var setBarMin$1 = function (options, min) {
1357
+ var setBarMin = function (options, min) {
1344
1358
  options.hAxis.viewWindow.min = min;
1345
1359
  };
1346
1360
 
1347
- var setBarMax$1 = function (options, max) {
1361
+ var setBarMax = function (options, max) {
1348
1362
  options.hAxis.viewWindow.max = max;
1349
1363
  };
1350
1364
 
1351
- var setStacked$2 = function (options, stacked) {
1365
+ var setStacked = function (options, stacked) {
1352
1366
  options.isStacked = stacked ? stacked : false;
1353
1367
  };
1354
1368
 
1355
- var setXtitle$2 = function (options, title) {
1369
+ var setXtitle = function (options, title) {
1356
1370
  options.hAxis.title = title;
1357
1371
  options.hAxis.titleTextStyle.italic = false;
1358
1372
  };
1359
1373
 
1360
- var setYtitle$2 = function (options, title) {
1374
+ var setYtitle = function (options, title) {
1361
1375
  options.vAxis.title = title;
1362
1376
  options.vAxis.titleTextStyle.italic = false;
1363
1377
  };
1364
1378
 
1365
- var jsOptions$2 = jsOptionsFunc(defaultOptions$2, hideLegend$2, setTitle$2, setMin$2, setMax$2, setStacked$2, setXtitle$2, setYtitle$2);
1379
+ var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
1366
1380
 
1367
1381
  var resize = function (callback) {
1368
1382
  if (window.attachEvent) {
@@ -1373,12 +1387,12 @@
1373
1387
  callback();
1374
1388
  };
1375
1389
 
1376
- var defaultExport$2 = function defaultExport(library) {
1390
+ var defaultExport = function defaultExport(library) {
1377
1391
  this.name = "google";
1378
1392
  this.library = library;
1379
1393
  };
1380
1394
 
1381
- defaultExport$2.prototype.renderLineChart = function renderLineChart (chart) {
1395
+ defaultExport.prototype.renderLineChart = function renderLineChart (chart) {
1382
1396
  var this$1 = this;
1383
1397
 
1384
1398
  this.waitForLoaded(chart, function () {
@@ -1392,14 +1406,14 @@
1392
1406
  chartOptions.pointSize = 0;
1393
1407
  }
1394
1408
 
1395
- var options = jsOptions$2(chart, chart.options, chartOptions);
1409
+ var options = jsOptions(chart, chart.options, chartOptions);
1396
1410
  var data = this$1.createDataTable(chart.data, chart.xtype);
1397
1411
 
1398
1412
  this$1.drawChart(chart, "LineChart", data, options);
1399
1413
  });
1400
1414
  };
1401
1415
 
1402
- defaultExport$2.prototype.renderPieChart = function renderPieChart (chart) {
1416
+ defaultExport.prototype.renderPieChart = function renderPieChart (chart) {
1403
1417
  var this$1 = this;
1404
1418
 
1405
1419
  this.waitForLoaded(chart, function () {
@@ -1417,12 +1431,12 @@
1417
1431
  chartOptions.pieHole = 0.5;
1418
1432
  }
1419
1433
  if ("legend" in chart.options) {
1420
- hideLegend$2(chartOptions, chart.options.legend);
1434
+ hideLegend(chartOptions, chart.options.legend);
1421
1435
  }
1422
1436
  if (chart.options.title) {
1423
- setTitle$2(chartOptions, chart.options.title);
1437
+ setTitle(chartOptions, chart.options.title);
1424
1438
  }
1425
- var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1439
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
1426
1440
 
1427
1441
  var data = new this$1.library.visualization.DataTable();
1428
1442
  data.addColumn("string", "");
@@ -1433,18 +1447,18 @@
1433
1447
  });
1434
1448
  };
1435
1449
 
1436
- defaultExport$2.prototype.renderColumnChart = function renderColumnChart (chart) {
1450
+ defaultExport.prototype.renderColumnChart = function renderColumnChart (chart) {
1437
1451
  var this$1 = this;
1438
1452
 
1439
1453
  this.waitForLoaded(chart, function () {
1440
- var options = jsOptions$2(chart, chart.options);
1454
+ var options = jsOptions(chart, chart.options);
1441
1455
  var data = this$1.createDataTable(chart.data, chart.xtype);
1442
1456
 
1443
1457
  this$1.drawChart(chart, "ColumnChart", data, options);
1444
1458
  });
1445
1459
  };
1446
1460
 
1447
- defaultExport$2.prototype.renderBarChart = function renderBarChart (chart) {
1461
+ defaultExport.prototype.renderBarChart = function renderBarChart (chart) {
1448
1462
  var this$1 = this;
1449
1463
 
1450
1464
  this.waitForLoaded(chart, function () {
@@ -1455,14 +1469,14 @@
1455
1469
  }
1456
1470
  }
1457
1471
  };
1458
- var options = jsOptionsFunc(defaultOptions$2, hideLegend$2, setTitle$2, setBarMin$1, setBarMax$1, setStacked$2, setXtitle$2, setYtitle$2)(chart, chart.options, chartOptions);
1472
+ var options = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart, chart.options, chartOptions);
1459
1473
  var data = this$1.createDataTable(chart.data, chart.xtype);
1460
1474
 
1461
1475
  this$1.drawChart(chart, "BarChart", data, options);
1462
1476
  });
1463
1477
  };
1464
1478
 
1465
- defaultExport$2.prototype.renderAreaChart = function renderAreaChart (chart) {
1479
+ defaultExport.prototype.renderAreaChart = function renderAreaChart (chart) {
1466
1480
  var this$1 = this;
1467
1481
 
1468
1482
  this.waitForLoaded(chart, function () {
@@ -1472,14 +1486,14 @@
1472
1486
  areaOpacity: 0.5
1473
1487
  };
1474
1488
 
1475
- var options = jsOptions$2(chart, chart.options, chartOptions);
1489
+ var options = jsOptions(chart, chart.options, chartOptions);
1476
1490
  var data = this$1.createDataTable(chart.data, chart.xtype);
1477
1491
 
1478
1492
  this$1.drawChart(chart, "AreaChart", data, options);
1479
1493
  });
1480
1494
  };
1481
1495
 
1482
- defaultExport$2.prototype.renderGeoChart = function renderGeoChart (chart) {
1496
+ defaultExport.prototype.renderGeoChart = function renderGeoChart (chart) {
1483
1497
  var this$1 = this;
1484
1498
 
1485
1499
  this.waitForLoaded(chart, "geochart", function () {
@@ -1489,7 +1503,7 @@
1489
1503
  colors: chart.options.colors || ["#f6c7b6", "#ce502d"]
1490
1504
  }
1491
1505
  };
1492
- var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1506
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
1493
1507
 
1494
1508
  var data = new this$1.library.visualization.DataTable();
1495
1509
  data.addColumn("string", "");
@@ -1500,12 +1514,12 @@
1500
1514
  });
1501
1515
  };
1502
1516
 
1503
- defaultExport$2.prototype.renderScatterChart = function renderScatterChart (chart) {
1517
+ defaultExport.prototype.renderScatterChart = function renderScatterChart (chart) {
1504
1518
  var this$1 = this;
1505
1519
 
1506
1520
  this.waitForLoaded(chart, function () {
1507
1521
  var chartOptions = {};
1508
- var options = jsOptions$2(chart, chart.options, chartOptions);
1522
+ var options = jsOptions(chart, chart.options, chartOptions);
1509
1523
 
1510
1524
  var series = chart.data, rows2 = [], i, j, data, d;
1511
1525
  for (i = 0; i < series.length; i++) {
@@ -1530,7 +1544,7 @@
1530
1544
  });
1531
1545
  };
1532
1546
 
1533
- defaultExport$2.prototype.renderTimeline = function renderTimeline (chart) {
1547
+ defaultExport.prototype.renderTimeline = function renderTimeline (chart) {
1534
1548
  var this$1 = this;
1535
1549
 
1536
1550
  this.waitForLoaded(chart, "timeline", function () {
@@ -1541,7 +1555,7 @@
1541
1555
  if (chart.options.colors) {
1542
1556
  chartOptions.colors = chart.options.colors;
1543
1557
  }
1544
- var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1558
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
1545
1559
 
1546
1560
  var data = new this$1.library.visualization.DataTable();
1547
1561
  data.addColumn({type: "string", id: "Name"});
@@ -1555,14 +1569,16 @@
1555
1569
  });
1556
1570
  };
1557
1571
 
1558
- defaultExport$2.prototype.destroy = function destroy (chart) {
1572
+ // TODO remove resize events
1573
+ defaultExport.prototype.destroy = function destroy (chart) {
1559
1574
  if (chart.chart) {
1560
1575
  chart.chart.clearChart();
1561
1576
  }
1562
1577
  };
1563
1578
 
1564
- defaultExport$2.prototype.drawChart = function drawChart (chart, type, data, options) {
1579
+ defaultExport.prototype.drawChart = function drawChart (chart, type, data, options) {
1565
1580
  this.destroy(chart);
1581
+ if (chart.destroyed) { return; }
1566
1582
 
1567
1583
  if (chart.options.code) {
1568
1584
  window.console.log("var data = new google.visualization.DataTable(" + data.toJSON() + ");\nvar chart = new google.visualization." + type + "(element);\nchart.draw(data, " + JSON.stringify(options) + ");");
@@ -1574,7 +1590,7 @@
1574
1590
  });
1575
1591
  };
1576
1592
 
1577
- defaultExport$2.prototype.waitForLoaded = function waitForLoaded (chart, pack, callback) {
1593
+ defaultExport.prototype.waitForLoaded = function waitForLoaded (chart, pack, callback) {
1578
1594
  var this$1 = this;
1579
1595
 
1580
1596
  if (!callback) {
@@ -1606,7 +1622,7 @@
1606
1622
  }
1607
1623
  };
1608
1624
 
1609
- defaultExport$2.prototype.runCallbacks = function runCallbacks () {
1625
+ defaultExport.prototype.runCallbacks = function runCallbacks () {
1610
1626
  var cb, call;
1611
1627
  for (var i = 0; i < callbacks.length; i++) {
1612
1628
  cb = callbacks[i];
@@ -1620,7 +1636,7 @@
1620
1636
  };
1621
1637
 
1622
1638
  // cant use object as key
1623
- defaultExport$2.prototype.createDataTable = function createDataTable (series, columnType) {
1639
+ defaultExport.prototype.createDataTable = function createDataTable (series, columnType) {
1624
1640
  var i, j, s, d, key, rows = [], sortedLabels = [];
1625
1641
  for (i = 0; i < series.length; i++) {
1626
1642
  s = series[i];
@@ -1676,6 +1692,202 @@
1676
1692
  return data;
1677
1693
  };
1678
1694
 
1695
+ function formatSeriesData(data, keyType) {
1696
+ var r = [], j, keyFunc;
1697
+
1698
+ if (keyType === "number") {
1699
+ keyFunc = toFloat;
1700
+ } else if (keyType === "datetime") {
1701
+ keyFunc = toDate;
1702
+ } else {
1703
+ keyFunc = toStr;
1704
+ }
1705
+
1706
+ if (keyType === "bubble") {
1707
+ for (j = 0; j < data.length; j++) {
1708
+ r.push([toFloat(data[j][0]), toFloat(data[j][1]), toFloat(data[j][2])]);
1709
+ }
1710
+ } else {
1711
+ for (j = 0; j < data.length; j++) {
1712
+ r.push([keyFunc(data[j][0]), toFloat(data[j][1])]);
1713
+ }
1714
+ }
1715
+
1716
+ if (keyType === "datetime") {
1717
+ r.sort(sortByTime);
1718
+ } else if (keyType === "number") {
1719
+ r.sort(sortByNumberSeries);
1720
+ }
1721
+
1722
+ return r;
1723
+ }
1724
+ function detectXType(series, noDatetime, options) {
1725
+ if (dataEmpty(series)) {
1726
+ if ((options.xmin || options.xmax) && (!options.xmin || isDate(options.xmin)) && (!options.xmax || isDate(options.xmax))) {
1727
+ return "datetime";
1728
+ } else {
1729
+ return "number";
1730
+ }
1731
+ } else if (detectXTypeWithFunction(series, isNumber)) {
1732
+ return "number";
1733
+ } else if (!noDatetime && detectXTypeWithFunction(series, isDate)) {
1734
+ return "datetime";
1735
+ } else {
1736
+ return "string";
1737
+ }
1738
+ }
1739
+
1740
+ function detectXTypeWithFunction(series, func) {
1741
+ var i, j, data;
1742
+ for (i = 0; i < series.length; i++) {
1743
+ data = toArr(series[i].data);
1744
+ for (j = 0; j < data.length; j++) {
1745
+ if (!func(data[j][0])) {
1746
+ return false;
1747
+ }
1748
+ }
1749
+ }
1750
+ return true;
1751
+ }
1752
+
1753
+ // creates a shallow copy of each element of the array
1754
+ // elements are expected to be objects
1755
+ function copySeries(series) {
1756
+ var newSeries = [], i, j;
1757
+ for (i = 0; i < series.length; i++) {
1758
+ var copy = {};
1759
+ for (j in series[i]) {
1760
+ if (series[i].hasOwnProperty(j)) {
1761
+ copy[j] = series[i][j];
1762
+ }
1763
+ }
1764
+ newSeries.push(copy);
1765
+ }
1766
+ return newSeries;
1767
+ }
1768
+
1769
+ function processSeries(chart, keyType, noDatetime) {
1770
+ var i;
1771
+
1772
+ var opts = chart.options;
1773
+ var series = chart.rawData;
1774
+
1775
+ // see if one series or multiple
1776
+ chart.singleSeriesFormat = (!isArray(series) || typeof series[0] !== "object" || isArray(series[0]));
1777
+ if (chart.singleSeriesFormat) {
1778
+ series = [{name: opts.label, data: series}];
1779
+ }
1780
+
1781
+ // convert to array
1782
+ // must come before dataEmpty check
1783
+ series = copySeries(series);
1784
+ for (i = 0; i < series.length; i++) {
1785
+ series[i].data = toArr(series[i].data);
1786
+ }
1787
+
1788
+ chart.xtype = keyType ? keyType : (opts.discrete ? "string" : detectXType(series, noDatetime, opts));
1789
+
1790
+ // right format
1791
+ for (i = 0; i < series.length; i++) {
1792
+ series[i].data = formatSeriesData(series[i].data, chart.xtype);
1793
+ }
1794
+
1795
+ return series;
1796
+ }
1797
+
1798
+ function processSimple(chart) {
1799
+ var perfectData = toArr(chart.rawData), i;
1800
+ for (i = 0; i < perfectData.length; i++) {
1801
+ perfectData[i] = [toStr(perfectData[i][0]), toFloat(perfectData[i][1])];
1802
+ }
1803
+ return perfectData;
1804
+ }
1805
+
1806
+ function dataEmpty(data, chartType) {
1807
+ if (chartType === "PieChart" || chartType === "GeoChart" || chartType === "Timeline") {
1808
+ return data.length === 0;
1809
+ } else {
1810
+ for (var i = 0; i < data.length; i++) {
1811
+ if (data[i].data.length > 0) {
1812
+ return false;
1813
+ }
1814
+ }
1815
+ return true;
1816
+ }
1817
+ }
1818
+
1819
+ function addDownloadButton(chart) {
1820
+ var element = chart.element;
1821
+ var link = document.createElement("a");
1822
+
1823
+ var download = chart.options.download;
1824
+ if (download === true) {
1825
+ download = {};
1826
+ } else if (typeof download === "string") {
1827
+ download = {filename: download};
1828
+ }
1829
+ link.download = download.filename || "chart.png"; // https://caniuse.com/download
1830
+
1831
+ link.style.position = "absolute";
1832
+ link.style.top = "20px";
1833
+ link.style.right = "20px";
1834
+ link.style.zIndex = 1000;
1835
+ link.style.lineHeight = "20px";
1836
+ link.target = "_blank"; // for safari
1837
+ var image = document.createElement("img");
1838
+ image.alt = "Download";
1839
+ image.style.border = "none";
1840
+ // icon from font-awesome
1841
+ // http://fa2png.io/
1842
+ image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAABCFBMVEUAAADMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMywEsqxAAAAV3RSTlMAAQIDBggJCgsMDQ4PERQaHB0eISIjJCouLzE0OTo/QUJHSUpLTU5PUllhYmltcHh5foWLjI+SlaCio6atr7S1t7m6vsHHyM7R2tze5Obo7fHz9ff5+/1hlxK2AAAA30lEQVQYGUXBhVYCQQBA0TdYWAt2d3d3YWAHyur7/z9xgD16Lw0DW+XKx+1GgX+FRzM3HWQWrHl5N/oapW5RPe0PkBu+UYeICvozTWZVK23Ao04B79oJrOsJDOoxkZoQPWgX29pHpCZEk7rEvQYiNSFq1UMqvlCjJkRBS1R8hb00Vb/TajtBL7nTHE1X1vyMQF732dQhyF2o6SAwrzP06iUQzvwsArlnzcOdrgBhJyHa1QOgO9U1GsKuvjUTjavliZYQ8nNPapG6sap/3nrIdJ6bOWzmX/fy0XVpfzZP3S8OJT3g9EEiJwAAAABJRU5ErkJggg==";
1843
+ link.appendChild(image);
1844
+ element.style.position = "relative";
1845
+
1846
+ chart.__downloadAttached = true;
1847
+
1848
+ // mouseenter
1849
+ chart.__enterEvent = addEvent(element, "mouseover", function(e) {
1850
+ var related = e.relatedTarget;
1851
+ // check download option again to ensure it wasn't changed
1852
+ if ((!related || (related !== this && !childOf(this, related))) && chart.options.download) {
1853
+ link.href = chart.toImage(download);
1854
+ element.appendChild(link);
1855
+ }
1856
+ });
1857
+
1858
+ // mouseleave
1859
+ chart.__leaveEvent = addEvent(element, "mouseout", function(e) {
1860
+ var related = e.relatedTarget;
1861
+ if (!related || (related !== this && !childOf(this, related))) {
1862
+ if (link.parentNode) {
1863
+ link.parentNode.removeChild(link);
1864
+ }
1865
+ }
1866
+ });
1867
+ }
1868
+
1869
+ // https://stackoverflow.com/questions/10149963/adding-event-listener-cross-browser
1870
+ function addEvent(elem, event, fn) {
1871
+ if (elem.addEventListener) {
1872
+ elem.addEventListener(event, fn, false);
1873
+ return fn;
1874
+ } else {
1875
+ var fn2 = function() {
1876
+ // set the this pointer same as addEventListener when fn is called
1877
+ return(fn.call(elem, window.event));
1878
+ };
1879
+ elem.attachEvent("on" + event, fn2);
1880
+ return fn2;
1881
+ }
1882
+ }
1883
+
1884
+ // https://gist.github.com/shawnbot/4166283
1885
+ function childOf(p, c) {
1886
+ if (p === c) { return false; }
1887
+ while (c && c !== p) { c = c.parentNode; }
1888
+ return c === p;
1889
+ }
1890
+
1679
1891
  var pendingRequests = [], runningRequests = 0, maxRequests = 4;
1680
1892
 
1681
1893
  function pushRequest(url, success, error) {
@@ -1764,7 +1976,12 @@
1764
1976
  }
1765
1977
  }
1766
1978
 
1767
- function fetchDataSource(chart, dataSource) {
1979
+ function fetchDataSource(chart, dataSource, showLoading) {
1980
+ // only show loading message for urls and callbacks
1981
+ if (showLoading && chart.options.loading && (typeof dataSource === "string" || typeof dataSource === "function")) {
1982
+ setText(chart.element, chart.options.loading);
1983
+ }
1984
+
1768
1985
  if (typeof dataSource === "string") {
1769
1986
  pushRequest(dataSource, function (data) {
1770
1987
  chart.rawData = data;
@@ -1789,94 +2006,14 @@
1789
2006
  }
1790
2007
  }
1791
2008
 
1792
- function addDownloadButton(chart) {
1793
- var element = chart.element;
1794
- var link = document.createElement("a");
1795
-
1796
- var download = chart.options.download;
1797
- if (download === true) {
1798
- download = {};
1799
- } else if (typeof download === "string") {
1800
- download = {filename: download};
1801
- }
1802
- link.download = download.filename || "chart.png"; // https://caniuse.com/download
1803
-
1804
- link.style.position = "absolute";
1805
- link.style.top = "20px";
1806
- link.style.right = "20px";
1807
- link.style.zIndex = 1000;
1808
- link.style.lineHeight = "20px";
1809
- link.target = "_blank"; // for safari
1810
- var image = document.createElement("img");
1811
- image.alt = "Download";
1812
- image.style.border = "none";
1813
- // icon from font-awesome
1814
- // http://fa2png.io/
1815
- image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAMAAAC6V+0/AAABCFBMVEUAAADMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMywEsqxAAAAV3RSTlMAAQIDBggJCgsMDQ4PERQaHB0eISIjJCouLzE0OTo/QUJHSUpLTU5PUllhYmltcHh5foWLjI+SlaCio6atr7S1t7m6vsHHyM7R2tze5Obo7fHz9ff5+/1hlxK2AAAA30lEQVQYGUXBhVYCQQBA0TdYWAt2d3d3YWAHyur7/z9xgD16Lw0DW+XKx+1GgX+FRzM3HWQWrHl5N/oapW5RPe0PkBu+UYeICvozTWZVK23Ao04B79oJrOsJDOoxkZoQPWgX29pHpCZEk7rEvQYiNSFq1UMqvlCjJkRBS1R8hb00Vb/TajtBL7nTHE1X1vyMQF732dQhyF2o6SAwrzP06iUQzvwsArlnzcOdrgBhJyHa1QOgO9U1GsKuvjUTjavliZYQ8nNPapG6sap/3nrIdJ6bOWzmX/fy0XVpfzZP3S8OJT3g9EEiJwAAAABJRU5ErkJggg==";
1816
- link.appendChild(image);
1817
- element.style.position = "relative";
1818
-
1819
- chart.__downloadAttached = true;
1820
-
1821
- // mouseenter
1822
- chart.__enterEvent = addEvent(element, "mouseover", function(e) {
1823
- var related = e.relatedTarget;
1824
- // check download option again to ensure it wasn't changed
1825
- if ((!related || (related !== this && !childOf(this, related))) && chart.options.download) {
1826
- link.href = chart.toImage(download);
1827
- element.appendChild(link);
1828
- }
1829
- });
1830
-
1831
- // mouseleave
1832
- chart.__leaveEvent = addEvent(element, "mouseout", function(e) {
1833
- var related = e.relatedTarget;
1834
- if (!related || (related !== this && !childOf(this, related))) {
1835
- if (link.parentNode) {
1836
- link.parentNode.removeChild(link);
1837
- }
1838
- }
1839
- });
1840
- }
1841
-
1842
- // https://stackoverflow.com/questions/10149963/adding-event-listener-cross-browser
1843
- function addEvent(elem, event, fn) {
1844
- if (elem.addEventListener) {
1845
- elem.addEventListener(event, fn, false);
1846
- return fn;
1847
- } else {
1848
- var fn2 = function() {
1849
- // set the this pointer same as addEventListener when fn is called
1850
- return(fn.call(elem, window.event));
1851
- };
1852
- elem.attachEvent("on" + event, fn2);
1853
- return fn2;
1854
- }
1855
- }
1856
-
1857
- function removeEvent(elem, event, fn) {
1858
- if (elem.removeEventListener) {
1859
- elem.removeEventListener(event, fn, false);
1860
- } else {
1861
- elem.detachEvent("on" + event, fn);
1862
- }
1863
- }
1864
-
1865
- // https://gist.github.com/shawnbot/4166283
1866
- function childOf(p, c) {
1867
- if (p === c) { return false; }
1868
- while (c && c !== p) { c = c.parentNode; }
1869
- return c === p;
1870
- }
1871
-
1872
2009
  function getAdapterType(library) {
1873
2010
  if (library) {
1874
2011
  if (library.product === "Highcharts") {
1875
2012
  return defaultExport$1;
1876
2013
  } else if (library.charts) {
1877
- return defaultExport$2;
1878
- } else if (isFunction(library)) {
1879
2014
  return defaultExport;
2015
+ } else if (isFunction(library)) {
2016
+ return defaultExport$2;
1880
2017
  }
1881
2018
  }
1882
2019
  throw new Error("Unknown adapter");
@@ -1905,22 +2042,10 @@
1905
2042
  }
1906
2043
  }
1907
2044
 
1908
- function dataEmpty(data, chartType) {
1909
- if (chartType === "PieChart" || chartType === "GeoChart" || chartType === "Timeline") {
1910
- return data.length === 0;
1911
- } else {
1912
- for (var i = 0; i < data.length; i++) {
1913
- if (data[i].data.length > 0) {
1914
- return false;
1915
- }
1916
- }
1917
- return true;
1918
- }
1919
- }
1920
-
1921
2045
  function renderChart(chartType, chart) {
1922
- if (chart.options.messages && chart.options.messages.empty && dataEmpty(chart.data, chartType)) {
1923
- setText(chart.element, chart.options.messages.empty);
2046
+ if (dataEmpty(chart.data, chartType)) {
2047
+ var message = chart.options.empty || (chart.options.messages && chart.options.messages.empty) || "No data";
2048
+ setText(chart.element, message);
1924
2049
  } else {
1925
2050
  callAdapter(chartType, chart);
1926
2051
  if (chart.options.download && !chart.__downloadAttached && chart.adapter === "chartjs") {
@@ -1954,121 +2079,6 @@
1954
2079
  }
1955
2080
  }
1956
2081
 
1957
- // process data
1958
-
1959
- var toFormattedKey = function (key, keyType) {
1960
- if (keyType === "number") {
1961
- key = toFloat(key);
1962
- } else if (keyType === "datetime") {
1963
- key = toDate(key);
1964
- } else {
1965
- key = toStr(key);
1966
- }
1967
- return key;
1968
- };
1969
-
1970
- var formatSeriesData = function (data, keyType) {
1971
- var r = [], key, j;
1972
- for (j = 0; j < data.length; j++) {
1973
- if (keyType === "bubble") {
1974
- r.push([toFloat(data[j][0]), toFloat(data[j][1]), toFloat(data[j][2])]);
1975
- } else {
1976
- key = toFormattedKey(data[j][0], keyType);
1977
- r.push([key, toFloat(data[j][1])]);
1978
- }
1979
- }
1980
- if (keyType === "datetime") {
1981
- r.sort(sortByTime);
1982
- } else if (keyType === "number") {
1983
- r.sort(sortByNumberSeries);
1984
- }
1985
- return r;
1986
- };
1987
-
1988
- function detectXType(series, noDatetime, options) {
1989
- if (dataEmpty(series)) {
1990
- if ((options.xmin || options.xmax) && (!options.xmin || isDate(options.xmin)) && (!options.xmax || isDate(options.xmax))) {
1991
- return "datetime";
1992
- } else {
1993
- return "number";
1994
- }
1995
- } else if (detectXTypeWithFunction(series, isNumber)) {
1996
- return "number";
1997
- } else if (!noDatetime && detectXTypeWithFunction(series, isDate)) {
1998
- return "datetime";
1999
- } else {
2000
- return "string";
2001
- }
2002
- }
2003
-
2004
- function detectXTypeWithFunction(series, func) {
2005
- var i, j, data;
2006
- for (i = 0; i < series.length; i++) {
2007
- data = toArr(series[i].data);
2008
- for (j = 0; j < data.length; j++) {
2009
- if (!func(data[j][0])) {
2010
- return false;
2011
- }
2012
- }
2013
- }
2014
- return true;
2015
- }
2016
-
2017
- // creates a shallow copy of each element of the array
2018
- // elements are expected to be objects
2019
- function copySeries(series) {
2020
- var newSeries = [], i, j;
2021
- for (i = 0; i < series.length; i++) {
2022
- var copy = {};
2023
- for (j in series[i]) {
2024
- if (series[i].hasOwnProperty(j)) {
2025
- copy[j] = series[i][j];
2026
- }
2027
- }
2028
- newSeries.push(copy);
2029
- }
2030
- return newSeries;
2031
- }
2032
-
2033
- function processSeries(chart, keyType, noDatetime) {
2034
- var i;
2035
-
2036
- var opts = chart.options;
2037
- var series = chart.rawData;
2038
-
2039
- // see if one series or multiple
2040
- if (!isArray(series) || typeof series[0] !== "object" || isArray(series[0])) {
2041
- series = [{name: opts.label, data: series}];
2042
- chart.hideLegend = true;
2043
- } else {
2044
- chart.hideLegend = false;
2045
- }
2046
-
2047
- // convert to array
2048
- // must come before dataEmpty check
2049
- series = copySeries(series);
2050
- for (i = 0; i < series.length; i++) {
2051
- series[i].data = toArr(series[i].data);
2052
- }
2053
-
2054
- chart.xtype = keyType ? keyType : (opts.discrete ? "string" : detectXType(series, noDatetime, opts));
2055
-
2056
- // right format
2057
- for (i = 0; i < series.length; i++) {
2058
- series[i].data = formatSeriesData(series[i].data, chart.xtype);
2059
- }
2060
-
2061
- return series;
2062
- }
2063
-
2064
- function processSimple(chart) {
2065
- var perfectData = toArr(chart.rawData), i;
2066
- for (i = 0; i < perfectData.length; i++) {
2067
- perfectData[i] = [toStr(perfectData[i][0]), toFloat(perfectData[i][1])];
2068
- }
2069
- return perfectData;
2070
- }
2071
-
2072
2082
  // define classes
2073
2083
 
2074
2084
  var Chart = function Chart(element, dataSource, options) {
@@ -2086,7 +2096,7 @@
2086
2096
 
2087
2097
  Chartkick.charts[element.id] = this;
2088
2098
 
2089
- fetchDataSource(this, dataSource);
2099
+ fetchDataSource(this, dataSource, true);
2090
2100
 
2091
2101
  if (this.options.refresh) {
2092
2102
  this.startRefresh();
@@ -2122,7 +2132,7 @@
2122
2132
  if (options) {
2123
2133
  this.__updateOptions(options);
2124
2134
  }
2125
- fetchDataSource(this, dataSource);
2135
+ fetchDataSource(this, dataSource, true);
2126
2136
  };
2127
2137
 
2128
2138
  Chart.prototype.setOptions = function setOptions (options) {
@@ -2176,8 +2186,8 @@
2176
2186
  if (this.adapter === "chartjs") {
2177
2187
  if (download && download.background && download.background !== "transparent") {
2178
2188
  // https://stackoverflow.com/questions/30464750/chartjs-line-chart-set-background-color
2179
- var canvas = this.chart.chart.canvas;
2180
- var ctx = this.chart.chart.ctx;
2189
+ var canvas = this.chart.canvas;
2190
+ var ctx = this.chart.ctx;
2181
2191
  var tmpCanvas = document.createElement("canvas");
2182
2192
  var tmpCtx = tmpCanvas.getContext("2d");
2183
2193
  tmpCanvas.width = ctx.canvas.width;
@@ -2190,13 +2200,14 @@
2190
2200
  return this.chart.toBase64Image();
2191
2201
  }
2192
2202
  } else {
2193
- // TODO throw error in next major version
2194
- // throw new Error("Feature only available for Chart.js");
2195
- return null;
2203
+ throw new Error("Feature only available for Chart.js");
2196
2204
  }
2197
2205
  };
2198
2206
 
2199
2207
  Chart.prototype.destroy = function destroy () {
2208
+ this.destroyed = true;
2209
+ this.stopRefresh();
2210
+
2200
2211
  if (this.__adapterObject) {
2201
2212
  this.__adapterObject.destroy(this);
2202
2213
  }
@@ -2441,6 +2452,14 @@
2441
2452
  }
2442
2453
  }
2443
2454
  },
2455
+ destroyAll: function() {
2456
+ for (var chartId in Chartkick.charts) {
2457
+ if (Chartkick.charts.hasOwnProperty(chartId)) {
2458
+ Chartkick.charts[chartId].destroy();
2459
+ delete Chartkick.charts[chartId];
2460
+ }
2461
+ }
2462
+ },
2444
2463
  config: config,
2445
2464
  options: {},
2446
2465
  adapters: adapters,
@@ -2454,6 +2473,16 @@
2454
2473
  // not ideal, but allows for simpler integration
2455
2474
  if (typeof window !== "undefined" && !window.Chartkick) {
2456
2475
  window.Chartkick = Chartkick;
2476
+
2477
+ // clean up previous charts before Turbolinks loads new page
2478
+ document.addEventListener("turbolinks:before-render", function() {
2479
+ Chartkick.destroyAll();
2480
+ });
2481
+
2482
+ // use setTimeout so charting library can come later in same JS file
2483
+ setTimeout(function() {
2484
+ window.dispatchEvent(new Event("chartkick:load"));
2485
+ }, 0);
2457
2486
  }
2458
2487
 
2459
2488
  // backwards compatibility for esm require