Wkhtmltopdf Command Error: with Chart.js responsive: false option - ruby-on-rails

I'm generating Charjs graphs in rails with wicked_pdf and wkhtmltopdf (ver 0.12.4). i've updated wkhtmltopdf gem from ver 0.12.3.1 to ver 0.12.4 because it uses a lot of RAM memory and takes too much time when generate long PDFs, but charjs graphs worked. Now, with the new version, occurs an error when responsive chart option is set to false:
When set it to true, there is no errors but it does not work, even if the parent block has width and height setting.
i don't know how to solve this with the newest version of wkhtmltopdf and gem downgrade isn't an option.
pls help.
i've tried by setting width and height to the parent container and chartjs canvas, more javascript_delay in wkhtmltpdf, no animations in charjs, onbeforeprint callback with recomended function by charjs doc
html
<div class="canvas-holder" style="width: 800px; height: 1200px;">
<canvas id="real-costs-bar-chart-1" width="800" height="1200" style="width: 800px; height: 1200px;"></canvas>
</div>
charjs code
var ctx = document.getElementById(canvas_id).getContext('2d');
new Chart(ctx, {
type: 'horizontalBar',
data: {
datasets: [{
label: 'Real',
data: data1,
backgroundColor: backgroundColor1,
borderColor: borderColor1,
borderWidth: 1
},
{
label: 'Proyectado',
data: data2,
backgroundColor: backgroundColor2,
borderColor: borderColor2,
borderWidth: 1
}
],
// These labels appear in the legend and in the tooltips when hovering different arcs
labels: labels
},
options:{
title: {
display: true,
text: title,
fontSize: 10,
fontColor: '#00397B',
lineHeight: 3
},
responsive: false,
legend:{
position: 'bottom',
fontSize: 10
},
scales: {
xAxes: [{
ticks: {
// Include a dollar sign in the ticks
callback: function(value, index, values) {
return 'USD ' + number_to_cl(value);
}
}
}]
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var label =
data.datasets[tooltipItem.datasetIndex].label || '',
value =
data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
if (label) {
label += ': ';
}
label += 'USD ' + number_to_cl(value);
return label;
}
}
}
}
})
wicked_pdf config
pdf = WickedPdf.new.pdf_from_string(
template,
pdf: "Report_#{cost_report_type}", javascript_delay: 2000,
header: { content: header, spacing: 10 },
footer: { center: 'Pagina [page] de [topage]', spacing: 5 },
margin: {
top: 35,
bottom: 15
},
encoding: 'UTF-8',
zoom: 0.8,
orientation: 'Portrait'
)

Related

call chartjs option on rails chartkick

