Dear I have small html5 canvas project that getting example from codepen to drag&drop image using html5 canvas. Example work fine, but I have problem once new image placed, then all of them are overlap in image area. Below is javascript code
<script>
var imgW;
function drawImg() {
var x = document.getElementById('myCanvas');
var canvax = x.getContext('2d');
var imgElement = document.getElementById('imgCanvas');
var imgObj = new Image();
imgObj.src = imgElement.src;
var imgW = imgObj.width;
var imgH = imgObj.height;
var imgX = canvax.canvas.width * .5 - imgW * .5;
var imgY = canvax.canvas.height * .5 - imgH * .5;
imgObj.onload = function () {
canvax.clearRect(imgX, imgY, imgW, imgH);
canvax.drawImage(imgObj, imgX, imgY, imgW, imgH);
};
}
$(document).ready(function () {
$('.listImg li').draggable({ containment: 'document', opacity: 0.60, revert: false, helper: 'clone',
start: function () {
$('.infoDrag').text('Start Drag');
},
drag: function () {
$('.infoDrag').text('on Dragging');
},
stop: function () {
$('.infoDrag').text('Stop Dragging');
} });
$('#myCanvas').droppable({ hoverClass: 'dashborder', tolerance: 'pointer',
drop: function (ev, ui) {
var droppedItem = $(ui.draggable).clone();
var canvasImg = $(this).find('img');
var newSrc = droppedItem.find('img').attr('src');
canvasImg.attr("src", newSrc);
drawImg();
} });
$('#myCanvas').dblclick(function () {
$('#myCanvas').draggable();
});
});
</script>
My need is to clear image before place new image. I may need to use clearRect method. But since tried several but not work. Any advise or guidance would be greatly appreciated, Thanks.
Instead of using the size and position of a (newly) loaded image as the bounding rectangle you feed to clearRect() use the size of the canvas itself.
Simply change
canvax.clearRect(imgX, imgY, imgW, imgH);
to
canvax.clearRect(0, 0, x.width, x.height);
Related
I am using PDF.js to show PDF in browser. PDF.js uses canvas to render PDF. I have js scripts that draws the lines on the canvas when user double clicks on the canvas. It also adds X check mark to remove the already drawn line.
based on my research i cannot simply just remove the line from the canvas because underneath pixels are gone when you draw something on it. To get it working i have to store lines and then clear canvas and re-load canvas and re-draw lines
Issue
I am not able to store canvas and restore canvas. When i click on X i was able to get lines re-drawn but canvas does not get restored. Canvas remains blank
Run the demo in full page
$(function () {
var $canvas = $("#myCanvas");
var canvasEl = $canvas.get(0);
var ctx = canvasEl.getContext("2d");
var lines = [];
var backupCanvas = document.createElement("canvas");
var loadingTask = pdfjsLib.getDocument('https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf');
loadingTask.promise.then(function (doc) {
console.log("This file has " + doc._pdfInfo.numPages + " pages");
doc.getPage(1).then(page => {
var scale = 1;
var viewPort = page.getViewport(scale);
canvasEl.width = viewPort.width;
canvasEl.height = viewPort.height;
canvasEl.style.width = "100%";
canvasEl.style.height = "100%";
var wrapper = document.getElementById("wrapperDiv");
wrapper.style.width = Math.floor(viewPort.width / scale) + 'px';
wrapper.style.height = Math.floor(viewPort.height / scale) + 'px';
page.render({
canvasContext: ctx,
viewport: viewPort
});
storeCanvas();
});
});
function storeCanvas() {
backupCanvas.width = canvasEl.width;
backupCanvas.height = canvasEl.height;
backupCanvas.ctx = backupCanvas.getContext("2d");
backupCanvas.ctx.drawImage(canvasEl, 0, 0);
}
function restoreCanvas() {
ctx.drawImage(backupCanvas, 0, 0);
}
$canvas.dblclick(function (e) {
var mousePos = getMousePos(canvasEl, e);
var line = { startX: 0, startY: mousePos.Y, endX: canvasEl.width, endY: mousePos.Y, pageY: e.pageY };
lines.push(line);
drawLine(line, lines.length - 1);
});
function drawLine(line, index) {
// draw line
ctx.beginPath();
ctx.strokeStyle = '#df4b26';
ctx.moveTo(line.startX, line.startY);
ctx.lineTo(line.endX, line.endY);
ctx.closePath();
ctx.stroke();
// add remove mark
var top = line.pageY;
var left = canvasEl.width + 20;
var $a = $("<a href='#' class='w-remove-line'>")
.data("line-index", index)
.attr("style", "line-height:0")
.css({ top: top, left: left, position: 'absolute' })
.html("x")
.click(function () {
var index = $(this).data("line-index");
$(".w-remove-line").remove();
ctx.clearRect(0, 0, canvasEl.width, canvasEl.height);
// restore canvas
restoreCanvas();
lines.splice(index, 1);
for (var i = 0; i < lines.length; i++) {
drawLine(lines[i], i);
}
});
$("body").append($a);
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
X: Math.floor(evt.clientX - rect.left),
Y: Math.floor(evt.clientY - rect.top),
};
}
});
canvas {
border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.2.228/pdf.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<b> Double Click on PDF to draw line and then click on X to remove lines</b>
<div id="wrapperDiv">
<canvas id="myCanvas"></canvas>
</div>
The PDF.js render() function is async so you need to store the canvas after the render has finished. Your code is firing storeCanvas() too early and storing a blank canvas. Easy fix, render() returns a promise so ...
page.render({
canvasContext: ctx,
viewport: viewPort
}).then( () => {
storeCanvas();
});
https://jsfiddle.net/fyLant01/1/
Reference: from https://github.com/mozilla/pdf.js/blob/master/src/display/api.js#L998
/**
* Begins the process of rendering a page to the desired context.
* #param {RenderParameters} params Page render parameters.
* #return {RenderTask} An object that contains the promise, which
* is resolved when the page finishes rendering.
*/
i try to build an image uploader for my app. So i need to resize the images.
But often i got the false width value in the img tag.
Not every time. But sometimes when i load the picture 3 times or sometimes if i change the picture then there is the old width in. But also not everytime.
$(document).on('pageshow', '#profil', function () {
$('#content').height(getRealContentHeight());
var max_height = getRealContentHeight();
var max_width = $(window).width();
var username = getUrlParameter('user');
var data;
var x, y, w, h;
var preview;
var reader;
var pic = document.getElementById('pic');
var jcrop_api;
$('#upload').bind("change", function () {
preview = new Image();
var file = document.querySelector('input[type=file]').files[0];
reader = new FileReader();
reader.onloadend = function () {
if (jcrop_api) {
jcrop_api.setImage(reader.result);
}
preview.src = reader.result;
document.getElementById('pic').src = preview.src;
alert(pic.height); //there is the false value...sometimes....
alert(pic.width);
var size = calculateAspectRatioFit(pic.width, pic.height, max_width, max_height);
alert("heigth:" + size.height);
alert("width:" + size.width);
// document.getElementById('pic').height = size.height;
// document.getElementById('pic').width = size.width;
jQuery(function ($) {
$('#pic').Jcrop({
aspectRatio: 1,
minSize: [50, 50],
maxSize: [300, 300],
onChange: showCoords,
onSelect: showCoords
}, function () {
jcrop_api = this;
});
});
function showCoords(c) {
x = c.x;
y = c.y;
w = c.w;
h = c.h;
};
function calculateAspectRatioFit(srcWidth, srcHeight, maxWidth, maxHeight) {
var ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
return {width: srcWidth * ratio, height: srcHeight * ratio};
}
};
if (file) {
reader.readAsDataURL(file);
} else {
preview.src = "";
}
});
$('#continue').bind("click", function () {
//ajax upload
});
});
Could be one of two issues:
1) Are you setting your '#pic' element's height or width dimensions in css or inline? You may be getting the element's dimensions, not the image's.
2) You are setting 'src' on this img but not waiting until the image has been loaded. You might try:
$("#pic").on("load", function() {
//get dimensions now
});
Do you have to display the image at all? Otherwise you can load it in js using:
var img = new Image();
Then use the jQuery load event handler on this as above. Then set:
img.src = 'image url';
Can you try the following:
$("#pic").height();
$("#pic").width();
$("#pic").outerHeight();
$("#pic").outerWidth();
Instead of:
pic.height
pic.width
And see the right one that suits?
I have this code
<canvas id="Con1" width="500" height="500"></canvas>
<script type="text/javascript">
var Rxt = document.getElementById('Con1').getContext('2d');
Rxt.fillStyle = 'green';
Rxt.fillRect(0, 0, 2000, 2000);
Rxt.rotate(.2);
var Img = document.createElement('img');
Img.src = 'images/009-Invoice1-A4-SET-PAD.png';
Img.onload = function () {
Rxt.drawImage(Img, 50, 0, 200, 200);
}
var down = false;
Rxt.canvas.addEventListener('mousedown', function () {
down = true;
}, false);
Rxt.canvas.addEventListener('mouseup', function () {
down = false;
}, false);
Rxt.canvas.addEventListener('mousemove', function (event) {
if (down) {
Rxt.translate(0, -50);
Rxt.drawImage(Img, event.clientX - this.offsetLeft,
event.clientY - this.offsetTop, 100, 100);
Rxt.translate(0, 50);
}
}, false);
</script>
I've tried this and I'm adding an image on the canvas and dragging it. It works but the image is dragging continuously and it prints duplicate images but the output should be smooth. I also want to add a label to that image and have it moveable.
You need to clear the canvas each time you want to draw something and redraw everything.
I'd also suggest that you look up canvas context .restore() and .save() as they are very useful when dealing with canvas transformations
As for the label you'd probably have to use the fillText or stokeText methods
See if this helps at all
http://pastebin.com/kuaTbuhW
I am placing an image on the canvas using drap & drop but the problem is, after dropping the image on canvas, image is loosing it's original position where it is dropped.
Sometimes it comes down from the original position and sometimes moves to right. Here is the code:
$("#draggable1").draggable({
stop: function(event, ui)
{
var canv = document.getElementById("tools_sketch");
var rect = canv.getBoundingClientRect();
x = event.clientX - rect.left;
y = event.clientY - rect.top;
ans = confirm("Is it correct position?");
if (ans)
{
dropimg_over_ground("img1", x, y);
$('#draggable1').remove();
}
}
});
dropimg_over_ground = function(imgid, lefti, topi)
{
var c = document.getElementById("tools_sketch");
var ctx = c.getContext("2d");
var img = document.getElementById(imgid);
ctx.drawImage(img, lefti, topi);
}
I have searched forum alot and tried many solutions but it's not worked.
Just subtract the offset of the container:
$('#drag').draggable({
stop: function(e, ui){
console.log('drag');
console.log($(this).offset().top - $('#canvas').offset().top)
console.log($(this).offset().left - $('#canvas').offset().left)
}
});
$("#canvas").droppable({
accept: "#drag",
drop: function (event, ui) {
},
out: function (event, ui) {
console.log('dragged out');
}
});
Working example,
http://jsfiddle.net/kBM6u/6/
check the console for the results
Regards
I use the Jquery Jcrop for cropping my images. Now I'm implementing a slider for resizing the image. I want the cropping and resizing to happend on the same page.
I do it like this:
$(document).ready(function() {
var img = $('#cropbox')[0]; // Get my img elem
var orgwidth, orgheight;
$("<img/>") // Make in memory copy of image to avoid css issues
.attr("src", $(img).attr("src"))
.load(function() {
orgwidth = this.width; // Note: $(this).width() will not
orgheight = this.height; // work for in memory images.
});
$('#cropbox').Jcrop({
onSelect: updateCoords
});
$("#imageslider").slider({
value: 100,
max: 100,
min: 1,
slide: function(event, ui) {
//$('ul#grid li').css('font-size',ui.value+"px");
resizeImage(orgwidth, orgheight);
}
});
});
And my simple resizeImage function:
function resizeImage(orgwidth, orgheight) {
var value = $('#imageslider').slider('option', 'value');
var width = orgwidth * (value / 100);
var height = orgheight * (value / 100);
$('#cropbox').width(width);
$('#cropbox').height(height);
$('#tester').val("org: "+orgwidth+" now: "+width);
}
The problem is that, as soon I turn on Jcrop I can't resize the image. How can I use both these functions at the same time?
I ended up destroying the jCrop while resizing and putting it back on after resize. Thanks anyway. Code:
function resizeImage(orgwidth, orgheight) {
jcrop_api.destroy();
var value = $('#imageslider').slider('option', 'value');
var width = orgwidth * (value / 100);
var height = orgheight * (value / 100);
$('#cropbox').width(width);
$('#cropbox').height(height);
$('#rw').val(width);
$('#rh').val(height);
initJcrop();
}
I had the same task to accomplish: resize the image with a slider where jCrop is applied. There are some more elements you have to resize also that jCrop created, not only the image. I ended up patching the jCrop plugin and here is the patch for latest jCrop-0.9.10.
Patch your jCrop. If you don't know how to apply the patch, just put the resizeImage function to line 1578 of jCrop (unimified version ofcourse):
--- /home/dr0bz/Desktop/jquery.Jcrop.js
+++ /home/dr0bz/workspace/profile_tuning/js/lib/jquery.Jcrop.js
## -1573,6 +1573,15 ##
ui: {
holder: $div,
selection: $sel
+ },
+
+ resizeImage: function(width, height) {
+ boundx = width;
+ boundy = height;
+ $([$img2, $img, $div, $trk]).each(function(index, element)
+ {
+ element.width(width).height(height);
+ });
}
};
Get the jCrop API:
var jCropApi;
$('#photo').Jcrop({}, function()
{
jCropApi = this;
});
Calc new height and width. If your are doing it with a slider, let the slider say return the new width of the image and you calculate new height with aspect ratio of the image:
var aspectRatio = width / height;
// newWidth returned by slider
var newHeight = Math.round(width / aspectRatio);
jCropApi.resizeImage(newWidth, newHeight);
There are some other points to keep an eye on. After each resize your should look that crop area is still in the viewport of the image. If you need i could post the complete source how i've done it for me: jCrop + jquery ui slider to resize the image.
Regards
What you can also do is make use of the setImage function of Jcrop, when the slider changes, call the setImage with the Jcrop api and set new width and height values like this:
var jcrop_api;
$('#cropbox').Jcrop({
onSelect: updateCoords
}, function() {
jcrop_api = this;
});
$("#imageslider").slider({
value: 100,
max: 100,
min: 1,
slide: function(event, ui) {
var value = $('#imageslider').slider('option', 'value');
var width = orgwidth * (value / 100);
var height = orgheight * (value / 100);
jcrop_api.setImage($(img).attr("src"), function() {
this.setOptions({
boxWidth: width,
boxHeight: height
});
});
$('#tester').val("org: "+orgwidth+" now: "+width);
}
});
What I am not sure about this technique is if it is the best solution because everytime you call the setImage function, jcrop creates a new Image object.
If what you want is that the resizing should be proportional, I don't think you need the slider (since it seems to be incompatible with jCrop). You could use jCrop and in the onChange event, ensure the proportionality (that is, implement the resizeImage function, modified).
That's what I think.
As an extension to Hermann Bier answer, i have added the jquery animation.
The resizing looks way better when it's animated :)
Implemented in Jcrop version: jquery.Jcrop.js v0.9.12
Locate the code:
ui: {
holder: $div,
selection: $sel
}
in jquery.Jcrop.js around line 1573
and replace it with:
ui: {
holder: $div,
selection: $sel
},
resizeImage: function(width, height) {
animationsTid = 500;
boundx = width;
boundy = height;
$($img2).animate({
width: width,
height: height,
}, { duration: animationsTid, queue: false });
$($img).animate({
width: width,
height: height,
}, { duration: animationsTid, queue: false });
$($div).animate({
width: width,
height: height,
}, { duration: animationsTid, queue: false });
$($trk).animate({
width: width,
height: height,
}, { duration: animationsTid, queue: false });
/*
//Old way of resizing, but without animation
$([$img2, $img, $div, $trk]).each(function(index, element){
element.width(width).height(height);
});
*/
}
Call to the function will animate the resize.
Feel free to delete the code between /* */ - I just kept it as an reference
Happy Coding :)