admin管理员组文章数量:1289637
I am using EvoPdf version 7.5. We have this html that has been used to generate a pdf report for quite some time with no issues, but its just straight up HTML and css, there was not javascript being used. We want to add charts using chart.js, but when I add it to the existing report to test if it will show, nothing appears.
Here is my HTML
@using System.Linq
@using RazorEngine
@using System.Text.RegularExpressions
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link href="/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel='stylesheet' href='/[email protected]/font/bootstrap-icons.css'>
</head>
<body id="Body">
<div class="section">
<div class="mx-auto" style="height: 50px;"></div>
<div class="lblTitle">
<h1>This is where the chart should be</h1>
<div style="width: 80%; margin: auto;">
<canvas id="myChart"></canvas>
</div>
<h1>This is where the chart should end</h1>
</div>
</div>
<script src=".js"></script>
<script src="~/Scripts/local_chart.js"></script>
</body>
</html>
Here is a sample of the javascript
const ctx = document.getElementById('myChart');
const startPoint = 58, progressPoint = 65, maxPoint = 100;
const xAxisLabel = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'];
const expected = (start, end, steps) => {
const stepSize = (end.y - start.y) / steps;
return Array.from({ length: steps + 1 }, (_, i) => ({ x: i < steps ? start.x : end.x, y: start.y + stepSize * i }));
};
const customPointCircleCanvas = (ctx, size = 10) => ({
draw: ({ point: { x, y } }) => {
ctx.beginPath();
ctx.arc(x, y, size, 0, 2 * Math.PI);
ctx.fillStyle = '#3498db';
ctx.fill();
ctx.lineWidth = 3;
ctx.strokeStyle = '#FFFFFF';
ctx.stroke();
}
});
const htmlPlanTimelineLegendPlugin = {
id: 'htmlLegend',
afterUpdate(chart, _, { containerID }) {
const container = document.getElementById(containerID);
if (!container) return;
container.innerHTML = '';
chart.legend.legendItems.forEach(({ fillStyle, text }, index) => {
const legendDiv = document.createElement('div');
legendDiv.innerHTML = `<span style="background:${fillStyle};width:10px;height:10px;display:inline-block;margin-right:5px;"></span>${text}`;
legendDiv.style.cursor = 'pointer';
legendDiv.onclick = () => {
chart.setDatasetVisibility(index, !chart.isDatasetVisible(index));
chart.update();
};
container.appendChild(legendDiv);
});
}
};
const getGradient = (ctx, { left, right, bottom, top }, colorStart, colorEnd, isVertical = false) => {
if (!left) return;
const gradient = ctx.createLinearGradient(isVertical ? 0 : left, isVertical ? bottom : 0, isVertical ? 0 : right, isVertical ? top : 0);
gradient.addColorStop(0, colorStart);
gradient.addColorStop(1, colorEnd);
return gradient;
};
new Chart(ctx, {
type: 'line',
data: {
labels: xAxisLabel,
datasets: [
{ label: 'Label 1', data: expected({ x: 'Jan', y: startPoint }, { x: 'Apr', y: maxPoint }, 7), borderColor: 'transparent', pointRadius: 0, spanGaps: true },
{ label: 'Label 2', data: expected({ x: 'Jan', y: startPoint }, { x: 'Jan', y: startPoint }, 1), pointStyle: 'circle', pointRadius: 7, borderColor: '#FFF', backgroundColor: '#3498db' },
{ label: 'Label 3', data: expected({ x: 'Mar', y: progressPoint }, { x: 'Mar', y: progressPoint }, 1), pointStyle: 'circle', pointRadius: 30, borderColor: '#FFF', backgroundColor: '#3498db' },
{
label: 'Label 4',
data: [ { x: 'Jan', y: startPoint }, { x: 'Mar', y: progressPoint }, { x: 'Jul', y: maxPoint } ],
segment: {
borderDash: (ctx) => ctx.p0.skip || ctx.p1.skip ? [6, 6] : undefined,
backgroundColor: ({ chart: { ctx, chartArea } }) => getGradient(ctx, chartArea, 'rgba(205, 205, 205, 0.4)', 'rgba(255, 99, 132, 0.4)', true) || 'transparent'
},
spanGaps: true, radius: 0,
borderColor: ({ chart: { ctx, chartArea } }) => getGradient(ctx, chartArea, 'rgba(52, 152, 219, 1)', 'rgba(255, 99, 132, 0.4)') || 'transparent',
borderWidth: 3, backgroundColor: 'rgba(255, 99, 132, 0.4)', fill: 'stack'
}
]
},
options: {
responsive: true,
events: [],
scales: {
y: { grid: { display: false }, title: { display: true, text: 'Y Scale', font: { family: 'Arial', size: 20 } }, ticks: { maxTicksLimit: 5, callback: (value) => `${value}%` } },
x: { grid: { display: false }, title: { display: true, text: 'X Scale', font: { family: 'Arial', size: 20 } } }
},
plugins: {
htmlLegend: { containerID: 'legend-container' },
legend: { display: true, labels: { color: 'black' } }
}
},
plugins: [htmlPlanTimelineLegendPlugin]
});
This is all I see
I know the code works because I added it to one of our web pages (we use Asp.Net) and it renders just fine there:
I tried setting the JavaScriptEnabled to true when setting up the converter, but that didnt really seem to make a difference.
var htmlToPdfConverter = new HtmlToPdfConverter { LicenseKey = _evoLicenceKey };
htmlToPdfConverter.PdfDocumentOptions.PdfPageSize = GetPageSize(_principal.Profile.CountryCode);
htmlToPdfConverter.PdfDocumentOptions.TopMargin = 20f;
htmlToPdfConverter.PdfDocumentOptions.RightMargin = 20f;
htmlToPdfConverter.PdfDocumentOptions.BottomMargin = 20f;
htmlToPdfConverter.PdfDocumentOptions.LeftMargin = 20f;
htmlToPdfConverter.PdfDocumentOptions.FitWidth = true;
htmlToPdfConverter.PdfDocumentOptions.EmbedFonts = true;
htmlToPdfConverter.JavaScriptEnabled = true; // Enable JavaScript execution
Am I missing a setting? Does version 7.5 allow this?
I am using EvoPdf version 7.5. We have this html that has been used to generate a pdf report for quite some time with no issues, but its just straight up HTML and css, there was not javascript being used. We want to add charts using chart.js, but when I add it to the existing report to test if it will show, nothing appears.
Here is my HTML
@using System.Linq
@using RazorEngine
@using System.Text.RegularExpressions
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link href="https://cdn.jsdelivr/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel='stylesheet' href='https://cdn.jsdelivr/npm/[email protected]/font/bootstrap-icons.css'>
</head>
<body id="Body">
<div class="section">
<div class="mx-auto" style="height: 50px;"></div>
<div class="lblTitle">
<h1>This is where the chart should be</h1>
<div style="width: 80%; margin: auto;">
<canvas id="myChart"></canvas>
</div>
<h1>This is where the chart should end</h1>
</div>
</div>
<script src="https://cdn.jsdelivr/npm/chart.js"></script>
<script src="~/Scripts/local_chart.js"></script>
</body>
</html>
Here is a sample of the javascript
const ctx = document.getElementById('myChart');
const startPoint = 58, progressPoint = 65, maxPoint = 100;
const xAxisLabel = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'];
const expected = (start, end, steps) => {
const stepSize = (end.y - start.y) / steps;
return Array.from({ length: steps + 1 }, (_, i) => ({ x: i < steps ? start.x : end.x, y: start.y + stepSize * i }));
};
const customPointCircleCanvas = (ctx, size = 10) => ({
draw: ({ point: { x, y } }) => {
ctx.beginPath();
ctx.arc(x, y, size, 0, 2 * Math.PI);
ctx.fillStyle = '#3498db';
ctx.fill();
ctx.lineWidth = 3;
ctx.strokeStyle = '#FFFFFF';
ctx.stroke();
}
});
const htmlPlanTimelineLegendPlugin = {
id: 'htmlLegend',
afterUpdate(chart, _, { containerID }) {
const container = document.getElementById(containerID);
if (!container) return;
container.innerHTML = '';
chart.legend.legendItems.forEach(({ fillStyle, text }, index) => {
const legendDiv = document.createElement('div');
legendDiv.innerHTML = `<span style="background:${fillStyle};width:10px;height:10px;display:inline-block;margin-right:5px;"></span>${text}`;
legendDiv.style.cursor = 'pointer';
legendDiv.onclick = () => {
chart.setDatasetVisibility(index, !chart.isDatasetVisible(index));
chart.update();
};
container.appendChild(legendDiv);
});
}
};
const getGradient = (ctx, { left, right, bottom, top }, colorStart, colorEnd, isVertical = false) => {
if (!left) return;
const gradient = ctx.createLinearGradient(isVertical ? 0 : left, isVertical ? bottom : 0, isVertical ? 0 : right, isVertical ? top : 0);
gradient.addColorStop(0, colorStart);
gradient.addColorStop(1, colorEnd);
return gradient;
};
new Chart(ctx, {
type: 'line',
data: {
labels: xAxisLabel,
datasets: [
{ label: 'Label 1', data: expected({ x: 'Jan', y: startPoint }, { x: 'Apr', y: maxPoint }, 7), borderColor: 'transparent', pointRadius: 0, spanGaps: true },
{ label: 'Label 2', data: expected({ x: 'Jan', y: startPoint }, { x: 'Jan', y: startPoint }, 1), pointStyle: 'circle', pointRadius: 7, borderColor: '#FFF', backgroundColor: '#3498db' },
{ label: 'Label 3', data: expected({ x: 'Mar', y: progressPoint }, { x: 'Mar', y: progressPoint }, 1), pointStyle: 'circle', pointRadius: 30, borderColor: '#FFF', backgroundColor: '#3498db' },
{
label: 'Label 4',
data: [ { x: 'Jan', y: startPoint }, { x: 'Mar', y: progressPoint }, { x: 'Jul', y: maxPoint } ],
segment: {
borderDash: (ctx) => ctx.p0.skip || ctx.p1.skip ? [6, 6] : undefined,
backgroundColor: ({ chart: { ctx, chartArea } }) => getGradient(ctx, chartArea, 'rgba(205, 205, 205, 0.4)', 'rgba(255, 99, 132, 0.4)', true) || 'transparent'
},
spanGaps: true, radius: 0,
borderColor: ({ chart: { ctx, chartArea } }) => getGradient(ctx, chartArea, 'rgba(52, 152, 219, 1)', 'rgba(255, 99, 132, 0.4)') || 'transparent',
borderWidth: 3, backgroundColor: 'rgba(255, 99, 132, 0.4)', fill: 'stack'
}
]
},
options: {
responsive: true,
events: [],
scales: {
y: { grid: { display: false }, title: { display: true, text: 'Y Scale', font: { family: 'Arial', size: 20 } }, ticks: { maxTicksLimit: 5, callback: (value) => `${value}%` } },
x: { grid: { display: false }, title: { display: true, text: 'X Scale', font: { family: 'Arial', size: 20 } } }
},
plugins: {
htmlLegend: { containerID: 'legend-container' },
legend: { display: true, labels: { color: 'black' } }
}
},
plugins: [htmlPlanTimelineLegendPlugin]
});
This is all I see
I know the code works because I added it to one of our web pages (we use Asp.Net) and it renders just fine there:
I tried setting the JavaScriptEnabled to true when setting up the converter, but that didnt really seem to make a difference.
var htmlToPdfConverter = new HtmlToPdfConverter { LicenseKey = _evoLicenceKey };
htmlToPdfConverter.PdfDocumentOptions.PdfPageSize = GetPageSize(_principal.Profile.CountryCode);
htmlToPdfConverter.PdfDocumentOptions.TopMargin = 20f;
htmlToPdfConverter.PdfDocumentOptions.RightMargin = 20f;
htmlToPdfConverter.PdfDocumentOptions.BottomMargin = 20f;
htmlToPdfConverter.PdfDocumentOptions.LeftMargin = 20f;
htmlToPdfConverter.PdfDocumentOptions.FitWidth = true;
htmlToPdfConverter.PdfDocumentOptions.EmbedFonts = true;
htmlToPdfConverter.JavaScriptEnabled = true; // Enable JavaScript execution
Am I missing a setting? Does version 7.5 allow this?
Share Improve this question edited Feb 19 at 21:36 Ian asked Feb 19 at 17:35 IanIan 114 bronze badges 5 |1 Answer
Reset to default 0The javascript code for chart.js has an issue at the function:
const getGradient = (ctx, { left, right, bottom, top }, colorStart, colorEnd, isVertical = false) => {
if (!left) return;
//......
}
When the function is called, the second argument provided is chart.chartArea
; but the first calls to the function occur before the chartArea
is computed, so for those first calls the second argument is null
, and the attempt to destructure it results in an error.
To make it run with a null
second argument one might delay destructuring to after a guard against null
is run:
const getGradient = (ctx, chartArea, colorStart, colorEnd, isVertical = false) => {
if (!charArea) return;
const { left, right, bottom, top } = chartArea;
if (!left) return;
//......
}
Then the first calls with null
argument pass without event and the later calls, after chartArea
was computed will produce the useful results.
The original code should not run in browser either because of that issue, and there's not enough information for a certain explanation of why it worked in OP's tests. The most probable explanation seems to me that the code was run through a bundler stack that included a transpiler, which transformed the destructuring in the argument to something more tame and resilient to null
arguments.
Here's a runnable version of the full code in a jsFiddle, that has everything set in the html tab, so it can easily copied and pasted to evoPDF's online demo (with the "Convert HTML String" option checked) - here's a screen capture of the generated pdf.
本文标签: aspnetEvoPdf not rendering chart from chartjsStack Overflow
版权声明:本文标题:asp.net - EvoPdf not rendering chart from chart.js - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741480569a2381144.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
htmlToPdfConverter
run with a delay allowing the animations to complete? – kikon Commented Feb 19 at 17:40ctx
out of the javascript (possibly as the content of a new div) - things likectx.toString()
orctx.getContext("2d").toString()
will do for starters. – kikon Commented Feb 19 at 17:43getGradient
function that doesn't work with the latest chart.js; after correction, the chart shows identically in browser and in evoPDF online demo. On the Online Demo I set the radiobutton "Convert HTML String" and pasted the html+javascript, as in this jsFiddle, where everything is the html tab. Here's a screen capture of the evoPDF generated pdf. – kikon Commented Feb 21 at 23:02