Get Chart.js to work with ImportMap in Rails 7 - ruby-on-rails

I tried:
./bin/importmap pin chart.js
which added this to config/importmap.rb
pin "chart.js", to: "https://ga.jspm.io/npm:chart.js#3.9.1/dist/chart.mjs"
In application.js I added:
import 'chart.js'
When I try to create a new Chart I get "Chart is not defined".
If I try
import Chart from 'chart.js'
I get "The requested module 'chart.js' does not provide an export named 'default'"
import Chart from 'chart.js/auto'
says "Failed to resolve module specifier 'chart.js/auto'"

I had the same struggle this weekend and kept happening upon this article, so posting my solution here.
A couple things of note:
Chart.js seems to have some hardcoded accessory files that aren't registered as dependencies in the CDN. For example, mine kept 404ing on c1719c72.js and chunks/helpers.segment.js. For this reason, it works better if you don't use the --download flag when running bin/importmap pin. Credit to this article: Using chart.js with importmaps in rail 7.
Importing Chart from chart.js requires a little magic from here: Chart.js - Where do I find which components should be registered?. Specifically, lines 3-4 of barchart_controller.js below.
Here's a summary of the file contents that worked for me on a fairly plain Rails 7 build with importmaps:
config/importmap.rb - Note: Running bin/importmap pin chart.js should pull in one dependency (#kurkle/color). Be sure to skip --download, or you're in for a world of pain.
# Pin npm packages by running ./bin/importmap
pin "application", preload: true
pin "#hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "#hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "#hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
pin "chart.js", to: "https://ga.jspm.io/npm:chart.js#4.2.0/dist/chart.js"
pin "#kurkle/color", to: "https://ga.jspm.io/npm:#kurkle/color#0.3.2/dist/color.esm.js"
app/javascript/application.js
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "#hotwired/turbo-rails"
import "controllers"
import "chart.js"
app/javascript/controllers/barchart_controller.js
import {Controller} from "#hotwired/stimulus"
import { Chart, registerables } from "chart.js";
Chart.register(...registerables);
export default class extends Controller {
static targets = ['myChart'];
canvasContext() {
return this.myChartTarget.getContext('2d');
}
connect() {
new Chart(this.canvasContext(), {
type: 'bar',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
}
}
Content from the div in my model's app/views/widgets/show.html.erb
<div data-controller="barchart">
<canvas id="bar-chart" data-barchart-target="myChart" width="800" height="450"></canvas>
</div>
Don't forget to rebuild assets (bin/rails assets:precompile).

Related

HighCharts node-export-server y-axis labels missing

We have setup our own HighCharts node-export-server as shown in the official documentation. We are able to get images back from the server, however when requesting a column chart the y-axis labels are missing. If we submit the same chart data to https://export.highcharts.com/ we get the correct image.
Here is the chart data as submitted (to both servers):
{
'chart': {
'type': 'column',
'width': 800,
'height': 500
},
'title': { 'text': '' },
'xAxis': { 'categories': ['Damage Code'], 'crosshair': true },
'yAxis': {
'min': 0,
'title': { 'text': 'Tire Life (Hours)' },
'plotLines': [{
'value': 800,
'color': '#929292',
'dashStyle': 'shortdash',
'width': 2
} ]
},
'colors': ['#ff0000', '#000000', '#787878', '#5eb749', '#2893d1', '#5ec7bd', '#f79226', '#ff7043', '#ee3124', '#a9a9a9', '#333333'],
'tooltip': { 'enabled': false },
'plotOptions': {
'series': {
'dataLabels': {
'align': 'center',
'color': '#282E32',
'enabled': true,
'format': '{point.label}'
}
},
'column': {
'pointPadding': 0.2,
'borderWidth': 0
}
},
'series': [{"name":"(111) Test Code Description 1","showInLegend":true,"data":[{"y":1000,"label":"111 10%"}]},{"name":"(222) Test Code Description 2","showInLegend":true,"data":[{"y":2000,"label":"222 20%"}]},{"name":"(1212) Test Code Description 12","showInLegend":true,"data":[{"y":1200,"label":"1212 120%"}]}]
}
And the image returned from the node-server:
I've checked out the GitHub (https://github.com/highcharts/node-export-server ) page and not much has happened there since we setup the node-server so there is nothing new to deploy from there.
Updated: Getting back to this I see the repository has some changes since I last checked. I've grabbed the latest code in the repository and re-published to my chart server. The issue continues, but I've got some additional information now.
If I set the yAxis rotation to 0 (zero) it shows. Any other rotation (270 is the default) results in the title showing as 'dots' as shown in the image above.
So this will show the title:
'yAxis': {
'min': 0,
'title': { 'text': 'Tire Life (Hours)', rotation: 0 },
This will not:
'yAxis': {
'min': 0,
'title': { 'text': 'Tire Life (Hours)', rotation: 270 },
I don't consider rotation zero a solution, but hopefully this helps to identify the issue.

Highcharts Export Server: Polar Chart Ignoring Formatters in Callback

We're currently generating a polar chart in HighCharts that renders correctly on the client-side (in the browser), and correctly applies formatters to the xAxis, yAxis, and plotOptions. Here is a jsFiddle that shows how it is rendering (correctly) in the browser: https://jsfiddle.net/cmodzelewski/38f03Lse/1/
On the server side, we are constructing a JSON payload and sending it to a node-export-server instance and returning a PNG. Based on our research, it is clear that formatters need to be included in the callback key of our JSON payload and passed to the server as a string, rather than in the infile key.
That's fine, and so we're converting our formatter functions into strings, composing them into the options object in our callback key, and then redrawing the chart at the end of our callback key.
This approach works great for non-polar charts, but if polar == true the export server returns a valid PNG from the export server, however that chart does not apply our formatter functions to the xAxis, yAxis, or plotOptions.series.
Here is the JSON payload that we are sending to a node-export-server instance:
{
"callback": "function (chart) {var options = chart.options;var xAxisFormatter = function () { var extra_hrs = 0; if (this.value == 0) { extra_hrs = 12; }; return ((this.value / 0.5)/60) + extra_hrs + ':00'; };if (\"labels\" in options[\"xAxis\"]) { options[\"xAxis\"][\"labels\"][\"formatter\"] = xAxisFormatter; } else { options[\"xAxis\"][\"labels\"] = { \"formatter\": xAxisFormatter, \"style\": { \"fontSize\": \"8px\" } }; };var yAxisFormatter = function () { return Highcharts.numberFormat(this.value, 2, '.', ',') + \"%\"; };if (\"labels\" in options[\"yAxis\"]) { options[\"yAxis\"][\"labels\"][\"formatter\"] = yAxisFormatter; } else { options[\"yAxis\"][\"labels\"] = { \"formatter\": yAxisFormatter, \"style\": { \"fontSize\": \"8px\" } };};var plotOptionsFormatter = function () { return Highcharts.numberFormat(this.value, 2, '.', ',') + \"%\"; };options[\"plotOptions\"][\"series\"][\"dataLabels\"][\"formatter\"] = plotOptionsFormatter;chart = new Highcharts.chart(chart.container, options);chart.redraw();}",
"infile": "{chart: {backgroundColor: \"white\", borderWidth: 0, height: 300, polar: true, width: 300}, colors: [\"#16C1F3\", \"#3C6E71\", \"#EAC435\", \"#E63946\", \"#33658A\", \"#DFD6A7\", \"#627264\", \"#86CCA5\", \"#6268B0\", \"#E8D33F\", \"#DA2C38\"], credits: {enabled: false, position: {align: \"right\", verticalAlign: \"bottom\"}, text: \"(c) Insight Industry Inc., 2017.\"}, exporting: {enabled: false}, legend: {enabled: false}, plotOptions: {column: {groupPadding: 0, pointPadding: 0}, series: {dataLabels: {}, pointInterval: 30, pointStart: 0}}, series: [{data: [{name: \"12:00am - 4:59am\", x: 0, y: 2.737994945240101}, {name: \"5:00am - 5:29am\", x: 150, y: 1.6287559674248806}, {name: \"5:30am - 5:59am\", x: 165, y: 1.6849199663016006}, {name: \"6:00am - 6:29am\", x: 180, y: 5.9112608817747825}, {name: \"6:30am - 6:59am\", x: 195, y: 11.513619769727605}, {name: \"7:00am - 7:29am\", x: 210, y: 17.98652064026959}, {name: \"7:30am - 7:59am\", x: 225, y: 17.733782645324347}, {name: \"8:00am - 8:29am\", x: 240, y: 20.190957596180848}, {name: \"8:30am - 8:59am\", x: 255, y: 7.848918843021623}, {name: \"9:00am - 9:59am\", x: 270, y: 8.438640831227183}, {name: \"10:00am - 10:59am\", x: 300, y: 3.1592249368155008}, {name: \"11:00am - 11:59am\", x: 330, y: 1.1654029766919405}], name: null, pointPlacement: \"on\", type: \"column\"}], title: {text: null}, tooltip: {style: {fontSize: \"10px\"}, valueDecimals: 1, valueSuffix: \"%\"}, xAxis: {labels: {style: {fontSize: \"10px\"}}, max: 360, min: 0, tickInterval: 30, title: {text: null}}, yAxis: {labels: {style: {fontSize: \"10px\"}}, max: 25.0, min: 0, showLastLabel: false, tickInterval: 5, title: {style: {color: \"#0A3B61\", fontSize: \"9px\", fontWeight: \"bold\"}, text: \"Workers, Aged 25+\"}}}",
"scale": 2,
"type": "png"
}
We have recreated what we (suspect) is the process that the node export server goes through, and have definitely recreated the (weird) behavior that we're seeing in this jsFiddle: https://jsfiddle.net/cmodzelewski/v4gm6t9a/2/
Are we missing something blatantly obvious (which is what we suspect)? Or is there a better way of doing this to get the behavior we're looking for?
Any help would be very much appreciated!
In your fiddle with the suspected process, and in your callback, you are setting the axis labels in the following way:
options["yAxis"]["labels"]
This will set an object labels on the yAxis element, however, since you can have several axis in highcharts, they are indexed, and stored as such. That means you have to edit the first axis like this:
options["yAxis"][0]["labels"]
Here is a picture of the yAxis object in the incorrect configuration:
Here is a picture of the yAxis object in the correct configuration:
Working example using your second fiddle: https://jsfiddle.net/ewolden/v4gm6t9a/4/

Export to Excel not working when deployed

This is the code I used to create a data table with export functionality.
oTable = $("#tblSearch").DataTable({
"jQueryUI": true,
"sPaginationType": "full_numbers",
"iDisplayLength": 10,
"bSort": true,
"aaSorting": [[0, "desc"]],
"lengthMenu": [[5, 10, 25, 50], [5, 10, 25, 50]],
"autoWidth": true,
"scrollCollapse": true,
"dom": 'T<"clear">lfrtip',
"tableTools": {
"sSwfPath": "../../swf/copy_csv_xls.swf",
"aButtons": ["xls"]
}
});
Export is working in my local but when I deployed in server, the button does not appear.
Change the sSwfPath to an absolute path.
"tableTools": {
"sSwfPath": "http://cdn.datatables.net/tabletools/2.2.3/swf/copy_csv_xls_pdf.swf",
"aButtons": ["xls"]
}
here using the dataTables CDN. The problem is, that the relative path messes up when you deploy to your IIS or whatever windows platform you are using. This is a very common problem.

Highcharts - null values are plotted on stacked area chart, in latest version

I am upgrading from Highcharts 2.2.4 to 3.0.4. I am dealing with a time series with stacked area chart. As a real-time updating chart, I wanted it to show the stacked area up to the latest hour. With the upgrade to highcharts 3.0.4, now it looks as if the data is falling to 0 -value on the next interval. I would rather see the sharp cutoff on the end, when the rest of the series is filled with nulls.
This is related to a issue on the Github repo for Highcharts, the issue has been closed, but there is still a lot of discussion around it. https://github.com/highslide-software/highcharts.com/issues/1836
Is there a known workaround to get the 2.2.4 effect in the 3.0.4 version?
$(function () {
$('#container').highcharts({
chart: {
type: 'area'
},
plotOptions: {
area: {
stacking: 'normal'
}
},
series: [{
data: [635, 635, 809, 947, 1402, 3634, null,null,null,null]
}, {
data: [107, 107, 111, 133, 221, 767, null,null,null,null]
}, {
data: [203, 203, 276, 408, 547, 729, null,null,null,null]
}, {
data: [31, 31, 54, 156, 339, 818, null,null,null,null]
}, {
data: [2, 2, 2, 6, 13, 30, null,null,null,null]
}]
});
});
Here is a jsfiddle with Highcharts 2.2.4 : http://jsfiddle.net/ricksuggs/gzcaL/6/
Here is what it looks like after upgrading: http://jsfiddle.net/ricksuggs/6vCHe/
A patch has been applied, but a problem is still there in the 3.0.10 release.
I had the problem and some other users too, only a few days ago (see https://github.com/highslide-software/highcharts.com/issues/2734 or https://github.com/highslide-software/highcharts.com/issues/2069)
When you set connectNulls to true, it doesn't connects, and when you set it to false it connects : http://jsfiddle.net/SEU5v/
The fix :
if (!connectNulls && (!pointMap[x] || pointMap[x].y === null)) { // #1836
instead of
if (connectNulls && (!pointMap[x] || pointMap[x].y === null)) { // #1836
in http://code.highcharts.com/highcharts.src.js (line 14868)
The problem is not resolved ! Why this edit is being rejected ??

Table loads previous row which is deleted when sorting

I am trying to add jquery table sorter. It is working. I have a delete row option in each row with a button, and when I delete a row and try to sort the table again the previously deleted data is loading. How can I solve it. My code is here ,
setTimeout(function(){
if (!self.isFirstInit) {
$('#fixedTable').tablesorter({
headers: {
0:{sorter: false},
1:{sorter: false},
2:{sorter: false}
}
});
self.isFirstInit = true;
$("#fixedTable").fixheadertable({
colratio: [32, 32, 32, 130, 130, 110, 110, 86, 86, 93, 93],
height: 574,
zebra: true,
resizeCol: true
});
}
$('#fixedTable').triggerHandler('update');
}, 200);
Use $('#fixedTable').trigger('update'); not .triggerHandler().

Resources