Draw multiple draggable circle HTML5 Canvas - javascript

I have to draw mutiple draggable circles on an HTML5 canvas, and also I should move the circles after creating it. But while dragging to draw there are multiple frames created. How can I remove it without reloading the page?
Here is a demo of my code:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var isDown = false;
function handleMouseDown(e) {
e.preventDefault();
// e.stopPropagation();
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
isDown = true;
}
function handleMouseUp(e) {
if (!isDown) {
return;
}
e.preventDefault();
// e.stopPropagation();
isDown = false;
}
function handleMouseOut(e) {
if (!isDown) {
return;
}
e.preventDefault();
//e.stopPropagation();
isDown = false;
}
function handleMouseMove(e) {
if (!isDown) {
return;
}
e.preventDefault();
//e.stopPropagation();
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
if (isDown) {
var dx = Math.abs(startX - mouseX);
var dy = Math.abs(startY - mouseY);
var midX = (startX + mouseX) / 2;
var midY = (startY + mouseY) / 2;
var r = Math.sqrt(dx * dx + dy * dy) / 2;
alert(midX, midY);
draw(midX, midY, r);
}
}
function draw(midX, midY, r) {
// ctx.save();
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(midX, midY, r, 0, 2 * Math.PI, false);
//ctx.restore();
//ctx.stroke();
ctx.fillStyle = getRandomColor();
ctx.fill();
}
function getRandomColor() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
$("#canvas").mousedown(function(e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function(e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function(e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function(e) {
handleMouseOut(e);
});
#canvas {
border: 1px solid blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h4>Drag to draw circles</h4>
<canvas id="canvas" width=600 height=400></canvas>
<button onclick="location.reload()">Reset</button>

You can clear the canvas without reloading the page by using ctx.clearRect() like so:
ctx.clearRect(0, 0, canvas.width, canvas.height);
Working Live Demo:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var isDown = false;
function handleMouseDown(e) {
e.preventDefault();
// e.stopPropagation();
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
isDown = true;
}
function handleMouseUp(e) {
if (!isDown) {
return;
}
e.preventDefault();
// e.stopPropagation();
isDown = false;
}
function handleMouseOut(e) {
if (!isDown) {
return;
}
e.preventDefault();
//e.stopPropagation();
isDown = false;
}
function handleMouseMove(e) {
if (!isDown) {
return;
}
e.preventDefault();
//e.stopPropagation();
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
if(isDown)
{
var dx = Math.abs(startX - mouseX);
var dy = Math.abs(startY - mouseY);
var midX = (startX + mouseX) / 2;
var midY = (startY + mouseY) / 2;
var r = Math.sqrt(dx * dx + dy * dy) / 2;
//alert(midX,midY);
draw(midX,midY,r);
}
}
function draw(midX,midY,r)
{
// ctx.save();
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(midX, midY, r, 0, 2 * Math.PI, false);
//ctx.restore();
//ctx.stroke();
ctx.fillStyle = getRandomColor();
ctx.fill();
}
function getRandomColor() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function (e) {
handleMouseOut(e);
});
document.getElementById("clear").onclick = function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
};
#canvas {
border:1px solid blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h4>Drag to draw circles</h4>
<canvas id="canvas" width=600 height=400></canvas>
<button id="clear">Reset</button>
JSFiddle Version: https://jsfiddle.net/j9y7fqyx/

Related

Get image data from canvas

I'm trying to add a signature feature to a web app. Users should have the possibility to sign with a pencil on a touch screen device. I'm using HTML5 canvas, JavaScript and PHP to get things done. I found a script for both mouse and touch support.
The drawing on the canvas works fine. When I submit the form, the scribble will get cropped properly (so it seems). But the generated base64-png data (saved in a database) is an empty image.
Here's the JS code I'm using:
var canvas, ctx;
var mouseX, mouseY, mouseDown = 0;
var touchX, touchY;
var lastX, lastY = -1;
canvas = document.getElementById('scribble-canvas');
ctx = canvas.getContext('2d');
canvas.addEventListener('mousedown', scribbleMouseDown, false);
canvas.addEventListener('mousemove', scribbleMouseMove, false);
canvas.addEventListener('mouseup', scribbleMouseUp, false);
canvas.addEventListener('touchstart', scribbleTouchStart, false);
canvas.addEventListener('touchend', scribbleTouchEnd, false);
canvas.addEventListener('touchmove', scribbleTouchMove, false);
function drawLine(ctx, x, y, size) {
if (lastX == -1) {
lastX = x;
lastY = y;
}
ctx.strokeStyle = "#000000";
ctx.lineCap = "round";
ctx.lineWidth = size;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(x, y);
ctx.stroke();
ctx.closePath();
lastX = x;
lastY = y;
}
function scribbleMouseDown() {
mouseDown = 1;
drawLine(ctx, mouseX, mouseY, 3);
}
function scribbleMouseUp() {
mouseDown = 0;
lastX = -1;
lastY = -1;
}
function scribbleMouseMove(e) {
getMousePos(e);
if (mouseDown == 1) {
drawLine(ctx, mouseX, mouseY, 3);
}
}
function getMousePos(e) {
if ( ! e) {
var e = event;
}
if (e.offsetX) {
mouseX = e.offsetX;
mouseY = e.offsetY;
}
else if (e.layerX) {
mouseX = e.layerX;
mouseY = e.layerY;
}
}
function scribbleTouchStart() {
getTouchPos();
drawLine(ctx, touchX, touchY, 3);
event.preventDefault();
}
function scribbleTouchEnd() {
lastX = -1;
lastY = -1;
}
function scribbleTouchMove(e) {
getTouchPos(e);
drawLine(ctx, touchX, touchY, 3);
event.preventDefault();
}
function getTouchPos(e) {
if ( ! e) {
var e = event;
}
if (e.touches) {
if (e.touches.length == 1) {
var touch = e.touches[0];
touchX = touch.pageX - touch.target.offsetLeft;
touchY = touch.pageY - touch.target.offsetTop;
}
}
}
function crop(canvas) {
var w = canvas.width, h = canvas.height;
var pix = {x:[], y:[]};
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var x, y, index;
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
index = (y * w + x) * 4;
if (imageData.data[index+3] > 0) {
pix.x.push(x);
pix.y.push(y);
}
}
}
pix.x.sort(function(a,b){return a-b});
pix.y.sort(function(a,b){return a-b});
var n = pix.x.length-1;
w = 1 + pix.x[n] - pix.x[0];
h = 1 + pix.y[n] - pix.y[0];
var cut = ctx.getImageData(pix.x[0], pix.y[0], w, h);
document.body.style.opacity = 0;
canvas.width = w;
canvas.height = h;
ctx.putImageData(cut, 0, 0);
return canvas.toDataURL();
}
On the PHP side I just pick the data returned by the crop() function and save it to the database.
What I tried so far is to strip off the touch support to see if it works just on mouse devices.
Additional code as suggested by user traktor:
The following jQuery code submits the form with the image data to the PHP script:
$(document).on('click', '#scribble-submit', function(e) {
e.preventDefault();
var btn = $(this);
var data = crop(document.querySelector('#scribble-canvas'));
$.post('/scribble/ax/ins_scribble', $('#form-scribble').serialize() + '&data=' + data, function(ans) {
window.location.href = '/' + btn.data('redirect');
});
});
The PHP part looks like this (using the CI3 framework):
$post = $this->input->post();
$this->db->where('id', $id);
$this->db->update('personen', ['signatur' => $post['data']]);
echo TRUE;
So far, jQuery and PHP works fine. The data is successfully inserted into the database. The LONGBLOB field contains this code:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMQAAAC3CAYAAABNEPEEAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAxKADAAQAAAABAAAAtwAAAAB1wSLaAAAYVElEQVR4Ae2dCZQeVZXHmyUhIYQ1gBAgHSDsCAxbWNPsO4ZBBBkwERxQcEARUUdQdJyj6DjA0VE2YdhBhs2ASAhDwo4gy4GwBmggILIZgbAKM79/893O7er1W r7arn3nH /W reu/ef71Xb63qhdpCssbAMhg0CowBoyuh4iaDYeAeUI0szcnt4P9AJ/gbGEiGer6dN5/EZoG7wGvgzyC3slBuLe9tuArRSGAFSjdsCWA3bmv0RcFsMFih4JRuWQVNUIGaC14E1YpsWA8sAp4DSmtxsGQlXKoSynbFy 48yrsY/VfwPHgDqLKsAN4G/wVuAJmWVlUIFYC9we5AN78TJAvpROJUcPp7IlpBVwFSQV8ebABCssvAFzDtwuya19aWZoVYGceXBWPBumAXoEKsp8Z4sBoYDkL6Z AFfnoJPANWAu B/h4Q/NSn2IMjrS6TunXLgTXAYC2bWtf/BTeCaeBNkClpZIVYGM9EyilAXYyRoFVPbBWieeDlSvgB4afAh2A2SLZGRPUrjewyfUQufwQq6OpGqIvhQxV4HVsou/MievipQowB6goqVHnYAWwC1HXycg4Hvwb3 8hW6/VWiHE4sBFYC6wH9gbqugxVHuDE50AnSBbSicQN1mVS/ipUtwEVNPVbld7HICQ7DKgFOQkcmzDpKY6fANcCVZDcip4AVwENnlRo 8M7/Canp4PbwXXgSLAlEEkh5WFgPK7uB84CyfKibuAIkEuZjNV3AjX/Scfs Ap U8uhZjQkGPAMqFulnoTGE1ZeFP4eHAByI8OxdEdwA/COSL8UfA3sDDT9GRIMDMbAlzlBPYdXgZUnTR5MApmX1bDw6 A YMYrVK0OCQbqYeBfuNiXKc1CfgNktku9Lcb9DmiGxgx/EP1woBmYkGCgHgZW5eKDgR6uVr7sYauylzlJGipjJ2XOyjAo7wzshAO QkifAZbKkmMrYoymxczQu9HXz5KBYUuhGNgcbzQbaeVNocYai4GWywpYcDzwgx7NHIUEA2kysB2JPwx8pTgqzQyHmrb6b96oY4Z6YZwXDNTJwIZc/9/Ayp/WuzYGLZVvk7sZpMW1kGCgmQzsQGZW/hQ ALQG1hLR2EEbsMygE1piRWRadgb2hYCbgZXDa9C1s7mpYmOHl8nVDFm7qRZEZsHAAga iGrlUOFdQFP TZPPkpM3IMYOTaM MuqDAe2BOg68BqxcXt/HealFaQOeZawZppBgIAsM3IQRVi470XdvllHaeWgZq3KEBANZYOAIjHgMWNl8E33dtA0bSwbqo1mm/5R2hpF MFAFAxtwru86nVjFtTWd2sFVflv3hJpSiYuCgfQYUCWwB7YqhypJKjKCVH8ILDNt6AsJBrLGgLpJ6i5ZOX0cXd2phss4UtR dMtIc8AhwUAWGdCAuhNYWU3l4a1MLIMP0UOCgSwzoKlXK6 z0dsbYezCLpFxTo/ZJUdGqJlkQBXi7Ypl sDFXo228uckaDXuB41OPNILBlJg4GjStDL7CnpHvXn4FkI7DE003xsSDGSdAbUSeoFNsjzYvEtrwJ/9ScO/97BOA9KMJIKBZjDwTTKxVkIPcr22ULdcQAqW6Bz0JetOMRIIBprDQAfZ GlYleW65QZSsApxed2pRQLBQHMZuJDsrPyqcnTUmr2NIfQtUZN7TYkwGMgJA2dipxboJKNBzWMJqxCjupL65M9sp4caDOSBAX2Y4FxnaAd6uzsesqoKIWjPuUnyo8MWH2EwkGUG1LPRxJBkT7BXl1bDHw2g/aBkzRrSiEuCgSwwcDRG2FiipnUJtQ6LAfW7TGz1z44jDAbywsD1GFr3uoS6S1arFNq4Ii8khJ3BgGeg7nUJLcJZhXjDpxx6MJBDBjqw2Q8BLqjWh824wCrEC9VeHOcHAxlkoOZ1CXWPRjiHooVwZISaWwZqXpdQhRjl3J7v9FCDgbwyUPO6hCrESOf1PKeHGgzkmYF7Mf7VigNVrUvoyxo2hrgizwyE7cFAgoGjObayPaR1CbUQi7tE3nJ6qMFA3hmoel1CFWI95/USTg81GMg7A504MNM5cRj6gO9LqEKs5S5YxumhBgNFYEBjCev5aM1t6kBOqUIs4k7QR8pCgoEiMTATZ6Y5h7ZHX90d91BVIea6GK 76FCDgVwzcB7W/6Xigb5G2V7RewVRIXpREhEFZGAGPs1yfv2D03uoqhAhwUAZGNBYwmRzU5JhVIgkI3FcVAbud47pA8n6RmwviQrRi5KIKCgDnfh1R8U3LTX0Of0aFaLCUASFZ0Af8j7feTkFfXV33KVGhUgyEsdFZkCb/p6qOLgN4cSks1EhkozEcZEZ0Jf93nEOHuz0LjUqRJKROC46A36tbZWks1EhkozEcdEZuMQ5OAq9x2xTVAjHTqilYOBuvLTZpjXRe8w2RYUoRRkIJx0DA842RYVwTIVaGgY02/RoxVvNNrVX9PgGkxERYakY0GzTI87j7r1N0UI4VkItFQN97m1atFQUhLP9MTCMH8aD5cFOYFMwHGiK8kWwNLA3K19H14tk hcK2kF6MXgF5E383qZJGL8z0K7YtpOBvYgtPaQcDCyOm uDq8AD4AVg5aCaUF/JUxp5k9Ux Elgvp4nB9RCjJVSEa9bXITFYGAcbuj at59QgW7EPoPXXNYtej6/cCz4Aygp wTIOsfzdZs05 AuJB0lX1VCL9a5/Wus JP7hnYEw9UYDVw7B489uPVXOJfA/pgnd5D1vGLoK8u03LEq4UZCSTt4CdSkGuA8sy6aE3ioIqRqgtdok91WLMxvRIXQb4ZaMd83egfAz2t7f72FX7A778Fa4BhoBoZw8lXgmS6HxOnSpH1r7hs72zXrFPX9wVOc5GXoofklwEVaG1Y0/9ISBZSHWsgfCc4BajCbAG6CgFhraJCr0H4t8CzwOer CyLXhTy9nZV4CNdpD4SG5IvBlbFXBVutfR6ynUCf5NNP4P47UDa8iwZWJ6qJFkWzZaZrQq7hgxfcJEXZ9n6sK0HA q7bwZ CvxN9fq5/PZ5oL5 s0SVwGx4tlmZ1piPxg1/cfZ2faPssy7i6hoTjsuax8DWZHU4 BV4Gljh8 HpxGsdoRWibpK35QaONT7JqszBMLNXXci2vV3EDEWEZJKBXbHqIvAUsBvow07irwN7ALUerRL1w/Vg1cDa7JvSKmOGkK/GVGZnh87fwUXcoYiQTDGwJdZ8GWhl1W5cMtw9UxZ/Ysx9zl5V1G0yaKNM gMwPicrYisX8YgiQjLBwCismATUKtgNs3AucRo77AtGgCyKCtczwNush2/W5BIMMhsPkXEbuQj1SUNay4BmjfTE/wl4EtjNsvA84nTP8iC7YKTZrVAzYVkTde/Mxp/JuHVcxOuKCGkZA0uS8zRgN8jCF4g7FaiA5Um0m3o6MD86M2i8xs1mn7p2bXoiWcQ76K0ckMmesoq6GBrgfQTsfliobm1eZR8MNz8Ufh10LYBlxCHNgpl90ttWcBH6YVlFhjSNgeHktCPwN0b3Qa3CEWApkGdR4VclsEKnUJUkK3I2hpht0rtqq0UonKDIkKYwsBq5qLD4GRndA3UziiadOGTlrKtrkhEHT3Z2nayVuvfBa2AMkGh2IyR9BnYli68CrRvoPkgeAr8AN qgYDIbf8ZVfFKvJJOiQc H4BVn3XJODzUdBjpI9iSgroNVBtS2Y8FvgKZViyb JSK1FN7vzPiqCiF57pOg669mOkLSY0CV4HSwrcviHvQNwCwXVzT1fueQtki0u PMqFYh3nUWre30UBvHgHidWsGnXbKa9lO8uhRFlkdx7lnnoNZZMifWbPmp1sHeqsqcEzkxaE/s/M ErcdxrPWFMojGqk A8RVnMzlWtQrxV3dHbHDtokKtg4GjufYzQAugXjTDpKnVMom6hrtXHJaeObEu00xn2YpOD7U Bjbi8ilAK8xaAJVoilWLcGWrDPI982ItxO3O0rXQlwevurhQq2NgLKerVdgfbOwu1bTq5u64bOpE57DXXXRrVasQWof4G1gKKG40iAoBCTWI1he AtQ1GFG5/i3CO8FFleOyBppuNfG6xbUiXNpl6vUeW3W3dCeFOjQG1LIeCNQ31s322I/jkLa20yDBeJGeBfGbD6dbCyHDngc2A6CWIqQ6Bk7ldM0kedF44Shwr48ssd7ufPe6i266Osrl IENqhX3uvtBY4iQoTGgbQjXgj0Sp1/G8aEgKsMCYnw3yesLzmi Nt9lOc23EC 7H2LHqyNjEFUVYV93zlPo3wVXuLhQP2Gg0xHhdRfdVFU9IesVKeMHfYXQwNok1iKMiYFDDZy1J8lETxuNJUJ6M6CWdH0Xva7TW6VuRsafcpnP6a/LJONDBmZAlUErz2u402Y5PdSeDGzPoX/jz28X6nlm845UKZeoZKdurx82dH3QymYAfts8m3KZk/Yi3QKML4UvAb9hj8OQCgPthNrLZHy9U4lvZaClhQucTV9KGqO sBl8R/LHOO5mQC3DzcC4Uvg08N0BDkMcA1PRPV/a09RqaceAj4DZ1WsPn/pT9uNj6CG9GeirZRBXURl6c VjpnJgZUthFl6A6nA2aeG0S/yg k2LJFS/WH2rt11c2VVVBn0YusMRcSv63qCbUPdbqAsYmIn6S7AmeA9cD1otKzoD7nJ6t6pla1 LN n JRSNDW5J8BMtQ77LxQnufp5prvhZJrUGfuywkp1U8nAM/h8LOhwPP0ffAsx2caHmiwFtvzfR2lGfog1o1kpc3ecZ5YucgsvzHC Po2uGIiTfDFyD VbWu/ea RZC7vnV6lXy7W9DrF GVDR3rhVNyYNA8 kxZhAb RXdTz8RoinzPmU7Yq3WaGpMBaKsohXnE8EzwDjZtaxkFMzvg/FHg3u7r8v155/2dWi2yU70 zz6u6ao8Qc6HsTHd4C1FEX1uSx XYGjVsbvH8zpOe5kza6UUdQS3AOMtBllJKGgPm NXxpE2709ZzA/f 9OnjzYyQX8Xa3A5Y4DEXdAAf0sq0uHu3s7F30jT0RyUK3f/MB6ZX9ySXS1Djs4Xy9DVxMbkn8GRuLCps6NS9AfcsdtfVUI1RoTvzXW4ooeamJh YqTWmf4YdEdLpF/mlnazfl7u9O71L4qxEvupLK1EIfi 1bOf1UGrUiH5J BVXHhc2B158p0p/er7s8vNuAo02ByS/x 0vmu5tSvZnIYkmMGOrDdyrVC7VoekkzkLLvwYfSFhnRV/k/Sa5/m98f5dyc8SDDg9y7dmfit 7CvLtMb3b9 8kVq60 76MKpG PRPs4rVY6Q4jAwDFe2du5c5fRB1VGcMQ/Y0/KQQa/I9wmbYP6vwPvAfB6Xb5fC gQDB3Ps1x56TLUmzu3z8FZirXCoL11kOQznzNe30PcqsrMl9K0dn/3a2ukca/q1Kjmbs62QdKKvV9XV Tl5V0y9D5ivg65a5se1sLTCwEHu/uo D6 FGS1M6evUVlA U0siGb9mEey7yPkoX/fIuM1hXvUM/JhLrByfW/3lC644yyX07wuiC6N14MnTwMg6vzCehSPGgD4tql3bdo8/bz/UEv6zS6jPd05rSTRD13zV deJvmGGbAtT6mdAuyyuBFYZFGqlumZRAbHE5qNrwa4osjKOqEUw/75fFMfCj24GjkDTa9F2j8/s/qVGZTTXneISvBl9yRrTytplGhNpRsnI2ilrBoY9dTGg7Rm/A3Z//4S Tl0pVi5em/AjYAkf24hEW5yGFuEudz5d2mJ7IvvGMrAFyWlq9TVg5XbbRmah2mUJX93IhFuUlgZW5s/z6EWdUm4RvS3P9hh3fz9E/yIY8lTrwkMw/0V3zopOz6O6GEZrE5/JdJRH7SDC3DOgWaWdnRdaVzoPfODi6la/TQr2RM37VuhN8eVx58/n6mYnEsgKA7q3GudaWdWAelIaxq3rMnkHfZ80MmlCmuPJ4z AEaZwiSbkG1mkz4Ame74H/L3VTGIqsgypPgAss0tSySX9RHdzPsiXIe HT9 0yKFOBrT/zG/eU VIVfzepvfI6degPdUcG5/490nSKrWa1pBiMKAey03A7q1CLcqlKpq2ehn4TKemmmNjE1 J5PwT5KjGJh ptZCBU8nbyuW96NrO3xS5llwsY4VTm5JrYzLRCyF6C87sb29MspFKCxlYjby1/eZ YPdVq9N1yaJVXD2Nc1WoRgI9bWeCPMg4jNwMLFQx9jLCzooeQX4Z0H/8 YUz/1z0Ge441H4Y2Jd4e4IoDMk/A/ IC3cBu695Xw5o6h053hF3aVNzjszSYEAtwyxglUHhoWlkVMQ0tRKvptTI 1oRnSyRT1vj62nufuq XlEi/ t2dQIpPAmsQvhl/boTjwSaysD25HY9sHup8BbQ0I17pFdo0e7cvwMjcVShvS2uc7vg2lnuPup /gwMAyFDZGAc52le2irDkUO8Lk7LFgPasPcwsPuo8ERgs4aoIUNhIGaXhsJSts ZjHnJD0EclG2Ts2tdzC5l994MxbIDOEmbSX3LoC5wqlLNwlyqhjQ4cc0u Rd/7mlw pFcegy0k7QGylpr0CKwibZ3a1U6pAYGYnapBtIycslh2OFbBemKC6mDgZhdqoO8Fl2q926 Am4EvkKMaZE9hcl2HJ7E7FL bucxmOwrwlscxxuNDbiP30wQ24AkI4kUGdBWDN2z24BViD nmF/pkvbb1GMQlv3brzUFqwgKHwJae2iJFHGWabRjcq7TQ80WA9tgzm5gb2fWneiKD2kgA38gLXvi/FsD042kGsfAMiTlv5Ch 3UdmNS4LCIlY8BXCD2BQrLDgGaMpoD7wEfAHlyXo4ekxMCjpGtEb5FSHpFs9QxswCX/CjRgtvuj8C6gRbeQFBhYnTT9xxBWTSGPSLI6Btbi9APBOcBXBOnqJoWkyMBE0jbS9f73kinmFUkPzoDGCslZJN2fS8GuYGkQkiIDU0jbKsQdKeYTSQ/MgI0VLua0Z4DdE4XHAb9HicOQtBjQrJKR/6O0Mol0B2Sgv7HCDK7SDtaQJjGgt6f B1iF0G7JkOYxMNBY4TvNMyNyMgaWRXkdWIXQloCQ5jAQY4Xm8FxVLnr/wSqDQrUYIekyEGOFdPmtK/WtuNoqxJy6UoqLh8KAvp6uLuo8YLwrjLECJGRB9P6t3RjtiQlpPAPDSVLTpSeA5Iv/4j73Y4Uibe6bwA0xedWUCBvGwIaktCOYCjYGXh7k4Fvgjz4y9NYycD3ZWwtxa2tNKUzuvkW40vFrPCs8G6xTFI L1EL4QfR7RblBLfRjoBZhJnZp28Ud4G5QGClShdCmvl0qd0Z6SPUMqEXoAOoSbQn6WsuZSvxVQK94Fk6KVCHmubvjdRcd6gAMlLJFSPJRpAqR9C2OB2dALYK dLETGAc DZIylYjCtghJZ6NCJBkpz7G1CHrBf2zC7ZkcF3KMkPCz12FUiF6UFDqi9GOEwe5uVIjBGCrO79YiTMUlDZq9aGV/NpgGzvc/lE0vUoXwzb7Xy3ZPvb/RIng2hqAXqUKs4vz1uosulTpQizATJko5RhisBBSpQnzgnF3C6WVSo0Uo090exNeT N22FOjbrmWTvXD4YvAcMB4svIW4bwC9cx5SEgb0yRkrAE g64WhIov82wR8CfwSPA3Mfx9OIX40CCkZA PxV3uYrDAkZ1KKQoe6RRoffA94f81vhZo1ihYBEsouj0CAFYxb0IvSRdDndLSafBTQf N8CpifPpxP/BlgfRASDLRdDQf6HpMVklkF4GQPfDgdvOT8Mv8UaszwU6AxxBogJBjowYAqgRUYVY77wOQeZ2T3YASm6eMIGhfo/Y6HgMZD5k8yPIDfQoKBARlQN0mVwrcUz3CsreELgyyKFhIPAb8BL4Bkwbfjm/jte0CtRnzsCxIaLQs1OsEMpXcDtuhFeC8zONCClLYpqOC9AV4FzRR9b3YloLfM1MVZE2wOVgOLgb5EXcHvgsf6 jHiGsdAkSuECtu2QN0K9a/7kueJfB10gjOB unqovhFPg5rFj3FVQGWA5uCbcCEik7QrzzOL 8C2SO7bgPxjgckpC1FrhDGnQrh5WCsRQwSvs3vmtNXRVEhHAPeB3oLr69CqXRXAZoO1bWqTCuApcDKQDNE/T35 amH/Iij88GcHrFx0DQGylAhROYOQPPyS4M3gQrwSkCFvRXydzLVgPn2SqgK CCQbSEtZKAsFaIvilUp1J05HuhJLi70HnEaMp9E9dRXq6MB/oUgvgwCCVmTMleI5L1Qt2Y0sO7Oiujq73eAYWCwLpOe hqsa5pXT3oV/rcqoSrEeyAk4wz8P tCAtne45WMAAAAAElFTkSuQmCC
Using this data as an image source for the img tag results in the empty image.
The problem is this jQuery line:
$.post('/scribble/ax/ins_scribble', $('#form-scribble').serialize() + '&data=' + data, function(ans) {
Combining the serialize function and an addition of &data= didn't work. So I changed it to:
$.post('/scribble/ax/ins_scribble', { data: data }, function(ans) {
You code runs fine:
var canvas, ctx;
var mouseX, mouseY, mouseDown = 0;
var touchX, touchY;
var lastX, lastY = -1;
canvas = document.getElementById('scribble-canvas');
ctx = canvas.getContext('2d');
canvas.addEventListener('mousedown', scribbleMouseDown, false);
canvas.addEventListener('mousemove', scribbleMouseMove, false);
canvas.addEventListener('mouseup', scribbleMouseUp, false);
canvas.addEventListener('touchstart', scribbleTouchStart, false);
canvas.addEventListener('touchend', scribbleTouchEnd, false);
canvas.addEventListener('touchmove', scribbleTouchMove, false);
function drawLine(ctx, x, y, size) {
if (lastX == -1) {
lastX = x;
lastY = y;
}
ctx.strokeStyle = "#000000";
ctx.lineCap = "round";
ctx.lineWidth = size;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(x, y);
ctx.stroke();
ctx.closePath();
lastX = x;
lastY = y;
}
function scribbleMouseDown() {
mouseDown = 1;
drawLine(ctx, mouseX, mouseY, 3);
}
function scribbleMouseUp() {
mouseDown = 0;
lastX = -1;
lastY = -1;
}
function scribbleMouseMove(e) {
getMousePos(e);
if (mouseDown == 1) {
drawLine(ctx, mouseX, mouseY, 3);
}
}
function getMousePos(e) {
if (!e) {
var e = event;
}
if (e.offsetX) {
mouseX = e.offsetX;
mouseY = e.offsetY;
} else if (e.layerX) {
mouseX = e.layerX;
mouseY = e.layerY;
}
}
function scribbleTouchStart() {
getTouchPos();
drawLine(ctx, touchX, touchY, 3);
event.preventDefault();
}
function scribbleTouchEnd() {
lastX = -1;
lastY = -1;
}
function scribbleTouchMove(e) {
getTouchPos(e);
drawLine(ctx, touchX, touchY, 3);
event.preventDefault();
}
function getTouchPos(e) {
if (!e) {
var e = event;
}
if (e.touches) {
if (e.touches.length == 1) {
var touch = e.touches[0];
touchX = touch.pageX - touch.target.offsetLeft;
touchY = touch.pageY - touch.target.offsetTop;
}
}
}
function crop(canvas) {
var w = canvas.width,
h = canvas.height;
var pix = {
x: [],
y: []
};
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var x, y, index;
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
index = (y * w + x) * 4;
if (imageData.data[index + 3] > 0) {
pix.x.push(x);
pix.y.push(y);
}
}
}
pix.x.sort(function(a, b) {
return a - b
});
pix.y.sort(function(a, b) {
return a - b
});
if (pix.x.length == 0) {
return '#';
}
var n = pix.x.length - 1;
w = 1 + pix.x[n] - pix.x[0];
h = 1 + pix.y[n] - pix.y[0];
var cut = ctx.getImageData(pix.x[0], pix.y[0], w, h);
//document.body.style.opacity = 0;
canvas.width = w;
canvas.height = h;
ctx.putImageData(cut, 0, 0);
return canvas.toDataURL();
}
document.getElementById('scribble-submit').addEventListener('click', function(e) {
e.preventDefault();
var data = crop(document.querySelector('#scribble-canvas'));
document.getElementById('scribble-result').setAttribute('src', data);
});
<html>
<body>
<canvas id="scribble-canvas" style="width:200; height:200; border: 1px solid blue;"></canvas>
<br>
<button id="scribble-submit">
Run
</button>
<br>
Output:
<br>
<img src="#" id="scribble-result" />
</body>
</html>
You either send the wrong data or use different data to render.
If you are saving into a .png file, you may want to strip out the initial data:image/png;base64, before turning that into bytes.

Issue when dragging text on canvas if slightly scrolled down

When I scroll slightly down on my canvas, it does not allow me to drag my text at all. Examples (These are GIFs) -
https://gyazo.com/e60d2efd924ced758c2c6441391804db
GIF explained: So you saw the drag was working when I was on top of the page but when I scrolled slightly down. It completely stopped working. I added a few console.logs around, and what I know is the click event listener for the canvas is working but it isn't detected the text when I slightly scroll down on the page.
I based my drag code from: http://jsfiddle.net/m1erickson/9xAGa/ | What you can see is if you change the canvas size width: 667 and height: 800, and when you scroll slightly down, you will have the same issue I am having.
HTML Code:
<div id="middle_container">
<div class="center_container">
<canvas id="canvas" width="667px" height="800px"></canvas>
</div>
</div>
JavaScript Code:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var $canvas = $("#canvas");
var BB=canvas.getBoundingClientRect();
var offsetX = BB.left;
var offsetY = BB.top;
var mx;
var my;
var texts = [];
var images = [];
var dragF = -1;
var mode = "none";
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for(const { text, x, y, width, height } of texts) {
ctx.fillText(text, x, y);
}
}
function addNewText(string_text) {
var y = texts.length * 20 + 20;
var text = {
text: string_text,
x: 20,
y: y
};
ctx.font = "32px verdana";
ctx.textBaseline = "top";
text.width = ctx.measureText(text.text).width;
text.height = 32;
texts.push(text);
draw();
}
function hitDrag(x,y,textIndex) {
var r=texts[textIndex];
return (x>r.x && x<r.x+r.width && y>r.y && y<r.y+r.height);
}
function myDrag(a,e) {
if (a == "down") {
e.preventDefault();
e.stopPropagation();
mx=parseInt(e.clientX-offsetX);
my=parseInt(e.clientY-offsetY);
for(var i=0;i<texts.length;i++){
if(hitDrag(mx,my,i)){
console.log("found");
dragF = i;
}
}
}
}
addNewText("Hello World")
$("#canvas").mousedown(function(e) {
myDrag("down", e);
});
The problem is this line of code:
var BB=canvas.getBoundingClientRect();
which is only populated once at the start of your script. The .getBoundingClientRect() method returns the position of a HTML element relative to the viewport.
Well if you scroll the window, the viewport moves - as the canvas element - but the BB object still holds the position of your canvas at startup.
The fix is rather simple - you need to use the actual position of the canvas element by calling .getBoundingClientRect() again on mouse down and on mouse move.
I've prepared a little sample based on your code and the fiddle you've linked:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var $canvas = $("#canvas");
var BB = canvas.getBoundingClientRect();
var offsetX = BB.left;
var offsetY = BB.top;
var mx;
var my;
var texts = [];
var images = [];
var dragF = -1;
var mode = "none";
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (const {
text,
x,
y,
width,
height
} of texts) {
ctx.fillText(text, x, y);
}
}
function addNewText(string_text) {
var y = texts.length * 20 + 20;
var text = {
text: string_text,
x: 20,
y: y
};
ctx.font = "32px verdana";
ctx.textBaseline = "top";
text.width = ctx.measureText(text.text).width;
text.height = 32;
texts.push(text);
draw();
}
function myDrag(a, e) {
if (a == "down") {
e.preventDefault();
e.stopPropagation();
let rect = canvas.getBoundingClientRect();
mx = parseInt(e.clientX - rect.left);
my = parseInt(e.clientY - rect.top);
for (var i = 0; i < texts.length; i++) {
if (hitDrag(mx, my, i)) {
// console.log("found");
dragF = i;
}
}
}
}
function hitDrag(x, y, textIndex) {
var r = texts[textIndex];
return (x > r.x && x < r.x + r.width && y > r.y && y < r.y + r.height);
}
function handleMouseMove(e) {
if (dragF < 0) {
return;
}
e.preventDefault();
let rect = canvas.getBoundingClientRect();
mouseX = parseInt(e.clientX - rect.left);
mouseY = parseInt(e.clientY - rect.top);
var dx = mouseX - mx;
var dy = mouseY - my;
mx = mouseX;
my = mouseY;
var text = texts[dragF];
text.x += dx;
text.y += dy;
draw();
}
function handleMouseUp(e) {
e.preventDefault();
dragF = -1;
}
addNewText("Hello World")
$("#canvas").mousedown(function(e) {
myDrag("down", e);
});
$("#canvas").mousemove(function(e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function(e) {
handleMouseUp(e);
});
body {
background-color: ivory;
}
#canvas {
border: 1px solid red;
}
#theText {
width: 10em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="middle_container">
<div class="center_container">
<canvas id="canvas" width="667px" height="800px"></canvas>
</div>
</div>
<br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br>

