pax_global_header 0000666 0000000 0000000 00000000064 12765073766 0014535 g ustar 00root root 0000000 0000000 52 comment=f385804303260601320874367c6ca498859fba85
chartkick.js-2.1.0/ 0000775 0000000 0000000 00000000000 12765073766 0014113 5 ustar 00root root 0000000 0000000 chartkick.js-2.1.0/.gitignore 0000664 0000000 0000000 00000000031 12765073766 0016075 0 ustar 00root root 0000000 0000000 examples/Chart.bundle.js
chartkick.js-2.1.0/CHANGELOG.md 0000664 0000000 0000000 00000003152 12765073766 0015725 0 ustar 00root root 0000000 0000000 ## 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.txt 0000664 0000000 0000000 00000002054 12765073766 0015737 0 ustar 00root root 0000000 0000000 Copyright (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.md 0000664 0000000 0000000 00000013356 12765073766 0015402 0 ustar 00root root 0000000 0000000 # 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.json 0000664 0000000 0000000 00000000535 12765073766 0016127 0 ustar 00root root 0000000 0000000 {
"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.js 0000664 0000000 0000000 00000122156 12765073766 0016423 0 ustar 00root root 0000000 0000000 /*
* 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/ 0000775 0000000 0000000 00000000000 12765073766 0015731 5 ustar 00root root 0000000 0000000 chartkick.js-2.1.0/examples/index.html 0000664 0000000 0000000 00000065244 12765073766 0017741 0 ustar 00root root 0000000 0000000
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.json 0000664 0000000 0000000 00000001172 12765073766 0020120 0 ustar 00root root 0000000 0000000 {"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.json 0000664 0000000 0000000 00000000721 12765073766 0016401 0 ustar 00root root 0000000 0000000 {
"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"
]
}