Border not aligned properly in PDF [Snippet attached] - javascript

I am making a very simple react application with ver minimal of content.
index.js:
<div className="App">
<div id="printable-div">
<h1>Generate PDF</h1>
<p>Create a screenshot from the page, and put it in a PDF file.</p>
<p style={{ color: "red" }}>
*Open this page in new window and press the button.
</p>
</div>
<br />
<button id="print" onClick={printPDF}>
PRINT
</button>
</div>
Where here the div with id printable-div will gets printed.
I also applied a css for this like,
#printable-div {
border: 2px solid #000;
padding: 20px;
}
But while click on the button, the download of pdf happens whereas on opening the pdf file, the border is not aligned properly.
Also here, the order needs to be to the page but whereas it applied only to the div.
Libraries used:
-> jsPdf
-> html2canvas
And the code executed on click on the print button as follows,
const printPDF = () => {
const domElement = document.getElementById("printable-div");
html2canvas(domElement).then((canvas) => {
const imgData = canvas.toDataURL("image/png");
const pdf = new jsPdf();
pdf.addImage(imgData, "JPEG", 0, 0);
pdf.save(`${new Date().toISOString()}.pdf`);
});
};
Complete working example:
Can anyone humbly help me to achieve the result of making the border properly aligned to the entire page?
It is okay if the libraries used needs to be changed to other alternative..
Requirement:
The entire page needs to have border visible with all sides equal spacing and the content needs to be inside of the border..

I checked your codesandbox and it seems you'd already applied #Ihsan's solution, but to build on that solution I found that jsPDF has a fromHMTL function, so you can skip rendering to a canvas first.
const printPDF = () => {
const domElement = document.getElementById("printable-div");
const doc = new jsPdf();
doc.fromHTML(domElement, 10, 5); // position within rectangle
doc.rect(5, 5, 200, 0.3);
doc.rect(5, 5, 0.3, 285);
doc.rect(5, 290, 200, 0.3);
// doc.rect(5, 30, 200, 0.3); // this is the "middle" horizontal bar
doc.rect(205, 5, 0.3, 285);
doc.save(`${new Date().toISOString()}.pdf`);
};
I commented out the middle horizontal bar as this bar's vertical position just needs to be tweaked for where you want/need it.
Edit
Instead of a bunch of rectangles you can draw a single rectangle and stroke it to create the outer border, and use a line to fill in the horizontal "bar". IMO this reads a little more cleanly.
const printPDF = () => {
const domElement = document.getElementById("printable-div");
const doc = new jsPdf();
// Create border
doc.rect(5, 5, 200, 285, "S").line(5, 45, 205, 45, "S");
// Inject HTML
doc.fromHTML(domElement, 10, 5);
// Save out to PDF
doc.save(`${new Date().toISOString()}.pdf`);
};
In fairness I think Ihsan should get the bulk of the credit as this is basically their answer, I just got the content in there by a different means, and positioned the copied HTML.

following to my comment, this is the example you can use to setup you pdf layout. you can try it on online editor
var doc = new jsPDF();
doc.setFillColor("#000000")
doc.rect(5, 5, 200, 0.3)
doc.rect(5, 5, 0.3, 285)
doc.rect(5, 290, 200, 0.3)
doc.rect(5, 30, 200, 0.3)
doc.rect(205, 5, 0.3, 285)

Related

fabricjs how to double-click a picture(or rect) to edit text and name it

How to combine images and text with fabricjs and edit text when double clicking the combined object,
Still combine after editing text,
Please tell me how to edit text when rendering image and text combinations
const canvas = new fabric.Canvas("canvas");
// a rect
const rect = new fabric.Rect({
stroke: "#000",
strokeWidth: 1,
fill: "#ccc",
left: 170,
top: 80,
width: 50,
height: 50
});
// a text for describe rect
const text = new fabric.IText("describe rect", {
fontFamily: "Comic Sans",
fontSize: 14,
stroke: "#000",
strokeWidth: 1,
fill: "#000",
left: 170,
top: 80
});
// 1 Combine the above two things but can not edit text
// 2 use LabeledRect also
Based on your requirements, you can
Create a subclass of Image class (or whatever object that you need to attach a label to)
Make it create an instance of IText or Textbox and save an internal reference to it
By hooking into the event handlers on the image (e.g. double click), manually manage the events of the text. Make sure to keep the position and dimensions of the text updated when the image is modified.
Take a look at this answer: Resize Fabric Rect without resizing Textbox. It does something very similar to what you've described.