line and rectangle in canvas

I trying to create a canvas in which we can draw straight line and rectangle using mouse events in function of the selected input .
I attach a mousedown, mousemove, and mouseup event listener to the canvas DOM
and use the appropriate fuctions when the line input or rectangle input
is selected
but it draws nothing.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var storedLines = [];
var startX = 0;
var startY = 0;
var isDown;
var isDrawing = false;
ctx.strokeStyle = "orange";
ctx.lineWidth = 3;
function handleRecUp() {
isDrawing = false;
canvas.style.cursor = "default";
}
function handleRecMove(e) {
if (isDrawing) {
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.rect(startX, startY, mouseX - startX, mouseY - startY);
ctx.stroke();
}
}
function handleRecDown(e) {
canvas.style.cursor = "crosshair";
isDrawing = true
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
}
function handleMouseDown(e) {
e.preventDefault();
e.stopPropagation();
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
isDown = true;
startX = mouseX;
startY = mouseY;
}
function handleMouseMove(e) {
e.preventDefault();
e.stopPropagation();
if (!isDown) {
return;
}
redrawStoredLines();
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
// draw the current line
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(mouseX, mouseY);
ctx.stroke()
}
function handleMouseUp(e) {
e.preventDefault();
e.stopPropagation();
isDown = false;
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
storedLines.push({
x1: startX,
y1: startY,
x2: mouseX,
y2: mouseY
});
redrawStoredLines();
}
function handleMouseOut(e) {
e.preventDefault();
e.stopPropagation();
if(!isDown){return;}
isDown = false;
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
storedLines.push({
x1: startX,
y1: startY,
x2: mouseX,
y2: mouseY
});
redrawStoredLines();
}
function redrawStoredLines() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (storedLines.length == 0) {
return;
}
// redraw each stored line
for (var i = 0; i < storedLines.length; i++) {
ctx.beginPath();
ctx.moveTo(storedLines[i].x1, storedLines[i].y1);
ctx.lineTo(storedLines[i].x2, storedLines[i].y2);
ctx.stroke();
}
}
let l = document.getElementById("line");
let c = document.getElementById("clear");
let r = document.getElementById("rect");
if(l.checked === true)
{
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function (e) {
handleMouseOut(e);
});
}
if(c.checked === true)
{
storedLines.length = 0;
redrawStoredLines();
}
if(r.checked === true)
{
$("#canvas").on('mousedown', function (e) {
handleRecDown(e);
}).on('mouseup', function(e) {
handleRecUp();
}).on('mousemove', function(e) {
handleRecMove(e);
});
}
body {
background-color: ivory;
padding:10px;
}
canvas {
border:1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width=300 height=300></canvas><br/>
<div>
<input type="radio" name="shape" id="clear" value="clear" checked>Clear<br>
<input type="radio" name="shape" id="line" value="line">Line<br>
<input type="radio" name="shape" id="rect" value="rect">Rectangle<br>
</div>
Your if structure is only executed once, so when a user clicks on something, the changes are not recorded.
Try something like this:
$("input[type=radio]").on("change", handleRadioChanges);
function handleRadioChanges(event){
if (l.checked === true) {
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function (e) {
handleMouseOut(e);
});
}
if (c.checked === true) {
storedLines.length = 0;
redrawStoredLines();
}
if (r.checked === true) {
$("#canvas").on('mousedown', function (e) {
handleRecDown(e);
}).on('mouseup', function (e) {
handleRecUp();
}).on('mousemove', function (e) {
handleRecMove(e);
});
}
}
Complete Javascript sample with more bugfixes:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var storedLines = [];
var startX = 0;
var startY = 0;
var isDown;
var type = "line"; // current type
ctx.strokeStyle = "orange";
ctx.lineWidth = 3;
function handleMouseDown(e) {
e.preventDefault();
e.stopPropagation();
canvas.style.cursor = "crosshair";
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
isDown = true;
startX = mouseX;
startY = mouseY;
}
function handleMouseMove(e) {
e.preventDefault();
e.stopPropagation();
if (!isDown) return;
redrawStoredLines();
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
if(type == "rect"){
ctx.beginPath();
ctx.rect(startX, startY, mouseX - startX, mouseY - startY);
ctx.stroke();
}
if(type == "line"){
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(mouseX, mouseY);
ctx.stroke();
}
}
function handleMouseUp(e) {
canvas.style.cursor = "default";
e.preventDefault();
e.stopPropagation();
isDown = false;
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
storedLines.push({
type: type,
x1: startX,
y1: startY,
x2: mouseX,
y2: mouseY
});
redrawStoredLines();
}
function handleMouseOut(e) {
e.preventDefault();
e.stopPropagation();
if (!isDown) return;
isDown = false;
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
storedLines.push({
type: type,
x1: startX,
y1: startY,
x2: mouseX,
y2: mouseY
});
redrawStoredLines();
}
function redrawStoredLines() {
console.log(storedLines);
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (storedLines.length == 0) return;
// redraw each stored line
for (var i = 0; i < storedLines.length; i++) {
if(storedLines[i].type == "line"){
ctx.beginPath();
ctx.moveTo(storedLines[i].x1, storedLines[i].y1);
ctx.lineTo(storedLines[i].x2, storedLines[i].y2);
ctx.stroke();
}
if(storedLines[i].type == "rect"){
ctx.beginPath();
ctx.rect(storedLines[i].x1, storedLines[i].y1,
storedLines[i].x2 - storedLines[i].x1, storedLines[i].y2 - storedLines[i].y1);
ctx.stroke();
}
}
}
let l = document.getElementById("line");
let c = document.getElementById("clear");
let r = document.getElementById("rect");
$("input[type=radio]").on("change", handleRadioChanges);
function handleRadioChanges(event) {
if(l.checked){
type = "line";
}
if(r.checked){
type = "rect";
}
if (c.checked === true) {
storedLines.length = 0;
redrawStoredLines();
}
}
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
handleMouseUp(e);
});
Did you try fabric.js?
If not you should, very simple js library which works on canvas, you can draw rectangle, circle, line, traingle etc. with bulit in support for drag n drop, resize, rotate etc.
I created a sample for you, check here

