pax_global_header00006660000000000000000000000064127650737660014535gustar00rootroot0000000000000052 comment=f385804303260601320874367c6ca498859fba85 chartkick.js-2.1.0/000077500000000000000000000000001276507376600141135ustar00rootroot00000000000000chartkick.js-2.1.0/.gitignore000066400000000000000000000000311276507376600160750ustar00rootroot00000000000000examples/Chart.bundle.js chartkick.js-2.1.0/CHANGELOG.md000066400000000000000000000031521276507376600157250ustar00rootroot00000000000000## 2.1.0 - Added basic support for new Google Charts loader - Added `configure` function - Dropped jQuery and Zepto dependencies for AJAX - Fixed legend colors on scatter chart for Chart.js ## 2.0.1 - Added scatter chart for Chart.js - Fixed error with `xtitle` and `ytitle` on column and bar charts - Fixed all zeros with Chart.js - Fixed odd tick spacing with Chart.js ## 2.0.0 - Chart.js is now the default adapter - yay open source! - Axis types are automatically detected - no need for `discrete: true` - Better date support - New official API - Fixed min and max for Chart.js bar charts ## 1.5.1 - Added bar chart for Chart.js - Added `library` option for series - Better tick selection for time and discrete scales ## 1.5.0 - Added Chart.js adapter **beta** - Added `smarterDates` option (temporary until 2.0) - Added `smarterDiscrete` option (temporary until 2.0) - Fixed line height on timeline charts ## 1.4.2 - Added `label` option - Better tooltip for dates for Google Charts ## 1.4.1 - Fixed regression with `min: null` ## 1.4.0 - Added scatter chart - Added axis titles ## 1.3.0 - Added timelines - Added `adapter` option ## 1.2.2 - Added `colors` option ## 1.2.1 - Added `discrete` option ## 1.2.0 - Added geo chart - Added `stacked` option ## 1.1.1 - Made sure options can be overridden - Added support for Google Charts localization ## 1.1.0 - Added bar chart and area chart - Resize charts when window is resized ## 1.0.2 - Added library option ## 1.0.1 - Added support for Highcharts 2.1+ - Fixed sorting for line chart with multiple series and Google Charts ## 1.0.0 - First major release chartkick.js-2.1.0/LICENSE.txt000066400000000000000000000020541276507376600157370ustar00rootroot00000000000000Copyright (c) 2013 Andrew Kane MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. chartkick.js-2.1.0/README.md000066400000000000000000000133561276507376600154020ustar00rootroot00000000000000# Chartkick.js Create beautiful JavaScript charts with minimal code [See it in action](http://ankane.github.io/chartkick.js/examples/) Supports [Chart.js](http://www.chartjs.org/), [Google Charts](https://developers.google.com/chart/), and [Highcharts](http://www.highcharts.com/) Also available for [React](https://github.com/ankane/react-chartkick), [Ruby](https://github.com/ankane/chartkick), [Python](https://github.com/mher/chartkick.py), and [Elixir](https://github.com/buren/chartkick-ex) ## Usage Create a div for the chart ```html
``` Line chart ```javascript new Chartkick.LineChart("chart-1", {"2013-02-10 00:00:00 -0800": 11, "2013-02-11 00:00:00 -0800": 6}); ``` Pie chart ```javascript new Chartkick.PieChart("chart-1", [["Blueberry", 44],["Strawberry", 23]]); ``` Column chart ```javascript new Chartkick.ColumnChart("chart-1", [["Sun", 32],["Mon", 46],["Tue", 28]]); ``` Bar chart ```javascript new Chartkick.BarChart("chart-1", [["Work", 32],["Play", 1492]]); ``` Area chart ```javascript new Chartkick.AreaChart("chart-1", {"2013-02-10 00:00:00 -0800": 11, "2013-02-11 00:00:00 -0800": 6}); ``` Scatter chart ```javascript new Chartkick.ScatterChart("chart-1", [[174.0, 80.0], [176.5, 82.3], [180.3, 73.6], [167.6, 74.1], [188.0, 85.9]]); ``` Geo chart - *Google Charts* ```javascript new Chartkick.GeoChart("chart-1", [["United States",44],["Germany",23],["Brazil",22]]); ``` Timeline - *Google Charts* ```javascript new Chartkick.Timeline("chart-1", [["Washington", "1789-04-29", "1797-03-03"],["Adams", "1797-03-03", "1801-03-03"]]); ``` Multiple series ```javascript data = [ {"name":"Workout", "data": {"2013-02-10 00:00:00 -0800": 3, "2013-02-17 00:00:00 -0800": 4}}, {"name":"Call parents", "data": {"2013-02-10 00:00:00 -0800": 5, "2013-02-17 00:00:00 -0800": 3}} ]; new Chartkick.LineChart("chart-1", data); ``` ### Say Goodbye To Timeouts Make your pages load super fast and stop worrying about timeouts. Give each chart its own endpoint. ```javascript new Chartkick.LineChart("chart-1", "/stocks"); ``` ### Options Min and max values ```javascript new Chartkick.LineChart("chart-1", data, {"min": 1000, "max": 5000}); ``` `min` defaults to 0 for charts with non-negative values. Use `null` to let the charting library decide. Colors ```javascript new Chartkick.LineChart("chart-1", data, {"colors": ["pink", "#999"]}); ``` Stacked columns or bars ```javascript new Chartkick.ColumnChart("chart-1", data, {"stacked": true}); ``` Discrete axis ```javascript new Chartkick.LineChart("chart-1", data, {"discrete": true}); ``` Label (for single series) ```javascript new Chartkick.LineChart("chart-1", data, {"label": "Value"}); ``` Axis titles ```javascript new Chartkick.LineChart("chart-1", data, {"xtitle": "Time", "ytitle": "Population"}); ``` You can pass options directly to the charting library with: ```javascript new Chartkick.LineChart("chart-1", data, {"library": {"backgroundColor": "pink"}}); ``` ### Data Pass data as an array or object ```javascript new Chartkick.PieChart("chart-1", {"Blueberry": 44, "Strawberry": 23}); new Chartkick.PieChart("chart-1", [["Blueberry", 44],["Strawberry", 23]]); ``` Times can be a `Date`, a timestamp, or a string (strings are parsed) ```javascript new Chartkick.LineChart("chart-1", [[new Date(), 5],[1368174456, 4],["2013-05-07 00:00:00 UTC", 7]]); ``` ## Installation Download [directly](https://raw.githubusercontent.com/ankane/chartkick.js/master/chartkick.js), or with npm or Bower: ```sh npm install chartkick # or bower install chartkick ``` For Chart.js (works with 2.1+), [download the bundle](http://www.chartjs.org/docs/#getting-started-download-chart-js) and use: ```html ``` For Google Charts, use: ```html ``` For Highcharts (works with 2.1+), [download it](http://www.highcharts.com/download) and use: ```html ``` ### Localization To specify a language for Google Charts, add: ```html ``` after the JavaScript files and before your charts. ### Adapter If more than one charting library is loaded, choose between them with: ```javascript new Chartkick.LineChart("chart-1", data, {"adapter": "google"}); // or highcharts ``` ### API Access a chart with: ```javascript var chart = Chartkick.charts["chart-id"]; ``` Get the underlying chart object with: ```javascript chart.getChartObject(); ``` You can also use: ```javascript chart.getElement(); chart.getData(); chart.getOptions(); ``` ## Examples To run the files in the `examples` directory, you'll need a web server. Run: ```sh python -m SimpleHTTPServer ``` and visit [http://localhost:8000/examples/](http://localhost:8000/examples/) ## Upgrading ### 2.0 Breaking changes - Chart.js is now the default adapter if multiple are loaded - yay open source! - Axis types are automatically detected - no need for `discrete: true` - Better date support - dates are no longer treated as UTC ## Credits Chartkick uses [iso8601.js](https://github.com/Do/iso8601.js) to parse dates and times. ## History View the [changelog](https://github.com/ankane/chartkick.js/blob/master/CHANGELOG.md) Chartkick.js follows [Semantic Versioning](http://semver.org/) ## Contributing Everyone is encouraged to help improve this project. Here are a few ways you can help: - [Report bugs](https://github.com/ankane/chartkick.js/issues) - Fix bugs and [submit pull requests](https://github.com/ankane/chartkick.js/pulls) - Write, clarify, or fix documentation - Suggest or add new features chartkick.js-2.1.0/bower.json000066400000000000000000000005351276507376600161270ustar00rootroot00000000000000{ "name": "chartkick", "version": "2.1.0", "main": "chartkick.js", "ignore": [ "**/.*" ], "homepage": "https://github.com/ankane/chartkick.js", "authors": [ "Andrew Kane " ], "description": "Create beautiful Javascript charts with minimal code", "keywords": [ "charts" ], "license": "MIT" } chartkick.js-2.1.0/chartkick.js000066400000000000000000001221561276507376600164230ustar00rootroot00000000000000/* * Chartkick.js * Create beautiful JavaScript charts with minimal code * https://github.com/ankane/chartkick.js * v2.1.0 * MIT License */ /*jslint browser: true, indent: 2, plusplus: true, vars: true */ (function (window) { 'use strict'; var config = window.Chartkick || {}; var Chartkick, ISO8601_PATTERN, DECIMAL_SEPARATOR, adapters = []; var DATE_PATTERN = /^(\d\d\d\d)(\-)?(\d\d)(\-)?(\d\d)$/i; var GoogleChartsAdapter, HighchartsAdapter, ChartjsAdapter; // helpers function isArray(variable) { return Object.prototype.toString.call(variable) === "[object Array]"; } function isFunction(variable) { return variable instanceof Function; } function isPlainObject(variable) { return !isFunction(variable) && variable instanceof Object; } // https://github.com/madrobby/zepto/blob/master/src/zepto.js function extend(target, source) { var key; for (key in source) { if (isPlainObject(source[key]) || isArray(source[key])) { if (isPlainObject(source[key]) && !isPlainObject(target[key])) { target[key] = {}; } if (isArray(source[key]) && !isArray(target[key])) { target[key] = []; } extend(target[key], source[key]); } else if (source[key] !== undefined) { target[key] = source[key]; } } } function merge(obj1, obj2) { var target = {}; extend(target, obj1); extend(target, obj2); return target; } // https://github.com/Do/iso8601.js ISO8601_PATTERN = /(\d\d\d\d)(\-)?(\d\d)(\-)?(\d\d)(T)?(\d\d)(:)?(\d\d)?(:)?(\d\d)?([\.,]\d+)?($|Z|([\+\-])(\d\d)(:)?(\d\d)?)/i; 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++) { if (data[j][1] < 0) { return true; } } } return false; } function jsOptionsFunc(defaultOptions, hideLegend, setMin, setMax, setStacked, setXtitle, setYtitle) { return function (series, opts, chartOptions) { var options = merge({}, defaultOptions); options = merge(options, chartOptions || {}); // hide legend // this is *not* an external option! if (opts.hideLegend) { hideLegend(options); } // min if ("min" in opts) { setMin(options, opts.min); } else if (!negativeValues(series)) { setMin(options, 0); } // max if (opts.max) { setMax(options, opts.max); } if ("stacked" in opts) { setStacked(options, opts.stacked); } if (opts.colors) { options.colors = opts.colors; } if (opts.xtitle) { setXtitle(options, opts.xtitle); } if (opts.ytitle) { setYtitle(options, opts.ytitle); } // merge library last options = merge(options, opts.library || {}); return options; }; } function setText(element, text) { if (document.body.innerText) { element.innerText = text; } else { element.textContent = text; } } function chartError(element, message) { setText(element, "Error Loading Chart: " + message); element.style.color = "#ff0000"; } function getJSON(element, url, success) { ajaxCall(url, success, function (jqXHR, textStatus, errorThrown) { var message = (typeof errorThrown === "string") ? errorThrown : errorThrown.message; chartError(element, message); }); } function ajaxCall(url, success, error) { var $ = window.jQuery || window.Zepto || window.$; if ($) { $.ajax({ dataType: "json", url: url, success: success, error: error }); } else { var xhr = new XMLHttpRequest(); xhr.open("GET", url, true); xhr.setRequestHeader("Content-Type", "application/json"); xhr.onload = function () { if (xhr.status === 200) { success(JSON.parse(xhr.responseText), xhr.statusText, xhr); } else { error(xhr, "error", xhr.statusText); } }; xhr.send(); } } function errorCatcher(chart, callback) { try { callback(chart); } catch (err) { chartError(chart.element, err.message); throw err; } } function fetchDataSource(chart, callback) { if (typeof chart.dataSource === "string") { getJSON(chart.element, chart.dataSource, function (data, textStatus, jqXHR) { chart.data = data; errorCatcher(chart, callback); }); } else { chart.data = chart.dataSource; errorCatcher(chart, callback); } } // type conversions function toStr(n) { return "" + n; } function toFloat(n) { return parseFloat(n); } function toDate(n) { var matches, year, month, day; if (typeof n !== "object") { if (typeof n === "number") { n = new Date(n * 1000); // ms } else 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 // 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); } } return n; } function toArr(n) { if (!isArray(n)) { var arr = [], i; for (i in n) { if (n.hasOwnProperty(i)) { arr.push([i, n[i]]); } } n = arr; } return n; } function sortByTime(a, b) { return a[0].getTime() - b[0].getTime(); } function sortByNumber(a, b) { return a - b; } function loadAdapters() { if (!HighchartsAdapter && "Highcharts" in window) { HighchartsAdapter = new function () { var Highcharts = window.Highcharts; this.name = "highcharts"; var defaultOptions = { chart: {}, xAxis: { title: { text: null }, labels: { style: { fontSize: "12px" } } }, yAxis: { title: { text: null }, labels: { style: { fontSize: "12px" } } }, title: { text: null }, credits: { enabled: false }, legend: { borderWidth: 0 }, tooltip: { style: { fontSize: "12px" } }, plotOptions: { areaspline: {}, series: { marker: {} } } }; var hideLegend = function (options) { options.legend.enabled = false; }; var setMin = function (options, min) { options.yAxis.min = min; }; var setMax = function (options, max) { options.yAxis.max = max; }; var setStacked = function (options, stacked) { options.plotOptions.series.stacking = stacked ? "normal" : null; }; var setXtitle = function (options, title) { options.xAxis.title.text = title; }; var setYtitle = function (options, title) { options.yAxis.title.text = title; }; var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setMin, setMax, setStacked, setXtitle, setYtitle); this.renderLineChart = function (chart, chartType) { chartType = chartType || "spline"; var chartOptions = {}; if (chartType === "areaspline") { chartOptions = { plotOptions: { areaspline: { stacking: "normal" }, series: { marker: { enabled: false } } } }; } var options = jsOptions(chart.data, chart.options, chartOptions), data, i, j; options.xAxis.type = chart.options.discrete ? "category" : "datetime"; if (!options.chart.type) { options.chart.type = chartType; } options.chart.renderTo = chart.element.id; var series = chart.data; for (i = 0; i < series.length; i++) { data = series[i].data; if (!chart.options.discrete) { for (j = 0; j < data.length; j++) { data[j][0] = data[j][0].getTime(); } } series[i].marker = {symbol: "circle"}; } options.series = series; new Highcharts.Chart(options); }; this.renderScatterChart = function (chart) { var chartOptions = {}; var options = jsOptions(chart.data, chart.options, chartOptions); options.chart.type = "scatter"; options.chart.renderTo = chart.element.id; options.series = chart.data; new Highcharts.Chart(options); }; this.renderPieChart = function (chart) { var chartOptions = {}; if (chart.options.colors) { chartOptions.colors = chart.options.colors; } var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {}); options.chart.renderTo = chart.element.id; options.series = [{ type: "pie", name: chart.options.label || "Value", data: chart.data }]; new Highcharts.Chart(options); }; this.renderColumnChart = function (chart, chartType) { chartType = chartType || "column"; var series = chart.data; var options = jsOptions(series, chart.options), i, j, s, d, rows = []; options.chart.type = chartType; options.chart.renderTo = chart.element.id; for (i = 0; i < series.length; i++) { s = series[i]; for (j = 0; j < s.data.length; j++) { d = s.data[j]; if (!rows[d[0]]) { rows[d[0]] = new Array(series.length); } rows[d[0]][i] = d[1]; } } var categories = []; for (i in rows) { if (rows.hasOwnProperty(i)) { categories.push(i); } } options.xAxis.categories = categories; var newSeries = []; for (i = 0; i < series.length; i++) { d = []; for (j = 0; j < categories.length; j++) { d.push(rows[categories[j]][i] || 0); } newSeries.push({ name: series[i].name, data: d }); } options.series = newSeries; new Highcharts.Chart(options); }; var self = this; this.renderBarChart = function (chart) { self.renderColumnChart(chart, "bar"); }; this.renderAreaChart = function (chart) { self.renderLineChart(chart, "areaspline"); }; }; adapters.push(HighchartsAdapter); } if (!GoogleChartsAdapter && window.google && (window.google.setOnLoadCallback || window.google.charts)) { GoogleChartsAdapter = new function () { var google = window.google; this.name = "google"; var loaded = {}; var callbacks = []; var runCallbacks = function () { var cb, call; for (var i = 0; i < callbacks.length; i++) { cb = callbacks[i]; call = google.visualization && ((cb.pack === "corechart" && google.visualization.LineChart) || (cb.pack === "timeline" && google.visualization.Timeline)); if (call) { cb.callback(); callbacks.splice(i, 1); i--; } } }; var waitForLoaded = function (pack, callback) { if (!callback) { callback = pack; pack = "corechart"; } callbacks.push({pack: pack, callback: callback}); if (loaded[pack]) { runCallbacks(); } else { loaded[pack] = true; // https://groups.google.com/forum/#!topic/google-visualization-api/fMKJcyA2yyI var loadOptions = { packages: [pack], callback: runCallbacks }; if (config.language) { loadOptions.language = config.language; } if (window.google.setOnLoadCallback) { google.load("visualization", "1", loadOptions); } else { google.charts.load("current", loadOptions); } } }; // Set chart options var defaultOptions = { chartArea: {}, fontName: "'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif", pointSize: 6, legend: { textStyle: { fontSize: 12, color: "#444" }, alignment: "center", position: "right" }, curveType: "function", hAxis: { textStyle: { color: "#666", fontSize: 12 }, titleTextStyle: {}, gridlines: { color: "transparent" }, baselineColor: "#ccc", viewWindow: {} }, vAxis: { textStyle: { color: "#666", fontSize: 12 }, titleTextStyle: {}, baselineColor: "#ccc", viewWindow: {} }, tooltip: { textStyle: { color: "#666", fontSize: 12 } } }; var hideLegend = function (options) { options.legend.position = "none"; }; var setMin = function (options, min) { options.vAxis.viewWindow.min = min; }; var setMax = function (options, max) { options.vAxis.viewWindow.max = max; }; var setBarMin = function (options, min) { options.hAxis.viewWindow.min = min; }; var setBarMax = function (options, max) { options.hAxis.viewWindow.max = max; }; var setStacked = function (options, stacked) { options.isStacked = !!stacked; }; var setXtitle = function (options, title) { options.hAxis.title = title; options.hAxis.titleTextStyle.italic = false; }; var setYtitle = function (options, title) { options.vAxis.title = title; options.vAxis.titleTextStyle.italic = false; }; var jsOptions = jsOptionsFunc(defaultOptions, hideLegend, setMin, setMax, setStacked, setXtitle, setYtitle); // cant use object as key var createDataTable = function (series, columnType) { var i, j, s, d, key, rows = []; for (i = 0; i < series.length; i++) { s = series[i]; for (j = 0; j < s.data.length; j++) { d = s.data[j]; key = (columnType === "datetime") ? d[0].getTime() : d[0]; if (!rows[key]) { rows[key] = new Array(series.length); } rows[key][i] = toFloat(d[1]); } } var rows2 = []; var day = true; var value; for (i in rows) { if (rows.hasOwnProperty(i)) { if (columnType === "datetime") { value = new Date(toFloat(i)); day = day && isDay(value); } else if (columnType === "number") { value = toFloat(i); } else { value = i; } rows2.push([value].concat(rows[i])); } } if (columnType === "datetime") { rows2.sort(sortByTime); } // create datatable var data = new google.visualization.DataTable(); columnType = columnType === "datetime" && day ? "date" : columnType; data.addColumn(columnType, ""); for (i = 0; i < series.length; i++) { data.addColumn("number", series[i].name); } data.addRows(rows2); return data; }; var resize = function (callback) { if (window.attachEvent) { window.attachEvent("onresize", callback); } else if (window.addEventListener) { window.addEventListener("resize", callback, true); } callback(); }; this.renderLineChart = function (chart) { waitForLoaded(function () { var options = jsOptions(chart.data, chart.options); var data = createDataTable(chart.data, chart.options.discrete ? "string" : "datetime"); chart.chart = new google.visualization.LineChart(chart.element); resize(function () { chart.chart.draw(data, options); }); }); }; this.renderPieChart = function (chart) { waitForLoaded(function () { var chartOptions = { chartArea: { top: "10%", height: "80%" } }; if (chart.options.colors) { chartOptions.colors = chart.options.colors; } var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {}); var data = new google.visualization.DataTable(); data.addColumn("string", ""); data.addColumn("number", "Value"); data.addRows(chart.data); chart.chart = new google.visualization.PieChart(chart.element); resize(function () { chart.chart.draw(data, options); }); }); }; this.renderColumnChart = function (chart) { waitForLoaded(function () { var options = jsOptions(chart.data, chart.options); var data = createDataTable(chart.data, "string"); chart.chart = new google.visualization.ColumnChart(chart.element); resize(function () { chart.chart.draw(data, options); }); }); }; this.renderBarChart = function (chart) { waitForLoaded(function () { var chartOptions = { hAxis: { gridlines: { color: "#ccc" } } }; var options = jsOptionsFunc(defaultOptions, hideLegend, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart.data, chart.options, chartOptions); var data = createDataTable(chart.data, "string"); chart.chart = new google.visualization.BarChart(chart.element); resize(function () { chart.chart.draw(data, options); }); }); }; this.renderAreaChart = function (chart) { waitForLoaded(function () { var chartOptions = { isStacked: true, pointSize: 0, areaOpacity: 0.5 }; var options = jsOptions(chart.data, chart.options, chartOptions); var data = createDataTable(chart.data, chart.options.discrete ? "string" : "datetime"); chart.chart = new google.visualization.AreaChart(chart.element); resize(function () { chart.chart.draw(data, options); }); }); }; this.renderGeoChart = function (chart) { waitForLoaded(function () { var chartOptions = { legend: "none", colorAxis: { colors: chart.options.colors || ["#f6c7b6", "#ce502d"] } }; var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {}); var data = new google.visualization.DataTable(); data.addColumn("string", ""); data.addColumn("number", chart.options.label || "Value"); data.addRows(chart.data); chart.chart = new google.visualization.GeoChart(chart.element); resize(function () { chart.chart.draw(data, options); }); }); }; this.renderScatterChart = function (chart) { waitForLoaded(function () { var chartOptions = {}; var options = jsOptions(chart.data, chart.options, chartOptions); var data = createDataTable(chart.data, "number"); chart.chart = new google.visualization.ScatterChart(chart.element); resize(function () { chart.chart.draw(data, options); }); }); }; this.renderTimeline = function (chart) { waitForLoaded("timeline", function () { var chartOptions = { legend: "none" }; if (chart.options.colors) { chartOptions.colors = chart.options.colors; } var options = merge(merge(defaultOptions, chartOptions), chart.options.library || {}); var data = new google.visualization.DataTable(); data.addColumn({type: "string", id: "Name"}); data.addColumn({type: "date", id: "Start"}); data.addColumn({type: "date", id: "End"}); data.addRows(chart.data); chart.element.style.lineHeight = "normal"; chart.chart = new google.visualization.Timeline(chart.element); resize(function () { chart.chart.draw(data, options); }); }); }; }; adapters.push(GoogleChartsAdapter); } if (!ChartjsAdapter && "Chart" in window) { ChartjsAdapter = new function () { var Chart = window.Chart; this.name = "chartjs"; var baseOptions = { maintainAspectRatio: false, animation: false }; var defaultOptions = { scales: { yAxes: [ { ticks: { maxTicksLimit: 4 }, scaleLabel: { fontSize: 16, // fontStyle: "bold", fontColor: "#333" } } ], xAxes: [ { gridLines: { drawOnChartArea: false }, scaleLabel: { fontSize: 16, // fontStyle: "bold", fontColor: "#333" }, time: {}, ticks: {} } ] }, legend: {} }; // 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", "#3B3EAC" ]; var hideLegend = function (options) { options.legend.display = false; }; var setMin = function (options, min) { if (min !== null) { options.scales.yAxes[0].ticks.min = min; } }; var setMax = function (options, 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) { options.scales.xAxes[0].stacked = !!stacked; options.scales.yAxes[0].stacked = !!stacked; }; var setXtitle = function (options, title) { options.scales.xAxes[0].scaleLabel.display = true; options.scales.xAxes[0].scaleLabel.labelString = title; }; var setYtitle = function (options, title) { options.scales.yAxes[0].scaleLabel.display = true; options.scales.yAxes[0].scaleLabel.labelString = title; }; var drawChart = function(chart, type, data, options) { chart.element.innerHTML = ""; var ctx = chart.element.getElementsByTagName("CANVAS")[0]; chart.chart = new Chart(ctx, { type: type, data: data, options: options }); }; // http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb 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; }; var setLabelSize = function (chart, data, options) { var maxLabelSize = Math.ceil(chart.element.offsetWidth / 4.0 / data.labels.length); if (maxLabelSize > 25) { maxLabelSize = 25; } options.scales.xAxes[0].ticks.callback = function (value) { value = toStr(value); if (value.length > maxLabelSize) { return value.substring(0, maxLabelSize - 2) + "..."; } else { return value; } }; }; var jsOptions = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setMin, setMax, setStacked, setXtitle, setYtitle); var createDataTable = function (chart, options, chartType) { var datasets = []; var labels = []; var colors = chart.options.colors || defaultColors; var day = true; var week = true; var dayOfWeek; var month = true; var year = true; var hour = true; var minute = true; var detectType = (chartType === "line" || chartType === "area") && !chart.options.discrete; var series = chart.data; var sortedLabels = []; var i, j, s, d, key, rows = []; for (i = 0; i < series.length; i++) { s = series[i]; for (j = 0; j < s.data.length; j++) { d = s.data[j]; key = detectType ? d[0].getTime() : d[0]; if (!rows[key]) { rows[key] = new Array(series.length); } rows[key][i] = toFloat(d[1]); if (sortedLabels.indexOf(key) === -1) { sortedLabels.push(key); } } } if (detectType) { sortedLabels.sort(sortByNumber); } var rows2 = []; for (j = 0; j < series.length; j++) { rows2.push([]); } var value; var k; for (k = 0; k < sortedLabels.length; k++) { i = sortedLabels[k]; if (detectType) { value = new Date(toFloat(i)); // TODO make this efficient day = day && isDay(value); if (!dayOfWeek) { dayOfWeek = value.getDay(); } week = week && isWeek(value, dayOfWeek); month = month && isMonth(value); year = year && isYear(value); hour = hour && isHour(value); minute = minute && isMinute(value); } else { value = i; } labels.push(value); for (j = 0; j < series.length; j++) { rows2[j].push(rows[i][j]); } } for (i = 0; i < series.length; i++) { s = series[i]; var backgroundColor = chartType !== "line" ? addOpacity(colors[i], 0.5) : colors[i]; var dataset = { label: s.name, data: rows2[i], fill: chartType === "area", borderColor: colors[i], backgroundColor: backgroundColor, pointBackgroundColor: colors[i], borderWidth: 2 }; datasets.push(merge(dataset, s.library || {})); } if (detectType && labels.length > 0) { var minTime = labels[0].getTime(); var maxTime = labels[0].getTime(); for (i = 1; i < labels.length; i++) { value = labels[i].getTime(); if (value < minTime) { minTime = value; } if (value > maxTime) { maxTime = value; } } var timeDiff = (maxTime - minTime) / (86400 * 1000.0); if (!options.scales.xAxes[0].time.unit) { var step; if (year || timeDiff > 365 * 10) { options.scales.xAxes[0].time.unit = "year"; step = 365; } else if (month || timeDiff > 30 * 10) { options.scales.xAxes[0].time.unit = "month"; step = 30; } else if (day || timeDiff > 10) { options.scales.xAxes[0].time.unit = "day"; 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) { 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; } } 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"; } } } var data = { labels: labels, datasets: datasets }; return data; }; this.renderLineChart = function (chart, chartType) { var areaOptions = {}; if (chartType === "area") { // TODO fix area stacked // 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 data = createDataTable(chart, options, chartType || "line"); options.scales.xAxes[0].type = chart.options.discrete ? "category" : "time"; drawChart(chart, "line", data, options); }; this.renderPieChart = function (chart) { var options = merge(baseOptions, chart.options.library || {}); var labels = []; var values = []; for (var i = 0; i < chart.data.length; i++) { var point = chart.data[i]; labels.push(point[0]); values.push(point[1]); } var data = { labels: labels, datasets: [ { data: values, backgroundColor: chart.options.colors || defaultColors } ] }; drawChart(chart, "pie", data, options); }; this.renderColumnChart = function (chart, chartType) { var options; if (chartType === "bar") { options = jsOptionsFunc(merge(baseOptions, defaultOptions), hideLegend, setBarMin, setBarMax, setStacked, setXtitle, setYtitle)(chart.data, chart.options); } else { options = jsOptions(chart.data, chart.options); } var data = createDataTable(chart, options, "column"); setLabelSize(chart, data, options); drawChart(chart, (chartType === "bar" ? "horizontalBar" : "bar"), data, options); }; var self = this; this.renderAreaChart = function (chart) { self.renderLineChart(chart, "area"); }; this.renderBarChart = function (chart) { self.renderColumnChart(chart, "bar"); }; this.renderScatterChart = function (chart) { var options = jsOptions(chart.data, chart.options); var colors = chart.options.colors || defaultColors; var datasets = []; var series = chart.data; for (var i = 0; i < series.length; i++) { var s = series[i]; var d = []; for (var j = 0; j < s.data.length; j++) { d.push({ x: toFloat(s.data[j][0]), y: toFloat(s.data[j][1]) }); } datasets.push({ label: s.name, showLine: false, data: d, borderColor: colors[i], backgroundColor: colors[i], pointBackgroundColor: colors[i] }) } var data = {datasets: datasets}; options.scales.xAxes[0].type = "linear"; options.scales.xAxes[0].position = "bottom"; drawChart(chart, "line", data, options); }; }; adapters.unshift(ChartjsAdapter); } } // TODO remove chartType if cross-browser way // to get the name of the chart class function renderChart(chartType, chart) { var i, adapter, fnName, adapterName; fnName = "render" + chartType; adapterName = chart.options.adapter; loadAdapters(); for (i = 0; i < adapters.length; i++) { adapter = adapters[i]; if ((!adapterName || adapterName === adapter.name) && isFunction(adapter[fnName])) { return adapter[fnName](chart); } } throw new Error("No adapter found"); } // process data var toFormattedKey = function (key, keyType) { if (keyType === "number") { key = toFloat(key); } else if (keyType === "datetime") { key = toDate(key); } else { key = toStr(key); } return key; }; var formatSeriesData = function (data, keyType) { var r = [], key, j; for (j = 0; j < data.length; j++) { key = toFormattedKey(data[j][0], keyType); r.push([key, toFloat(data[j][1])]); } if (keyType === "datetime") { r.sort(sortByTime); } return r; }; function isMinute(d) { return d.getMilliseconds() === 0 && d.getSeconds() === 0; } function isHour(d) { return isMinute(d) && d.getMinutes() === 0; } function isDay(d) { return isHour(d) && d.getHours() === 0; } function isWeek(d, dayOfWeek) { return isDay(d) && d.getDay() === dayOfWeek; } function isMonth(d) { return isDay(d) && d.getDate() === 1; } function isYear(d) { return isMonth(d) && d.getMonth() === 0; } function isDate(obj) { 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) { var i, j, data; for (i = 0; i < series.length; i++) { data = toArr(series[i].data); for (j = 0; j < data.length; j++) { if (!isDate(data[j][0])) { return true; } } } return false; } function processSeries(series, opts, keyType) { var i; // see if one series or multiple if (!isArray(series) || typeof series[0] !== "object" || isArray(series[0])) { series = [{name: opts.label || "Value", data: series}]; opts.hideLegend = true; } else { opts.hideLegend = false; } if ((opts.discrete === null || opts.discrete === undefined)) { opts.discrete = detectDiscrete(series); } if (opts.discrete) { keyType = "string"; } // right format for (i = 0; i < series.length; i++) { series[i].data = formatSeriesData(toArr(series[i].data), keyType); } return series; } function processSimple(data) { var perfectData = toArr(data), i; for (i = 0; i < perfectData.length; i++) { perfectData[i] = [toStr(perfectData[i][0]), toFloat(perfectData[i][1])]; } return perfectData; } function processTime(data) { var i; for (i = 0; i < data.length; i++) { data[i][1] = toDate(data[i][1]); data[i][2] = toDate(data[i][2]); } return data; } function processLineData(chart) { chart.data = processSeries(chart.data, chart.options, "datetime"); renderChart("LineChart", chart); } function processColumnData(chart) { chart.data = processSeries(chart.data, chart.options, "string"); renderChart("ColumnChart", chart); } function processPieData(chart) { chart.data = processSimple(chart.data); renderChart("PieChart", chart); } function processBarData(chart) { chart.data = processSeries(chart.data, chart.options, "string"); renderChart("BarChart", chart); } function processAreaData(chart) { chart.data = processSeries(chart.data, chart.options, "datetime"); renderChart("AreaChart", chart); } function processGeoData(chart) { chart.data = processSimple(chart.data); renderChart("GeoChart", chart); } function processScatterData(chart) { chart.data = processSeries(chart.data, chart.options, "number"); renderChart("ScatterChart", chart); } function processTimelineData(chart) { chart.data = processTime(chart.data); renderChart("Timeline", chart); } function setElement(chart, element, dataSource, opts, callback) { var elementId; if (typeof element === "string") { elementId = element; element = document.getElementById(element); if (!element) { throw new Error("No element with id " + elementId); } } chart.element = element; chart.options = opts || {}; 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; fetchDataSource(chart, callback); } // define classes Chartkick = { LineChart: function (element, dataSource, opts) { setElement(this, element, dataSource, opts, processLineData); }, PieChart: function (element, dataSource, opts) { setElement(this, element, dataSource, opts, processPieData); }, ColumnChart: function (element, dataSource, opts) { setElement(this, element, dataSource, opts, processColumnData); }, BarChart: function (element, dataSource, opts) { setElement(this, element, dataSource, opts, processBarData); }, AreaChart: function (element, dataSource, opts) { setElement(this, element, dataSource, opts, processAreaData); }, GeoChart: function (element, dataSource, opts) { setElement(this, element, dataSource, opts, processGeoData); }, ScatterChart: function (element, dataSource, opts) { setElement(this, element, dataSource, opts, processScatterData); }, Timeline: function (element, dataSource, opts) { setElement(this, element, dataSource, opts, processTimelineData); }, charts: {}, configure: function (options) { for (var key in options) { if (options.hasOwnProperty(key)) { config[key] = options[key]; } } } }; if (typeof module === "object" && typeof module.exports === "object") { module.exports = Chartkick; } else { window.Chartkick = Chartkick; } }(window)); chartkick.js-2.1.0/examples/000077500000000000000000000000001276507376600157315ustar00rootroot00000000000000chartkick.js-2.1.0/examples/index.html000066400000000000000000000652441276507376600177410ustar00rootroot00000000000000 Chartkick.js

