DOM elements not ready in AngularJS Directive's link() function - javascript

I'm creating a AngularJS directive that is supposed to have a C3.js-based chart in it. Problem is that the C3 library does not see the DOM element it's supposed to attach to. The directive's link function looks something like this:
link: function(scope, element, attrs) {
scope.someid = 'id';
scope.chart = c3.generate({
bindto: "#somechart"+scope.someid,
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250],
['data2', 50, 20, 10, 40, 15, 25]
]
}
});
console.log($("#somechart"+scope.someid).size()); // this is a test, outputs 0
}
The template for the directive has this in it:
<div id="#somechart{{ scope.someid }}">...</div>
The problem is that the c3.generate()'s bindto does not see the #somechartid. The console.log() I've put in outputs 0 which means the element is not present in the DOM at the moment when the link function is called.
If I call the same chart-generating code from the browser's console or even from some ng-click the chart gets rendered.
Is there a way to overcome this problem without using a solution like $timeout?
UPDATE 2014-07-15 15:33 Changed the code sample and added relevant line from directive's template.

Use $timeout function in your link function if you want to manipulate dom, which is not yet generated. See this

Have you tried something like this
link: function(scope, element, attrs) {
scope.chart = c3.generate({
bindto: element[0],
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250],
['data2', 50, 20, 10, 40, 15, 25]
]
}
});
}

Maybe usage of element.find('#id') will help:
link: function(scope, element, attrs) {
var item = element.find('#somechartid');
scope.chart = c3.generate({
bindto: item,
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250],
['data2', 50, 20, 10, 40, 15, 25]
]
}
});
}

Related

cannot use multiple doc.html() for the same document

To my understanding after going through GitHub, documentation and stack overflow:
doc.html() is supposed to be able to take in a string with html formatting (AKA rich text)
There has been work done to ensure that doc.html() is able to produce multiple html snippets within the same pdf document
To produce more than one html in the same document, one is supposed to utilize the callback function and nest any further edits to the pdf.
doc.html() does not behave in the same sense as the other functions (text, rect, etc.) where you can add as many as you want.
var pageWidth = 1000,
lineHeight = 1,
margin = 20,
maxLineWidth = pageWidth - margin * 2,
fontSize = 11,
ptsPerMM = 72 / 25.6,
oneLineHeight = (fontSize * lineHeight) / ptsPerMM;
var doc = new jspdf.jsPDF({
orientation: 'p',
unit: 'pt',
format: 'letter',
lineHeight: lineHeight
});
var field1 = "<b>this is field 1 </b>";
var field2 = "<b>this is field 2 </b>";
//add first html
doc.html("<body>" + field1 + "</body>", {
callback: function (doc) {
//do nothing
},
width: maxLineWidth ,
windowWidth: maxLineWidth ,
html2canvas: {
backgroundColor: 'lightyellow',
width: maxLineWidth ,
height: 150
},
backgroundColor: 'lightblue',
x: 10,
y: 10,
autoPaging: 'text'
});
//add second html
doc.html("<body>" + field2 + "</body>", {
callback: function (doc) {
//do nothing
},
width: maxLineWidth ,
windowWidth: maxLineWidth ,
html2canvas: {
backgroundColor: 'lightyellow',
width: maxLineWidth ,
height: 150
},
backgroundColor: 'lightblue',
x: 10,
y: 10,
autoPaging: 'text'
});
//export pdf
window.open(doc.output('bloburl'));
The code above does not work. how can I fix this issue where I cannot export multiple html snippets in the same pdf document?
I went over GitHub, documentation and stack overflow and for the first time ever, whenever someone asks a question related to this topic, they don't seem to get an answer.
I would really appreciate it if someone could help me figure this out.
I've tried returning doc within the callback and reusing that but that didn't seem to work
Found it!
just use await and make sure to return doc inside the callback
something like this
var doc = new jspdf.jsPDF({
orientation: 'p',
unit: 'pt',
format: 'letter'
});
var field = "<b>html test </b>";
doc.text(10, 10, "test");
//add first html
await doc.html(field, {
callback: function (doc) {
return doc;
},
width: 210,
windowWidth: 210,
html2canvas: {
backgroundColor: 'lightyellow',
width: 210,
height: 150
},
backgroundColor: 'lightblue',
x: 10,
y: 50,
autoPaging: 'text'
});
window.open(doc.output('bloburl'));

How to add html content to each page of jsPDF?