Is it possible to drag an image within canvas as well as draw on the same canvas?

Here I'm trying to draw on a html5 canvas as well as upload some images and drag them within the canvas. The problem is I can do one or the other but not both.
What I've realised is that the canvas must be Cleared before dragging takes place but by doing that I'm clearing the drawing and if I don't clear the canvas it draws but dragging an image leaves trail behind. Can anyone point me to right direction please.
function init() {
canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
w = canvas.width;
h = canvas.height;
img = document.getElementById("drag");
canvas.addEventListener("mousemove", function (e) { findxy('move', e) }, false);
canvas.addEventListener("mousedown", function (e) { findxy('down', e) }, false);
canvas.addEventListener("mouseup", function (e) { findxy('up', e) }, false);
canvas.addEventListener("mouseout", function (e) { findxy('out', e) }, false);
imageLoader = document.getElementById('imageLoader');
imageLoader.addEventListener('change', handleImage, false);
var contexts = [];
contexts.push(canvas.getContext('2d'));
function clearAll() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
canvas.onclick = function (e) { handleClick(e, 1); };
function handleClick(e, contextIndex) {
e.stopPropagation();
var mouseX = parseInt(e.clientX - e.target.offsetLeft);
var mouseY = parseInt(e.clientY - e.target.offsetTop);
// clearAll();
for (var i = 0; i < states.length; i++) {
var state = states[i];
if (state.dragging) {
state.dragging = false;
state.draw();
continue;
}
if (state.contextIndex === contextIndex
&& mouseX > state.x && mouseX < state.x + state.width
&& mouseY > state.y && mouseY < state.y + state.height)
{
state.dragging = true;
state.offsetX = mouseX - state.x;
state.offsetY = mouseY - state.y;
state.contextIndex = contextIndex;
}
state.draw();
}
}
canvas.onmousemove = function (e) { handleMousemove(e, 1); }
function handleMousemove(e, contextIndex) {
e.stopPropagation();
var mouseX = parseInt(e.clientX - e.target.offsetLeft);
var mouseY = parseInt(e.clientY - e.target.offsetTop);
// clearAll();
for (var i = 0; i < states.length; i++) {
var state = states[i];
if (state.dragging) {
state.x = mouseX - state.offsetX;
state.y = mouseY - state.offsetY;
state.contextIndex = contextIndex;
}
state.draw();
}
}
var states = [];
states.push(addState(0, 0, img));
function addState(x, y, image) {
state = {}
state.dragging = false;
state.contextIndex = 1;
state.image = image;
state.x = x;
state.y = y;
state.width = image.width;
state.height = image.height;
state.offsetX = 0;
state.offsetY = 0;
state.draw = function () {
var context = contexts[this.contextIndex - 1];
if (this.dragging) {
context.strokeStyle = 'red';
context.strokeRect(this.x, this.y, this.width + 5, this.height + 5);
}
context.drawImage(this.image, this.x, this.y);
};
state.draw();
return(state);
}
}//end of init()
var imgArray = [];
function handleImage(e) {
var reader = new FileReader();
reader.onload = function (event) {
imgArray.push(img);
for(i = 0; i < imgArray.length; i++){
img.src = imgArray[i];
img.setAtX = i * 50;
img.setAtY = i * 0;
img.onload = function() {
ctx.drawImage(this, this.setAtX, this.setAtY);
};
img.src = event.target.result;
}
};
reader.readAsDataURL(e.target.files[0]);
}
function findxy(res, e) {
if (res === 'down') {
prevX = currX;
prevY = currY;
currX = e.clientX - canvas.offsetLeft;
currY = e.clientY - canvas.offsetTop;
flag = true;
dot_flag = true;
if (dot_flag) {
ctx.beginPath();
ctx.fillStyle = x;
ctx.fillRect(currX, currY, 2, 2);
ctx.closePath();
dot_flag = false;
}
}
if (res === 'up' || res === "out") {
flag = false;
}
if (res === 'move') {
if (flag) {
prevX = currX;
prevY = currY;
currX = e.clientX - canvas.offsetLeft;
currY = e.clientY - canvas.offsetTop;
draw();
}
}
}
//Draw lines or text
function draw() {
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = x;
ctx.lineWidth = y;
ctx.stroke();
ctx.closePath();
ctx.fillStyle = x;
ctx.font = "Italic Bold 14pt Times, serif";
ctx.fillText(message, prevX, prevY);
}
Here is a mashup of the code i linked to and your own.
All parameters related to drawing the image and translating it around the canvas is covered.
var canvas = document.getElementById("canvas");
var ctx;
var x = 75;
var y = 50;
var WIDTH = 400;
var HEIGHT = 300;
var dragok = false;
var img = document.getElementById("img");
var lines = [{
x: x,
y: y
}];
function rect(x, y, w, h) {
ctx.beginPath();
ctx.rect(x, y, w, h);
ctx.closePath();
ctx.fill();
}
function clear() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
}
function init() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
return setInterval(draw, 1000/24);
}
function draw() {
clear();
ctx.drawImage(img, x - img.width / 2, y - img.height / 2);
ctx.beginPath();
ctx.moveTo(lines[0].x,lines[0].y);
for(var i = 1; i < lines.length; i++) {
var line = lines[i];
ctx.lineTo(lines[i].x,lines[i].y);
}
ctx.stroke();
ctx.closePath();
//rect(x - 15, y - 15, 30, 30);
}
function myMove(e) {
if (dragok) {
x = e.pageX - canvas.offsetLeft;
y = e.pageY - canvas.offsetTop;
lines = lines.slice(lines.length - 100)
lines.push({
x: x,
y: y
});
}
}
function myDown(e) {
if (e.pageX < x + img.width / 2 + canvas.offsetLeft && e.pageX > x - img.width / 2 +
canvas.offsetLeft && e.pageY < y + img.height / 2 + canvas.offsetTop &&
e.pageY > y - img.height / 2 + canvas.offsetTop) {
x = e.pageX - canvas.offsetLeft;
y = e.pageY - canvas.offsetTop;
dragok = true;
canvas.onmousemove = myMove;
}
}
function myUp() {
dragok = false;
canvas.onmousemove = null;
}
init();
canvas.onmousedown = myDown;
canvas.onmouseup = myUp;
//Change image for the heck of it ^^
setInterval(function() {
img.src = 'https://placeholdit.imgix.net/~text?txtsize=60&txt=' +
Math.floor(Math.random() * 10) +
'&w=100&h=100';
}, 3000)
<canvas id="canvas" width="400" height="300">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
<img id="img" src="https://placeholdit.imgix.net/~text?txtsize=60&txt=1&w=100&h=100">
Updated my answer to draw lines
My final code that's working , I had to add two canvases one for the drawing and one for the dragging images. Fabric frame work helped a lot. https://jsfiddle.net/tn07Bond/982s4bgv/2/
<div id="canvasesdiv">
<canvas id="images" width=600 height=400 style="position: absolute;
left: 0;
top: 0;
border: 1px solid blue;
z-index: 1;">
This text is displayed if your browser does not support HTML5 Canvas</canvas>
<canvas id="drawing" width=600 height=400 style="position: absolute;
left: 0;
top: 0;
border: 1px solid red;
z-index: 2;">
This text is displayed if your browser does not support HTML5 Canvas</canvas>
<input type="file" id="imageLoader" class="imageLoader" name="imageLoader"/>
<input type="image" src="images/PenForCanvas.png" alt="pen" title="Draw on canvas"
id="Drawing" style="cursor: pointer; margin: 5px 0 0 200px;">
<input type="image" src="images/drag.png" alt="drag" title="Drag this image" id="Images" style="cursor: pointer;">
</div>
<script>
var drawing, drawingCtx,images,imagesCtx, message = "", img, imageLoader, prevX = 10, currX = 10, prevY = 10, currY = 10,
dot_flag = false, flag = false, x = "black", y = 2, formElement, canvasLeft, canvasTop, imgData, data,
startOffsetX = 0, startOffsetY = 0;
(function () {
// Drawing canvas
drawing = document.getElementById("drawing");
drawingCtx = drawing.getContext("2d");
//Uploading and dragging images
images = new fabric.Canvas('images');
document.getElementById('imageLoader').addEventListener("change", function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function (f) {
var data = f.target.result;
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({left: 0, top: 0, angle: 00,width:40, height:40}).scale(0.9);
images.add(oImg).renderAll();
var a = images.setActiveObject(oImg);
var dataURL = images.toDataURL({format: 'png', quality: 0.8});
});
};
reader.readAsDataURL(file);
});
w = drawing.width;
h = drawing.height;
//Mouse events
drawing.addEventListener("mousemove", function (e) { findxy('move', e) }, false);
drawing.addEventListener("mousedown", function (e) { findxy('down', e) }, false);
drawing.addEventListener("mouseup", function (e) { findxy('up', e) }, false);
drawing.addEventListener("mouseout", function (e) { findxy('out', e) }, false);
Drawing = document.getElementById("Drawing");
Drawing.addEventListener("click", bringDrawingToFront);
Images = document.getElementById("Images");
Images.addEventListener("click", bringImagesToFront);
imageLoader = document.getElementById('imageLoader');
imageLoader.addEventListener('change', bringImagesToFront);
//Drawing
function findxy(res, e) {
if (res === 'down') {
prevX = currX;
prevY = currY;
currX = e.clientX - drawing.offsetLeft;
currY = e.clientY - drawing.offsetTop;
flag = true;
dot_flag = true;
if (dot_flag) {
drawingCtx.beginPath();
drawingCtx.fillStyle = x;
drawingCtx.fillRect(currX, currY, 2, 2);
drawingCtx.closePath();
dot_flag = false;
}
}
if (res === 'up' || res === "out") {
flag = false;
}
if (res === 'move') {
if (flag) {
prevX = currX;
prevY = currY;
currX = e.clientX - drawing.offsetLeft;
currY = e.clientY - drawing.offsetTop;
draw();
}
}
}
function save() {
imgData = drawingCtx.getImageData(0, 0, drawing.width, drawing.height);
}
function restore() {
drawingCtx.putImageData(imgData, 0, 0);
}
function bringDrawingToFront() {
drawing.style.zIndex = 1;
document.getElementById("images").style.zIndex = 0;
}
function bringImagesToFront() {
drawing.style.zIndex = 0;
document.getElementById("images").style.zIndex = 1;
}
//Draw lines or text
function draw() {
drawingCtx.beginPath();
drawingCtx.moveTo(prevX, prevY);
drawingCtx.lineTo(currX, currY);
drawingCtx.strokeStyle = x;
drawingCtx.lineWidth = y;
drawingCtx.stroke();
drawingCtx.closePath();
drawingCtx.fillStyle = x;
drawingCtx.font = "Italic Bold 14pt Times, serif";
drawingCtx.fillText(message, prevX, prevY);
save();
}
})();
</script>

