require 'json' require 'bigdecimal' module Chartjs module ChartHelpers CHART_TYPES = %w[ bar bubble doughnut horizontal_bar line pie polar_area radar scatter ] module Explicit CHART_TYPES.each do |type| define_method "chartjs_#{type}_chart" do |data, options = {}, plugins = {}| # def chartjs_polar_area_chart(data, options = {}, plugins = {}) chart type, data, options, plugins # chart 'polar_area', data, options, plugins end # end end include Chartjs::ChartHelpers end module Implicit CHART_TYPES.each do |type| define_method "#{type}_chart" do |data, options = {}, plugins = {}| # def polar_area_chart(data, options = {}, plugins = {}) chart type, data, options, plugins # chart 'polar_area', data, options, plugins end # end end include Chartjs::ChartHelpers end private def chart(type, data, options, plugins) opts = options.dup @chart_id ||= -1 element_id = opts.delete(:id) || "chart-#{@chart_id += 1}" css_class = opts.delete(:class) || 'chart' width = opts.delete(:width) || '400' height = opts.delete(:height) || '400' canvas = content_tag :canvas, '', id: element_id, class: css_class, width: width, height: height script = javascript_tag(nonce: true) do <<-END.squish.html_safe (function() { var initChart = function() { var ctx = document.getElementById(#{element_id.to_json}); var chart = new Chart(ctx, { type: "#{camel_case type}", data: #{to_javascript_string data}, options: #{to_javascript_string opts}, plugins: #{to_javascript_string plugins}, }); }; if (typeof Chart !== "undefined" && Chart !== null) { initChart(); } else { /* W3C standard */ if (window.addEventListener) { window.addEventListener("load", initChart, false); } /* IE */ else if (window.attachEvent) { window.attachEvent("onload", initChart); } } })(); END end canvas + script end # polar_area -> polarArea def camel_case(string) string.gsub(/_([a-z])/) { $1.upcase } end def to_javascript_string(element) case element when Hash hash_elements = [] element.each do |key, value| hash_elements << camel_case(key.to_s).to_json + ':' + to_javascript_string(value) end '{' + hash_elements.join(',') + '}' when Array array_elements = [] element.each do |value| array_elements << to_javascript_string(value) end '[' + array_elements.join(',') + ']' when String if element.match(/^\s*function.*}\s*$/m) # Raw-copy function definitions to the output without surrounding quotes. element else element.to_json end when BigDecimal element.to_s else element.to_json end end end end