I am trying to convert my html page to pdf using jsPDF. Essentially i am using the html method of jsPDF, giving it a source, and options and then in the callback function i would save the document.
But i am having a problem when it comes to dividing the single html document into mulitple divs and saving each div in a page. I am trying the below code and it renders all the pages blank.
My html looks like
<div class = "resultpage" >
<div class = "print-section-1">
//some content
</div>
<div class = "print-section-2">
//some content again
</div>
<div class = "print-section-3">
//content...
</div>
</div>
My js looks like :
window.jsPDF = window.jspdf.jsPDF;
let doc = new jsPDF({
orientation : "portrait",
unit : 'px',
format : 'a4',
hotfixes : ["px_scaling"],
putOnlyUsedFonts : true
})
doc.html($(".prints-section-1")[0], {
x: 10,
y : 10,
margin : [50, 200, 50, 200],
autoPaging : "text"
})
doc.addPage()
doc.html($(".print-section-2")[0], {
x: 10,
y : 10,
margin : [50, 200, 50, 200],
autoPaging : "text"
})
doc.addPage()
doc.html($(".print-section-3")[0], {
x: 10,
y : 10,
margin : [50, 200, 50, 200],
autoPaging : "text"
})
doc.save("test")
This renders all the pages empty.
If i modify the js, to have a chaining of callbacks like below, i am able to get the last div (print-side-2 in this case) printed but the pages previous to it are blank.
doc.html($(".print-section-1")[0], {
callback : function(doc) {
doc.addPage();
doc.html($(".print-section-2")[0], {
callback : function(doc) {
doc.save("test.pdf")
}
x: 10,
y : 10,
margin : [50, 200, 50, 200],
autoPaging : "text"
})
}
x: 10,
y : 10,
margin : [50, 200, 50, 200],
autoPaging : "text"
})
Can anyone point out what i am doing wrong ? I searched for solutions but many use deprecated methods like addFromHTtml, and some suggested using line breaks like "<!--ADD_PAGE>" _ and
style = "page-break-before : always" but both don't work. I looked into the documentation and it hasn't been great support. Please help me.
Referencing this answer (refrencing)
Just use await and make sure to return doc inside the callback
something like this
var doc = new jspdf.jsPDF({
orientation: 'p',
unit: 'pt',
format: 'letter'
});
var field = "<b>html test </b>";
doc.text(10, 10, "test");
//add first html
await doc.html(field, {
callback: function (doc) {
return doc;
},
width: 210,
windowWidth: 210,
html2canvas: {
backgroundColor: 'lightyellow',
width: 210,
height: 150
},
backgroundColor: 'lightblue',
x: 10,
y: 50,
autoPaging: 'text'
});
window.open(doc.output('bloburl'));
now you can call doc.html as many times as you want for that same document
Originally posted by #bakuur in https://github.com/parallax/jsPDF/issues/3074#issuecomment-1328427528

Trying to remove black fill under lines in billboard.js line chart

I am using the same example line chart shown here. However, I have black fill under the lines on my chart. How do I remove the black fill from under the lines. In the documentation under LineChartOptions there it only shows two configurable options, HidePoints and LinePoint. Here is my example. The same thing happens to my time series chart. Thank you.
var lineChart = bb.generate({
data: {
columns: [
["data1", 30, 200, 100, 400, 150, 250],
["data2", 50, 20, 10, 40, 15, 25]
],
type: "line", // for ESM specify as: line()
},
bindto: "#lineChart"
});
Adding fill: none to the bb-chart-lines class should do the trick.
Add this to your CSS:
.bb-chart-lines {
fill: none;
}
Link to Codepen

Incorrect visualization of c3.js graph

I am trying to draw a very basic line chart using c3.js in react. But the the chart output appears with dark areas around the lines, which I assume is not a feature of the graph, because I used another graph library and the dark areas persisted. Anyone knows what the source of error can be?
Here is a picture of how the chart looks like:
Here is the code:
import React from "react";
import * as c3 from 'c3'
class Hello extends React.Component {
drawGraph = () =>
{
var chart = c3.generate({
bindto: this.refs.chart,
data: {
xs: {
'data1': 'x1',
'data2': 'x2',
},
columns: [
['x1', 10, 30, 45, 50, 70, 100],
['x2', 30, 50, 75, 100, 120],
['data1', 30, 200, 100, 400, 150, 250],
['data2', 20, 180, 240, 100, 190]
]
}
});
}
render() {
return (
<div>
<br/>
<div id='chart' ref={'chart'} style={{width: '100%', height: '100%'}}><button onClick={this.drawGraph}>draw</button></div>
</div>
);
}
}
export default Hello;
If the package was installed using npm (i.e. npm install c3 or yarn add c3), it's necessary import the styles from .css files: Inside the main component, add the line
import "c3/c3.min.css";
Apparently the problem can be solved just by adding a single line of code in the beginning:
import "../../node_modules/c3/c3.css";
If you come across here as I did from top results of google search, you will be probably surprised why both of other solutions don't work.
In Vue 3 Cli there is issue with .css file loader not working properly, but you can circumvent this if you add to your main.js file, following line:
require('c3/c3.css');// C3 chart styles
This will enable you to use c3 in rest of your project, with importing c3 in components like so:
<template>
<div id="testChart"></div>
</template>
<script>
var c3 = require('c3');
export default {
async mounted() {
c3.generate({
bindto: "#testChart",
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250],
['data2', 50, 20, 10, 40, 15, 25]
]
}
});
}
};
</script>

How can I bind at a later time a billboardjs chart?

The docs say that when the chart is not bound, it'll start observing the chart.element property. I've tried not setting the bindto property for the options object passed to generate, and also setting it to null.
But if I later set the chart.element property to anything i.e. chart.element = document.getElementById("#chart-here"), nothing happens.
What is the correct approach of doing this? Or is it something that I misunderstood?
Thanks.
You just need to use setTimeout https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout
var generateChart = function () {
bb.generate({
data: {
columns: [
["data1", 30, 200, 100, 400, 150, 250],
["data2", 50, 20, 10, 40, 15, 25]
]
},
bindto: "#chart-here"
});
};
setTimeout(generateChart, 2000)
<title>billboard.js</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/billboard.js/dist/billboard.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/billboard.js/dist/billboard.min.css">
Chart will appear in 2 seconds...
<div id="chart-here"></div>

Categories

Resources