HTML Canvas - Drag and resize uploaded image

I am doing a drawing app for a college project and currently im able to upload images into the canvas and i want to make those images resizable/draggable.
I've seen this great example and tried to apply it in my project for hours but with no success.
Is it possible to apply it to an uploaded image instead of preloaded image like in that example?
My javascript code to upload image and a fiddle. Thanks in advance.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
function el(id){return document.getElementById(id);}
function readImage() {
if ( this.files && this.files[0] ) {
var FR= new FileReader();
FR.onload = function(e) {
var img = new Image();
img.onload = function() {
ctx.drawImage(img, true, true);
};
img.src = e.target.result;
};
FR.readAsDataURL( this.files[0] );
}
}
el("fileUpload").addEventListener("change", readImage, false);
As you have provided a nice example, I just included those methods and variables in your code and added jquery then declared the var img = new Image(); variable outside of the readImage function.
That's it I did and it worked as you expected.
Here you go,
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var isDown = false;
var pi2 = Math.PI * 2;
var resizerRadius = 8;
var rr = resizerRadius * resizerRadius;
var draggingResizer = {
x: 0,
y: 0
};
var imageX = 50;
var imageY = 50;
var imageWidth, imageHeight, imageRight, imageBottom;
var draggingImage = false;
var startX;
var startY;
function el(id){return document.getElementById(id);}
var img = new Image();
function readImage() {
if ( this.files && this.files[0] ) {
var FR= new FileReader();
FR.onload = function(e) {
img = new Image();
img.onload = function() {
imageWidth = img.width;
imageHeight = img.height;
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight
draw(true, false);
};
img.src = e.target.result;
};
FR.readAsDataURL( this.files[0] );
}
}
el("fileUpload").addEventListener("change", readImage, false);
function draw(withAnchors, withBorders) {
// clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw the image
ctx.drawImage(img, 0, 0, img.width, img.height, imageX, imageY, imageWidth, imageHeight);
// optionally draw the draggable anchors
if (withAnchors) {
drawDragAnchor(imageX, imageY);
drawDragAnchor(imageRight, imageY);
drawDragAnchor(imageRight, imageBottom);
drawDragAnchor(imageX, imageBottom);
}
// optionally draw the connecting anchor lines
if (withBorders) {
ctx.beginPath();
ctx.moveTo(imageX, imageY);
ctx.lineTo(imageRight, imageY);
ctx.lineTo(imageRight, imageBottom);
ctx.lineTo(imageX, imageBottom);
ctx.closePath();
ctx.stroke();
}
}
function drawDragAnchor(x, y) {
ctx.beginPath();
ctx.arc(x, y, resizerRadius, 0, pi2, false);
ctx.closePath();
ctx.fill();
}
function anchorHitTest(x, y) {
var dx, dy;
// top-left
dx = x - imageX;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (0);
}
// top-right
dx = x - imageRight;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (1);
}
// bottom-right
dx = x - imageRight;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (2);
}
// bottom-left
dx = x - imageX;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (3);
}
return (-1);
}
function hitImage(x, y) {
return (x > imageX && x < imageX + imageWidth && y > imageY && y < imageY + imageHeight);
}
function handleMouseDown(e) {
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
draggingResizer = anchorHitTest(startX, startY);
draggingImage = draggingResizer < 0 && hitImage(startX, startY);
}
function handleMouseUp(e) {
draggingResizer = -1;
draggingImage = false;
draw(true, false);
}
function handleMouseOut(e) {
handleMouseUp(e);
}
function handleMouseMove(e) {
if (draggingResizer > -1) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// resize the image
switch (draggingResizer) {
case 0:
//top-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageY = mouseY;
imageHeight = imageBottom - mouseY;
break;
case 1:
//top-right
imageY = mouseY;
imageWidth = mouseX - imageX;
imageHeight = imageBottom - mouseY;
break;
case 2:
//bottom-right
imageWidth = mouseX - imageX;
imageHeight = mouseY - imageY;
break;
case 3:
//bottom-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageHeight = mouseY - imageY;
break;
}
if(imageWidth<25){imageWidth=25;}
if(imageHeight<25){imageHeight=25;}
// set the image right and bottom
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight;
// redraw the image with resizing anchors
draw(true, true);
} else if (draggingImage) {
imageClick = false;
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// move the image by the amount of the latest drag
var dx = mouseX - startX;
var dy = mouseY - startY;
imageX += dx;
imageY += dy;
imageRight += dx;
imageBottom += dy;
// reset the startXY for next time
startX = mouseX;
startY = mouseY;
// redraw the image with border
draw(false, true);
}
}
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function (e) {
handleMouseOut(e);
});
#canvas {
border:1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type='file' id="fileUpload" />
<canvas id="canvas" width="500" height="500"></canvas>

Categories

Resources