I am implementing charts in our sites, Here using chartkick plugin. But some customization is not supported by chartkick, But we can use chartjs, highchart and google chart by using import options indirectly. chartkick is support the above charts in its configuration.
So we choose chartjs, Here we are customizing legend and tooltip. Found the options in chartjs but unable to implement in chartkick helper.
Need your help guys, here i am facing issue like unable to mention the customization options in rails tag. Because found customization options by using javascript, but i need to add this options inside rails tag<%= %>
These are things have used for implementation.
chart js version 2.9.4
added chartkick by added gem 'chartkick' to gemfile
added chartkick, require Chart.bundle
using chartjs inside chartkick by use adapter option to the chartkick helper
<%= area_chart data, library: {
legend: {
position: 'right',
labels: {
boxWidth: 15,
boxHeight: 15
}
}
}, id: 'consult-chart', adapter: 'chartjs' %>
Found the options for customizing legend and tooltip.
Added customization in legend is -> added few extra label to normal label
Added customization in tooltip is -> changed background color and added extra text.
The below one is the options for above customization by use of direct chart js implementaion.
<script>
var ctx = document.getElementById("myChart-total");
var myLegendContainer = document.getElementById("legends");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["0", "5", "10", "15", "20", "25"],
datasets: [
{
label: "Revenue",
lineTension: 0,
backgroundColor : "#e969e5",
borderColor : "#d93da9",
//backgroundColor: "#d93da9",
data: [0, 10, 23, 25, 60, 70]
}
]
},
options: {
layout: {
padding: {
bottom: 100
}
},
legend: {
position: 'right',
labels : {
generateLabels: function(chart){
var data = chart.data;
var legends = Array.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
return {
text: dataset.label,
fillStyle: (!Array.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
hidden: !chart.isDatasetVisible(i),
lineCap: dataset.borderCapStyle,
lineDash: dataset.borderDash,
lineDashOffset: dataset.borderDashOffset,
lineJoin: dataset.borderJoinStyle,
lineWidth: dataset.borderWidth,
strokeStyle: dataset.borderColor,
pointStyle: dataset.pointStyle,
// Below is extra data used for toggling the datasets
datasetIndex: i
};
}, this) : [];
var title_o = {
text: 'Past 6 months: $826.53',
strokeStyle: 'transparent',
fillStyle: 'transparent',
lineWidth: 0
};
var title_tw = {
text: 'Month-to-date: $67.91',
strokeStyle: 'transparent',
fillStyle: 'transparent',
lineWidth: 0
};
var title_th = {
text: 'Past 7 days: $26.53',
strokeStyle: 'transparent',
fillStyle: 'transparent',
lineWidth: 0
};
legends.push(title_o);
legends.push(title_tw);
legends.push(title_th);
return legends;
},
boxWidth: 15,
boxHeight: 20
}
},
scales: {
yAxes: [{
ticks: {
beginAtZero:true
},
}],
xAxes: [{
gridLines: {
color: "rgba(0, 0, 0, 0)",
}
}]
},
tooltips: {
yAlign: 'bottom',
callbacks: {
title: function(tooltipItem, data) {
return "September "+data['labels'][tooltipItem[0]['index']];
},
label: function(tooltipItem, data) {
return "$"+data['datasets'][0]['data'][tooltipItem['index']];
},
},
backgroundColor: 'grey'
}
}
});
Here how can add the options for legend and tooltip
For legend customization, this option should be mention inside rails tag =>
legend: {
position: 'right',
labels : {
generateLabels: function(chart){
var data = chart.data;
var legends = Array.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
return {
text: dataset.label,
fillStyle: (!Array.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
hidden: !chart.isDatasetVisible(i),
lineCap: dataset.borderCapStyle,
lineDash: dataset.borderDash,
lineDashOffset: dataset.borderDashOffset,
lineJoin: dataset.borderJoinStyle,
lineWidth: dataset.borderWidth,
strokeStyle: dataset.borderColor,
pointStyle: dataset.pointStyle,
datasetIndex: i
};
}, this) : [];
var title_o = {
text: 'Past 6 months: $826.53',
strokeStyle: 'transparent',
fillStyle: 'transparent',
lineWidth: 0
};
legends.push(title_o);
return legends;
},
boxWidth: 15,
boxHeight: 20
}
},
For tooltip customization, this option should be mention inside rails tag =>
tooltips: {
yAlign: 'bottom',
callbacks: {
title: function(tooltipItem, data) {
return "September "+data['labels'][tooltipItem[0]['index']];
},
label: function(tooltipItem, data) {
return "$"+data['datasets'][0]['data'][tooltipItem['index']];
},
},
backgroundColor: 'grey'
}
==========================================-------------------=========================
But how i need to mention the above options in rails tag, because rails tag no supporting javascript function.
I added inside the quotes, but its not working, added like as below
<%= area_chart data, library: {
layout: {
padding: {
bottom: 1
}
},
legend: {
position: 'right',
labels: {
boxWidth: 15,
boxHeight: 15,
generateLabels: 'function(chart){
var data = chart.data;
var legends = Array.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
return {
text: dataset.label,
fillStyle: (!Array.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
hidden: !chart.isDatasetVisible(i),
lineCap: dataset.borderCapStyle,
lineDash: dataset.borderDash,
lineDashOffset: dataset.borderDashOffset,
lineJoin: dataset.borderJoinStyle,
lineWidth: dataset.borderWidth,
strokeStyle: dataset.borderColor,
pointStyle: dataset.pointStyle,
// Below is extra data used for toggling the datasets
datasetIndex: i
};
}, this) : [];
var title_o = {
text: "Past 6 months: $826.53",
strokeStyle: "transparent",
fillStyle: "transparent",
lineWidth: 0
};
legends.push(title_o);
return legends;
}',
}
},
tooltips: {
yAlign: 'bottom',
callbacks: "{
title: function(tooltipItem, data) {
return data['labels'][tooltipItem[0]['index']];
},
label: function(tooltipItem, data) {
return data['datasets'][0]['data'][tooltipItem['index']];
},
}",
backgroundColor: 'grey'
}
}, id: 'consult-chart', adapter: 'chartjs', width: "500px", height: "341px" %>
Please help me here, how to implement these customization options?

