I have API that generate pdf file after saving values into database. My customer needed to generate this pdf and then send it by mail. He sended my photo of how should that pdf look like. I recreated it, it looks same as in that picture but it is hard to read because there are missing vertical lines. I looked trought docs and also tried to google, bud I did not found anyithing.
Here is how my PDF looks like:
As you can see, vertical lines are missing and because of that is harder to read.
Is there any possibility to add vertical lines?
Here is my code:
let doc = new PDFDocument({ margin: 30, size: "A4" });
doc.pipe(
fs.createWriteStream(`${problemName}_${creationDate}` + ".pdf")
);
const table = {
title:
"Zápis koordinátora " +
koordinatorName +
" zo dna " +
creationDate +
".",
divider: {
header: { disabled: true },
horizontal: { disabled: false, width: 1, opacity: 1 },
padding: 5,
columnSpacing: 10,
},
headers: [
{ width: 130, renderer: null },
{ width: 130, renderer: null },
{ width: 130, renderer: null },
{ width: 130, renderer: null },
],
rows: [
["Nazov", problemName, "", ""],
[
"Nazov staveniska (Projekt)",
constructionName,
"Na vedomie komu",
"mailing list 1",
],
[
"Vytvoril koordinator BOZP",
koordinatorName,
"Priorita",
problemPriority,
],
["Datum zistenia", creationDate, "Datum odstranenia", ""],
[
"Zodpovedny za vyriesenie zistenia",
"Janko Maly",
"Celkovy pocet zisteni v dni",
10,
],
["Miesto zistenia", discoveryPlace, "Zistenie císlo", 1],
["Popis", problemText],
[
"Navrh na udelenie sankcie",
"50€",
"Pre spolocnost",
adressedFor,
],
],
};
doc.table(table, {
prepareHeader: () => doc.font("Helvetica-Bold").fontSize(8),
prepareRow: (row, indexColumn, indexRow, rectRow, rectCell) => {
doc.font("Helvetica").fontSize(8);
indexColumn === 0;
},
});
doc.end();
I am using pdfkit-table package.
Thank you all
By definition simple PDF structure is not tabular there is one cell (the page) and that one column can be subdivide into two or more rows with null spaces between the text sub columns.
That is why tables are difficult to sub[ex]tract
So adding coloured rows in one area is fairly simple to make like a table, thus to make vertical sub dividers is more difficult, However that feature was added in January 2022 https://github.com/natancabral/pdfkit-table/files/7865078/document-5.pdf
For exsample see https://github.com/natancabral/pdfkit-table/issues/16#issuecomment-1012389097
Related
I am trying to create a multiline footer with pdfmake; what I was able to do until now:
const docDefinition = {
footer: [
{
stack: [
{ text: "Line 1" },
{ text: "Line 2" },
{ text: "Line 3" },
{ text: "Line 4" }
], style: 'footer'
}
],
styles: {
footer: {
fontSize: 6, bold: true, alignment: 'center'
}
}
};
While this creates what I want, the style is not correct. As soon as I increase the font size, the bottom line starts to disappear. If I set the font size to 12, only the first two lines appear in the generated PDF on the server-side.
What change do I need to make here?
You just need to add margin to the page and you can accommodate as many lines as you want. e.g. Enter the code below in pdfmake playground: http://pdfmake.org/playground.html
// playground requires you to assign document definition to a variable called dd
let textFooter = `
A 12.4% discretionary service charge will be added to your bill. All prices are inclusive of VAT. Thank You!\n\n
This is line 2 - 263139\n
Line 3 comes here\n
Go big or go home!!!
`;
var dd = {
header: function(currentPage, pageCount, pageSize) {
return [
{ text: 'simple text\naaa\nbbb\nccc\nddd', alignment: 'center', fontSize: 9 },
]
},
footer: function(currentPage, pageCount, pageSize) {
return [
{ text: textFooter, alignment: 'center', fontSize: 9 },
]
},
// margin: [left, top, right, bottom]
pageMargins: [ 40, 60, 40, 100 ],
content: [
'First paragraph',
'Another paragraph, this time a little bit longer to make sure, this line will be divided into at least two lines'
]
}
In the code above, I have set margin bottom to 100 which gives us space to include 4 lines.
I wan't to set all bars the same width, because if I have few bars they get super big, and If I have a lot bars they get very thin.
Here is what I mean:
I have bar width 50 because I tought this was the size of the bar, but it keeps making bars small if the amount increases.
Here is my code:
$(document).ready(function () {
var chart = c3.generate({
bindto: '#stocked',
size: {
height: 320,
width: 1500
},
data: {
labels: ['y',1,2,3,4,5,6],
columns: [
['MUSCLE', <?php echo substr($muscle,1,strlen($muscle)); ?>],
['FAT', <?php echo substr($fat,1,strlen($fat)); ?>]
],
groups: [
['MUSCLE', 'FAT']
],
type: 'bar',
colors: {
MUSCLE: '#75e3ff',
FAT: '#23bbe8'
}
},
bar: {
// width: { ratio: 0.8 }
width: 50,
},
axis: {
x: {
type: 'categories',
show: true,
label: {
text: 'Measurements',
position: 'outer-middle'
},
tick: {
format: "%b",
fit: true,
},
},
y: {
label: {
text: '<?php echo $_SESSION["unit"]; ?>',
position: 'outer-middle'
}
},
},
// subchart: {
// show: true
// },
// zoom: {
// enabled: true
// }
});
});
Thanks and greetings!
The width of your bars is the result of the width of your chart and the amount of data you have populating it. My recommendation would be to size your chart or the container holding your chart accordingly. This will prevent having large white spaces in between each of your bars and result in a more uniform look between your charts.
ex: pseudo code of how to determine how wide you chart should be.
var chart = c3.generate({
size: {
height: 240,
width: function () {
return 6 * 20 + 15
},
data: {
columns: [
['sample', 30, 200, 100, 400, 150, 250]
]
}
});
Here you can see that there of 6 pieces of data and each data is given 20 space and then an extra 15 to account for the axis/labels etc. If each you had 50 data then it should be width: 6 * 20 + 15 ..... of course now you have different width chart but the bar widths and space between bars should be pretty uniform. The more data the longer the chart. You might need to "20" and "15" to get the look you want.
Draw a basic line chart using Chart.js version 2.8.0.
Observe the rightmost data point is cut off. But the leftmost data point (the first data point) looks intact.
I’ve changed the size of the data point circles by changing values of pointRadius. But even in the smallest value, the data point still gets cut off.
I’m not using any plugin or fancy settings. I am filling the chart are with light gray background colour. But other than that, everything else is a box standard Chart.js.
I’ve recreated the issue here:
https://codepen.io/LeoU/pen/gVLybO
And here is my options settings.
options: {
legend: {
display: false,
},
tooltips: {
callbacks: {
label: function (tooltipItem, data) {
var tooltipValue = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
return "£" + parseInt(tooltipValue).toLocaleString();
}
}
},
scales: {
yAxes: [{
gridLines: {
color: "white",
lineWidth: 2
},
ticks: {
beginAtZero: true,
min: 0,
stepSize: 500000,
callback: function(value, index, values) {
return "£" + value.toLocaleString();
},
},
scaleLabel: {
display: true,
labelString: "Median house price"
}
}],
xAxes: [{
display: false,
ticks: {
display: false
}
}]
}
},
Has anyone seen a similar problem with Chart.js?
You can use offset
scales: {
xAxes: [{
offset: true
}]
}
I fixed this by adding padding value to the right hand side of the chart.
I played around with the exact number and 4 looked about right for my chart. But I’d imagine the right number will depend on the size of your pointRadius and other variables you have.
This is what it looks like for me with the changes.
options: {
layout: {
padding: {
left: 0,
right: 4,
top: 0,
bottom: 0
}
}
}
For more about padding for Chart.js, this is their instruction page.
https://www.chartjs.org/docs/latest/configuration/layout.html
It is annoying. And, this should be a default setting, really. But this fixed the problem for me.
So I have created a basic line chart using Chartjs. How would I go about changing the color of the points (pointBackgroundColor) depending on the value of the data? For example, if the data point is less than 10 it changes to red, or if the data point is between 10 and 20 it changes to blue?
const CHART = document.getElementById("lineChart");
let lineChart = new Chart(CHART, {
type: 'line',
data: {
labels: ["5/10/2010", "5/11/2010", "5/12/2010", "5/13/2010", "5/14/2010", "5/15/2010", "5/16/2010"],
datasets: [
{
label: "Theta",
fill: false,
lineTension: 0,
backgroundColor: "rgba(75,192,192,0.4)",
borderColor: "rgba(9,31,62)",
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: "rgba(0,191,255)",
pointBackgroundColor: "rgba(0,191,255)",
pointBorderWidth: 5,
pointBorderRadius: 5,
pointHoverBackgroundColor: "rgba(75,192,192,1)",
pointHoverBorderColor: "rgba(220,220,220,1)",
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data: [15, 28, 11, 3, 34, 65, 20],
}
]
},
options: {
maintainAspectRatio: false,
responsive: true,
legend: {
display: false,
},
scales: {
yAxes:[{
ticks: {
fontColor: "#091F3e",
beginAtZero: true,
steps: 10,
stepSize: 10,
max: 100
},
gridLines: {
display: false
}
}],
xAxes:[{
ticks: {
fontColor: "#091F3e",
fontSize: "10",
},
gridLines: {
display: false
}
}]
}
}
});
You can use a closure on any option and manipulate the returned value according to the context. In the example bellow I'm the pointBackgroundColor is red when the current value is greater then 0 and blue otherwise.
pointBackgroundColor: function (context) {
let value = context.dataset.data[context.dataIndex];
return value > 0
? 'red'
: 'blue';
},
Here is another thing that may help you Change bar color depending on value.
Its original answer from Tot Zam
Adding the code sample in case the link doesn't work.
var colorChangeValue = 50; //set this to whatever is the decidingcolor change value
var dataset = myChart.data.datasets[0];
for (var i = 0; i < dataset.data.length; i++) {
if (dataset.data[i] > colorChangeValue) {
dataset.backgroundColor[i] = chartColors.red;
}
}
myChart.update();
Its about bars background, but you can try work around and find same solution.
I need to put some additional labels on my charts, so I'm using shapes. Here is the result:
http://jsfiddle.net/z3n3qobm/91/
But I need to align the circles from the example with the labels of the X-axis. The chart must be responsive and the total of labels depends from the database.
I have a function that generates the initial position of the shapes in '%', but it misaligns when I change the window's size.
I did some calculations, but when the chart resizes it doesn't keep a fixed proportion.
Someone have an idea how to use shapes at the same position of the X-axis labels?
Unfortunately ZingChart does not provide a way to scale shapes and labels based on sizing. Hooks are available to position labels on nodes, but not on scale items themselves.
Now there I do have a solution to your issue, but just to be clear this is more of a hack utilizing tricks with ZingChart and multiple charts. I removed the shapes in your chart and decided to replicate those circles utilizing a second chart.
The main goal of this was to utilize a scatter chart, modify the look of each scatter node to replicate what you are trying to achieve, and to hide all the superficial items that were unnecessary (scales, removed plotarea margins). Do note that I'm using a mixed chart, one series for the scatter chart, and another for a dummy bar chart to force the scales to match how the chart above is displayed.
http://jsfiddle.net/mikeschultz/q6arebsu/1/
(Snippet below incase the jsfiddle is deleted in the future).
This can be also accomplished by combining the two charts into a single graphset, but I find working with separate charts is more flexible.
var myData = {
"graphset":[
{
"globals":{
"overflow":"visible"
},
"plot":{
"animation":{
"effect":"ANIMATION_EXPAND_BOTTOM",
"sequence":null,
"speed":10
},
"aspect":"jumped"
},
"plotarea": {
"margin-bottom": 30
},
"type":"mixed",
"series":[
{
"type":"bar",
"values":[46,46,53,50],
"background-color":"#5e36e6",
"value-box":{
"placement":"bottom-in",
"rules":[
{
"rule":"%v==0",
"visible":false
}
],
"thousands-separator":".",
"font-color":"#fff"
},
"palette":0
},
{
"type":"bar",
"values":[52,53,61,58],
"background-color":"#0099cd",
"value-box":{
"placement":"top",
"rules":[
{
"rule":"%v==0",
"visible":false
}
],
"thousands-separator":".",
"font-color":"#fff"
},
"palette":1
},
{
"type":"line",
"values":[150,105,399,159],
"marker":{
"size":0,
"border-width":0,
"background-color":"transparent"
},
"line-color":"#99cc33",
"line-width":3,
"value-box":{
"placement":"top",
"rules":[
{
"rule":"%v==0",
"visible":false
}
],
"thousands-separator":"."
},
"palette":2
}
],
"background-color":"#3F0767",
"scale-x":{
"tick":{
"alpha":0
},
"zooming":false,
"labels":["AB","CDE","FG","HI JKL"],
"line-width":0,
"zoom-to":null
},
"scale-y":{
"guide":{
"alpha":0.25,
"line-style":"solid",
"line-color":"#5a3b77"
},
"short":true,
"tick":{
"alpha":0
},
"line-width":0
},
"scroll-x":false
},
]
};
zingchart.render({
id : 'myChart',
data : myData,
height: 400
});
var bubbleConfig = {
type: 'mixed',
backgroundColor:"#3F0767",
scaleX: {
visible: false
},
scaleY: {
visible: false
},
plotarea: {
marginTop : 0,
marginBottom: 0,
maskTolerance: [0,0]
},
plot: {
marker: {
size: 30,
borderColor: '#371876',
borderWidth: 3,
backgroundColor: 'transparent'
},
tooltip: {
visible: false
}
},
scaleY: {
values: "0:2:1",
visible: false
},
series: [
{
type:'scatter',
values: [
[0,1],
[1,1],
[2,1],
[3,1]
],
valueBox: {
visible: true,
text: 'foobar',
fontColor: '#fff',
fontSize: '15px',
fontWeight: 'normal',
placement: 'over',
rules: [
{
rule: '%i == 0',
text: '35%'
},
{
rule: '%i == 1',
text: '51%'
},
{
rule: '%i == 2',
text: '15%'
},
{
rule: '%i == 3',
text: '36%'
}
]
}
},
{
type:'bar',
values: []
}
]
}
zingchart.render({
id : 'myBubbles',
data : bubbleConfig,
height: 80
});
<html>
<head>
<script src="http://cdn.zingchart.com/zingchart.min.js"></script>
</head>
<body>
<div id="myChart"></div>
<div id='myBubbles'></div>
</body>
</html>