app/assets/javascripts/pghero/chartkick.js in pghero-2.8.1 vs app/assets/javascripts/pghero/chartkick.js in pghero-2.8.2

- old
+ new

@@ -1,17 +1,17 @@ -/* +/*! * Chartkick.js * Create beautiful charts with one line of JavaScript * https://github.com/ankane/chartkick.js - * v3.2.0 + * v4.0.2 * MIT License */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : - (global = global || self, global.Chartkick = factory()); + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Chartkick = factory()); }(this, (function () { 'use strict'; function isArray(variable) { return Object.prototype.toString.call(variable) === "[object Array]"; } @@ -53,46 +53,10 @@ return target; } var DATE_PATTERN = /^(\d\d\d\d)(-)?(\d\d)(-)?(\d\d)$/i; - // https://github.com/Do/iso8601.js - 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; - var DECIMAL_SEPARATOR = String(1.5).charAt(1); - - function parseISO8601(input) { - var day, hour, matches, milliseconds, minutes, month, offset, result, seconds, type, year; - type = Object.prototype.toString.call(input); - if (type === "[object Date]") { - return input; - } - if (type !== "[object String]") { - return; - } - matches = input.match(ISO8601_PATTERN); - if (matches) { - year = parseInt(matches[1], 10); - month = parseInt(matches[3], 10) - 1; - day = parseInt(matches[5], 10); - hour = parseInt(matches[7], 10); - minutes = matches[9] ? parseInt(matches[9], 10) : 0; - seconds = matches[11] ? parseInt(matches[11], 10) : 0; - milliseconds = matches[12] ? parseFloat(DECIMAL_SEPARATOR + matches[12].slice(1)) * 1000 : 0; - result = Date.UTC(year, month, day, hour, minutes, seconds, milliseconds); - if (matches[13] && matches[14]) { - offset = matches[15] * 60; - if (matches[17]) { - offset += parseInt(matches[17], 10); - } - offset *= matches[14] === "-" ? -1 : 1; - result -= offset * 60 * 1000; - } - return new Date(result); - } - } - // end iso8601.js - function negativeValues(series) { var i, j, data; for (i = 0; i < series.length; i++) { data = series[i].data; for (j = 0; j < data.length; j++) { @@ -118,19 +82,20 @@ if (typeof n === "number") { n = new Date(n * 1000); // ms } else { n = toStr(n); if ((matches = n.match(DATE_PATTERN))) { - year = parseInt(matches[1], 10); - month = parseInt(matches[3], 10) - 1; - day = parseInt(matches[5], 10); - return new Date(year, month, day); - } else { // str + year = parseInt(matches[1], 10); + month = parseInt(matches[3], 10) - 1; + day = parseInt(matches[5], 10); + return new Date(year, month, day); + } else { // try our best to get the str into iso8601 // TODO be smarter about this var str = n.replace(/ /, "T").replace(" ", "").replace("UTC", "Z"); - n = parseISO8601(str) || new Date(n); + // Date.parse returns milliseconds if valid and NaN if invalid + n = new Date(Date.parse(str) || n); } } } return n; } @@ -152,12 +117,12 @@ return function (chart, opts, chartOptions) { var series = chart.data; var options = merge({}, defaultOptions); options = merge(options, chartOptions || {}); - if (chart.hideLegend || "legend" in opts) { - hideLegend(options, opts.legend, chart.hideLegend); + if (chart.singleSeriesFormat || "legend" in opts) { + hideLegend(options, opts.legend, chart.singleSeriesFormat); } if (opts.title) { setTitle(options, opts.title); } @@ -359,139 +324,146 @@ } var baseOptions = { maintainAspectRatio: false, animation: false, - tooltips: { - displayColors: false, - callbacks: {} + plugins: { + legend: {}, + tooltip: { + displayColors: false, + callbacks: {} + }, + title: { + font: { + size: 20 + }, + color: "#333" + } }, - legend: {}, - title: {fontSize: 20, fontColor: "#333"} + interaction: {} }; - var defaultOptions = { + var defaultOptions$2 = { scales: { - yAxes: [ - { - ticks: { - maxTicksLimit: 4 + y: { + ticks: { + maxTicksLimit: 4 + }, + title: { + font: { + size: 16 }, - scaleLabel: { - fontSize: 16, - // fontStyle: "bold", - fontColor: "#333" - } - } - ], - xAxes: [ - { - gridLines: { - drawOnChartArea: false + color: "#333" + }, + grid: {} + }, + x: { + grid: { + drawOnChartArea: false + }, + title: { + font: { + size: 16 }, - scaleLabel: { - fontSize: 16, - // fontStyle: "bold", - fontColor: "#333" - }, - time: {}, - ticks: {} - } - ] + color: "#333" + }, + time: {}, + ticks: {} + } } }; // http://there4.io/2012/05/02/google-chart-color-list/ var defaultColors = [ "#3366CC", "#DC3912", "#FF9900", "#109618", "#990099", "#3B3EAC", "#0099C6", "#DD4477", "#66AA00", "#B82E2E", "#316395", "#994499", "#22AA99", "#AAAA11", "#6633CC", "#E67300", "#8B0707", "#329262", "#5574A6", "#651067" ]; - var hideLegend = function (options, legend, hideLegend) { + var hideLegend$2 = function (options, legend, hideLegend) { if (legend !== undefined) { - options.legend.display = !!legend; + options.plugins.legend.display = !!legend; if (legend && legend !== true) { - options.legend.position = legend; + options.plugins.legend.position = legend; } } else if (hideLegend) { - options.legend.display = false; + options.plugins.legend.display = false; } }; - var setTitle = function (options, title) { - options.title.display = true; - options.title.text = title; + var setTitle$2 = function (options, title) { + options.plugins.title.display = true; + options.plugins.title.text = title; }; - var setMin = function (options, min) { + var setMin$2 = function (options, min) { if (min !== null) { - options.scales.yAxes[0].ticks.min = toFloat(min); + options.scales.y.min = toFloat(min); } }; - var setMax = function (options, max) { - options.scales.yAxes[0].ticks.max = toFloat(max); + var setMax$2 = function (options, max) { + options.scales.y.max = toFloat(max); }; - var setBarMin = function (options, min) { + var setBarMin$1 = function (options, min) { if (min !== null) { - options.scales.xAxes[0].ticks.min = toFloat(min); + options.scales.x.min = toFloat(min); } }; - var setBarMax = function (options, max) { - options.scales.xAxes[0].ticks.max = toFloat(max); + var setBarMax$1 = function (options, max) { + options.scales.x.max = toFloat(max); }; - var setStacked = function (options, stacked) { - options.scales.xAxes[0].stacked = !!stacked; - options.scales.yAxes[0].stacked = !!stacked; + var setStacked$2 = function (options, stacked) { + options.scales.x.stacked = !!stacked; + options.scales.y.stacked = !!stacked; }; - var setXtitle = function (options, title) { - options.scales.xAxes[0].scaleLabel.display = true; - options.scales.xAxes[0].scaleLabel.labelString = title; + var setXtitle$2 = function (options, title) { + options.scales.x.title.display = true; + options.scales.x.title.text = title; }; - var setYtitle = function (options, title) { - options.scales.yAxes[0].scaleLabel.display = true; - options.scales.yAxes[0].scaleLabel.labelString = title; + var setYtitle$2 = function (options, title) { + options.scales.y.title.display = true; + options.scales.y.title.text = title; }; // https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb - var addOpacity = function(hex, opacity) { + var addOpacity = function (hex, opacity) { var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? "rgba(" + parseInt(result[1], 16) + ", " + parseInt(result[2], 16) + ", " + parseInt(result[3], 16) + ", " + opacity + ")" : hex; }; // check if not null or undefined // https://stackoverflow.com/a/27757708/1177228 - var notnull = function(x) { + var notnull = function (x) { return x != null; }; var setLabelSize = function (chart, data, options) { var maxLabelSize = Math.ceil(chart.element.offsetWidth / 4.0 / data.labels.length); if (maxLabelSize > 25) { maxLabelSize = 25; } else if (maxLabelSize < 10) { maxLabelSize = 10; } - if (!options.scales.xAxes[0].ticks.callback) { - options.scales.xAxes[0].ticks.callback = function (value) { - value = toStr(value); + if (!options.scales.x.ticks.callback) { + options.scales.x.ticks.callback = function (value) { + value = toStr(this.getLabelForValue(value)); if (value.length > maxLabelSize) { return value.substring(0, maxLabelSize - 2) + "..."; } else { return value; } }; } }; - var setFormatOptions = function(chart, options, chartType) { + var setFormatOptions$1 = function (chart, options, chartType) { var formatOptions = { prefix: chart.options.prefix, suffix: chart.options.suffix, thousands: chart.options.thousands, decimal: chart.options.decimal, @@ -527,53 +499,53 @@ // set step size formatOptions.byteScale = scale; } if (chartType !== "pie") { - var myAxes = options.scales.yAxes; + var axis = options.scales.y; if (chartType === "bar") { - myAxes = options.scales.xAxes; + axis = options.scales.x; } if (formatOptions.byteScale) { - if (!myAxes[0].ticks.stepSize) { - myAxes[0].ticks.stepSize = formatOptions.byteScale / 2; + if (!axis.ticks.stepSize) { + axis.ticks.stepSize = formatOptions.byteScale / 2; } - if (!myAxes[0].ticks.maxTicksLimit) { - myAxes[0].ticks.maxTicksLimit = 4; + if (!axis.ticks.maxTicksLimit) { + axis.ticks.maxTicksLimit = 4; } } - if (!myAxes[0].ticks.callback) { - myAxes[0].ticks.callback = function (value) { + if (!axis.ticks.callback) { + axis.ticks.callback = function (value) { return formatValue("", value, formatOptions, true); }; } } - if (!options.tooltips.callbacks.label) { + if (!options.plugins.tooltip.callbacks.label) { if (chartType === "scatter") { - options.tooltips.callbacks.label = function (item, data) { - var label = data.datasets[item.datasetIndex].label || ''; + options.plugins.tooltip.callbacks.label = function (context) { + var label = context.dataset.label || ''; if (label) { label += ': '; } - return label + '(' + item.xLabel + ', ' + item.yLabel + ')'; + return label + '(' + context.label + ', ' + context.formattedValue + ')'; }; } else if (chartType === "bubble") { - options.tooltips.callbacks.label = function (item, data) { - var label = data.datasets[item.datasetIndex].label || ''; + options.plugins.tooltip.callbacks.label = function (context) { + var label = context.dataset.label || ''; if (label) { label += ': '; } - var dataPoint = data.datasets[item.datasetIndex].data[item.index]; - return label + '(' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.v + ')'; + var dataPoint = context.raw; + return label + '(' + dataPoint.x + ', ' + dataPoint.y + ', ' + dataPoint.v + ')'; }; } else if (chartType === "pie") { // need to use separate label for pie charts - options.tooltips.callbacks.label = function (tooltipItem, data) { - var dataLabel = data.labels[tooltipItem.index]; + options.plugins.tooltip.callbacks.label = function (context) { + var dataLabel = context.label; var value = ': '; if (isArray(dataLabel)) { // show value on first line of multiline label // need to clone because we are changing the value @@ -581,28 +553,28 @@ dataLabel[0] += value; } else { dataLabel += value; } - return formatValue(dataLabel, data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index], formatOptions); + return formatValue(dataLabel, context.parsed, formatOptions); }; } else { - var valueLabel = chartType === "bar" ? "xLabel" : "yLabel"; - options.tooltips.callbacks.label = function (tooltipItem, data) { - var label = data.datasets[tooltipItem.datasetIndex].label || ''; + var valueLabel = chartType === "bar" ? "x" : "y"; + options.plugins.tooltip.callbacks.label = function (context) { + var label = context.dataset.label || ''; if (label) { label += ': '; } - return formatValue(label, tooltipItem[valueLabel], formatOptions); + return formatValue(label, context.parsed[valueLabel], formatOptions); }; } } }; - var jsOptions = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle); + var jsOptions$2 = jsOptionsFunc(merge(baseOptions, defaultOptions$2), hideLegend$2, setTitle$2, setMin$2, setMax$2, setStacked$2, setXtitle$2, setYtitle$2); - var createDataTable = function (chart, options, chartType, library) { + var createDataTable = function (chart, options, chartType) { var datasets = []; var labels = []; var colors = chart.options.colors || defaultColors; @@ -700,40 +672,65 @@ } rows2.push(d$1); } } + var color; + var backgroundColor; + for (i = 0; i < series.length; i++) { s = series[i]; - var color = s.color || colors[i]; - var backgroundColor = chartType !== "line" ? addOpacity(color, 0.5) : color; + // use colors for each bar for single series format + if (chart.options.colors && chart.singleSeriesFormat && (chartType === "bar" || chartType === "column") && !s.color) { + color = colors; + backgroundColor = []; + for (var j$3 = 0; j$3 < colors.length; j$3++) { + backgroundColor[j$3] = addOpacity(color[j$3], 0.5); + } + } else { + color = s.color || colors[i]; + backgroundColor = chartType !== "line" ? addOpacity(color, 0.5) : color; + } var dataset = { label: s.name || "", data: rows2[i], fill: chartType === "area", borderColor: color, backgroundColor: backgroundColor, - pointBackgroundColor: color, - borderWidth: 2, - pointHoverBackgroundColor: color + borderWidth: 2 }; + var pointChart = chartType === "line" || chartType === "area" || chartType === "scatter" || chartType === "bubble"; + if (pointChart) { + dataset.pointBackgroundColor = color; + dataset.pointHoverBackgroundColor = color; + dataset.pointHitRadius = 50; + } + + if (chartType === "bubble") { + dataset.pointBackgroundColor = backgroundColor; + dataset.pointHoverBackgroundColor = backgroundColor; + dataset.pointHoverBorderWidth = 2; + } + if (s.stack) { dataset.stack = s.stack; } var curve = seriesOption(chart, s, "curve"); if (curve === false) { - dataset.lineTension = 0; + dataset.tension = 0; + } else if (pointChart) { + dataset.tension = 0.4; } var points = seriesOption(chart, s, "points"); if (points === false) { dataset.pointRadius = 0; - dataset.pointHitRadius = 5; + dataset.pointHoverRadius = 0; } dataset = merge(dataset, chart.options.dataset || {}); dataset = merge(dataset, s.library || {}); dataset = merge(dataset, s.dataset || {}); @@ -743,29 +740,41 @@ var xmin = chart.options.xmin; var xmax = chart.options.xmax; if (chart.xtype === "datetime") { - // hacky check for Chart.js >= 2.9.0 - // https://github.com/chartjs/Chart.js/compare/v2.8.0...v2.9.0 - var gte29 = "math" in library.helpers; - var ticksKey = gte29 ? "ticks" : "time"; if (notnull(xmin)) { - options.scales.xAxes[0][ticksKey].min = toDate(xmin).getTime(); + options.scales.x.ticks.min = toDate(xmin).getTime(); } if (notnull(xmax)) { - options.scales.xAxes[0][ticksKey].max = toDate(xmax).getTime(); + options.scales.x.ticks.max = toDate(xmax).getTime(); } } else if (chart.xtype === "number") { if (notnull(xmin)) { - options.scales.xAxes[0].ticks.min = xmin; + options.scales.x.ticks.min = xmin; } if (notnull(xmax)) { - options.scales.xAxes[0].ticks.max = xmax; + options.scales.x.ticks.max = xmax; } } + // for empty datetime chart + if (chart.xtype === "datetime" && labels.length === 0) { + if (notnull(xmin)) { + labels.push(toDate(xmin)); + } + if (notnull(xmax)) { + labels.push(toDate(xmax)); + } + day = false; + week = false; + month = false; + year = false; + hour = false; + minute = false; + } + if (chart.xtype === "datetime" && labels.length > 0) { var minTime = (notnull(xmin) ? toDate(xmin) : labels[0]).getTime(); var maxTime = (notnull(xmax) ? toDate(xmax) : labels[0]).getTime(); for (i = 1; i < labels.length; i++) { @@ -778,47 +787,47 @@ } } var timeDiff = (maxTime - minTime) / (86400 * 1000.0); - if (!options.scales.xAxes[0].time.unit) { + if (!options.scales.x.time.unit) { var step; if (year || timeDiff > 365 * 10) { - options.scales.xAxes[0].time.unit = "year"; + options.scales.x.time.unit = "year"; step = 365; } else if (month || timeDiff > 30 * 10) { - options.scales.xAxes[0].time.unit = "month"; + options.scales.x.time.unit = "month"; step = 30; } else if (day || timeDiff > 10) { - options.scales.xAxes[0].time.unit = "day"; + options.scales.x.time.unit = "day"; step = 1; } else if (hour || timeDiff > 0.5) { - options.scales.xAxes[0].time.displayFormats = {hour: "MMM D, h a"}; - options.scales.xAxes[0].time.unit = "hour"; + options.scales.x.time.displayFormats = {hour: "MMM d, h a"}; + options.scales.x.time.unit = "hour"; step = 1 / 24.0; } else if (minute) { - options.scales.xAxes[0].time.displayFormats = {minute: "h:mm a"}; - options.scales.xAxes[0].time.unit = "minute"; + options.scales.x.time.displayFormats = {minute: "h:mm a"}; + options.scales.x.time.unit = "minute"; step = 1 / 24.0 / 60.0; } if (step && timeDiff > 0) { var unitStepSize = Math.ceil(timeDiff / step / (chart.element.offsetWidth / 100.0)); if (week && step === 1) { unitStepSize = Math.ceil(unitStepSize / 7.0) * 7; } - options.scales.xAxes[0].time.unitStepSize = unitStepSize; + options.scales.x.time.stepSize = unitStepSize; } } - if (!options.scales.xAxes[0].time.tooltipFormat) { + if (!options.scales.x.time.tooltipFormat) { if (day) { - options.scales.xAxes[0].time.tooltipFormat = "ll"; + options.scales.x.time.tooltipFormat = "PP"; } else if (hour) { - options.scales.xAxes[0].time.tooltipFormat = "MMM D, h a"; + options.scales.x.time.tooltipFormat = "MMM d, h a"; } else if (minute) { - options.scales.xAxes[0].time.tooltipFormat = "h:mm a"; + options.scales.x.time.tooltipFormat = "h:mm a"; } } } var data = { @@ -827,53 +836,53 @@ }; return data; }; - var defaultExport = function defaultExport(library) { + var defaultExport$2 = function defaultExport(library) { this.name = "chartjs"; this.library = library; }; - defaultExport.prototype.renderLineChart = function renderLineChart (chart, chartType) { + defaultExport$2.prototype.renderLineChart = function renderLineChart (chart, chartType) { var chartOptions = {}; // fix for https://github.com/chartjs/Chart.js/issues/2441 if (!chart.options.max && allZeros(chart.data)) { chartOptions.max = 1; } - var options = jsOptions(chart, merge(chartOptions, chart.options)); - setFormatOptions(chart, options, chartType); + var options = jsOptions$2(chart, merge(chartOptions, chart.options)); + setFormatOptions$1(chart, options, chartType); - var data = createDataTable(chart, options, chartType || "line", this.library); + var data = createDataTable(chart, options, chartType || "line"); if (chart.xtype === "number") { - options.scales.xAxes[0].type = "linear"; - options.scales.xAxes[0].position = "bottom"; + options.scales.x.type = "linear"; + options.scales.x.position = "bottom"; } else { - options.scales.xAxes[0].type = chart.xtype === "string" ? "category" : "time"; + options.scales.x.type = chart.xtype === "string" ? "category" : "time"; } this.drawChart(chart, "line", data, options); }; - defaultExport.prototype.renderPieChart = function renderPieChart (chart) { + defaultExport$2.prototype.renderPieChart = function renderPieChart (chart) { var options = merge({}, baseOptions); if (chart.options.donut) { - options.cutoutPercentage = 50; + options.cutout = "50%"; } if ("legend" in chart.options) { - hideLegend(options, chart.options.legend); + hideLegend$2(options, chart.options.legend); } if (chart.options.title) { - setTitle(options, chart.options.title); + setTitle$2(options, chart.options.title); } options = merge(options, chart.options.library || {}); - setFormatOptions(chart, options, "pie"); + setFormatOptions$1(chart, options, "pie"); var labels = []; var values = []; for (var i = 0; i < chart.data.length; i++) { var point = chart.data[i]; @@ -893,65 +902,77 @@ }; this.drawChart(chart, "pie", data, options); }; - defaultExport.prototype.renderColumnChart = function renderColumnChart (chart, chartType) { + defaultExport$2.prototype.renderColumnChart = function renderColumnChart (chart, chartType) { var options; if (chartType === "bar") { - var barOptions = merge(baseOptions, defaultOptions); - delete barOptions.scales.yAxes[0].ticks.maxTicksLimit; - options = jsOptionsFunc(barOptions, hideLegend, setTitle, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart, chart.options); + var barOptions = merge(baseOptions, defaultOptions$2); + barOptions.indexAxis = "y"; + + // ensure gridlines have proper orientation + barOptions.scales.x.grid.drawOnChartArea = true; + barOptions.scales.y.grid.drawOnChartArea = false; + delete barOptions.scales.y.ticks.maxTicksLimit; + + options = jsOptionsFunc(barOptions, hideLegend$2, setTitle$2, setBarMin$1, setBarMax$1, setStacked$2, setXtitle$2, setYtitle$2)(chart, chart.options); } else { - options = jsOptions(chart, chart.options); + options = jsOptions$2(chart, chart.options); } - setFormatOptions(chart, options, chartType); - var data = createDataTable(chart, options, "column", this.library); + setFormatOptions$1(chart, options, chartType); + var data = createDataTable(chart, options, "column"); if (chartType !== "bar") { setLabelSize(chart, data, options); } - this.drawChart(chart, (chartType === "bar" ? "horizontalBar" : "bar"), data, options); + this.drawChart(chart, "bar", data, options); }; - defaultExport.prototype.renderAreaChart = function renderAreaChart (chart) { + defaultExport$2.prototype.renderAreaChart = function renderAreaChart (chart) { this.renderLineChart(chart, "area"); }; - defaultExport.prototype.renderBarChart = function renderBarChart (chart) { + defaultExport$2.prototype.renderBarChart = function renderBarChart (chart) { this.renderColumnChart(chart, "bar"); }; - defaultExport.prototype.renderScatterChart = function renderScatterChart (chart, chartType) { + defaultExport$2.prototype.renderScatterChart = function renderScatterChart (chart, chartType) { chartType = chartType || "scatter"; - var options = jsOptions(chart, chart.options); - setFormatOptions(chart, options, chartType); + var options = jsOptions$2(chart, chart.options); + setFormatOptions$1(chart, options, chartType); - if (!("showLines" in options)) { - options.showLines = false; + if (!("showLine" in options)) { + options.showLine = false; } - var data = createDataTable(chart, options, chartType, this.library); + var data = createDataTable(chart, options, chartType); - options.scales.xAxes[0].type = "linear"; - options.scales.xAxes[0].position = "bottom"; + options.scales.x.type = "linear"; + options.scales.x.position = "bottom"; + // prevent grouping hover and tooltips + if (!("mode" in options.interaction)) { + options.interaction.mode = "nearest"; + } + this.drawChart(chart, chartType, data, options); }; - defaultExport.prototype.renderBubbleChart = function renderBubbleChart (chart) { + defaultExport$2.prototype.renderBubbleChart = function renderBubbleChart (chart) { this.renderScatterChart(chart, "bubble"); }; - defaultExport.prototype.destroy = function destroy (chart) { + defaultExport$2.prototype.destroy = function destroy (chart) { if (chart.chart) { chart.chart.destroy(); } }; - defaultExport.prototype.drawChart = function drawChart (chart, type, data, options) { + defaultExport$2.prototype.drawChart = function drawChart (chart, type, data, options) { this.destroy(chart); + if (chart.destroyed) { return; } var chartOptions = { type: type, data: data, options: options @@ -1006,10 +1027,13 @@ areaspline: {}, area: {}, series: { marker: {} } + }, + time: { + useUTC: false } }; var hideLegend$1 = function (options, legend, hideLegend) { if (legend !== undefined) { @@ -1055,11 +1079,11 @@ options.yAxis.title.text = title; }; var jsOptions$1 = jsOptionsFunc(defaultOptions$1, hideLegend$1, setTitle$1, setMin$1, setMax$1, setStacked$1, setXtitle$1, setYtitle$1); - var setFormatOptions$1 = function(chart, options, chartType) { + var setFormatOptions = function(chart, options, chartType) { var formatOptions = { prefix: chart.options.prefix, suffix: chart.options.suffix, thousands: chart.options.thousands, decimal: chart.options.decimal, @@ -1118,11 +1142,11 @@ var options = jsOptions$1(chart, chart.options, chartOptions), data, i, j; options.xAxis.type = chart.xtype === "string" ? "category" : (chart.xtype === "number" ? "linear" : "datetime"); if (!options.chart.type) { options.chart.type = chartType; } - setFormatOptions$1(chart, options, chartType); + setFormatOptions(chart, options, chartType); var series = chart.data; for (i = 0; i < series.length; i++) { series[i].name = series[i].name || "Value"; data = series[i].data; @@ -1163,11 +1187,11 @@ if (chart.options.title) { setTitle$1(chartOptions, chart.options.title); } var options = merge(chartOptions, chart.options.library || {}); - setFormatOptions$1(chart, options, "pie"); + setFormatOptions(chart, options, "pie"); var series = [{ type: "pie", name: chart.options.label || "Value", data: chart.data }]; @@ -1178,11 +1202,11 @@ defaultExport$1.prototype.renderColumnChart = function renderColumnChart (chart, chartType) { chartType = chartType || "column"; var series = chart.data; var options = jsOptions$1(chart, chart.options), i, j, s, d, rows = [], categories = []; options.chart.type = chartType; - setFormatOptions$1(chart, options, chartType); + setFormatOptions(chart, options, chartType); for (i = 0; i < series.length; i++) { s = series[i]; for (j = 0; j < s.data.length; j++) { @@ -1236,10 +1260,11 @@ } }; defaultExport$1.prototype.drawChart = function drawChart (chart, data, options) { this.destroy(chart); + if (chart.destroyed) { return; } options.chart.renderTo = chart.element.id; options.series = data; if (chart.options.code) { @@ -1251,11 +1276,11 @@ var loaded = {}; var callbacks = []; // Set chart options - var defaultOptions$2 = { + var defaultOptions = { chartArea: {}, fontName: "'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif", pointSize: 6, legend: { textStyle: { @@ -1293,11 +1318,11 @@ fontSize: 12 } } }; - var hideLegend$2 = function (options, legend, hideLegend) { + var hideLegend = function (options, legend, hideLegend) { if (legend !== undefined) { var position; if (!legend) { position = "none"; } else if (legend === true) { @@ -1309,62 +1334,62 @@ } else if (hideLegend) { options.legend.position = "none"; } }; - var setTitle$2 = function (options, title) { + var setTitle = function (options, title) { options.title = title; options.titleTextStyle = {color: "#333", fontSize: "20px"}; }; - var setMin$2 = function (options, min) { + var setMin = function (options, min) { options.vAxis.viewWindow.min = min; }; - var setMax$2 = function (options, max) { + var setMax = function (options, max) { options.vAxis.viewWindow.max = max; }; - var setBarMin$1 = function (options, min) { + var setBarMin = function (options, min) { options.hAxis.viewWindow.min = min; }; - var setBarMax$1 = function (options, max) { + var setBarMax = function (options, max) { options.hAxis.viewWindow.max = max; }; - var setStacked$2 = function (options, stacked) { + var setStacked = function (options, stacked) { options.isStacked = stacked ? stacked : false; }; - var setXtitle$2 = function (options, title) { + var setXtitle = function (options, title) { options.hAxis.title = title; options.hAxis.titleTextStyle.italic = false; }; - var setYtitle$2 = function (options, title) { + var setYtitle = function (options, title) { options.vAxis.title = title; options.vAxis.titleTextStyle.italic = false; }; - var jsOptions$2 = jsOptionsFunc(defaultOptions$2, hideLegend$2, setTitle$2, setMin$2, setMax$2, setStacked$2, setXtitle$2, setYtitle$2); + var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setMin, setMax, setStacked, setXtitle, setYtitle); var resize = function (callback) { if (window.attachEvent) { window.attachEvent("onresize", callback); } else if (window.addEventListener) { window.addEventListener("resize", callback, true); } callback(); }; - var defaultExport$2 = function defaultExport(library) { + var defaultExport = function defaultExport(library) { this.name = "google"; this.library = library; }; - defaultExport$2.prototype.renderLineChart = function renderLineChart (chart) { + defaultExport.prototype.renderLineChart = function renderLineChart (chart) { var this$1 = this; this.waitForLoaded(chart, function () { var chartOptions = {}; @@ -1374,18 +1399,18 @@ if (chart.options.points === false) { chartOptions.pointSize = 0; } - var options = jsOptions$2(chart, chart.options, chartOptions); + var options = jsOptions(chart, chart.options, chartOptions); var data = this$1.createDataTable(chart.data, chart.xtype); this$1.drawChart(chart, "LineChart", data, options); }); }; - defaultExport$2.prototype.renderPieChart = function renderPieChart (chart) { + defaultExport.prototype.renderPieChart = function renderPieChart (chart) { var this$1 = this; this.waitForLoaded(chart, function () { var chartOptions = { chartArea: { @@ -1399,99 +1424,99 @@ } if (chart.options.donut) { chartOptions.pieHole = 0.5; } if ("legend" in chart.options) { - hideLegend$2(chartOptions, chart.options.legend); + hideLegend(chartOptions, chart.options.legend); } if (chart.options.title) { - setTitle$2(chartOptions, chart.options.title); + setTitle(chartOptions, chart.options.title); } - var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {}); + var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {}); var data = new this$1.library.visualization.DataTable(); data.addColumn("string", ""); data.addColumn("number", "Value"); data.addRows(chart.data); this$1.drawChart(chart, "PieChart", data, options); }); }; - defaultExport$2.prototype.renderColumnChart = function renderColumnChart (chart) { + defaultExport.prototype.renderColumnChart = function renderColumnChart (chart) { var this$1 = this; this.waitForLoaded(chart, function () { - var options = jsOptions$2(chart, chart.options); + var options = jsOptions(chart, chart.options); var data = this$1.createDataTable(chart.data, chart.xtype); this$1.drawChart(chart, "ColumnChart", data, options); }); }; - defaultExport$2.prototype.renderBarChart = function renderBarChart (chart) { + defaultExport.prototype.renderBarChart = function renderBarChart (chart) { var this$1 = this; this.waitForLoaded(chart, function () { var chartOptions = { hAxis: { gridlines: { color: "#ccc" } } }; - var options = jsOptionsFunc(defaultOptions$2, hideLegend$2, setTitle$2, setBarMin$1, setBarMax$1, setStacked$2, setXtitle$2, setYtitle$2)(chart, chart.options, chartOptions); + var options = jsOptionsFunc(defaultOptions, hideLegend, setTitle, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart, chart.options, chartOptions); var data = this$1.createDataTable(chart.data, chart.xtype); this$1.drawChart(chart, "BarChart", data, options); }); }; - defaultExport$2.prototype.renderAreaChart = function renderAreaChart (chart) { + defaultExport.prototype.renderAreaChart = function renderAreaChart (chart) { var this$1 = this; this.waitForLoaded(chart, function () { var chartOptions = { isStacked: true, pointSize: 0, areaOpacity: 0.5 }; - var options = jsOptions$2(chart, chart.options, chartOptions); + var options = jsOptions(chart, chart.options, chartOptions); var data = this$1.createDataTable(chart.data, chart.xtype); this$1.drawChart(chart, "AreaChart", data, options); }); }; - defaultExport$2.prototype.renderGeoChart = function renderGeoChart (chart) { + defaultExport.prototype.renderGeoChart = function renderGeoChart (chart) { var this$1 = this; - this.waitForLoaded(chart, function () { + this.waitForLoaded(chart, "geochart", function () { var chartOptions = { legend: "none", colorAxis: { colors: chart.options.colors || ["#f6c7b6", "#ce502d"] } }; - var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {}); + var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {}); var data = new this$1.library.visualization.DataTable(); data.addColumn("string", ""); data.addColumn("number", chart.options.label || "Value"); data.addRows(chart.data); this$1.drawChart(chart, "GeoChart", data, options); }); }; - defaultExport$2.prototype.renderScatterChart = function renderScatterChart (chart) { + defaultExport.prototype.renderScatterChart = function renderScatterChart (chart) { var this$1 = this; this.waitForLoaded(chart, function () { var chartOptions = {}; - var options = jsOptions$2(chart, chart.options, chartOptions); + var options = jsOptions(chart, chart.options, chartOptions); var series = chart.data, rows2 = [], i, j, data, d; for (i = 0; i < series.length; i++) { series[i].name = series[i].name || "Value"; d = series[i].data; @@ -1512,22 +1537,22 @@ this$1.drawChart(chart, "ScatterChart", data, options); }); }; - defaultExport$2.prototype.renderTimeline = function renderTimeline (chart) { + defaultExport.prototype.renderTimeline = function renderTimeline (chart) { var this$1 = this; this.waitForLoaded(chart, "timeline", function () { var chartOptions = { legend: "none" }; if (chart.options.colors) { chartOptions.colors = chart.options.colors; } - var options = merge(merge(defaultOptions$2, chartOptions), chart.options.library || {}); + var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {}); var data = new this$1.library.visualization.DataTable(); data.addColumn({type: "string", id: "Name"}); data.addColumn({type: "date", id: "Start"}); data.addColumn({type: "date", id: "End"}); @@ -1537,18 +1562,20 @@ this$1.drawChart(chart, "Timeline", data, options); }); }; - defaultExport$2.prototype.destroy = function destroy (chart) { + // TODO remove resize events + defaultExport.prototype.destroy = function destroy (chart) { if (chart.chart) { chart.chart.clearChart(); } }; - defaultExport$2.prototype.drawChart = function drawChart (chart, type, data, options) { + defaultExport.prototype.drawChart = function drawChart (chart, type, data, options) { this.destroy(chart); + if (chart.destroyed) { return; } if (chart.options.code) { window.console.log("var data = new google.visualization.DataTable(" + data.toJSON() + ");\nvar chart = new google.visualization." + type + "(element);\nchart.draw(data, " + JSON.stringify(options) + ");"); } @@ -1556,11 +1583,11 @@ resize(function () { chart.chart.draw(data, options); }); }; - defaultExport$2.prototype.waitForLoaded = function waitForLoaded (chart, pack, callback) { + defaultExport.prototype.waitForLoaded = function waitForLoaded (chart, pack, callback) { var this$1 = this; if (!callback) { callback = pack; pack = "corechart"; @@ -1580,33 +1607,33 @@ }; var config = chart.__config(); if (config.language) { loadOptions.language = config.language; } - if (pack === "corechart" && config.mapsApiKey) { + if (pack === "geochart" && config.mapsApiKey) { loadOptions.mapsApiKey = config.mapsApiKey; } this.library.charts.load("current", loadOptions); } }; - defaultExport$2.prototype.runCallbacks = function runCallbacks () { + defaultExport.prototype.runCallbacks = function runCallbacks () { var cb, call; for (var i = 0; i < callbacks.length; i++) { cb = callbacks[i]; - call = this.library.visualization && ((cb.pack === "corechart" && this.library.visualization.LineChart) || (cb.pack === "timeline" && this.library.visualization.Timeline)); + call = this.library.visualization && ((cb.pack === "corechart" && this.library.visualization.LineChart) || (cb.pack === "timeline" && this.library.visualization.Timeline) || (cb.pack === "geochart" && this.library.visualization.GeoChart)); if (call) { cb.callback(); callbacks.splice(i, 1); i--; } } }; // cant use object as key - defaultExport$2.prototype.createDataTable = function createDataTable (series, columnType) { + defaultExport.prototype.createDataTable = function createDataTable (series, columnType) { var i, j, s, d, key, rows = [], sortedLabels = []; for (i = 0; i < series.length; i++) { s = series[i]; series[i].name = series[i].name || "Value"; @@ -1746,11 +1773,16 @@ chartError(chart.element, err.message); throw err; } } - function fetchDataSource(chart, dataSource) { + function fetchDataSource(chart, dataSource, showLoading) { + // only show loading message for urls and callbacks + if (showLoading && chart.options.loading && (typeof dataSource === "string" || typeof dataSource === "function")) { + setText(chart.element, chart.options.loading); + } + if (typeof dataSource === "string") { pushRequest(dataSource, function (data) { chart.rawData = data; errorCatcher(chart); }, function (message) { @@ -1856,13 +1888,13 @@ function getAdapterType(library) { if (library) { if (library.product === "Highcharts") { return defaultExport$1; } else if (library.charts) { - return defaultExport$2; - } else if (isFunction(library)) { return defaultExport; + } else if (isFunction(library)) { + return defaultExport$2; } } throw new Error("Unknown adapter"); } @@ -1901,12 +1933,13 @@ return true; } } function renderChart(chartType, chart) { - if (chart.options.messages && chart.options.messages.empty && dataEmpty(chart.data, chartType)) { - setText(chart.element, chart.options.messages.empty); + if (dataEmpty(chart.data, chartType)) { + var message = chart.options.empty || (chart.options.messages && chart.options.messages.empty) || "No data"; + setText(chart.element, message); } else { callAdapter(chartType, chart); if (chart.options.download && !chart.__downloadAttached && chart.adapter === "chartjs") { addDownloadButton(chart); } @@ -1967,12 +2000,18 @@ r.sort(sortByNumberSeries); } return r; }; - function detectXType(series, noDatetime) { - if (detectXTypeWithFunction(series, isNumber)) { + function detectXType(series, noDatetime, options) { + if (dataEmpty(series)) { + if ((options.xmin || options.xmax) && (!options.xmin || isDate(options.xmin)) && (!options.xmax || isDate(options.xmax))) { + return "datetime"; + } else { + return "number"; + } + } else if (detectXTypeWithFunction(series, isNumber)) { return "number"; } else if (!noDatetime && detectXTypeWithFunction(series, isDate)) { return "datetime"; } else { return "string"; @@ -2015,21 +2054,27 @@ var series = chart.rawData; // see if one series or multiple if (!isArray(series) || typeof series[0] !== "object" || isArray(series[0])) { series = [{name: opts.label, data: series}]; - chart.hideLegend = true; + chart.singleSeriesFormat = true; } else { - chart.hideLegend = false; + chart.singleSeriesFormat = false; } - chart.xtype = keyType ? keyType : (opts.discrete ? "string" : detectXType(series, noDatetime)); + // convert to array + // must come before dataEmpty check + series = copySeries(series); + for (i = 0; i < series.length; i++) { + series[i].data = toArr(series[i].data); + } + chart.xtype = keyType ? keyType : (opts.discrete ? "string" : detectXType(series, noDatetime, opts)); + // right format - series = copySeries(series); for (i = 0; i < series.length; i++) { - series[i].data = formatSeriesData(toArr(series[i].data), chart.xtype); + series[i].data = formatSeriesData(series[i].data, chart.xtype); } return series; } @@ -2056,11 +2101,11 @@ this.options = merge(Chartkick.options, options || {}); this.dataSource = dataSource; Chartkick.charts[element.id] = this; - fetchDataSource(this, dataSource); + fetchDataSource(this, dataSource, true); if (this.options.refresh) { this.startRefresh(); } }; @@ -2092,11 +2137,11 @@ Chart.prototype.updateData = function updateData (dataSource, options) { this.dataSource = dataSource; if (options) { this.__updateOptions(options); } - fetchDataSource(this, dataSource); + fetchDataSource(this, dataSource, true); }; Chart.prototype.setOptions = function setOptions (options) { this.__updateOptions(options); this.redraw(); @@ -2160,17 +2205,18 @@ return tmpCanvas.toDataURL("image/png"); } else { return this.chart.toBase64Image(); } } else { - // TODO throw error in next major version - // throw new Error("Feature only available for Chart.js"); - return null; + throw new Error("Feature only available for Chart.js"); } }; Chart.prototype.destroy = function destroy () { + this.destroyed = true; + this.stopRefresh(); + if (this.__adapterObject) { this.__adapterObject.destroy(this); } if (this.__enterEvent) { @@ -2411,10 +2457,18 @@ if (Chartkick.charts.hasOwnProperty(chartId)) { callback(Chartkick.charts[chartId]); } } }, + destroyAll: function() { + for (var chartId in Chartkick.charts) { + if (Chartkick.charts.hasOwnProperty(chartId)) { + Chartkick.charts[chartId].destroy(); + delete Chartkick.charts[chartId]; + } + } + }, config: config, options: {}, adapters: adapters, addAdapter: addAdapter, use: function(adapter) { @@ -2424,9 +2478,19 @@ }; // not ideal, but allows for simpler integration if (typeof window !== "undefined" && !window.Chartkick) { window.Chartkick = Chartkick; + + // clean up previous charts before Turbolinks loads new page + document.addEventListener("turbolinks:before-render", function() { + Chartkick.destroyAll(); + }); + + // use setTimeout so charting library can come later in same JS file + setTimeout(function() { + window.dispatchEvent(new Event("chartkick:load")); + }, 0); } // backwards compatibility for esm require Chartkick.default = Chartkick;