Scale down a Konvajs stage without losing quality

Consider having a large (2000x1000) stage with some text in it. The stage gets downscaled to 1000x500 making the text unreadable. Then we try to enlarge the text by zooming it in.
Expected: the text should become readable again at some point.
Actual: the text remains unreadable (blurred) no matter how much we zoom in.
Try zooming the page in (with native browser zoom on desktop) after running the snippet:
const stage = new Konva.Stage({
container: 'container',
width: 2000,
height: 1000,
});
const layer = new Konva.Layer();
stage.add(layer);
const rect = new Konva.Text({
x : 50, y : 50, width: 100, height: 100,
fontSize: 12,
text: "This text should be readable when the viewport gets downscaled"
});
layer.add(rect).draw();
stage.scale({x: 0.5, y: 0.5});
stage.setAttrs({width: 1000, height: 500});
stage.draw();
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.6.0/konva.js"></script>
<div id="container"></div>
The quality loss can be avoided by downscaling with CSS only, like this:
const stage = new Konva.Stage({
container: 'container',
width: 2000,
height: 1000,
});
const layer = new Konva.Layer();
stage.add(layer);
const rect = new Konva.Text({
x : 50, y : 50, width: 100, height: 100,
fontSize: 12,
text: "This text should be readable when the viewport gets downscaled"
});
layer.add(rect).draw();
stage.getChildren().forEach(function(layer) {
layer.canvas._canvas.style.width = "1000px";
layer.canvas._canvas.style.height = "500px";
layer.hitCanvas.setSize(1000, 500);
layer.hitCanvas.context.scale(0.5, 0.5);
});
stage.draw();
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.6.0/konva.js"></script>
<div id="container"></div>
Note how text becomes readable at a certain level of zooming.
The workaround breaks Konvajs abstraction. What problems it can potentially cause? Is there a better way, which uses only public methods exposed by Konvajs?
In fabric.js it can be done like this (complete example here):
canvas.setDimensions({width: '1000px', height: '500px'}, {cssOnly: true});
Konva is a canvas framework. Canvas is a bitmap image unlike vector elements like SVG. So that "blur" should be expected. Technically to fix the issue you can redraw stage with higher pixelRatio on zoom event:
Konva.pixelRatio = 4
stage.draw();
That code will generate more pixels for canvas element. But the page may be very heavy in RAM in this case because Konva will have to produce very large canvas. In most of the mobile apps, you don't need native zooming and you can use responsive design. For zooming the stage, you can use Konva methods.

TweenMax at function out - how to implement conditional?

