|
@@ -2,7 +2,7 @@
|
|
* Chartkick.js
|
|
* Chartkick.js
|
|
* Create beautiful JavaScript charts with minimal code
|
|
* Create beautiful JavaScript charts with minimal code
|
|
* https://github.com/ankane/chartkick.js
|
|
* https://github.com/ankane/chartkick.js
|
|
- * v1.5.1
|
|
|
|
|
|
+ * v2.0.0
|
|
* MIT License
|
|
* MIT License
|
|
*/
|
|
*/
|
|
|
|
|
|
@@ -14,7 +14,7 @@
|
|
var config = window.Chartkick || {};
|
|
var config = window.Chartkick || {};
|
|
var Chartkick, ISO8601_PATTERN, DECIMAL_SEPARATOR, adapters = [];
|
|
var Chartkick, ISO8601_PATTERN, DECIMAL_SEPARATOR, adapters = [];
|
|
var DATE_PATTERN = /^(\d\d\d\d)(\-)?(\d\d)(\-)?(\d\d)$/i;
|
|
var DATE_PATTERN = /^(\d\d\d\d)(\-)?(\d\d)(\-)?(\d\d)$/i;
|
|
- var adapters = [];
|
|
|
|
|
|
+ var GoogleChartsAdapter, HighchartsAdapter, ChartjsAdapter;
|
|
|
|
|
|
// helpers
|
|
// helpers
|
|
|
|
|
|
@@ -68,7 +68,8 @@
|
|
if (type !== '[object String]') {
|
|
if (type !== '[object String]') {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- if (matches = input.match(ISO8601_PATTERN)) {
|
|
|
|
|
|
+ matches = input.match(ISO8601_PATTERN);
|
|
|
|
+ if (matches) {
|
|
year = parseInt(matches[1], 10);
|
|
year = parseInt(matches[1], 10);
|
|
month = parseInt(matches[3], 10) - 1;
|
|
month = parseInt(matches[3], 10) - 1;
|
|
day = parseInt(matches[5], 10);
|
|
day = parseInt(matches[5], 10);
|
|
@@ -211,7 +212,7 @@
|
|
if (typeof n !== "object") {
|
|
if (typeof n !== "object") {
|
|
if (typeof n === "number") {
|
|
if (typeof n === "number") {
|
|
n = new Date(n * 1000); // ms
|
|
n = new Date(n * 1000); // ms
|
|
- } else if (config.smarterDates && (matches = n.match(DATE_PATTERN))) {
|
|
|
|
|
|
+ } else if ((matches = n.match(DATE_PATTERN))) {
|
|
year = parseInt(matches[1], 10);
|
|
year = parseInt(matches[1], 10);
|
|
month = parseInt(matches[3], 10) - 1;
|
|
month = parseInt(matches[3], 10) - 1;
|
|
day = parseInt(matches[5], 10);
|
|
day = parseInt(matches[5], 10);
|
|
@@ -249,7 +250,7 @@
|
|
|
|
|
|
function loadAdapters() {
|
|
function loadAdapters() {
|
|
if (!HighchartsAdapter && "Highcharts" in window) {
|
|
if (!HighchartsAdapter && "Highcharts" in window) {
|
|
- var HighchartsAdapter = new function () {
|
|
|
|
|
|
+ HighchartsAdapter = new function () {
|
|
var Highcharts = window.Highcharts;
|
|
var Highcharts = window.Highcharts;
|
|
|
|
|
|
this.name = "highcharts";
|
|
this.name = "highcharts";
|
|
@@ -385,7 +386,7 @@
|
|
};
|
|
};
|
|
|
|
|
|
this.renderColumnChart = function (chart, chartType) {
|
|
this.renderColumnChart = function (chart, chartType) {
|
|
- var chartType = chartType || "column";
|
|
|
|
|
|
+ chartType = chartType || "column";
|
|
var series = chart.data;
|
|
var series = chart.data;
|
|
var options = jsOptions(series, chart.options), i, j, s, d, rows = [];
|
|
var options = jsOptions(series, chart.options), i, j, s, d, rows = [];
|
|
options.chart.type = chartType;
|
|
options.chart.type = chartType;
|
|
@@ -441,7 +442,7 @@
|
|
adapters.push(HighchartsAdapter);
|
|
adapters.push(HighchartsAdapter);
|
|
}
|
|
}
|
|
if (!GoogleChartsAdapter && window.google && window.google.setOnLoadCallback) {
|
|
if (!GoogleChartsAdapter && window.google && window.google.setOnLoadCallback) {
|
|
- var GoogleChartsAdapter = new function () {
|
|
|
|
|
|
+ GoogleChartsAdapter = new function () {
|
|
var google = window.google;
|
|
var google = window.google;
|
|
|
|
|
|
this.name = "google";
|
|
this.name = "google";
|
|
@@ -453,7 +454,7 @@
|
|
var cb, call;
|
|
var cb, call;
|
|
for (var i = 0; i < callbacks.length; i++) {
|
|
for (var i = 0; i < callbacks.length; i++) {
|
|
cb = callbacks[i];
|
|
cb = callbacks[i];
|
|
- call = google.visualization && ((cb.pack === "corechart" && google.visualization.LineChart) || (cb.pack === "timeline" && google.visualization.Timeline))
|
|
|
|
|
|
+ call = google.visualization && ((cb.pack === "corechart" && google.visualization.LineChart) || (cb.pack === "timeline" && google.visualization.Timeline));
|
|
if (call) {
|
|
if (call) {
|
|
cb.callback();
|
|
cb.callback();
|
|
callbacks.splice(i, 1);
|
|
callbacks.splice(i, 1);
|
|
@@ -557,7 +558,7 @@
|
|
var setXtitle = function (options, title) {
|
|
var setXtitle = function (options, title) {
|
|
options.hAxis.title = title;
|
|
options.hAxis.title = title;
|
|
options.hAxis.titleTextStyle.italic = false;
|
|
options.hAxis.titleTextStyle.italic = false;
|
|
- }
|
|
|
|
|
|
+ };
|
|
|
|
|
|
var setYtitle = function (options, title) {
|
|
var setYtitle = function (options, title) {
|
|
options.vAxis.title = title;
|
|
options.vAxis.title = title;
|
|
@@ -769,7 +770,7 @@
|
|
adapters.push(GoogleChartsAdapter);
|
|
adapters.push(GoogleChartsAdapter);
|
|
}
|
|
}
|
|
if (!ChartjsAdapter && "Chart" in window) {
|
|
if (!ChartjsAdapter && "Chart" in window) {
|
|
- var ChartjsAdapter = new function () {
|
|
|
|
|
|
+ ChartjsAdapter = new function () {
|
|
var Chart = window.Chart;
|
|
var Chart = window.Chart;
|
|
|
|
|
|
this.name = "chartjs";
|
|
this.name = "chartjs";
|
|
@@ -832,6 +833,16 @@
|
|
options.scales.yAxes[0].ticks.max = max;
|
|
options.scales.yAxes[0].ticks.max = max;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+ var setBarMin = function (options, min) {
|
|
|
|
+ if (min !== null) {
|
|
|
|
+ options.scales.xAxes[0].ticks.min = min;
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ var setBarMax = function (options, max) {
|
|
|
|
+ options.scales.xAxes[0].ticks.max = max;
|
|
|
|
+ };
|
|
|
|
+
|
|
var setStacked = function (options, stacked) {
|
|
var setStacked = function (options, stacked) {
|
|
options.scales.xAxes[0].stacked = !!stacked;
|
|
options.scales.xAxes[0].stacked = !!stacked;
|
|
options.scales.yAxes[0].stacked = !!stacked;
|
|
options.scales.yAxes[0].stacked = !!stacked;
|
|
@@ -889,6 +900,8 @@
|
|
var dayOfWeek;
|
|
var dayOfWeek;
|
|
var month = true;
|
|
var month = true;
|
|
var year = true;
|
|
var year = true;
|
|
|
|
+ var hour = true;
|
|
|
|
+ var minute = true;
|
|
var detectType = (chartType === "line" || chartType === "area") && !chart.options.discrete;
|
|
var detectType = (chartType === "line" || chartType === "area") && !chart.options.discrete;
|
|
|
|
|
|
var series = chart.data;
|
|
var series = chart.data;
|
|
@@ -917,11 +930,10 @@
|
|
}
|
|
}
|
|
|
|
|
|
var rows2 = [];
|
|
var rows2 = [];
|
|
- for (var j = 0; j < series.length; j++) {
|
|
|
|
|
|
+ for (j = 0; j < series.length; j++) {
|
|
rows2.push([]);
|
|
rows2.push([]);
|
|
}
|
|
}
|
|
|
|
|
|
- var day = true;
|
|
|
|
var value;
|
|
var value;
|
|
var k;
|
|
var k;
|
|
for (k = 0; k < sortedLabels.length; k++) {
|
|
for (k = 0; k < sortedLabels.length; k++) {
|
|
@@ -936,17 +948,19 @@
|
|
week = week && isWeek(value, dayOfWeek);
|
|
week = week && isWeek(value, dayOfWeek);
|
|
month = month && isMonth(value);
|
|
month = month && isMonth(value);
|
|
year = year && isYear(value);
|
|
year = year && isYear(value);
|
|
|
|
+ hour = hour && isHour(value);
|
|
|
|
+ minute = minute && isMinute(value);
|
|
} else {
|
|
} else {
|
|
value = i;
|
|
value = i;
|
|
}
|
|
}
|
|
labels.push(value);
|
|
labels.push(value);
|
|
- for (var j = 0; j < series.length; j++) {
|
|
|
|
- rows2[j].push(rows[i][j])
|
|
|
|
|
|
+ for (j = 0; j < series.length; j++) {
|
|
|
|
+ rows2[j].push(rows[i][j]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- for (var i = 0; i < series.length; i++) {
|
|
|
|
- var s = series[i];
|
|
|
|
|
|
+ for (i = 0; i < series.length; i++) {
|
|
|
|
+ s = series[i];
|
|
|
|
|
|
var backgroundColor = chartType !== "line" ? addOpacity(colors[i], 0.5) : colors[i];
|
|
var backgroundColor = chartType !== "line" ? addOpacity(colors[i], 0.5) : colors[i];
|
|
|
|
|
|
@@ -989,6 +1003,13 @@
|
|
} else if (day || timeDiff > 10) {
|
|
} else if (day || timeDiff > 10) {
|
|
options.scales.xAxes[0].time.unit = "day";
|
|
options.scales.xAxes[0].time.unit = "day";
|
|
step = 1;
|
|
step = 1;
|
|
|
|
+ } else if (hour) {
|
|
|
|
+ options.scales.xAxes[0].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";
|
|
|
|
+ step = 1 / 24.0 / 60.0;
|
|
}
|
|
}
|
|
|
|
|
|
if (step && timeDiff > 0) {
|
|
if (step && timeDiff > 0) {
|
|
@@ -1000,8 +1021,14 @@
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if (!options.scales.xAxes[0].time.tooltipFormat && day) {
|
|
|
|
- options.scales.xAxes[0].time.tooltipFormat = "ll";
|
|
|
|
|
|
+ if (!options.scales.xAxes[0].time.tooltipFormat) {
|
|
|
|
+ if (day) {
|
|
|
|
+ options.scales.xAxes[0].time.tooltipFormat = "ll";
|
|
|
|
+ } else if (hour) {
|
|
|
|
+ options.scales.xAxes[0].time.tooltipFormat = "MMM D, h a";
|
|
|
|
+ } else if (minute) {
|
|
|
|
+ options.scales.xAxes[0].time.tooltipFormat = "h:mm a";
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1019,6 +1046,11 @@
|
|
// TODO fix area stacked
|
|
// TODO fix area stacked
|
|
// areaOptions.stacked = true;
|
|
// areaOptions.stacked = true;
|
|
}
|
|
}
|
|
|
|
+ // fix for https://github.com/chartjs/Chart.js/issues/2441
|
|
|
|
+ if (!chart.options.max && allZeros(chart.data)) {
|
|
|
|
+ chart.options.max = 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
var options = jsOptions(chart.data, merge(areaOptions, chart.options));
|
|
var options = jsOptions(chart.data, merge(areaOptions, chart.options));
|
|
|
|
|
|
var data = createDataTable(chart, options, chartType || "line");
|
|
var data = createDataTable(chart, options, chartType || "line");
|
|
@@ -1026,7 +1058,7 @@
|
|
options.scales.xAxes[0].type = chart.options.discrete ? "category" : "time";
|
|
options.scales.xAxes[0].type = chart.options.discrete ? "category" : "time";
|
|
|
|
|
|
drawChart(chart, "line", data, options);
|
|
drawChart(chart, "line", data, options);
|
|
- }
|
|
|
|
|
|
+ };
|
|
|
|
|
|
this.renderPieChart = function (chart) {
|
|
this.renderPieChart = function (chart) {
|
|
var options = merge(baseOptions, chart.options.library || {});
|
|
var options = merge(baseOptions, chart.options.library || {});
|
|
@@ -1050,14 +1082,19 @@
|
|
};
|
|
};
|
|
|
|
|
|
drawChart(chart, "pie", data, options);
|
|
drawChart(chart, "pie", data, options);
|
|
- }
|
|
|
|
|
|
+ };
|
|
|
|
|
|
this.renderColumnChart = function (chart, chartType) {
|
|
this.renderColumnChart = function (chart, chartType) {
|
|
- var options = jsOptions(chart.data, chart.options);
|
|
|
|
|
|
+ var options;
|
|
|
|
+ if (chartType === "bar") {
|
|
|
|
+ options = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setBarMin, setBarMax, setStacked)(chart.data, chart.options);
|
|
|
|
+ } else {
|
|
|
|
+ options = jsOptions(chart.data, chart.options);
|
|
|
|
+ }
|
|
var data = createDataTable(chart, options, "column");
|
|
var data = createDataTable(chart, options, "column");
|
|
setLabelSize(chart, data, options);
|
|
setLabelSize(chart, data, options);
|
|
drawChart(chart, (chartType === "bar" ? "horizontalBar" : "bar"), data, options);
|
|
drawChart(chart, (chartType === "bar" ? "horizontalBar" : "bar"), data, options);
|
|
- }
|
|
|
|
|
|
+ };
|
|
|
|
|
|
var self = this;
|
|
var self = this;
|
|
|
|
|
|
@@ -1066,11 +1103,11 @@
|
|
};
|
|
};
|
|
|
|
|
|
this.renderBarChart = function (chart) {
|
|
this.renderBarChart = function (chart) {
|
|
- self.renderColumnChart(chart, "bar")
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ self.renderColumnChart(chart, "bar");
|
|
|
|
+ };
|
|
|
|
+ };
|
|
|
|
|
|
- adapters.push(ChartjsAdapter);
|
|
|
|
|
|
+ adapters.unshift(ChartjsAdapter);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1081,9 +1118,7 @@
|
|
fnName = "render" + chartType;
|
|
fnName = "render" + chartType;
|
|
adapterName = chart.options.adapter;
|
|
adapterName = chart.options.adapter;
|
|
|
|
|
|
- if (adapters.length == 0) {
|
|
|
|
- loadAdapters();
|
|
|
|
- }
|
|
|
|
|
|
+ loadAdapters();
|
|
|
|
|
|
for (i = 0; i < adapters.length; i++) {
|
|
for (i = 0; i < adapters.length; i++) {
|
|
adapter = adapters[i];
|
|
adapter = adapters[i];
|
|
@@ -1119,8 +1154,16 @@
|
|
return r;
|
|
return r;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+ function isMinute(d) {
|
|
|
|
+ return d.getMilliseconds() === 0 && d.getSeconds() === 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function isHour(d) {
|
|
|
|
+ return isMinute(d) && d.getMinutes() === 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
function isDay(d) {
|
|
function isDay(d) {
|
|
- return d.getMilliseconds() + d.getSeconds() + d.getMinutes() + d.getHours() === 0;
|
|
|
|
|
|
+ return isHour(d) && d.getHours() === 0;
|
|
}
|
|
}
|
|
|
|
|
|
function isWeek(d, dayOfWeek) {
|
|
function isWeek(d, dayOfWeek) {
|
|
@@ -1139,6 +1182,19 @@
|
|
return !isNaN(toDate(obj)) && toStr(obj).length >= 6;
|
|
return !isNaN(toDate(obj)) && toStr(obj).length >= 6;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ function allZeros(data) {
|
|
|
|
+ var i, j, d;
|
|
|
|
+ for (i = 0; i < data.length; i++) {
|
|
|
|
+ d = data[i].data;
|
|
|
|
+ for (j = 0; j < d.length; j++) {
|
|
|
|
+ if (d[j][1] != 0) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
function detectDiscrete(series) {
|
|
function detectDiscrete(series) {
|
|
var i, j, data;
|
|
var i, j, data;
|
|
for (i = 0; i < series.length; i++) {
|
|
for (i = 0; i < series.length; i++) {
|
|
@@ -1162,7 +1218,7 @@
|
|
} else {
|
|
} else {
|
|
opts.hideLegend = false;
|
|
opts.hideLegend = false;
|
|
}
|
|
}
|
|
- if (config.smarterDiscrete && (opts.discrete === null || opts.discrete === undefined)) {
|
|
|
|
|
|
+ if ((opts.discrete === null || opts.discrete === undefined)) {
|
|
opts.discrete = detectDiscrete(series);
|
|
opts.discrete = detectDiscrete(series);
|
|
}
|
|
}
|
|
if (opts.discrete) {
|
|
if (opts.discrete) {
|
|
@@ -1242,6 +1298,18 @@
|
|
chart.element = element;
|
|
chart.element = element;
|
|
chart.options = opts || {};
|
|
chart.options = opts || {};
|
|
chart.dataSource = dataSource;
|
|
chart.dataSource = dataSource;
|
|
|
|
+ chart.getElement = function () {
|
|
|
|
+ return element;
|
|
|
|
+ };
|
|
|
|
+ chart.getData = function () {
|
|
|
|
+ return chart.data;
|
|
|
|
+ };
|
|
|
|
+ chart.getOptions = function () {
|
|
|
|
+ return opts || {};
|
|
|
|
+ };
|
|
|
|
+ chart.getChartObject = function () {
|
|
|
|
+ return chart.chart;
|
|
|
|
+ };
|
|
Chartkick.charts[element.id] = chart;
|
|
Chartkick.charts[element.id] = chart;
|
|
fetchDataSource(chart, callback);
|
|
fetchDataSource(chart, callback);
|
|
}
|
|
}
|
|
@@ -1276,5 +1344,9 @@
|
|
charts: {}
|
|
charts: {}
|
|
};
|
|
};
|
|
|
|
|
|
- window.Chartkick = Chartkick;
|
|
|
|
|
|
+ if (typeof module === "object" && typeof module.exports === "object") {
|
|
|
|
+ module.exports = Chartkick;
|
|
|
|
+ } else {
|
|
|
|
+ window.Chartkick = Chartkick;
|
|
|
|
+ }
|
|
}(window));
|
|
}(window));
|