Line Chart

Pie Chart

Column Chart

Bar Chart

Area Chart

Scatter Chart

Timeline

Multiple Series Line

Multiple Series Bar

Multiple Series Bar Stacked

Multiple Series Column Stacked

Multiple Series Area

Multiple Series Scatter

Remote

One Series

Library Option

Geo Chart

Markers

Discrete Line Chart

Discrete Area Chart

Discrete Multiple Series

Different Data

Min

Max

Min Null

Axis Titles Line

Axis Titles Bar

Colors

Pie Colors

Line Label

Pie Label

Line Chart - Times

Line Chart - Single Time

Line Chart - Week Monday

Smarter Discrete

Column Labels

Time Labels

Unordered Data

Weekly Data

Minute Data

One Point

Zeros

Overlapping Labels

chartkick.js-2.1.0/examples/remote.json000066400000000000000000000011721276507376600201200ustar00rootroot00000000000000{"2013-02-10 00:00:00 -0800":11,"2013-02-11 00:00:00 -0800":6,"2013-02-12 00:00:00 -0800":3,"2013-02-13 00:00:00 -0800":2,"2013-02-14 00:00:00 -0800":5,"2013-02-15 00:00:00 -0800":3,"2013-02-16 00:00:00 -0800":8,"2013-02-17 00:00:00 -0800":6,"2013-02-18 00:00:00 -0800":6,"2013-02-19 00:00:00 -0800":12,"2013-02-20 00:00:00 -0800":5,"2013-02-21 00:00:00 -0800":5,"2013-02-22 00:00:00 -0800":3,"2013-02-23 00:00:00 -0800":1,"2013-02-24 00:00:00 -0800":10,"2013-02-25 00:00:00 -0800":1,"2013-02-26 00:00:00 -0800":3,"2013-02-27 00:00:00 -0800":2,"2013-02-28 00:00:00 -0800":3,"2013-03-01 00:00:00 -0800":2,"2013-03-02 00:00:00 -0800":8}chartkick.js-2.1.0/package.json000066400000000000000000000007211276507376600164010ustar00rootroot00000000000000{ "name": "chartkick", "version": "2.1.0", "homepage": "https://github.com/ankane/chartkick.js", "description": "Create beautiful JavaScript charts with minimal code", "main": "chartkick.js", "dependencies": { }, "keywords": [ "charts" ], "authors": [ "ankane" ], "license": "MIT", "repository": { "type": "git", "url": "https://github.com/ankane/chartkick.js" }, "ignore": [ "**/.*", "test", "tests" ] }