I'm using JS libraries: GSAP along with ScrollMagic.io by Jan Paepke.
Scrollmagic.io allows me to trigger some CSS changes on scrolling once certain trigger element is reached, the JS script looks like this:
var controller = new ScrollMagic.Controller();
var scene = new ScrollMagic.Scene({
triggerElement: "#trigger1"
})
.setTween(new TimelineMax().add([
TweenMax.to("header", 0.5, {backgroundColor: "rgba(40,80,01, 0.95)", height:"6%", width:"100%", top:"0", borderRadius:"0px"}),
TweenMax.to(".headernav", 0.5, {color:"white", fontSize:"1.5em", marginTop:"10px"}),
TweenMax.to(".circle", 0.5, {height:"35px", marginTop:"10px"}),
TweenMax.to("#logo", 0.5, {width:"70px", marginTop:"-10px", marginRight:"500px"})
]))
.addTo(controller);
In general - it would change position, background-color and font color of my menu once it is scrolled over white area of website so that it will still be noticable and easy to read.
The problem is my a:hover within menu stopped working.
I've found a workaround by using this:
$("#verticalnav p").hover(over, out);
function over(){
TweenMax.to(this, 0.5, {color:"rgb(181, 171, 171)", scale:"1.1"})
}
function out(){
TweenMax.to(this, 0.5, {color:"rgb(105, 105, 105)", scale:"1"})
}
This makes it work fine, but there's still one thing to be worked out - while background of menu is "white", color:"dimgray" of font is well noticable/readable, but it will also remain "dimgray" on the green background after scrolling.
Here's screenshot explanation to show it more clearly:
Default menu state with no hovers:
On:hover using js - changes color using script shown above:
Here some properties of menu have changed along with font color to be more readable on green background:
And here's how it looks like when the mouse is OUT of the link, leaving it "dimgray" because the script makes it:
My question is - how may I implement a conditional into this script:
$("#verticalnav p").hover(over, out);
function over(){
TweenMax.to(this, 0.5, {color:"rgb(181, 171, 171)", scale:"1.1"})
}
function out(){
TweenMax.to(this, 0.5, {color:"rgb(105, 105, 105)", scale:"1"})
}
so that it would read the current color value and run TweenMax.to with specific color according to this value?
I'm fairly green with JS so any kind of advice would be highly appreciated.
Regards,
Damian.
Actually it seems that the longer I don't get answer, the more creative i become.
Already worker it out, pretty much basic JS/jQuery was needed, posting it so maybe somebody could have some use of it later on.
Here's working code of function hover:
$("#verticalnav p").hover(over, out);
function over(){
TweenMax.to(this, 0.5, {color:"rgb(181, 171, 171)", scale:"1.1"})
};
function out(){
var kolor = $("header").css("background-color");
if (kolor == "rgba(255, 255, 255, 0.901961)") {
TweenMax.to(this, 0.5, {color:"rgb(105, 105, 105)", scale:"1"})
}
else {
TweenMax.to(this, 0.5, {color:"white", scale:"1"})
}
};

Fabricjs Textbox make the text shrink to fit

I would define a text box (single-line)
By default, with a character size of 16 (for example)
When the text gets bigger than the text box, I do not want it to wrap or the text box gets bigger, I want the text size to fit the maximum size of the text box. text. When the text returns to a smaller size, it can resume its initial size (in our example 16). Possibly manage a minimum size
If you have an idea, I take :)
thanks in advance
Test Case : http://jsfiddle.net/Da7SP/273/
// initialize fabric canvas and assign to global windows object for debug
var canvas = window._canvas = new fabric.Canvas('c');
// ADD YOUR CODE HERE
var canvas = window._canvas = new fabric.Canvas('c');
var t1 = new fabric.Textbox('My Text', {
width: 200,
top: 5,
left: 5,
fontSize: 16,
textAlign: 'center'
});
var t2 = new fabric.Textbox('My text is longer, but I do not want the box to grow, or the text to wrap. I only want the text to fit the available size', {
width: 200,
height: 200,
top: 250,
left: 5,
fontSize: 16,
textAlign: 'center'
});
canvas.add(t1);
canvas.add(t2);
A small video to explain what I want :
When the text gets bigger than the text box, I want the text size fit the maximum size of the text box.
This is a basic fiddle that can replicate your idea.
The point is that you have an event that fires on every text change and that can be used to do something before the textbox is rendered.
In this case i m shrinking font size based on a non standard parameter i added to textbox called fixedWidth
// ADD YOUR CODE HERE
var canvas = new fabric.Canvas('c');
var t1 = new fabric.Textbox('MyText', {
width: 150,
top: 5,
left: 5,
fontSize: 16,
textAlign: 'center',
fixedWidth: 150
});
canvas.on('text:changed', function(opt) {
var t1 = opt.target;
if (t1.width > t1.fixedWidth) {
t1.fontSize *= t1.fixedWidth / (t1.width + 1);
t1.width = t1.fixedWidth;
}
});
canvas.add(t1);
canvas {
border: 1px solid #999;
}
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
Here's a similar answer to https://stackoverflow.com/a/41335051/1469525 but this example modifies the fontSize up to a maxFontSize (the initial fontSize). This allows the text to shrink and then grow back to the original size, as well as preventing line wraps.
(Note, if you use this, you'll have to find a way to prevent the user from using the enter key. I put in a check that basically cancels it if an enter key is detected. My app actually has a separate form to enter the text, so I can control prevention through normal javascript. I'm not quite sure how to do that directly on a canvas element when it is editable like here...)
var canvas = new fabric.Canvas('c');
var t1 = new fabric.Textbox('MyText', {
width: 150,
top: 5,
left: 5,
fontSize: 16,
textAlign: 'center',
maxFontSize: 16,
});
canvas.on('text:changed', function(opt) {
var t1 = opt.target;
if (t1.text.match(/[\r\n]/)) return;
t1.set({
fontSize: t1.maxFontSize,
});
while (t1._textLines.length > 1) {
t1.set({
fontSize: t1.fontSize - 1,
});
}
});
canvas.add(t1);
canvas {
border: 1px solid #999;
}
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>

