chartkick 3.4.2 → 4.0.4

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.4
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,43 +794,47 @@
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
 
820
818
  if (step && timeDiff > 0) {
821
- var unitStepSize = Math.ceil(timeDiff / step / (chart.element.offsetWidth / 100.0));
822
- if (week && step === 1) {
823
- unitStepSize = Math.ceil(unitStepSize / 7.0) * 7;
819
+ // width not available for hidden elements
820
+ var width = chart.element.offsetWidth;
821
+ if (width > 0) {
822
+ var unitStepSize = Math.ceil(timeDiff / step / (width / 100.0));
823
+ if (week && step === 1) {
824
+ unitStepSize = Math.ceil(unitStepSize / 7.0) * 7;
825
+ }
826
+ options.scales.x.time.stepSize = unitStepSize;
824
827
  }
825
- options.scales.xAxes[0].time.unitStepSize = unitStepSize;
826
828
  }
827
829
  }
828
830
 
829
- if (!options.scales.xAxes[0].time.tooltipFormat) {
831
+ if (!options.scales.x.time.tooltipFormat) {
830
832
  if (day) {
831
- options.scales.xAxes[0].time.tooltipFormat = "ll";
833
+ options.scales.x.time.tooltipFormat = "PP";
832
834
  } else if (hour) {
833
- options.scales.xAxes[0].time.tooltipFormat = "MMM D, h a";
835
+ options.scales.x.time.tooltipFormat = "MMM d, h a";
834
836
  } else if (minute) {
835
- options.scales.xAxes[0].time.tooltipFormat = "h:mm a";
837
+ options.scales.x.time.tooltipFormat = "h:mm a";
836
838
  }
837
839
  }
838
840
  }
@@ -845,49 +847,49 @@
845
847
  return data;
846
848
  };
847
849
 
