Permalink
Browse files

First commit

  • Loading branch information...
0 parents commit 00c40769c133c462ded6df16a93bc8b5105413eb @ankane committed May 7, 2013
Showing with 330 additions and 0 deletions.
  1. +17 −0 .gitignore
  2. +4 −0 Gemfile
  3. +22 −0 LICENSE.txt
  4. +65 −0 README.md
  5. +1 −0 Rakefile
  6. +127 −0 app/assets/javascripts/chartkick.js
  7. +25 −0 chartkick.gemspec
  8. +3 −0 lib/chartkick.rb
  9. +16 −0 lib/chartkick/engine.rb
  10. +47 −0 lib/chartkick/helper.rb
  11. +3 −0 lib/chartkick/version.rb
@@ -0,0 +1,17 @@
+*.gem
+*.rbc
+.bundle
+.config
+.yardoc
+Gemfile.lock
+InstalledFiles
+_yardoc
+coverage
+doc/
+lib/bundler/man
+pkg
+rdoc
+spec/reports
+test/tmp
+test/version_tmp
+tmp
@@ -0,0 +1,4 @@
+source 'https://rubygems.org'
+
+# Specify your gem's dependencies in chartkick.gemspec
+gemspec
@@ -0,0 +1,22 @@
+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.
@@ -0,0 +1,65 @@
+# Chartkick
+
+Create beautiful Javascript charts in one line of Ruby
+
+[Demo](http://ankane.github.io/chartkick/)
+
+:two_hearts: A perfect companion to [groupdate](http://ankane.github.io/groupdate/)
+
+Works with Rails 3.0+
+
+## Usage
+
+Line chart
+
+```erb
+<%= line_chart User.group_by_day(:created_at).count %>
+```
+
+Pie chart
+
+```erb
+<%= pie_chart Goal.group("goals.name").count %>
+```
+
+Column chart
+
+```erb
+<%= column_chart Task.group_by_hour_of_day(:created_at).count %>
+```
+
+Multiple series (line chart only)
+
+```erb
+<%= line_chart Goal.all.map{|goal| {:name => goal.name, :data => goal.feats.group_by_week(:created_at).count } } %>
+```
+
+Customize (id and height)
+
+```erb
+<%= line_chart User.group_by_day(:created_at).count, :id => "users-chart", :height => "500px" %>
+```
+
+## Installation
+
+Add this line to your application's Gemfile:
+
+```ruby
+gem "chartkick"
+```
+
+And add the javascript files to your views.
+
+```erb
+<!-- 1. Google Charts first -->
+<!-- 2. chartkick.js runs as a Rails engine - no need to install it -->
+<%= javascript_include_tag "//www.google.com/jsapi", "chartkick" %>
+```
+
+## Contributing
+
+1. Fork it
+2. Create your feature branch (`git checkout -b my-new-feature`)
+3. Commit your changes (`git commit -am 'Add some feature'`)
+4. Push to the branch (`git push origin my-new-feature`)
+5. Create new Pull Request
@@ -0,0 +1 @@
+require "bundler/gem_tasks"
@@ -0,0 +1,127 @@
+/*jslint browser: true, indent: 2 */
+/*global google*/
+
+(function() {
+ 'use strict';
+
+ google.load("visualization", "1.0", {"packages": ["corechart"]});
+
+ // Set chart options
+ var defaultOptions = {
+ fontName: "'Lucida Grande', 'Lucida Sans Unicode', Verdana, Arial, Helvetica, sans-serif",
+ pointSize: 6,
+ legend: {
+ textStyle: {
+ fontSize: 12,
+ color: "#444"
+ },
+ alignment: "center"
+ },
+ curveType: "function",
+ hAxis: {
+ textStyle: {
+ color: "#666",
+ fontSize: 12
+ },
+ gridlines: {
+ color: "transparent"
+ },
+ baselineColor: "#ccc"
+ },
+ vAxis: {
+ textStyle: {
+ color: "#666",
+ fontSize: 12
+ },
+ baselineColor: "#ccc",
+ viewWindow: {
+ min: 0
+ }
+ },
+ tooltip: {
+ textStyle: {
+ color: "#666",
+ fontSize: 12
+ }
+ }
+ }, Chartkick = {
+ LineChart: function(elementId, series) {
+ google.setOnLoadCallback(function() {
+ // Create the data table.
+ var data = new google.visualization.DataTable(), rows = {}, i, j, k, s, d, rows2 = [], options, chart;
+
+ data.addColumn("datetime", "");
+ for (i = 0; i < series.length; i += 1) {
+ s = series[i];
+ data.addColumn("number", s.name);
+
+ for (j = 0; j < s.data.length; j += 1) {
+ d = s.data[j];
+ if (!rows[d[0]]) {
+ rows[d[0]] = new Array(series.length);
+ }
+ rows[d[0]][i] = d[1];
+ }
+ }
+
+ // columns
+ rows2 = [];
+ for (k in rows) {
+ rows2.push([new Date(k * 1000)].concat(rows[k]));
+ }
+ data.addRows(rows2);
+
+ options = defaultOptions; // TODO clone
+ if (series.length > 1) {
+ options.legend.position = "right";
+ } else {
+ options.legend.position = "none";
+ }
+ options.chartArea = null;
+
+ chart = new google.visualization.LineChart(document.getElementById(elementId));
+ chart.draw(data, options);
+ });
+ },
+ PieChart: function(elementId, series) {
+ google.setOnLoadCallback(function() {
+ // Create the data table.
+ var data = new google.visualization.DataTable();
+
+ // columns
+ data.addColumn("string", "");
+ data.addColumn("number", "Value");
+ data.addRows(series);
+
+ var options = defaultOptions; // TODO clone
+ options.legend.position = "right";
+ options.chartArea = {
+ top: "10%",
+ height: "80%"
+ };
+
+ var chart = new google.visualization.PieChart(document.getElementById(elementId));
+ chart.draw(data, options);
+ });
+ },
+ ColumnChart: function(elementId, series) {
+ google.setOnLoadCallback(function() {
+ var data = new google.visualization.DataTable();
+
+ // columns
+ data.addColumn("string", "");
+ data.addColumn("number", "Value");
+ data.addRows(series);
+
+ var options = defaultOptions; // TODO clone
+ options.legend.position = "none";
+ options.chartArea = null;
+
+ var chart = new google.visualization.ColumnChart(document.getElementById(elementId));
+ chart.draw(data, options);
+ });
+ }
+ };
+
+ window.Chartkick = Chartkick;
+})();
@@ -0,0 +1,25 @@
+# coding: utf-8
+lib = File.expand_path('../lib', __FILE__)
+$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
+require 'chartkick/version'
+
+Gem::Specification.new do |spec|
+ spec.name = "chartkick"
+ spec.version = Chartkick::VERSION
+ spec.authors = ["Andrew Kane"]
+ spec.email = ["acekane1@gmail.com"]
+ spec.description = %q{Create beautiful Javascript charts in one line of Ruby}
+ spec.summary = %q{Create beautiful Javascript charts in one line of Ruby}
+ spec.homepage = ""
+ spec.license = "MIT"
+
+ spec.files = `git ls-files`.split($/)
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
+ spec.require_paths = ["lib"]
+
+ spec.add_dependency "railties", ">= 3.1"
+
+ spec.add_development_dependency "bundler", "~> 1.3"
+ spec.add_development_dependency "rake"
+end
@@ -0,0 +1,3 @@
+require "chartkick/version"
+require "chartkick/engine"
+require "chartkick/helper"
@@ -0,0 +1,16 @@
+module Chartkick
+ class Engine < ::Rails::Engine
+
+ initializer "precompile", :group => :all do |app|
+ # use a proc instead of a string
+ app.config.assets.precompile << Proc.new{|path| path == "chartkick.js" }
+ end
+
+ initializer "helper" do |app|
+ ActiveSupport.on_load(:action_view) do
+ include Helper
+ end
+ end
+
+ end
+end
@@ -0,0 +1,47 @@
+module Chartkick
+ module Helper
+
+ def line_chart(series, options = {})
+ unless series.is_a?(Array) and series[0].is_a?(Hash)
+ series = [{:name => "Value", :data => series}]
+ end
+ series.each do |s|
+ s[:data] = s[:data].map{|k, v| [k.is_a?(Time) ? k : Time.parse(k), v] }.sort_by{|k, v| k }.map{|k, v| [k.to_i, v.to_f] }
+ end
+
+ html, element_id = chartkick_div(options)
+ html << content_tag(:script) do
+ concat "new Chartkick.LineChart(#{element_id.to_json}, #{series.to_json});".html_safe
+ end
+ html
+ end
+
+ def pie_chart(series, options = {})
+ series = series.to_a
+ html, element_id = chartkick_div(options)
+ html << content_tag(:script) do
+ concat "new Chartkick.PieChart(#{element_id.to_json}, #{series.to_json});".html_safe
+ end
+ html
+ end
+
+ def column_chart(series, options = {})
+ series = series.map{|k,v| [k.to_s, v.to_f] }
+ html, element_id = chartkick_div(options)
+ html << content_tag(:script) do
+ concat "new Chartkick.ColumnChart(#{element_id.to_json}, #{series.to_json});".html_safe
+ end
+ html
+ end
+
+ private
+
+ def chartkick_div(options)
+ @chartkick_chart_id ||= 0
+ element_id = options[:id] || "chart-#{@chartkick_chart_id += 1}"
+ height = options[:height] || "300px"
+ [content_tag(:div, :id => element_id, :style => "height: #{height};") {}, element_id]
+ end
+
+ end
+end
@@ -0,0 +1,3 @@
+module Chartkick
+ VERSION = "0.0.1"
+end

0 comments on commit 00c4076

Please sign in to comment.