how to change the Dojo GlossyCircularGauge text indicator position?

I want to move the text indicator to little down, am able to change the color and change the size of it but not the position.
Below is my code.
require(['dojox/gauges/GlossyCircularGauge','dojo/aspect', 'drawGreenYellowRedCurves', 'dojo/domReady!'], function (GlossyCircularGauge, aspect, drawGreenYellowRedCurves) {
var gauge = new GlossyCircularGauge({
background: [255, 255, 255, 0],
title: 'Value',
id: "glossyGauge",
width: 300,
height: 300
}, dojo.byId("CircularGauge"));
gauge.set('textIndicatorFont','normal small-caps bold 22pt Arial');
gauge.set('textIndicatorColor','#FFFFF');
aspect.after(gauge, "drawRange", drawGreenYellowRedCurves, true);
gauge.startup();
});
for reference http://jsfiddle.net/rameshcharykotha/dsmfg/14/
you can change the value of the internal attribute _designTextIndicatorY to update the text indicator position. Default value is 267.81589, but you can use a greater value to lower down the position of the text indicator.
Example:
require(['dojox/gauges/GlossyCircularGauge','dojo/aspect', 'drawGreenYellowRedCurves', 'dojo/domReady!'], function (GlossyCircularGauge, aspect, drawGreenYellowRedCurves) {
var gauge = new GlossyCircularGauge({
background: [255, 255, 255, 0],
title: 'Value',
id: "glossyGauge",
width: 300,
height: 300,
_designTextIndicatorY: 317.81589
}, dojo.byId("CircularGauge"));
gauge.set('textIndicatorFont','normal small-caps bold 22pt Arial');
gauge.set('textIndicatorColor','#FFFFF');
aspect.after(gauge, "drawRange", drawGreenYellowRedCurves, true);
gauge.startup();
});
This is not directly answering your question but it might still help, dojox/gauges have been deprecated your are encouraged to use dojox/dgauges instead. See doc: http://dojotoolkit.org/reference-guide/1.9/dojox/dgauges.html#dojox-dgauges
A little while ago i answered a similar question. There someone wants to change the rangecolors in the new dGauge. Have a look at this fiddle: http://jsfiddle.net/v7WwD/
Here's the part in the new dgauge that's intresting for you:
// Indicator Text
indicator = gauge._elementsIndex.scale._indicators[0];
var indicatorText = new TextIndicator();
indicatorText.set("indicator", indicator);
indicatorText.set("x", 100);
indicatorText.set("y", 100);
gauge.addElement("indicatorText", indicatorText);
To make it clear how to implement this, look at the entire code in my fiddle.
Regards, Miriam

Categories