I have a problem with jsPDF in wordpress website which built by elementor. The exported PDF starts from the middle of the page !
In normal content it works fine, but in product server it starts from the middle,
please check out This sample.
Is there a way to fix it?
This is the code I wrote :
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.4/jspdf.debug.js"></script>
<button class="btn" id="btn" onClick="printToPDF();">
Export to PDF
</button>
<div id="page">content</div>
<script>
function printToPDF() {
btn.innerText = "Converting...";
console.log('Converting...');
var printableArea = document.getElementById('page');
html2canvas(printableArea, {
useCORS: true,
onrendered: function(canvas) {
var pdf = new jsPDF('a', 'pt', 'a4');
var pageHeight = 1200;
var pageWidth = 1000;
for (var i = 0; i <= printableArea.clientHeight / pageHeight; i++) {
var srcImg = canvas;
var sX = 0;
var sY = pageHeight * i; // start 1 pageHeight down for every new page
var sWidth = pageWidth;
var sHeight = pageHeight;
var dX = 0;
var dY = 0;
var dWidth = pageWidth;
var dHeight = pageHeight;
window.onePageCanvas = document.createElement("canvas");
onePageCanvas.setAttribute('width', pageWidth);
onePageCanvas.setAttribute('height', pageHeight);
var ctx = onePageCanvas.getContext('2d');
ctx.drawImage(srcImg, sX, sY, sWidth, sHeight, dX, dY, dWidth, dHeight);
var canvasDataURL = onePageCanvas.toDataURL("image/png", 1.0);
var width = onePageCanvas.width;
var height = onePageCanvas.clientHeight;
if (i > 0) // if we're on anything other than the first page, add another page
pdf.addPage(612, 791); // 8.5" x 11" in pts (inches*72)
pdf.setPage(i + 1); // now we declare that we're working on that page
pdf.addImage(canvasDataURL, 'PNG', 20, 40, (width * .62), (height * .62)); // add content to the page
}
var today = new Date();
var date = today.getFullYear()+'-'+(today.getMonth()+1)+'-'+today.getDate();
pdf.save(date+'.pdf');
btn.innerText = " Export to PDF";
}
});
}
</script>
Related
I want know how to figure out if the puzzle is solved.
I am creating an app for creating custom 6-piece puzzle.
Here's the code:
function approved(){
// Get the canvas and context
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// Load the image
var img = new Image();
img.src = document.getElementById('puzzleprieview').src;
img.onload = function() {
// Set the canvas size
canvas.width = img.width;
canvas.height = img.height;
// Draw the image on the canvas
ctx.drawImage(img, 0, 0);
// Split the image into parts
var w = img.width / 3;
var h = img.height / 2;
for (var i = 0; i < 7; i++) {
var x = (i % 3) * w;
var y = Math.floor(i / 3) * h;
// Create a new canvas for each part
var partCanvas = document.createElement("canvas");
partCanvas.draggable="true";
partCanvas.className="sampcanvas"
$(".sampcanvas").draggable({snap: true});
partCanvas.width = w;
partCanvas.height = h;
var partCtx = partCanvas.getContext("2d");
// Draw the part of the image on the new canvas
partCtx.drawImage(canvas, x, y, w, h, 0, 0, w, h);
var number=Math.floor(Math.random() * 100);
// Do something with each part, such as append it to the document
const getRandom = (min, max) => Math.floor(Math.random()*(max-min+1)+min);
partCanvas.style.left= getRandom(0, 300 - 200)+'px'; // 👈🏼 Horizontally
partCanvas.style.top = getRandom(0, 300 - 200)+'px'; // 👈🏼 Vertically
document.getElementById('pieces').appendChild(partCanvas);
}
}
}
That code is used to create puzzle pieces and append them.
What I need to do is somehow compare the puzzle piece solving to the canvas that is created
Well, great task in general and question in particular !
To achieve this purpose you could, f.e. put into each puzzlePart block it's initial position using "data-" attributes:
var x = (i % 3) * w;
var y = Math.floor(i / 3) * h;
// Create a new canvas for each part
let partCanvas = document.createElement('canvas');
partCanvas.dataset.xx = x;
partCanvas.dataset.yy = y;
Next, whenever needed, you are able to compare current position of puzzle parts with their initial ones. I took initial position from .dataset and current using .getBoundingClientRect():
var canvasOffsets = canvas.getBoundingClientRect();
var elementScreenOffsets = partCanvas.getBoundingClientRect();
var elementOffsets = {
x: elementScreenOffsets.left - canvasOffsets.left,
y: elementScreenOffsets.top - canvasOffsets.top,
};
var initialOffsets = {
x: partCanvas.dataset.xx,
y: partCanvas.dataset.yy,
};
As an option, you could for example "freeze" puzzle parts on the screen when they're moreless in their initial position:
var FREEZE_DISTASNCE = 30;
if (
Math.abs(elementOffsets.x - initialOffsets.x) <
FREEZE_DISTASNCE &&
Math.abs(elementOffsets.y - initialOffsets.y) <
FREEZE_DISTASNCE
) {
makeNotDraggable(partCanvas);
partCanvas.style.left = partCanvas.dataset.xx;
partCanvas.style.top = partCanvas.dataset.yy;
partCanvas.style.zIndex = -1;
}
So eventually I decided to modify initial question's code to make it fully working using my ideas above. Plus I decided to implement this POC with "generic" image which you could pick
For drag-n-drop implementation I referenced this article: https://www.w3schools.com/howto/howto_js_draggable.asp
File inputs Api: https://developer.mozilla.org/ru/docs/Web/HTML/Element/Input/file
document
.querySelector('.js-puzzle-image')
.addEventListener('change', function () {
document.querySelector('.js-puzzle-image').style.display = 'none';
document.querySelector('#pieces').style.display = 'inline-block';
var imageSrc = window.URL.createObjectURL(this.files[0]);
approved(imageSrc);
});
function approved(imageSrc) {
const el_wrap = document.querySelector('#pieces');
// Get the canvas and context
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// Load the image
var img = new Image();
img.src = imageSrc;
img.onload = function () {
// Set the canvas size
canvas.width = img.width;
canvas.height = img.height;
el_wrap.style.width = `${img.width}px`;
el_wrap.style.height = `${img.height}px`;
// Draw the image on the canvas
ctx.drawImage(img, 0, 0);
// Split the image into parts
var w = img.width / 3;
var h = img.height / 2;
for (var i = 0; i < 6; i++) {
var x = (i % 3) * w;
var y = Math.floor(i / 3) * h;
// Create a new canvas for each part
let partCanvas = document.createElement('canvas');
partCanvas.dataset.xx = x;
partCanvas.dataset.yy = y;
partCanvas.draggable = 'true';
partCanvas.className = 'sampcanvas';
//$('.sampcanvas').draggable({ snap: true });
partCanvas.width = w;
partCanvas.height = h;
var partCtx = partCanvas.getContext('2d');
// Draw the part of the image on the new canvas
partCtx.drawImage(canvas, x, y, w, h, 0, 0, w, h);
// Do something with each part, such as append it to the document
const getRandom = (min, max) =>
Math.floor(Math.random() * (max - min + 1) + min);
partCanvas.style.left = getRandom(0, img.width - w) + 'px'; // 👈🏼 Horizontally
partCanvas.style.top = getRandom(0, img.height - h) + 'px'; // 👈🏼 Vertically
document.getElementById('pieces').appendChild(partCanvas);
// making elements "draggable", but "freeze" them when they're on the correct position
makeDraggable(partCanvas, () => {
var canvasOffsets = canvas.getBoundingClientRect();
var elementScreenOffsets = partCanvas.getBoundingClientRect();
var elementOffsets = {
x: elementScreenOffsets.left - canvasOffsets.left,
y: elementScreenOffsets.top - canvasOffsets.top,
};
var initialOffsets = {
x: partCanvas.dataset.xx,
y: partCanvas.dataset.yy,
};
var FREEZE_DISTASNCE = 30;
if (
Math.abs(elementOffsets.x - initialOffsets.x) <
FREEZE_DISTASNCE &&
Math.abs(elementOffsets.y - initialOffsets.y) <
FREEZE_DISTASNCE
) {
makeNotDraggable(partCanvas);
partCanvas.style.left = partCanvas.dataset.xx + 'px';
partCanvas.style.top = partCanvas.dataset.yy + 'px';
partCanvas.style.zIndex = -1;
}
});
}
canvas.style.display = 'none';
};
}
// https://www.w3schools.com/howto/howto_js_draggable.asp
var zIndexTracker = 0;
function makeNotDraggable(elmnt) {
elmnt.onmousedown = undefined;
}
function makeDraggable(elmnt, onDrop) {
var pos1 = 0,
pos2 = 0,
pos3 = 0,
pos4 = 0;
elmnt.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
elmnt.style.zIndex = ++zIndexTracker;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = elmnt.offsetTop - pos2 + 'px';
elmnt.style.left = elmnt.offsetLeft - pos1 + 'px';
}
function closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
onDrop();
}
}
#pieces {
position: relative;
border: 1px dashed red;
display: inline-block;
}
.sampcanvas {
position: absolute;
}
<input type="file" accept=".png, .jpg, .jpeg" class="js-puzzle-image" />
<div id="pieces" style="display: none">
<canvas id="canvas"></canvas>
</div>
Of course, this code snippet is "not ideal" from code quality perspective and should be re-worked to be more object-oriented, to have better code responsibility splitting, etc... But for demostration purposes, I believe, that's a good start
Try adding this
partCanvas.dataset.index = i;
and then you can in your drop function do something like this
const finished = () => {
const indexes = document.querySelectorAll('.sampcanvas')
.map(imgPart => imgPart.dataset.index)
.join('');
console.log(indexes);
return indexes === '0123456';
}
This code allows me to generate the PDF, from an image with canvas, when I generate it in cell or reduce the revolution (width x height), the image of the table in the PDF comes out in half; how could i fix it?
PDF - A4
Correct Image
Not correct image
<script type="text/javascript">
function demoFromHTML() {
var elementHTML = document.getElementById('resultados');
html2canvas(elementHTML, {
useCORS: true,
onrendered: function(canvas) {
var pdf = new jsPDF('p', 'pt', 'A4');
var pageHeight = 1695;
var pageWidth = 1250;
for (var i = 0; i <= elementHTML.clientHeight / pageHeight; i++) {
var srcImg = canvas;
var sX = 0;
var sY = pageHeight * i;
var sWidth = pageWidth;
var sHeight = pageHeight;
var dX = 0;
var dY = 0;
var dWidth = pageWidth;
var dHeight = pageHeight;
window.onePageCanvas = document.createElement("canvas");
onePageCanvas.setAttribute('width', pageWidth);
onePageCanvas.setAttribute('height', pageHeight);
var ctx = onePageCanvas.getContext('2d');
ctx.drawImage(srcImg, sX, sY, sWidth, sHeight, dX, dY, dWidth, dHeight);
var canvasDataURL = onePageCanvas.toDataURL("image/png", 1.0);
var width = onePageCanvas.width;
var height = onePageCanvas.clientHeight;
if (i > 0)
pdf.addPage(593, 780);
pdf.setPage(i + 1);
pdf.addImage(canvasDataURL, 'JPG', 20, 40, (width * .45), (height * .45));
}
pdf.save('cotizador.pdf');
}
});
}
</script>
I am trying to write to an A4 PDF
form = document.querySelector("#theform");
html2canvas(form).then(function(canvas) {
doc = new jsPDF({
unit: 'pt',
format: 'a4',
});
for (var i = 0; i <= form.clientHeight/842; i++) {
//! This is all just html2canvas stuff
var srcImg = canvas;
var sX = 0;
var sY = 842*i;
var sWidth = 595;
var sHeight = 842;
var dX = 0;
var dY = 0;
var dWidth = 595;
var dHeight = 842;
window.onePageCanvas = document.createElement("canvas");
onePageCanvas.setAttribute('width', 595);
onePageCanvas.setAttribute('height', 842);
var ctx = onePageCanvas.getContext('2d');
ctx.drawImage(srcImg,sX,sY,sWidth,sHeight,dX,dY,dWidth,dHeight);
var canvasDataURL = onePageCanvas.toDataURL("image/png", wid = canvas.width, hgt = canvas.height);
var hratio = hgt/wid
const pdfWidth = doc.internal.pageSize.width;
const TheHeight = doc.internal.pageSize.width;
const pdfHeight = TheHeight
if (i > 0) {
doc.addPage(595, 842);
}
//! now we declare that we're working on that page
doc.setPage(i+1);
doc.addImage(canvasDataURL, 'PNG', 10, 10, pdfWidth, pdfHeight);
}
doc.autoPrint();
window.open(doc.output('bloburl'), '_blank');
}
But the it is only creating a PDF for part of the left hand side and I can't see anything wrong.. It is as though what it is writing to the PDF is twice the size it should be.
I'm trying to use an image upload/cropping plugin simple cropper. I have it working fine but I'm dynamically inserting elements with the class .cropme that aren't getting the event binding. I've changed most of the click events to use .on() instead of .click(). Is there something I'm missing?
(function($) {
$.fn.simpleCropper = function () {
var image_dimension_x = 600;
var image_dimension_y = 600;
var scaled_width = 0;
var scaled_height = 0;
var x1 = 0;
var y1 = 0;
var x2 = 0;
var y2 = 0;
var current_image = null;
var aspX = 1;
var aspY = 1;
var file_display_area = null;
var ias = null;
var jcrop_api;
var bottom_html = "<input type='file' id='fileInput' name='files[]'/><canvas id='myCanvas' style='display:none;'></canvas><div id='modal'></div><div id='preview'><div class='buttons'><div class='cancel'></div><div class='ok'></div></div></div>";
$('body').append(bottom_html);
//add click to element
this.on('click', function () {
aspX = $(this).width();
aspY = $(this).height();
file_display_area = $(this);
$('#fileInput').click();
});
$(document).on('ready', function () {
//capture selected filename
$('#fileInput').on('change', function (click) {
imageUpload($('#preview').get(0));
// Reset input value
$(this).val("");
});
//ok listener
$('.ok').on('click', function () {
preview();
$('#preview').delay(100).hide();
$('#modal').hide();
jcrop_api.destroy();
reset();
});
//cancel listener
$('.cancel').on('click', function (event) {
$('#preview').delay(100).hide();
$('#modal').hide();
jcrop_api.destroy();
reset();
});
});
function reset() {
scaled_width = 0;
scaled_height = 0;
x1 = 0;
y1 = 0;
x2 = 0;
y2 = 0;
current_image = null;
aspX = 1;
aspY = 1;
file_display_area = null;
}
function imageUpload(dropbox) {
var file = $("#fileInput").get(0).files[0];
//var file = document.getElementById('fileInput').files[0];
var imageType = /image.*/;
if (file.type.match(imageType)) {
var reader = new FileReader();
reader.onload = function (e) {
// Clear the current image.
$('#photo').remove();
// Create a new image with image crop functionality
current_image = new Image();
current_image.src = reader.result;
current_image.id = "photo";
current_image.style['maxWidth'] = image_dimension_x + 'px';
current_image.style['maxHeight'] = image_dimension_y + 'px';
current_image.onload = function () {
// Calculate scaled image dimensions
if (current_image.width > image_dimension_x || current_image.height > image_dimension_y) {
if (current_image.width > current_image.height) {
scaled_width = image_dimension_x;
scaled_height = image_dimension_x * current_image.height / current_image.width;
}
if (current_image.width < current_image.height) {
scaled_height = image_dimension_y;
scaled_width = image_dimension_y * current_image.width / current_image.height;
}
if (current_image.width == current_image.height) {
scaled_width = image_dimension_x;
scaled_height = image_dimension_y;
}
}
else {
scaled_width = current_image.width;
scaled_height = current_image.height;
}
// Position the modal div to the center of the screen
$('#modal').css('display', 'block');
var window_width = $(window).width() / 2 - scaled_width / 2 + "px";
var window_height = $(window).height() / 2 - scaled_height / 2 + "px";
// Show image in modal view
$("#preview").css("top", window_height);
$("#preview").css("left", window_width);
$('#preview').show(500);
// Calculate selection rect
var selection_width = 0;
var selection_height = 0;
var max_x = Math.floor(scaled_height * aspX / aspY);
var max_y = Math.floor(scaled_width * aspY / aspX);
if (max_x > scaled_width) {
selection_width = scaled_width;
selection_height = max_y;
}
else {
selection_width = max_x;
selection_height = scaled_height;
}
ias = $(this).Jcrop({
onSelect: showCoords,
onChange: showCoords,
bgColor: '#747474',
bgOpacity: .4,
aspectRatio: aspX / aspY,
setSelect: [0, 0, selection_width, selection_height]
}, function () {
jcrop_api = this;
});
};
// Add image to dropbox element
dropbox.appendChild(current_image);
};
reader.readAsDataURL(file);
} else {
dropbox.innerHTML = "File not supported!";
}
}
function showCoords(c) {
x1 = c.x;
y1 = c.y;
x2 = c.x2;
y2 = c.y2;
}
function preview() {
// Set canvas
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// Delete previous image on canvas
context.clearRect(0, 0, canvas.width, canvas.height);
// Set selection width and height
var sw = x2 - x1;
var sh = y2 - y1;
// Set image original width and height
var imgWidth = current_image.naturalWidth;
var imgHeight = current_image.naturalHeight;
// Set selection koeficient
var kw = imgWidth / $("#preview").width();
var kh = imgHeight / $("#preview").height();
// Set canvas width and height and draw selection on it
canvas.width = aspX;
canvas.height = aspY;
context.drawImage(current_image,(x1 * kw),(y1 * kh),(sw * kw),(sh * kh), 0, 0, aspX, aspY);
// Convert canvas image to normal img
var dataUrl = canvas.toDataURL();
var imageFoo = document.createElement('img');
imageFoo.src = dataUrl;
// Append it to the body element
$('#preview').delay(100).hide();
$('#modal').hide();
file_display_area.html('');
file_display_area.append(imageFoo);
}
$(window).resize(function () {
// Position the modal div to the center of the screen
var window_width = $(window).width() / 2 - scaled_width / 2 + "px";
var window_height = $(window).height() / 2 - scaled_height / 2 + "px";
// Show image in modal view
$("#preview").css("top", window_height);
$("#preview").css("left", window_width);
});
};
}(jQuery));
I need to clean my code up but this is what I changed to make this work:
this.on('click', function () {
aspX = $(this).width();
aspY = $(this).height();
file_display_area = $(this);
$('#fileInput').click();
});
to
$('body').on('click', '.cropme', function () {
aspX = $(this).width();
aspY = $(this).height();
file_display_area = $(this);
$('#fileInput').click();
});
I'm trying to make each rectangle in this fiddle to move up and down so it looks like a music equalizer. I wants the bars to animate up and down, and have absolutely no idea how to do animations. Fiddles would really help :)
http://jsfiddle.net/kiransh/1jqhznt6/
HTML
<canvas id="myCanvas" height="100"> </canvas>
JavaScript
var width = 8;
var distance = 3;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.canvas.width = window.innerWidth;
var total = ctx.canvas.width;
var max = total/2+52;
var min = total/2-60;
ctx.fillStyle = "black";
ctx.globalAlpha=0.3;
for(var x = 0; x<total; x+=12)
{
if(x<= max && x>=min)
{
var height= Math.floor(Math.random()*40)+5;
}
else
{
var height= Math.floor(Math.random()*100)+5;
}
ctx.fillRect(x,100-height,width,height);
}
I don't know if this is the effect you need, but it should help you to start.
requestAnimationFrame is used to execute draw() at each frame. Each bar is re-defined after the specified delay, and then goes down.
var width = 8;
var distance = 3;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.canvas.width = window.innerWidth;
var total = ctx.canvas.width;
var max = total/2+52;
var min = total/2-60;
ctx.fillStyle = "black";
ctx.globalAlpha=0.3;
var bars = [];
var barsCount = Math.floor(total / 12);
var barsLastRefreshTime = null;
var barsRefreshInterval = 500;
setInterval(function() {
for(var i = 0; i<barsCount; i++) {
var x = i * 12;
if(x<= max && x>=min) {
var height= Math.floor(Math.random()*40)+5;
} else {
var height= Math.floor(Math.random()*100)+5;
}
bars[i] = height;
}
barsLastRefreshTime = (new Date()).getTime();
}, barsRefreshInterval);
function draw() {
var currentTime = (new Date()).getTime();
var timePassedRate = (barsRefreshInterval - (currentTime - barsLastRefreshTime)) / barsRefreshInterval;
ctx.clearRect(0,0,c.width,c.height);
for(var i = 0; i<bars.length; i++) {
var x = i * 12;
var height = bars[i] * timePassedRate;
ctx.fillRect(x,100-height,width,height);
}
requestAnimationFrame(draw);
}
draw();
(I can't find a way to save the fiddle ?!?)
You need to use a tick function to update your canvas. You can use requestAnimationFrame() and choose a time interval you'd like to animate on (you can determine this using Date.now()).
Then, keep a list of your bars and change their height. Then re-render it to your canvas.
Here is some quick hacky code...
var width = 8;
var distance = 3;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.canvas.width = window.innerWidth;
var total = ctx.canvas.width;
var max = total / 2 + 52;
var min = total / 2 - 60;
ctx.fillStyle = "black";
ctx.globalAlpha = 0.3;
var lastDrawTime = Date.now();
var draw = function () {
if (Date.now() - lastDrawTime < 60) {
return webkitRequestAnimationFrame(draw);
}
ctx.clearRect(0, 0, c.width, c.height);
for (var x = 0; x < total; x += 12) {
if (x <= max && x >= min) {
var height = Math.floor(Math.random() * 40) + 5;
} else {
var height = Math.floor(Math.random() * 100) + 5;
}
ctx.fillRect(x, 100 - height, width, height);
}
lastDrawTime = Date.now();
webkitRequestAnimationFrame(draw);
};
draw();
To do animation you have to clear the canvas and redraw the rectangles in their new position at each frame, using either setInterval() or setTimeout() or requestAnimationFrame().
The best is to use requestAnimationFrame() for adapation of frames per second.