Render Cell content as HTML in jsPDF-AutoTable

The text of a column in my table is required to render as HTML but the table can't render it, the following code is the way I'm generating the PDF:
var doc = new jsPDF({ format: 'a4', unit: 'px' });
doc.setFontSize(10);
var alignOption: any = { align: 'left' };
if (company) doc.text(`Company: ${company}`, 10, 15, alignOption);
if (division) doc.text(`Division: ${division}`, 10, 30, alignOption);
autoTable(doc, {
styles: { fontSize: 5 },
columnStyles: { 5: { cellWidth: 200 } },
margin: { top: 40, bottom: 40 },
head: [Object.keys(data[0])],
body: formatedData,
foot: [['total', '500']],
});
doc.save('hourlyReport.pdf');
The following image is the result I get:
Is there a way I can render the marked information as HTML?

how to add extra labels at load event in highcharts

Code is as below
chart: {
type: "funnel",
marginBottom: 25,
backgroundColor: "transparent",
events: {
load: function() {
var chart = this;
Highcharts.each(chart.series[0].data, function(p, i) {
chart.options.labels.items.push({
html: "less confident" + i,
style: { left: 550, top: 50 }
});
p.dataLabel.attr({
x: (chart.plotWidth - chart.plotLeft) / 2,
"text-anchor": "middle"
});
});
}
}
},
I see that you're trying to add a label for every point. Highcharts has build in functionality for this called data labels: https://api.highcharts.com/highcharts/series.line.dataLabels
Another approach is to use SVGRenderer.label: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#label

Creating hyperlink on the highcharts stacked bar chat

var s1 = "{ name : \'Space1\', data :[5, 3, 4, 7] },";
var s2 = "{ name :\'Space2\', data:[5, 4, 7] },";
var s3 = "{ name : \'Space3\', data:[5, 3, 7] }";
var series = s1+s2+s3;
var chartdata = {
chart: {
type: 'column'
},
title: {
text: 'Cost/Env'
},
xAxis: {
categories: ['Prod', 'Test', 'Dev', 'Sandbox']
},
yAxis: {
min: 0,
title: {
text: 'Cost of apps'
},
stackLabels: {
enabled: true,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
},
legend: {
align: 'right',
x: -30,
verticalAlign: 'top',
y: 25,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
},
tooltip: {
formatter: function () {
return '<b>' + this.x + '</b><br/>' +
this.series.name + ': ' + this.y + '<br/>' +
'Total: ' + this.point.stackTotal;
}
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
style: {
textShadow: '0 0 3px black'
}
}
}
},
series: [{}]
};
chartdata.series.data = series;
$('#stackedBar1').highcharts(chartdata);
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<div id="stackedBar1" style="display: inline; float: left; height: 300px; margin: 0px;"></div>
I have created a dashboard using Ko, highcharts and the data using JSON. I have to create a stacked bar chat, in which the series data is changing dynamically for each category. Example cat1 may have 3 series objects, and cat2 may have 0, cat3 may have 10 etc....I have two questions,
1. how to include this dynamic JSON objects into the series object. (I referred links, i got the solution, i have to try them)
2. Once i click on a bar-chat at a specific position(color), i have to show detailed information, (i already designed and currently showing in my dashboard, i need to switch to that part). Is their any information available to handle such situation.
thanks in advance,
shankar
1) You can use a ajax to load json (for example $.getJSON) and load data. Please not that data needs to be in correct format.
Further information about working with data you can find here
2) You can use tooltip formatter to customise content and print that on hover.
Referring to click event, you can add this action by point.events.click and then show your custom popup / div etc.

