Comments (23)
Hacked something to make this work. No idea if it's the proper solution, but I'll leave it here in case anyone is just looking for a way to Make It Work.
My actual implementation involves some classes wrapping chartkick and jquery datatables, but I've stripped it down to the bare bones for this example. Modify as needed for your purposes.
In some javascript file available in your view
window.exampleFunction = function () { return 'function_name example' }
In your view
<%= chartkick_render_chart_hack %>
In ApplicationHelper
FUNCTION_NAME_DELIMITER = 'FNNAME'
FUNCTION_START = 'FNSTART'
FUNCTION_END = 'FNEND'
# Assuming you are using the Highcharts adapter
def chartkick_render_chart_hack(chart_type = :column_chart, options = nil)
# Or generate the options elsewhere and pass them in. Just make sure to use the helpers.
options ||= {
library: {
xAxis: { labels: { formatter: js_inline('function () { return "inline_example"; }') } },
yAxis: { labels: { formatter: js_function_name('exampleFunction') } }
}
}
# chart_type might end up being :column_chart, :bar_chart, etc
# whatever chart method symbol from chartkick you want to use
rendered = send chart_type, data, options
# Strip out the delimiters from the generated html/js/json.
# The effect is it turns the JSON options into a plain javascript object.
# The function bodies/names are no longer strings. Magic.
rendered
.gsub(/"#{ChartTemplate::FUNCTION_NAME_DELIMITER}([^""]*)"/, '\1')
.gsub(/"#{FUNCTION_START}(.*)#{FUNCTION_END}"/, '\1')
.gsub('\"', '"')
end
# Example: onClick: js_function_name('someFunction').
# someFunction needs to be available as window.highchartsExtras.someFunction.
def js_function_name(fn)
"#{FUNCTION_NAME_DELIMITER}highchartsExtras.#{fn}"
end
# Example: onClick: js_inline('function () { alert("wooo"); }')
def js_inline(js)
"#{FUNCTION_START}#{js}#{FUNCTION_END}"
end
Of course, you need to make sure that you are using the helper functions to annotate your embedded 'js' code. You also need to make sure to always wrap the call to the actual chartkick method with the helper. So if you are rendering the chart in a controller in response to an AJAX call, it needs to use the helper method etc.
Haven't run this code, since it's extracted from a more complicated wrapper I'm building around chartkick, but it should work.
Disclaimer: this may be a mad way of implementing this, but it seems to work fine for my purposes.
Disclaimer 2: this can be implemented straight into the various chartkick methods: make js_inline and js_function_name(or equivalent) available in the view or as static methods, then have methods like column_chart innately try to parse out their output before they return it. However, I haven't actually looked into the chartkick internals to see what it would take.
from chartkick.
In line with the comment from @sebastianiorga, I developed the following solution:
require 'active_support/core_ext/module/aliasing'
module ChartkickMixinJavascriptFunctions
FUNCTION_NAME_DELIMITER = 'FNNAME'
FUNCTION_START = 'FNSTART'
FUNCTION_END = 'FNEND'
module Helper
def js_function_name(fn)
"#{ChartkickMixinJavascriptFunctions::FUNCTION_NAME_DELIMITER}#{fn}"
end
def js_inline(js)
"#{ChartkickMixinJavascriptFunctions::FUNCTION_START}#{js}#{ChartkickMixinJavascriptFunctions::FUNCTION_END}"
end
private
def chartkick_chart(klass, data_source, options)
rendered = super(klass, data_source, options)
rendered
.gsub(/"#{ChartkickMixinJavascriptFunctions::FUNCTION_NAME_DELIMITER}([^""]*)"/, '\1')
.gsub(/"#{ChartkickMixinJavascriptFunctions::FUNCTION_START}(.*)#{ChartkickMixinJavascriptFunctions::FUNCTION_END}"/, '\1')
.gsub('\"', '"')
.html_safe
end
end
end
Chartkick::Helper.send(:prepend, ChartkickMixinJavascriptFunctions::Helper)
Just put the code into the Chartkick initializer file, e.g. config/initializers/chartkick.rb
.
Afterwards, you can call e.g. line_chart
the usual way and wrap options strings into the js_inline
etc. helpers.
from chartkick.
just to add an example here
where I'm adding hs.tens_label_callback - and I don't want to clobber the options that are set through standard options like 'stacked'
<%= column_chart test_team_dashboard_path, download: "test", stacked: true, id: "test-chart" %>
<script>
var chart = Chartkick.charts["test-chart"];
var newOptions = {
library: {
animation: {
easing: 'easeOutQuad',"duration": 200
},
scales:{
yAxes: [{
ticks: {
beginAtZero:true,
suggestedMax: 20,
callback: hs.tens_label_callback
}
}]
}
}
}
var mergedOptions = jQuery.extend(chart.options,newOptions)
chart.setOptions(mergedOptions);
from chartkick.
Unfortunately, there's no way to pass a function at the moment since options are serialized to JSON.
from chartkick.
Pass the function in as a string and then parse it back?
(something like this http://ovaraksin.blogspot.fi/2013/10/pass-javascript-function-via-json.html)
from chartkick.
Ran into this issue as well. It is very difficult to do much customizing with Highcharts at all without the ability to pass a function.
from chartkick.
Adding a function method this way seems like the wrong approach. However, I definitely see why this would be useful. If anyone has other ideas about how to approach this, I'd love to hear them. I plan on starting work for Chartkick 2.0 soon, which will be all about customization.
from chartkick.
I haven't looked into the highcharts source very closely, but assuming the function can be named, could chartkick just require that you pass in that name instead of the actual javascript? That way you could keep things relatively unobtrusive but also simple.
If this sounds like a viable option to you, I could try to whip something up in a fork.
from chartkick.
I think events will be the best way to accomplish this.
$("#users-chart").on("chartkick:before", function (e) {
// customize options and data
})
from chartkick.
Aah, events make perfect sense.
from chartkick.
+1 as this is blocking us from using chartkick at the moment :(
from chartkick.
Sorry for a probably stupid question, but could you show us how to do that to configure HighChart so that items with 0 value don't appear in the graphs (using something like this: http://stackoverflow.com/questions/15834687/how-to-hide-zero-values-in-column-chart)
from chartkick.
@khelal you can use series#update to add a formatter described in the answers to that SO question via JS.
from chartkick.
Tried this:
$("#chart-3").highcharts().series[0].update({options: {dataLabels: {formatter: function() { if (this.y > 0) return this.point.name; }}}}, true);
Doesn't seem to work as we can't seem to be able to update the options once the graph has been displayed...
from chartkick.
@khelal not sure what the problem is, it has worked fine for me. Are you getting any JS errors? Maybe try changing something simple like the title to make sure the function is working as expected. Updating the chart after it's loaded should work, that's what the function is meant for.
from chartkick.
@tfwright what's the best way to know when the chart is loaded, and series#update
can be called?
from chartkick.
@summerville if you're using highcharts the chart object supports a load event. So the flow would be
- Create the chart object with chartkick
- Access the highchart object with js and set the load event to trigger a function
- That function sets a formatter (or whatever) on the chart using the update method
I warn you and anyone else though that if you have a lot of js this gets extremely bulky very fast. I ended up switching back to michelson/lazy_high_charts for that reason.
from chartkick.
Cool, thx @tfwright.
I love the async setup option of Chartkick, but not having an easy way to format the data on the client side and/or register click handlers is the biggest bummer.
I tried accessing the highchart object on domready like $('#some-chart').highchart()
but it returned undefined
because Chartkick hadn't initialized the chart yet (it's still waiting on the ajax callback).
Were you using the ajax load option when you were using Chartkick?
from chartkick.
@summerville ah, yeah I ran into that problem too. There's not a great solution to it, I ended up going with brandonaaron/livequery
from chartkick.
Is there any progress on this, I am looking for the proper fix to pass the js function to the labelformatter.
from chartkick.
@satheeshcsedct, yes I am wondering the same thing. All I want to do is add a measly '%' to the xAxis values. Why does it have to be so difficult? Is there a working workaround? I tried something like this, but I can't get it to work.
$(".highcharts-container").on("chartkick:before", function (e){
yAxis: {
labels: {
formatter: function () {
return this.value+'%';
}
}
}
});
from chartkick.
+1
from chartkick.
Just fyi, the preferred way to do this is to use the setOptions
method in the JavaScript API. https://github.com/ankane/chartkick#javascript-api
from chartkick.
Related Issues (20)
- Make chart download link image visible at all times HOT 2
- Better adding of plugins to Chart.js with Chartkick HOT 9
- Charts stuck at "Loading..." [example included] HOT 4
- CSP compliance breaks when used with Turbo Drive w/ and random nonce generator HOT 3
- Add support for chart.js 4.x HOT 3
- Add combo bar/line charts HOT 2
- Jruby Support HOT 1
- Support for Apex Charts HOT 1
- Add support for limiting the serie to a certain time frame HOT 1
- Support for polar (spiderweb) charts HOT 1
- Demo not rendering correctly in Safari HOT 2
- `createChart` is not fired after Turbo Frame renders the view HOT 8
- Comparisons in Two Date Ranges HOT 1
- Error importing Chartkick object HOT 2
- Provide ES module for JS with default exports HOT 1
- Rails 7 Setup Additional Step Needed HOT 4
- Canvas accessibility options like aria-label HOT 1
- preffix and suffix on column HOT 1
- X-axis is converted to integers even if datapoint contains alphanumeric characters HOT 1
- Some plugins not (fully) working with Chartkick with Importmaps HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from chartkick.