#223 Charts & Graphs (revised)
Sep 15, 2012 | 12 minutes | Performance, Views
If you have a lot of data, consider adding a graph to provide an overview of it. Here I show how to use Morris.js to chart an Order model and visualize trends in the data.
- Download:
- source codeProject Files in Zip (108 KB)
- mp4Full Size H.264 Video (33.6 MB)
- m4vSmaller H.264 Video (14.9 MB)
- webmFull Size VP8 Video (17.6 MB)
- ogvFull Size Theora Video (36 MB)
Resources
Note: I decided to refactor the code further after recording the episode. I moved the helper code into the Order model and changed the way the prices are grouped so there's no need for the ugly first.try(:total_price) call. The refactored version is below.
app/assets/javascripts/application.js
//= require raphael //= require morris
app/assets/javascripts/orders.js.coffe
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
jQuery ->
Morris.Line
element: 'orders_chart'
data: $('#orders_chart').data('orders')
xkey: 'purchased_at'
ykeys: ['price', 'shipping_price', 'download_price']
labels: ['Total Price', 'Shipping Price', 'Download Price']
preUnits: '$'
orders/index.html.erb
<%= content_tag :div, "", id: "orders_chart", data: {orders: Order.chart_data} %>
models/order.rb
def self.chart_data(start = 3.weeks.ago) total_prices = prices_by_day(start) shipping_prices = where(shipping: true).prices_by_day(start) download_prices = where(shipping: false).prices_by_day(start) (start.to_date..Date.today).map do |date| { purchased_at: date, price: total_prices[date] || 0, shipping_price: shipping_prices[date] || 0, download_price: download_prices[date] || 0 } end end def self.prices_by_day(start) orders = where(purchased_at: start.beginning_of_day..Time.zone.now) orders = orders.group("date(purchased_at)") orders = orders.select("purchased_at, sum(price) as total_price") orders.each_with_object({}) do |order, prices| prices[order.purchased_at.to_date] = order.total_price end end
rails console
Order.group("date(purchased_at)").select("purchased_at, sum(price) as total_price") o = _ o.purchased_at o.total_price


