Better way to use Ruby/Sinatra to pass data to Highcharts?
I'm generally of the opinion that if it ain't broke don't fix it, but my current solution to this issue (though it does work) seems really ugly. I am using Ruby, Sinatra, Haml, and Highcharts, and I'd like to be able to pass data grabbed in Ruby and send to Highcharts.
Currently, I'm essentially just creating a string object out of the entire Highcharts javascript and interpolating the ruby data into that. This works, but should I be taking a completely different approach to this? Here's exactly what I'm doing:
I've defined a HighChart class with several properties that I want to be able to change via Ruby (e.g. chart title, data, etc). The example below (which works!) only sets two of these properties, leaving the rest as default:
get '/' do
@chart = HighChart.new(options={
:title_text => "Test Title",
:series_data =>
{
'Calvin' => [10, 2, 17],
'Hobbes' => [11, 14, 6]
}
}
)
haml :index
end
I'm using Haml's javascript filter in the view:
:javascript
#{@chart.chart_js}
So far so good. The ugly part is the chart_js method. I have simply copied the full text of the HighChart javascript, pasted it in as a string, and then used Ruby interpolation to grab the variables from the HighChart object created in the controller:
def chart_js
chart_js = "
var chart1;
$(document).ready(function() {
chart1 = new Highcharts.Chart({
chart: {
renderTo: '#{render_to}',
type: '#{chart_type}'
},
title: {
te开发者_高级运维xt: '#{title_text}'
},
xAxis: {
categories: #{x_categories}
},
yAxis: {
title: {
text: '#{y_categories}'
}
},
series: [#{get_data_js(series_data)}]
});
});
"
end
And just in case it's helpful, here's the first part of the HighChart object class definition:
class HighChart
attr_accessor :render_to, :chart_type, :title_text, :x_categories,
:y_categories, :series_data
def initialize(options={})
self.render_to = options[:render_to] || 'container'
self.chart_type = options[:chart_type] || 'bar'
self.title_text = options[:title_text] || 'Fruit Consumption'
self.x_categories = options[:x_categories] || ['Apples', 'Bananas', 'Oranges']
self.y_categories = options[:y_categories] || 'Fruit eaten'
self.series_data = options[:series_data] || {'Jane' => [1, 0, 4],
'Bobbert' => [5, 7, 3],
'Zach' => [10, 2, 1]
}
end
You could make a view specifically for the Highcharts JS, and then use instance variables (eg. @render_to, @chart_type, etc.). That won't really clean up the code that much, but it will get rid of some of the "wrongness" of having a giant view string in your controller.
Fundamentally though there's not much else you can do; you have a bunch of server-side info, and it has to be written to the client (in the specific Highcharts format). There's just no getting around that.
The only other suggestion I can offer is to use intermediate JS variables. This would let you keep all of the JS in the view (without a JS-only view), and then you would just need to set some JS variables. This would look something like this:
var RENDER_TO = "@render_to";
var CHART_TYPE = "@chart_type";
// ...
$(document).ready(function() {
chart1 = new Highcharts.Chart({
chart: {
renderTo: RENDER_TO,
....
Now this actually involves more code, but it would let you totally separate your onReady code from the server-value-writing code.
Hope that helps.
精彩评论