848
- var defaultExport = function defaultExport(library) {
850
+ var defaultExport$2 = function defaultExport(library) {
849
851
  this.name = "chartjs";
850
852
  this.library = library;
851
853
  };
852
854
 
853
- defaultExport.prototype.renderLineChart = function renderLineChart (chart, chartType) {
855
+ defaultExport$2.prototype.renderLineChart = function renderLineChart (chart, chartType) {
854
856
  var chartOptions = {};
855
857
  // fix for https://github.com/chartjs/Chart.js/issues/2441
856
858
  if (!chart.options.max && allZeros(chart.data)) {
857
859
  chartOptions.max = 1;
858
860
  }
859
861
 
860
- var options = jsOptions(chart, merge(chartOptions, chart.options));
861
- setFormatOptions(chart, options, chartType);
862
+ var options = jsOptions$2(chart, merge(chartOptions, chart.options));
863
+ setFormatOptions$1(chart, options, chartType);
862
864
 
863
- var data = createDataTable(chart, options, chartType || "line", this.library);
865
+ var data = createDataTable(chart, options, chartType || "line");
864
866
 
865
867
  if (chart.xtype === "number") {
866
- options.scales.xAxes[0].type = "linear";
867
- options.scales.xAxes[0].position = "bottom";
868
+ options.scales.x.type = "linear";
869
+ options.scales.x.position = "bottom";
868
870
  } else {
869
- options.scales.xAxes[0].type = chart.xtype === "string" ? "category" : "time";
871
+ options.scales.x.type = chart.xtype === "string" ? "category" : "time";
870
872
  }
871
873
 
872
874
  this.drawChart(chart, "line", data, options);
873
875
  };
874
876
 
875
- defaultExport.prototype.renderPieChart = function renderPieChart (chart) {
877
+ defaultExport$2.prototype.renderPieChart = function renderPieChart (chart) {
876
878
  var options = merge({}, baseOptions);
877
879
  if (chart.options.donut) {
878
- options.cutoutPercentage = 50;
880
+ options.cutout = "50%";
879
881
  }
880
882
 
881
883
  if ("legend" in chart.options) {
882
- hideLegend(options, chart.options.legend);
884
+ hideLegend$2(options, chart.options.legend);
883
885
  }
884
886
 
885
887
  if (chart.options.title) {
886
- setTitle(options, chart.options.title);
888
+ setTitle$2(options, chart.options.title);
887
889
  }
888
890
 
889
891
  options = merge(options, chart.options.library || {});
890
- setFormatOptions(chart, options, "pie");
892
+ setFormatOptions$1(chart, options, "pie");
891
893
 
892
894
  var labels = [];
893
895
  var values = [];
@@ -911,61 +913,73 @@
911
913
  this.drawChart(chart, "pie", data, options);
912
914
  };
913
915
 
914
- defaultExport.prototype.renderColumnChart = function renderColumnChart (chart, chartType) {
916
+ defaultExport$2.prototype.renderColumnChart = function renderColumnChart (chart, chartType) {
915
917
  var options;
916
918
  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);
919
+ var barOptions = merge(baseOptions, defaultOptions$2);
920
+ barOptions.indexAxis = "y";
921
+
922
+ // ensure gridlines have proper orientation
923
+ barOptions.scales.x.grid.drawOnChartArea = true;
924
+ barOptions.scales.y.grid.drawOnChartArea = false;
925
+ delete barOptions.scales.y.ticks.maxTicksLimit;
926
+
927
+ options = jsOptionsFunc(barOptions, hideLegend$2, setTitle$2, setBarMin$1, setBarMax$1, setStacked$2, setXtitle$2, setYtitle$2)(chart, chart.options);
920
928
  } else {
921
- options = jsOptions(chart, chart.options);
929
+ options = jsOptions$2(chart, chart.options);
922
930
  }
923
- setFormatOptions(chart, options, chartType);
924
- var data = createDataTable(chart, options, "column", this.library);
931
+ setFormatOptions$1(chart, options, chartType);
932
+ var data = createDataTable(chart, options, "column");
925
933
  if (chartType !== "bar") {
926
934
  setLabelSize(chart, data, options);
927
935
  }
928
- this.drawChart(chart, (chartType === "bar" ? "horizontalBar" : "bar"), data, options);
936
+ this.drawChart(chart, "bar", data, options);
929
937
  };
930
938
 
931
- defaultExport.prototype.renderAreaChart = function renderAreaChart (chart) {
939
+ defaultExport$2.prototype.renderAreaChart = function renderAreaChart (chart) {
932
940
  this.renderLineChart(chart, "area");
933
941
  };
934
942
 
935
- defaultExport.prototype.renderBarChart = function renderBarChart (chart) {
943
+ defaultExport$2.prototype.renderBarChart = function renderBarChart (chart) {
936
944
  this.renderColumnChart(chart, "bar");
937
945
  };
938
946
 
939
- defaultExport.prototype.renderScatterChart = function renderScatterChart (chart, chartType) {
947
+ defaultExport$2.prototype.renderScatterChart = function renderScatterChart (chart, chartType) {
940
948
  chartType = chartType || "scatter";
941
949
 
942
- var options = jsOptions(chart, chart.options);
943
- setFormatOptions(chart, options, chartType);
950
+ var options = jsOptions$2(chart, chart.options);
951
+ setFormatOptions$1(chart, options, chartType);
944
952
 
945
- if (!("showLines" in options)) {
946
- options.showLines = false;
953
+ if (!("showLine" in options)) {
954
+ options.showLine = false;
947
955
  }
948
956
 
949
- var data = createDataTable(chart, options, chartType, this.library);
957
+ var data = createDataTable(chart, options, chartType);
958
+
959
+ options.scales.x.type = "linear";
960
+ options.scales.x.position = "bottom";
950
961
 
951
- options.scales.xAxes[0].type = "linear";
952
- options.scales.xAxes[0].position = "bottom";
962
+ // prevent grouping hover and tooltips
963
+ if (!("mode" in options.interaction)) {
964
+ options.interaction.mode = "nearest";
965
+ }
953
966
 
954
967
  this.drawChart(chart, chartType, data, options);
955
968
  };
956
969
 
957
- defaultExport.prototype.renderBubbleChart = function renderBubbleChart (chart) {
970
+ defaultExport$2.prototype.renderBubbleChart = function renderBubbleChart (chart) {
958
971
  this.renderScatterChart(chart, "bubble");
959
972
  };
960
973
 
961
- defaultExport.prototype.destroy = function destroy (chart) {
974
+ defaultExport$2.prototype.destroy = function destroy (chart) {
962
975
  if (chart.chart) {
963
976
  chart.chart.destroy();
964
977
  }
965
978
  };
966
979
 
967
- defaultExport.prototype.drawChart = function drawChart (chart, type, data, options) {
980
+ defaultExport$2.prototype.drawChart = function drawChart (chart, type, data, options) {
968
981
  this.destroy(chart);
982
+ if (chart.destroyed) { return; }
969
983
 
970
984
  var chartOptions = {
971
985
  type: type,
@@ -1024,6 +1038,9 @@
1024
1038
  series: {
1025
1039
  marker: {}
1026
1040
  }
1041
+ },
1042
+ time: {
1043
+ useUTC: false
1027
1044
  }
1028
1045
  };
1029
1046
 
@@ -1073,7 +1090,7 @@
1073
1090
 
1074
1091
  var jsOptions$1 = jsOptionsFunc(defaultOptions$1, hideLegend$1, setTitle$1, setMin$1, setMax$1, setStacked$1, setXtitle$1, setYtitle$1);
1075
1092
 
1076
- var setFormatOptions$1 = function(chart, options, chartType) {
1093
+ var setFormatOptions = function(chart, options, chartType) {
1077
1094
  var formatOptions = {
1078
1095
  prefix: chart.options.prefix,
1079
1096
  suffix: chart.options.suffix,
@@ -1136,7 +1153,7 @@
1136
1153
  if (!options.chart.type) {
1137
1154
  options.chart.type = chartType;
1138
1155
  }
1139
- setFormatOptions$1(chart, options, chartType);
1156
+ setFormatOptions(chart, options, chartType);
1140
1157
 
1141
1158
  var series = chart.data;
1142
1159
  for (i = 0; i < series.length; i++) {
@@ -1181,7 +1198,7 @@
1181
1198
  }
1182
1199
 
1183
1200
  var options = merge(chartOptions, chart.options.library || {});
1184
- setFormatOptions$1(chart, options, "pie");
1201
+ setFormatOptions(chart, options, "pie");
1185
1202
  var series = [{
1186
1203
  type: "pie",
1187
1204
  name: chart.options.label || "Value",
@@ -1196,7 +1213,7 @@
1196
1213
  var series = chart.data;
1197
1214
  var options = jsOptions$1(chart, chart.options), i, j, s, d, rows = [], categories = [];
1198
1215
  options.chart.type = chartType;
1199
- setFormatOptions$1(chart, options, chartType);
1216
+ setFormatOptions(chart, options, chartType);
1200
1217
 
1201
1218
  for (i = 0; i < series.length; i++) {
1202
1219
  s = series[i];
@@ -1254,6 +1271,7 @@
1254
1271
 
1255
1272
  defaultExport$1.prototype.drawChart = function drawChart (chart, data, options) {
1256
1273
  this.destroy(chart);
1274
+ if (chart.destroyed) { return; }
1257
1275
 
1258
1276
  options.chart.renderTo = chart.element.id;
1259
1277
  options.series = data;
@@ -1269,7 +1287,7 @@
1269
1287
  var callbacks = [];
1270
1288
 
1271
1289
  // Set chart options
1272
- var defaultOptions$2 = {
1290
+ var defaultOptions = {
1273
1291
  chartArea: {},
1274
1292
  fontName: "'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif",
1275
1293
  pointSize: 6,
@@ -1311,7 +1329,7 @@
1311
1329
  }
1312
1330
  };
1313
1331
 
1314
- var hideLegend$2 = function (options, legend, hideLegend) {
1332
+ var hideLegend = function (options, legend, hideLegend) {
1315
1333
  if (legend !== undefined) {
1316
1334
  var position;
1317
1335
  if (!legend) {
@@ -1327,42 +1345,42 @@
1327
1345
  }
1328
1346
  };
1329
1347
 
1330
- var setTitle$2 = function (options, title) {
1348
+ var setTitle = function (options, title) {
1331
1349
  options.title = title;
1332
1350
  options.titleTextStyle = {color: "#333", fontSize: "20px"};
1333
1351
  };
1334
1352
 
1335
- var setMin$2 = function (options, min) {
1353
+ var setMin = function (options, min) {
1336
1354
  options.vAxis.viewWindow.min = min;
1337
1355
  };
1338
1356
 
1339
- var setMax$2 = function (options, max) {
1357
+ var setMax = function (options, max) {
1340
1358
  options.vAxis.viewWindow.max = max;
1341
1359
  };
1342
1360
 
1343
- var setBarMin$1 = function (options, min) {
1361
+ var setBarMin = function (options, min) {
1344
1362
  options.hAxis.viewWindow.min = min;
1345
1363
  };
1346
1364
 
1347
- var setBarMax$1 = function (options, max) {
1365
+ var setBarMax = function (options, max) {
1348
1366
  options.hAxis.viewWindow.max = max;
1349
1367
  };
1350
1368
 
1351
- var setStacked$2 = function (options, stacked) {
1369
+ var setStacked = function (options, stacked) {
1352
1370
  options.isStacked = stacked ? stacked : false;
1353
1371
  };
1354
1372
 
1355
- var setXtitle$2 = function (options, title) {
1373
+ var setXtitle = function (options, title) {
1356
1374
  options.hAxis.title = title;
1357
1375
  options.hAxis.titleTextStyle.italic = false;
1358
1376
  };
1359
1377
 
1360
- var setYtitle$2 = function (options, title) {
1378
+ var setYtitle = function (options, title) {
1361
1379
  options.vAxis.title = title;
1362
1380
  options.vAxis.titleTextStyle.italic = false;
1363
1381
  };
1364
1382
 
1365
- var jsOptions$2 = jsOptionsFunc(defaultOptions$2, hideLegend$2, setTitle$2, setMin$2, setMax$2, setStacked$2, setXtitle$2, setYtitle$2);
1383
+ var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle);
1366
1384
 
1367
1385
  var resize = function (callback) {
1368
1386
  if (window.attachEvent) {
@@ -1373,12 +1391,12 @@
1373
1391
  callback();
1374
1392
  };
1375
1393
 
1376
- var defaultExport$2 = function defaultExport(library) {
1394
+ var defaultExport = function defaultExport(library) {
1377
1395
  this.name = "google";
1378
1396
  this.library = library;
1379
1397
  };
1380
1398
 
1381
- defaultExport$2.prototype.renderLineChart = function renderLineChart (chart) {
1399
+ defaultExport.prototype.renderLineChart = function renderLineChart (chart) {
1382
1400
  var this$1 = this;
1383
1401
 
1384
1402
  this.waitForLoaded(chart, function () {
@@ -1392,14 +1410,14 @@
1392
1410
  chartOptions.pointSize = 0;
1393
1411
  }
1394
1412
 
1395
- var options = jsOptions$2(chart, chart.options, chartOptions);
1413
+ var options = jsOptions(chart, chart.options, chartOptions);
1396
1414
  var data = this$1.createDataTable(chart.data, chart.xtype);
1397
1415
 
1398
1416
  this$1.drawChart(chart, "LineChart", data, options);
1399
1417
  });
1400
1418
  };
1401
1419
 
1402
- defaultExport$2.prototype.renderPieChart = function renderPieChart (chart) {
1420
+ defaultExport.prototype.renderPieChart = function renderPieChart (chart) {
1403
1421
  var this$1 = this;
1404
1422
 
1405
1423
  this.waitForLoaded(chart, function () {
@@ -1417,12 +1435,12 @@
1417
1435
  chartOptions.pieHole = 0.5;
1418
1436
  }
1419
1437
  if ("legend" in chart.options) {
1420
- hideLegend$2(chartOptions, chart.options.legend);
1438
+ hideLegend(chartOptions, chart.options.legend);
1421
1439
  }
1422
1440
  if (chart.options.title) {
1423
- setTitle$2(chartOptions, chart.options.title);
1441
+ setTitle(chartOptions, chart.options.title);
1424
1442
  }
1425
- var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1443
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
1426
1444
 
1427
1445
  var data = new this$1.library.visualization.DataTable();
1428
1446
  data.addColumn("string", "");
@@ -1433,18 +1451,18 @@
1433
1451
  });
1434
1452
  };
1435
1453
 
1436
- defaultExport$2.prototype.renderColumnChart = function renderColumnChart (chart) {
1454
+ defaultExport.prototype.renderColumnChart = function renderColumnChart (chart) {
1437
1455
  var this$1 = this;
1438
1456
 
1439
1457
  this.waitForLoaded(chart, function () {
1440
- var options = jsOptions$2(chart, chart.options);
1458
+ var options = jsOptions(chart, chart.options);
1441
1459
  var data = this$1.createDataTable(chart.data, chart.xtype);
1442
1460
 
1443
1461
  this$1.drawChart(chart, "ColumnChart", data, options);
1444
1462
  });
1445
1463
  };
1446
1464
 
1447
- defaultExport$2.prototype.renderBarChart = function renderBarChart (chart) {
1465
+ defaultExport.prototype.renderBarChart = function renderBarChart (chart) {
1448
1466
  var this$1 = this;
1449
1467
 
1450
1468
  this.waitForLoaded(chart, function () {
@@ -1455,14 +1473,14 @@
1455
1473
  }
1456
1474
  }
1457
1475
  };
1458
- var options = jsOptionsFunc(defaultOptions$2, hideLegend$2, setTitle$2, setBarMin$1, setBarMax$1, setStacked$2, setXtitle$2, setYtitle$2)(chart, chart.options, chartOptions);
1476
+ var options = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart, chart.options, chartOptions);
1459
1477
  var data = this$1.createDataTable(chart.data, chart.xtype);
1460
1478
 
1461
1479
  this$1.drawChart(chart, "BarChart", data, options);
1462
1480
  });
1463
1481
  };
1464
1482
 
1465
- defaultExport$2.prototype.renderAreaChart = function renderAreaChart (chart) {
1483
+ defaultExport.prototype.renderAreaChart = function renderAreaChart (chart) {
1466
1484
  var this$1 = this;
1467
1485
 
1468
1486
  this.waitForLoaded(chart, function () {
@@ -1472,14 +1490,14 @@
1472
1490
  areaOpacity: 0.5
1473
1491
  };
1474
1492
 
1475
- var options = jsOptions$2(chart, chart.options, chartOptions);
1493
+ var options = jsOptions(chart, chart.options, chartOptions);
1476
1494
  var data = this$1.createDataTable(chart.data, chart.xtype);
1477
1495
 
1478
1496
  this$1.drawChart(chart, "AreaChart", data, options);
1479
1497
  });
1480
1498
  };
1481
1499
 
1482
- defaultExport$2.prototype.renderGeoChart = function renderGeoChart (chart) {
1500
+ defaultExport.prototype.renderGeoChart = function renderGeoChart (chart) {
1483
1501
  var this$1 = this;
1484
1502
 
1485
1503
  this.waitForLoaded(chart, "geochart", function () {
@@ -1489,7 +1507,7 @@
1489
1507
  colors: chart.options.colors || ["#f6c7b6", "#ce502d"]
1490
1508
  }
1491
1509
  };
1492
- var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1510
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
1493
1511
 
1494
1512
  var data = new this$1.library.visualization.DataTable();
1495
1513
  data.addColumn("string", "");
@@ -1500,12 +1518,12 @@
1500
1518
  });
1501
1519
  };
1502
1520
 
1503
- defaultExport$2.prototype.renderScatterChart = function renderScatterChart (chart) {
1521
+ defaultExport.prototype.renderScatterChart = function renderScatterChart (chart) {
1504
1522
  var this$1 = this;
1505
1523
 
1506
1524
  this.waitForLoaded(chart, function () {
1507
1525
  var chartOptions = {};
1508
- var options = jsOptions$2(chart, chart.options, chartOptions);
1526
+ var options = jsOptions(chart, chart.options, chartOptions);
1509
1527
 
1510
1528
  var series = chart.data, rows2 = [], i, j, data, d;
1511
1529
  for (i = 0; i < series.length; i++) {
@@ -1530,7 +1548,7 @@
1530
1548
  });
1531
1549
  };
1532
1550
 
1533
- defaultExport$2.prototype.renderTimeline = function renderTimeline (chart) {
1551
+ defaultExport.prototype.renderTimeline = function renderTimeline (chart) {
1534
1552
  var this$1 = this;
1535
1553
 
1536
1554
  this.waitForLoaded(chart, "timeline", function () {
@@ -1541,7 +1559,7 @@
1541
1559
  if (chart.options.colors) {
1542
1560
  chartOptions.colors = chart.options.colors;
1543
1561
  }
1544
- var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {});
1562
+ var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {});
1545
1563
 
1546
1564
  var data = new this$1.library.visualization.DataTable();
1547
1565
  data.addColumn({type: "string", id: "Name"});
@@ -1555,14 +1573,16 @@
1555
1573
  });
1556
1574
  };
1557
1575
 
1558
- defaultExport$2.prototype.destroy = function destroy (chart) {
1576
+ // TODO remove resize events
1577
+ defaultExport.prototype.destroy = function destroy (chart) {
1559
1578
  if (chart.chart) {
1560
1579
  chart.chart.clearChart();
1561
1580
  }
1562
1581
  };
1563
1582
 
1564
- defaultExport$2.prototype.drawChart = function drawChart (chart, type, data, options) {
1583
+ defaultExport.prototype.drawChart = function drawChart (chart, type, data, options) {
1565
1584
  this.destroy(chart);
1585
+ if (chart.destroyed) { return; }
1566
1586
 
1567
1587
  if (chart.options.code) {
1568
1588
  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 +1594,7 @@
1574
1594
  });
1575
1595
  };
1576
1596
 
1577
- defaultExport$2.prototype.waitForLoaded = function waitForLoaded (chart, pack, callback) {
1597
+ defaultExport.prototype.waitForLoaded = function waitForLoaded (chart, pack, callback) {
1578
1598
  var this$1 = this;
1579
1599
 
1580
1600
  if (!callback) {
@@ -1606,7 +1626,7 @@
1606
1626
  }
1607
1627
  };
1608
1628
 
1609
- defaultExport$2.prototype.runCallbacks = function runCallbacks () {
1629
+ defaultExport.prototype.runCallbacks = function runCallbacks () {
1610
1630
  var cb, call;
1611
1631
  for (var i = 0; i < callbacks.length; i++) {
1612
1632
  cb = callbacks[i];
@@ -1620,7 +1640,7 @@
1620
1640
  };
1621
1641
 
1622
1642
  // cant use object as key
1623
- defaultExport$2.prototype.createDataTable = function createDataTable (series, columnType) {
1643
+ defaultExport.prototype.createDataTable = function createDataTable (series, columnType) {
1624
1644
  var i, j, s, d, key, rows = [], sortedLabels = [];
1625
1645
  for (i = 0; i < series.length; i++) {
1626
1646
  s = series[i];
@@ -1676,116 +1696,128 @@
1676
1696
  return data;
1677
1697
  };
1678
1698
 
1679
- var pendingRequests = [], runningRequests = 0, maxRequests = 4;
1699
+ function formatSeriesData(data, keyType) {
1700
+ var r = [], j, keyFunc;
1680
1701
 
1681
- function pushRequest(url, success, error) {
1682
- pendingRequests.push([url, success, error]);
1683
- runNext();
1684
- }
1702
+ if (keyType === "number") {
1703
+ keyFunc = toFloat;
1704
+ } else if (keyType === "datetime") {
1705
+ keyFunc = toDate;
1706
+ } else {
1707
+ keyFunc = toStr;
1708
+ }
1685
1709
 
1686
- function runNext() {
1687
- if (runningRequests < maxRequests) {
1688
- var request = pendingRequests.shift();
1689
- if (request) {
1690
- runningRequests++;
1691
- getJSON(request[0], request[1], request[2]);
1692
- runNext();
1710
+ if (keyType === "bubble") {
1711
+ for (j = 0; j < data.length; j++) {
1712
+ r.push([toFloat(data[j][0]), toFloat(data[j][1]), toFloat(data[j][2])]);
1713
+ }
1714
+ } else {
1715
+ for (j = 0; j < data.length; j++) {
1716
+ r.push([keyFunc(data[j][0]), toFloat(data[j][1])]);
1693
1717
  }
1694
1718
  }
1695
- }
1696
1719
 
1697
- function requestComplete() {
1698
- runningRequests--;
1699
- runNext();
1720
+ if (keyType === "datetime") {
1721
+ r.sort(sortByTime);
1722
+ } else if (keyType === "number") {
1723
+ r.sort(sortByNumberSeries);
1724
+ }
1725
+
1726
+ return r;
1700
1727
  }
1701
1728
 
1702
- function getJSON(url, success, error) {
1703
- ajaxCall(url, success, function (jqXHR, textStatus, errorThrown) {
1704
- var message = (typeof errorThrown === "string") ? errorThrown : errorThrown.message;
1705
- error(message);
1706
- });
1729
+ function detectXType(series, noDatetime, options) {
1730
+ if (dataEmpty(series)) {
1731
+ if ((options.xmin || options.xmax) && (!options.xmin || isDate(options.xmin)) && (!options.xmax || isDate(options.xmax))) {
1732
+ return "datetime";
1733
+ } else {
1734
+ return "number";
1735
+ }
1736
+ } else if (detectXTypeWithFunction(series, isNumber)) {
1737
+ return "number";
1738
+ } else if (!noDatetime && detectXTypeWithFunction(series, isDate)) {
1739
+ return "datetime";
1740
+ } else {
1741
+ return "string";
1742
+ }
1707
1743
  }
1708
1744
 
1709
- function ajaxCall(url, success, error) {
1710
- var $ = window.jQuery || window.Zepto || window.$;
1745
+ function detectXTypeWithFunction(series, func) {
1746
+ var i, j, data;
1747
+ for (i = 0; i < series.length; i++) {
1748
+ data = toArr(series[i].data);
1749
+ for (j = 0; j < data.length; j++) {
1750
+ if (!func(data[j][0])) {
1751
+ return false;
1752
+ }
1753
+ }
1754
+ }
1755
+ return true;
1756
+ }
1711
1757
 
1712
- if ($ && $.ajax) {
1713
- $.ajax({
1714
- dataType: "json",
1715
- url: url,
1716
- success: success,
1717
- error: error,
1718
- complete: requestComplete
1719
- });
1720
- } else {
1721
- var xhr = new XMLHttpRequest();
1722
- xhr.open("GET", url, true);
1723
- xhr.setRequestHeader("Content-Type", "application/json");
1724
- xhr.onload = function () {
1725
- requestComplete();
1726
- if (xhr.status === 200) {
1727
- success(JSON.parse(xhr.responseText), xhr.statusText, xhr);
1728
- } else {
1729
- error(xhr, "error", xhr.statusText);
1758
+ // creates a shallow copy of each element of the array
1759
+ // elements are expected to be objects
1760
+ function copySeries(series) {
1761
+ var newSeries = [], i, j;
1762
+ for (i = 0; i < series.length; i++) {
1763
+ var copy = {};
1764
+ for (j in series[i]) {
1765
+ if (series[i].hasOwnProperty(j)) {
1766
+ copy[j] = series[i][j];
1730
1767
  }
1731
- };
1732
- xhr.send();
1768
+ }
1769
+ newSeries.push(copy);
1733
1770
  }
1771
+ return newSeries;
1734
1772
  }
1735
1773
 
1736
- var config = {};
1737
- var adapters = [];
1774
+ function processSeries(chart, keyType, noDatetime) {
1775
+ var i;
1738
1776
 
1739
- // helpers
1777
+ var opts = chart.options;
1778
+ var series = chart.rawData;
1740
1779
 
1741
- function setText(element, text) {
1742
- if (document.body.innerText) {
1743
- element.innerText = text;
1744
- } else {
1745
- element.textContent = text;
1780
+ // see if one series or multiple
1781
+ chart.singleSeriesFormat = (!isArray(series) || typeof series[0] !== "object" || isArray(series[0]));
1782
+ if (chart.singleSeriesFormat) {
1783
+ series = [{name: opts.label, data: series}];
1746
1784
  }
1747
- }
1748
1785
 
1749
- // TODO remove prefix for all messages
1750
- function chartError(element, message, noPrefix) {
1751
- if (!noPrefix) {
1752
- message = "Error Loading Chart: " + message;
1786
+ // convert to array
1787
+ // must come before dataEmpty check
1788
+ series = copySeries(series);
1789
+ for (i = 0; i < series.length; i++) {
1790
+ series[i].data = toArr(series[i].data);
1753
1791
  }
1754
- setText(element, message);
1755
- element.style.color = "#ff0000";
1756
- }
1757
1792
 
1758
- function errorCatcher(chart) {
1759
- try {
1760
- chart.__render();
1761
- } catch (err) {
1762
- chartError(chart.element, err.message);
1763
- throw err;
1793
+ chart.xtype = keyType ? keyType : (opts.discrete ? "string" : detectXType(series, noDatetime, opts));
1794
+
1795
+ // right format
1796
+ for (i = 0; i < series.length; i++) {
1797
+ series[i].data = formatSeriesData(series[i].data, chart.xtype);
1764
1798
  }
1799
+
1800
+ return series;
1765
1801
  }
1766
1802
 
1767
- function fetchDataSource(chart, dataSource) {
1768
- if (typeof dataSource === "string") {
1769
- pushRequest(dataSource, function (data) {
1770
- chart.rawData = data;
1771
- errorCatcher(chart);
1772
- }, function (message) {
1773
- chartError(chart.element, message);
1774
- });
1775
- } else if (typeof dataSource === "function") {
1776
- try {
1777
- dataSource(function (data) {
1778
- chart.rawData = data;
1779
- errorCatcher(chart);
1780
- }, function (message) {
1781
- chartError(chart.element, message, true);
1782
- });
1783
- } catch (err) {
1784
- chartError(chart.element, err, true);
1785
- }
1803
+ function processSimple(chart) {
1804
+ var perfectData = toArr(chart.rawData), i;
1805
+ for (i = 0; i < perfectData.length; i++) {
1806
+ perfectData[i] = [toStr(perfectData[i][0]), toFloat(perfectData[i][1])];
1807
+ }
1808
+ return perfectData;
1809
+ }
1810
+
1811
+ function dataEmpty(data, chartType) {
1812
+ if (chartType === "PieChart" || chartType === "GeoChart" || chartType === "Timeline") {
1813
+ return data.length === 0;
1786
1814
  } else {
1787
- chart.rawData = dataSource;
1788
- errorCatcher(chart);
1815
+ for (var i = 0; i < data.length; i++) {
1816
+ if (data[i].data.length > 0) {
1817
+ return false;
1818
+ }
1819
+ }
1820
+ return true;
1789
1821
  }
1790
1822
  }
1791
1823
 
@@ -1869,14 +1901,132 @@
1869
1901
  return c === p;
1870
1902
  }
1871
1903
 
1904
+ var pendingRequests = [], runningRequests = 0, maxRequests = 4;
1905
+
1906
+ function pushRequest(url, success, error) {
1907
+ pendingRequests.push([url, success, error]);
1908
+ runNext();
1909
+ }
1910
+
1911
+ function runNext() {
1912
+ if (runningRequests < maxRequests) {
1913
+ var request = pendingRequests.shift();
1914
+ if (request) {
1915
+ runningRequests++;
1916
+ getJSON(request[0], request[1], request[2]);
1917
+ runNext();
1918
+ }
1919
+ }
1920
+ }
1921
+
1922
+ function requestComplete() {
1923
+ runningRequests--;
1924
+ runNext();
1925
+ }
1926
+
1927
+ function getJSON(url, success, error) {
1928
+ ajaxCall(url, success, function (jqXHR, textStatus, errorThrown) {
1929
+ var message = (typeof errorThrown === "string") ? errorThrown : errorThrown.message;
1930
+ error(message);
1931
+ });
1932
+ }
1933
+
1934
+ function ajaxCall(url, success, error) {
1935
+ var $ = window.jQuery || window.Zepto || window.$;
1936
+
1937
+ if ($ && $.ajax) {
1938
+ $.ajax({
1939
+ dataType: "json",
1940
+ url: url,
1941
+ success: success,
1942
+ error: error,
1943
+ complete: requestComplete
1944
+ });
1945
+ } else {
1946
+ var xhr = new XMLHttpRequest();
1947
+ xhr.open("GET", url, true);
1948
+ xhr.setRequestHeader("Content-Type", "application/json");
1949
+ xhr.onload = function () {
1950
+ requestComplete();
1951
+ if (xhr.status === 200) {
1952
+ success(JSON.parse(xhr.responseText), xhr.statusText, xhr);
1953
+ } else {
1954
+ error(xhr, "error", xhr.statusText);
1955
+ }
1956
+ };
1957
+ xhr.send();
1958
+ }
1959
+ }
1960
+
1961
+ var config = {};
1962
+ var adapters = [];
1963
+
1964
+ // helpers
1965
+
1966
+ function setText(element, text) {
1967
+ if (document.body.innerText) {
1968
+ element.innerText = text;
1969
+ } else {
1970
+ element.textContent = text;
1971
+ }
1972
+ }
1973
+
1974
+ // TODO remove prefix for all messages
1975
+ function chartError(element, message, noPrefix) {
1976
+ if (!noPrefix) {
1977
+ message = "Error Loading Chart: " + message;
1978
+ }
1979
+ setText(element, message);
1980
+ element.style.color = "#ff0000";
1981
+ }
1982
+
1983
+ function errorCatcher(chart) {
1984
+ try {
1985
+ chart.__render();
1986
+ } catch (err) {
1987
+ chartError(chart.element, err.message);
1988
+ throw err;
1989
+ }
1990
+ }
1991
+
1992
+ function fetchDataSource(chart, dataSource, showLoading) {
1993
+ // only show loading message for urls and callbacks
1994
+ if (showLoading && chart.options.loading && (typeof dataSource === "string" || typeof dataSource === "function")) {
1995
+ setText(chart.element, chart.options.loading);
1996
+ }
1997
+
1998
+ if (typeof dataSource === "string") {
1999
+ pushRequest(dataSource, function (data) {
2000
+ chart.rawData = data;
2001
+ errorCatcher(chart);
2002
+ }, function (message) {
2003
+ chartError(chart.element, message);
2004
+ });
2005
+ } else if (typeof dataSource === "function") {
2006
+ try {
2007
+ dataSource(function (data) {
2008
+ chart.rawData = data;
2009
+ errorCatcher(chart);
2010
+ }, function (message) {
2011
+ chartError(chart.element, message, true);
2012
+ });
2013
+ } catch (err) {
2014
+ chartError(chart.element, err, true);
2015
+ }
2016
+ } else {
2017
+ chart.rawData = dataSource;
2018
+ errorCatcher(chart);
2019
+ }
2020
+ }
2021
+
1872
2022
  function getAdapterType(library) {
1873
2023
  if (library) {
1874
2024
  if (library.product === "Highcharts") {
1875
2025
  return defaultExport$1;
1876
2026
  } else if (library.charts) {
1877
- return defaultExport$2;
1878
- } else if (isFunction(library)) {
1879
2027
  return defaultExport;
2028
+ } else if (isFunction(library)) {
2029
+ return defaultExport$2;
1880
2030
  }
1881
2031
  }
1882
2032
  throw new Error("Unknown adapter");
@@ -1905,22 +2055,10 @@
1905
2055
  }
1906
2056
  }
1907
2057
 
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
2058
  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);
2059
+ if (dataEmpty(chart.data, chartType)) {
2060
+ var message = chart.options.empty || (chart.options.messages && chart.options.messages.empty) || "No data";
2061
+ setText(chart.element, message);
1924
2062
  } else {
1925
2063
  callAdapter(chartType, chart);
1926
2064
  if (chart.options.download && !chart.__downloadAttached && chart.adapter === "chartjs") {
@@ -1954,121 +2092,6 @@
1954
2092
  }
1955
2093
  }
1956
2094
 
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
2095
  // define classes
2073
2096
 
2074
2097
  var Chart = function Chart(element, dataSource, options) {
@@ -2086,7 +2109,7 @@
2086
2109
 
2087
2110
  Chartkick.charts[element.id] = this;
2088
2111
 
2089
- fetchDataSource(this, dataSource);
2112
+ fetchDataSource(this, dataSource, true);
2090
2113
 
2091
2114
  if (this.options.refresh) {
2092
2115
  this.startRefresh();
@@ -2122,7 +2145,7 @@
2122
2145
  if (options) {
2123
2146
  this.__updateOptions(options);
2124
2147
  }
2125
- fetchDataSource(this, dataSource);
2148
+ fetchDataSource(this, dataSource, true);
2126
2149
  };
2127
2150
 
2128
2151
  Chart.prototype.setOptions = function setOptions (options) {
@@ -2176,8 +2199,8 @@
2176
2199
  if (this.adapter === "chartjs") {
2177
2200
  if (download && download.background && download.background !== "transparent") {
2178
2201
  // 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;
2202
+ var canvas = this.chart.canvas;
2203
+ var ctx = this.chart.ctx;
2181
2204
  var tmpCanvas = document.createElement("canvas");
2182
2205
  var tmpCtx = tmpCanvas.getContext("2d");
2183
2206
  tmpCanvas.width = ctx.canvas.width;
@@ -2190,13 +2213,14 @@
2190
2213
  return this.chart.toBase64Image();
2191
2214
  }
2192
2215
  } else {
2193
- // TODO throw error in next major version
2194
- // throw new Error("Feature only available for Chart.js");
2195
- return null;
2216
+ throw new Error("Feature only available for Chart.js");
2196
2217
  }
2197
2218
  };
2198
2219
 
2199
2220
  Chart.prototype.destroy = function destroy () {
2221
+ this.destroyed = true;
2222
+ this.stopRefresh();
2223
+
2200
2224
  if (this.__adapterObject) {
2201
2225
  this.__adapterObject.destroy(this);
2202
2226
  }
@@ -2441,6 +2465,14 @@
2441
2465
  }
2442
2466
  }
2443
2467
  },
2468
+ destroyAll: function() {
2469
+ for (var chartId in Chartkick.charts) {
2470
+ if (Chartkick.charts.hasOwnProperty(chartId)) {
2471
+ Chartkick.charts[chartId].destroy();
2472
+ delete Chartkick.charts[chartId];
2473
+ }
2474
+ }
2475
+ },
2444
2476
  config: config,
2445
2477
  options: {},
2446
2478
  adapters: adapters,
@@ -2454,6 +2486,16 @@
2454
2486
  // not ideal, but allows for simpler integration
2455
2487
  if (typeof window !== "undefined" && !window.Chartkick) {
2456
2488
  window.Chartkick = Chartkick;
2489
+
2490
+ // clean up previous charts before Turbolinks loads new page
2491
+ document.addEventListener("turbolinks:before-render", function() {
2492
+ Chartkick.destroyAll();
2493
+ });
2494
+
2495
+ // use setTimeout so charting library can come later in same JS file
2496
+ setTimeout(function() {
2497
+ window.dispatchEvent(new Event("chartkick:load"));
2498
+ }, 0);
2457
2499
  }
2458
2500
 
2459
2501
  // backwards compatibility for esm require