Auto chart height

The default highstock chart has height = 400px.
How can height chart be set for auto size based on chart axis and its sizes ?
See the example bellow, the navigation bar is over the volume panel.
http://jsfiddle.net/BYNsJ/
I know that I can set the height for the div but I have a solution that insert/remove axis/series dynamically in the chart and would be nice an auto height chart.
The example is the same Candlestick/Volume demo from Highchart site, but without height property in the div container.
// split the data set into ohlc and volume
var ohlc = [],
volume = [],
dataLength = data.length;
for (i = 0; i < dataLength; i++) {
ohlc.push([
data[i][0], // the date
data[i][1], // open
data[i][2], // high
data[i][3], // low
data[i][4] // close
]);
volume.push([
data[i][0], // the date
data[i][5] // the volume
])
}
// set the allowed units for data grouping
var groupingUnits = [[
'week', // unit name
[1] // allowed multiples
], [
'month',
[1, 2, 3, 4, 6]
]];
// create the chart
$('#container').highcharts('StockChart', {
rangeSelector: {
selected: 1
},
title: {
text: 'AAPL Historical'
},
yAxis: [{
title: {
text: 'OHLC'
},
height: 200,
lineWidth: 2
}, {
title: {
text: 'Volume'
},
top: 300,
height: 100,
offset: 0,
lineWidth: 2
}],
series: [{
type: 'candlestick',
name: 'AAPL',
data: ohlc,
dataGrouping: {
units: groupingUnits
}
}, {
type: 'column',
name: 'Volume',
data: volume,
yAxis: 1,
dataGrouping: {
units: groupingUnits
}
}]
});
});
});
Regards.
here is one example which is resize chart according screen.
http://jsfiddle.net/davide_vallicella/LuxFd/2/
Just don't set the height property in HighCharts and it will handle it dynamically for you so long as you set a height on the chart's containing element. It can be a fixed number or a even a percent if position is absolute.
http://api.highcharts.com/highcharts/chart.height
By default the height is calculated from the offset height of the containing element
find example here:- http://jsfiddle.net/wkkAd/149/
#container {
width:100%;
height:100%;
position:absolute;
}
hey I was using angular 2+ and highchart/highstock v.5, I think it will work in JS or jQuery also, here is a easy solution
HTML
<div id="container">
<chart type="StockChart" [options]="stockValueOptions"></chart>
</div>
CSS
#container{
height: 90%;
}
TS
this.stockValueOptions = {
chart: {
renderTo: 'container'
},
yAxis: [{
height: '60%'
},{
top: '65%',
height: '35%'
}]
}
Its working, and a easy one. Remove chart height add height in '%' for the yAxis.
Highcharts does not support dynamic height, you can achieve it by $(window).resize event:
$(window).resize(function()
{
chart.setSize(
$(document).width(),
$(document).height()/2,
false
);
});
See demo fiddle here.
You can set chart.height dynamically with chart.update method.
http://api.highcharts.com/highcharts/Chart.update
function resizeChartFromValues (chart) {
const pixelsForValue = 10
const axis = chart.yAxis[0]
chart.update({ chart: { height: (axis.max - axis.min) * pixelsForValue } })
}
const options = {
chart: {
events: {
load () {resizeChartFromValues(this)}
}
},
series: [{
data: [30, 70, 100],
}]
}
const chart = Highcharts.chart('container', options)
setTimeout(() => {
chart.series[0].setData([10, 20, 30])
resizeChartFromValues(chart)
}, 1000)
Live example: https://jsfiddle.net/a97fgsmc/
I had the same problem and I fixed it with:
<div id="container" style="width: 100%; height: 100%; position:absolute"></div>
No special options to the chart. The chart fits perfect to the browser even if I resize it.

Resources