fix line positioning in canvas [duplicate] - javascript

This question already has answers here:
Real mouse position in canvas
(5 answers)
Closed 5 years ago.
I have a canvas in a div like this
<div class="col-md-6">
<img src="{{ image }}" class="img-class img-thumbnail img-responsive">
<canvas id="can" class="hidden" style="position: absolute; width: 100%; height: 100%; top: 0px; left: 0px;"></canvas>
<div class="hidden hover-div" style="position: absolute; width: 100%; height: 100%; background-color: rgba(128, 128, 128, 0.07); top: 0;">
</div>
</div>
and the code to draw a line with it
var canvas, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
dot_flag = false;
var x = "black",
y = 2;
function initialize() {
canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
w = canvas.width;
h = canvas.height;
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);
}
function draw() {
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = x;
ctx.lineWidth = y;
ctx.stroke();
ctx.closePath();
}
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();
}
}
}
it works but the x,y co-ordinates are off, need help fixing this.
Here's a screen record demo of it's behaviour https://youtu.be/e8SUUZF81rk
the y pos is far down on the canvas compared to the mouse and x is slightly to the right.
I got this code from an example from here and edited it a little.

You need to set the canvas resolution to match the canvas display size, or scale the mouse coords to the canvas resolution.
To set the resolution to match the canvas display size
const bounds = canvasElement.getBoundingClientRect();
canvasElement.width = bounds.width;
canvasElement.height = bounds.height;
Or if you prefer you can scale the mouse position to match the canvas resolution
const bounds = canvasElement.getBoundingClientRect();
const scaleX = canvasElement.width / bounds.width;
const scaleY = canvasElement.height / bounds.height;
// then scale the mouse with the above scales
// in mouse event
mouseX = mouseEvent.clientX * scaleX;
mouseY = mouseEvent.clientY * scaleY;

Related

resize canvas and paint on right place

I have a canvas and I have loaded an Image on canvas. I can paint on the canvas
but in small browser size, some part of canvas will be hidden. So i have
used jQuery resize and it resize the canvas and show full image inside it and this is fine .
It resize canvas and full image is displayed. However, If I now paint on it , it paints/draws
far away the actual place. It happens only in resizing canvas but not on the full width of
browser. Is there any way to solve this issue.
I am looking for a ways to resize canvas and show full image on small device and should paint on actual place not far away.
Initially I want to show abit bigger canvas of width alteast 800px and height 400px
<canvas data-fieldid="1" id="can-1"class="image-canvas"></canvas>
Below is the js code that allows user to draw on image of canvas
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
sdsdfds
<script>
var flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
dot_flag = false;
var x = "red",
y = 3;
function init(fieldId) {
//fieldId are multiple Ids, but I get here one at a time
let canvas = document.getElementById('can-' + fieldId);
let ctx = canvas.getContext("2d");
ratio = 400 / 800;
canvas.width =
document.body.clientWidth < 800 ? document.body.clientWidth : 800;
canvas.height = canvas.width * ratio;
let base_image = new Image();
base_image.crossOrigin = "anonymous"
base_image.src = document.getElementById('image_' + fieldId).src
base_image.onload = function() {
ctx.drawImage(base_image,0,0,canvas.width, canvas.height);
};
canvas.addEventListener("mousemove", function(e) {
findxy('move', e, this)
}, false);
canvas.addEventListener("mousedown", function(e) {
findxy('down', e, this)
}, false);
canvas.addEventListener("mouseup", function(e) {
findxy('up', e, this)
}, false);
canvas.addEventListener("mouseout", function(e) {
findxy('out', e, this)
}, false);
}
function draw(ctx) {
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = x;
ctx.lineWidth = y;
ctx.stroke();
ctx.closePath();
}
function findxy(res, e,c) {
let ctx = c.getContext('2d');
if (res == 'down') {
prevX = currX;
prevY = currY;
currX = e.clientX - c.getBoundingClientRect().left;
currY = e.clientY - c.getBoundingClientRect().top;
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 - c.getBoundingClientRect().left;
currY = e.clientY - c.getBoundingClientRect().top;
draw(ctx);
}
}
}
$(document).ready(function() {
$(".image-canvas").each(function(canvas) {
init($(this).data("fieldid"));
});
});
</script>
The issue is CSS. When using 100% width and heights you will have issues. You can set the image width to the clientWidth and use the image ratio to maintain aspect. Use an event listener for resize to have the canvas change size is a browser is resized. Using an if statment we can have a max width of 800 and anything less is the clientWidth.
You mouse position should now be accurate without CSS.
var flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
dot_flag = false,
ratio;
var x = "red",
y = 3;
function init(fieldId) {
//fieldId are multiple Ids, but I get here one at a time
let canvas = document.getElementById("can-" + fieldId);
let ctx = canvas.getContext("2d");
ratio = 400 / 800;
canvas.width =
document.body.clientWidth < 800 ? document.body.clientWidth : 800;
canvas.height = canvas.width * ratio;
let base_image = new Image();
base_image.crossOrigin = "anonymous";
base_image.src = document.getElementById("image_" + fieldId).src;
base_image.onload = function () {
ctx.drawImage(base_image, 0, 0, canvas.width, canvas.height);
};
canvas.addEventListener(
"mousemove",
function (e) {
findxy("move", e, this);
},
false
);
canvas.addEventListener(
"mousedown",
function (e) {
findxy("down", e, this);
},
false
);
canvas.addEventListener(
"mouseup",
function (e) {
findxy("up", e, this);
},
false
);
canvas.addEventListener(
"mouseout",
function (e) {
findxy("out", e, this);
},
false
);
window.addEventListener("resize", () => {
resizeCanvas(canvas)
ctx.drawImage(base_image, 0, 0, canvas.width, canvas.height);
})
}
function draw(ctx) {
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = x;
ctx.lineWidth = y;
ctx.stroke();
ctx.closePath();
}
function findxy(res, e, c) {
let ctx = c.getContext("2d");
if (res == "down") {
prevX = currX;
prevY = currY;
currX = e.clientX - c.getBoundingClientRect().left;
currY = e.clientY - c.getBoundingClientRect().top;
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 - c.getBoundingClientRect().left;
currY = e.clientY - c.getBoundingClientRect().top;
draw(ctx);
}
}
}
$(document).ready(function () {
$(".image-canvas").each(function (canvas) {
//console.log($(this).data("fieldid"))
init($(this).data("fieldid"));
});
});
function resizeCanvas(canvas) {
ratio = 400 / 800;
canvas.width =
document.body.clientWidth < 800 ? document.body.clientWidth : 800;
canvas.height = canvas.width * ratio;
}
img {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<canvas data-fieldid='1'
id="can-1"
class="image-canvas"
style="position:absolute;top:10px;border:1px dotted;">
</canvas>
<canvas data-fieldid='2'
id="can-2"
class="image-canvas"
style="position:absolute;top:450px;border:1px dotted;">
</canvas>
<img src="https://images.unsplash.com/photo-1494548162494-384bba4ab999?ixid=MnwxMjA3fDB8MHxzZWFyY2h8MXx8c3VucmlzZXxlbnwwfHwwfHw%3D&ixlib=rb-1.2.1&w=1000&q=80" alt='view' id="image_1" class="images" />
<img src="https://media.istockphoto.com/photos/colored-powder-explosion-abstract-closeup-dust-on-backdrop-colorful-picture-id1072093690?k=6&m=1072093690&s=612x612&w=0&h=Eyk67XBt4sr3Bk1MubM6dHpvEVNICX4L7FumWhcTwuY=" alt='view' id="image_2" class="images" />

how to make drawable on dynamic canvas

I have display canvas dynamically based on records in db. Currently I have
two records in db and it shows two canvas in page.Now i should able to draw
on both cannvas however I can only draw on last canvas not on the both canvas.
Please check the image https://ibb.co/n7rvdk5 for more.
I am getting id 609 and 610.It can be 1,2 etc. This id are passed on canvas id to make it unique.
<div class="snap-field col-sm-12" style="height: 450px;">
loop here
<canvas data-fieldid="{{$draw->id}}"
id="image-canvas-{{$draw->id}}"
width="400" height="200"
class="image-canvas"
style="position:absolute;">
</canvas>
</div>
This is my js part and within document.ready function i have loaded the canvas . initEditableImageCanvas takes unique id. for example in this case it takes 609 and 610.I can draw on canvas with id 610 but not on 609.Maybe I need to make some changes here and I am not sure what should I do
<script>
var canvas, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
dot_flag = false;
var x = "red",
y = 2;
function initEditableImageCanvas(fieldId) {
canvas = document.getElementById('image-canvas-' + fieldId);
ctx = canvas.getContext("2d");
w = canvas.width;
h = canvas.height;
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);
}
function draw() {
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = x;
ctx.lineWidth = y;
ctx.stroke();
ctx.closePath();
}
function findxy(res, e) {
if (res == 'down') {
prevX = currX;
prevY = currY;
currX = e.clientX - canvas.getBoundingClientRect().left;
currY = e.clientY - canvas.getBoundingClientRect().top;
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.getBoundingClientRect().left;
currY = e.clientY - canvas.getBoundingClientRect().top;
draw();
}
}
}
$(document).ready(function() {
$(".image-canvas").each(function(canvas) {
//get id
initEditableImageCanvas($(this).data("fieldid"));
});
});
</script>
I am looking for help to fix it. I want draw in all canvas.
Any help? Thanks
In order to draw on a canvas, you can store it in a variable so that you are able to apply your logic.
let canvas = document.getElementById('canvasId');
let ctx = canvas.getContext('2d')
/*
Logic
*/
However, in your case, it turns out that since canvas and ctx are global variables, they get reassigned each time initEditableImageCanvas() is called within jQuery's each().
So even though the function findxy() is called whenever one event (i.e. mousemove) happens, it's not sufficient to draw on the right places. You
have to check if it is pointing to the right canvas.
This said, to prevent unexpected behaviors, prefer using local variables defined with let statement instead of global ones when working with multiple drawable canvas. One solution follows:
Change var -> let
Add a third parameter (c) to findxy()
Add an parameter (ctx) to draw()
// get rid of global canvas and ctx
var flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
dot_flag = false;
var x = "red",
y = 2;
function initEditableImageCanvas(fieldId) {
// use let
let canvas = document.getElementById('editable-image-canvas-' + fieldId);
ctx = canvas.getContext("2d");
w = canvas.width;
h = canvas.height;
/*
Attach this to each findxy
*/
canvas.addEventListener("mousemove", function(e) {
findxy('move', e, this)
}, false);
canvas.addEventListener("mousedown", function(e) {
findxy('down', e, this)
}, false);
canvas.addEventListener("mouseup", function(e) {
findxy('up', e, this)
}, false);
canvas.addEventListener("mouseout", function(e) {
findxy('out', e, this)
}, false);
}
function draw(ctx) {
// added parameter ctx
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = x;
ctx.lineWidth = y;
ctx.stroke();
ctx.closePath();
}
function findxy(res, e, c) {
// added parameter c and local ctx
let ctx = c.getContext('2d')
if (res == 'down') {
prevX = currX;
prevY = currY;
currX = e.clientX - c.getBoundingClientRect().left;
currY = e.clientY - c.getBoundingClientRect().top;
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 - c.getBoundingClientRect().left;
currY = e.clientY - c.getBoundingClientRect().top;
draw(ctx); // added argument
}
}
}
$(document).ready(function() {
$(".editable-image-canvas").each(function(canvas) {
// alert($(this).data("fieldid")) //give id 609 and 610
initEditableImageCanvas($(this).data("fieldid"));
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="snap-field col-sm-12" style="height: 450px;"> <div style="display:grid;"> <span>609</span> <canvas data-fieldid="609" id="editable-image-canvas-609" width="200" height="150" class="editable-image-canvas" style="position:relative;top:10%;border:1px dotted; margin-bottom:30px;"> </canvas> <span>610</span> <canvas data-fieldid="610" id="editable-image-canvas-610" width="200" height="150" class="editable-image-canvas" style="position:relative;top:10%;border:1px dotted;"> </canvas> </div><input type="hidden" name="field_{{$draw->id}}" id="editable-image-hidden-{{$draw->id}}"></div>

unable to draw on multiple canvas

How to load multiple canvas and enable drawing on it. Currently, It shows two canvas on my page but I can only draw in one canvas.
I have two records in database. foreach loop below make two canvas but I can only draw in only one canvas not on the both canvas. I should able to draw on both canvas and that is the things I want. I am looking for any help or any tips on how should I do so that I can draw on all canvas generated dynamically.
<body onload="init()">
<canvas id="can_{{$draw->id}}" width="1200" height="400"
style="position:absolute;top:10%;left:10%;border:2px solid;">
</canvas>
</body>
Below is the js code that allows user to draw on image of canvas
<script type="text/javascript">
var canvas, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
dot_flag = false;
var x = "red",
y = 2;
function init() {
for(let i=1;i<3;i++){
canvas = document.getElementById('can_'+i);
ctx = canvas.getContext("2d");
w = canvas.width;
h = canvas.height;
//
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);
}//end of for
}
function draw() {
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = x;
ctx.lineWidth = y;
ctx.stroke();
ctx.closePath();
}
function findxy(res, e) {
if (res == 'down') {
prevX = currX;
prevY = currY;
currX = e.clientX - canvas.getBoundingClientRect().left;
currY = e.clientY - canvas.getBoundingClientRect().top;
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.getBoundingClientRect().left;
currY = e.clientY -canvas.getBoundingClientRect().top;
draw();
}
}
}
</script>
Try something similar to this. Add the context to an array and see if you can draw to both. Not exactly sure the context thing is your problem but I think it is.
let canvas1 = document.getElementById("c1");
let canvas2 = document.getElementById("c2");
let ctx1 = canvas1.getContext("2d");
let ctx2 = canvas2.getContext("2d");
let ctx = [ctx1, ctx2];
function draw() {
ctx.forEach((ctx, i) => {
ctx.fillStyle = "lightblue";
ctx.fillRect(10, 10, 100, 100)
});
}
draw()
<canvas id='c1'></canvas>
<canvas id='c2'></canvas>
Adding what #Kaiido said for performance
let canvas1 = document.getElementById("c1");
let canvas2 = document.getElementById("c2");
let ctx1 = canvas1.getContext("2d");
let ctx2 = canvas2.getContext("2d");
ctx1.fillStyle = "lightblue";
ctx1.fillRect(50, 50, 100, 100)
ctx2.drawImage(canvas1, 0, 0)
<canvas id='c1'></canvas>
<canvas id='c2'></canvas>
Here's a solution that makes use of the fact we know which canvas generated a mouse event. Since we know that, we can use it to get the context of the correct canvas.
I show a message for mousemove and mousedown, indicating which canvas triggered the event.
<!doctype html>
<html>
<head>
<script>
"use strict";
var canvas, ctx, flag = false,
prevx = 0,
curx = 0,
prevy = 0,
cury = 0,
dot_flag = false;
var x = "red",
y = 2;
window.addEventListener('load', onLoaded, false);
function onLoaded(evt)
{
let canvasElems = document.querySelectorAll('canvas');
canvasElems.forEach(
can => {
can.addEventListener('mousemove', function(evt){ findxy('move', evt, this);}, false);
can.addEventListener('mousedown', function(evt){ findxy('down', evt, this);}, false);
can.addEventListener('mouseup', function(evt){ findxy('up', evt, this);}, false);
can.addEventListener('mouseout', function(evt){ findxy('out', evt, this);}, false);
} );
}
function findxy(reason, evt, elem)
{
if (reason=='up' || reason=='out')
flag = false;
if (reason == 'down')
{
document.querySelector('#output').textContent = elem.getAttribute('name') + ' was clicked';
prevx = curx;
prevy = cury;
curx = evt.clientX - elem.getBoundingClientRect().left;
cury = evt.clientY - elem.getBoundingClientRect().top;
flag = true;
dot_flag = true;
//if (dot_flag)
//{
let ctx = elem.getContext('2d');
ctx.beginPath();
ctx.fillStyle = x;
ctx.fillRect(curx, cury, 2, 2);
ctx.closePath();
dot_flag = false;
//}
}
else if (reason == 'move')
{
document.querySelector('#output').textContent = elem.getAttribute('name') + ' was moved over';
if (flag)
{
prevx = curx;
prevy = cury;
curx = evt.clientX - elem.getBoundingClientRect().left;
cury = evt.clientY - elem.getBoundingClientRect().top;
draw(elem);
}
}
}
function draw(tgtCanvas)
{
let ctx = tgtCanvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(prevx, prevy);
ctx.lineTo(curx, cury);
ctx.strokeStyle = x;
ctx.lineWidth = y;
ctx.stroke();
ctx.closePath();
}
</script>
<style>
canvas
{
margin: 4px;
border: solid 1px #333;
}
</style>
</head>
<body>
<canvas name='canvas1'></canvas><canvas name='canvas2'></canvas>
</br>
<span id='output'></span>
</body>
</html>

How to add dynamic labels to the dynamically added shapes on the Canvas?

I am trying to create a free-form drawing tool which allows to draw a shape (rectangle/triangle/line) and add the unique labels for each drawn shape. I got the free-form drawing tool code here: https://jsfiddle.net/k70m5qvh/.
Code:
<html>
<script type="text/javascript">
var canvas, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
dot_flag = false;
var x = "black",
y = 2;
function init() {
canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
w = canvas.width;
h = canvas.height;
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);
}
function color(obj) {
switch (obj.id) {
case "black":
x = "black";
break;
case "white":
x = "white";
break;
}
if (x == "white") y = 14;
else y = 2;
}
function draw() {
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = x;
ctx.lineWidth = y;
ctx.stroke();
//clear background
ctx.closePath();
}
function erase() {
var m = confirm("Want to clear");
if (m) {
ctx.clearRect(0, 0, w, h);
document.getElementById("canvasimg").style.display = "none";
}
}
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();
}
}
}
</script>
<body onload="init()">
<style>
.eraser {
cursor: cell;
}
</style>
<canvas id="can" width="400" height="400" style="position:absolute;top:10%;left:10%;border:1px solid black;"></canvas>
<div style="position:absolute;top:17%;left:67%;width: 40px; height:15px;border: 1px solid black; padding: 10px 5px;" id="black" onclick="color(this)">Draw</div>
<div style="position:absolute;top:37%;left:67%;width: 40px; height:15px;border: 1px solid black; padding: 10px 5px;" id="white" class="eraser" onclick="color(this)">Erase</div>
<img id="canvasimg" style="position:absolute;top:10%;left:52%;" style="display:none;">
</body>
</html>
But need a solution for the second part, that is adding dynamic labels for drawn objects.
Does anyone have experience of adding dynamic labels for dynamically added free-form shapes on canvas? Appreciate the help!

Show rectangle on canvas when mouse move

I want to draw rectangle on canvas. Below code is working fine except when i draw rectangle it does't show path when mouse is moving. When i left the mouse then rectangle is visible on canvas.
Please help,
Thanks
var canvas, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
currShape = 'rectangle',
mouseIsDown = 0,
startX, endX, startY, endY,
dot_flag = false;
var x = "white",
y = 2;
function init() {
canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
var imageObj = new Image(); //Canvas image Obj
imageObj.onload = function() {
ctx.drawImage(imageObj, 69, 50); //Load Image on canvas
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg'; //Load Image
w = canvas.width; // Canvas Width
h = canvas.height; // Canvas Height
//Check Shape to be draw
eventListener();
}
function eventListener(){
if(currShape=='rectangle'){
canvas.addEventListener("mousedown",function (e) {
mouseDown(e);
}, false);
canvas.addEventListener("mousemove",function (e){
mouseXY(e);
}, false);
canvas.addEventListener("mouseup", function (e){
mouseUp(e);
}, false);
}
}
function mouseUp(eve) {
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
if(currShape=='rectangle')
{
drawSquare(); //update on mouse-up
}
}
}
function mouseDown(eve) {
mouseIsDown = 1;
var pos = getMousePos(canvas, eve);
startX = endX = pos.x;
startY = endY = pos.y;
if(currShape=='rectangle')
{
drawSquare(); //update on mouse-up
}
}
function mouseXY(eve) {
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
//drawSquare();
}
}
function drawSquare() {
// creating a square
var w = endX - startX;
var h = endY - startY;
var offsetX = (w < 0) ? w : 0;
var offsetY = (h < 0) ? h : 0;
var width = Math.abs(w);
var height = Math.abs(h);
ctx.beginPath();
ctx.globalAlpha=0.7;
ctx.rect(startX + offsetX, startY + offsetY, width, height);
ctx.fillStyle = x;
ctx.fill();
ctx.lineWidth = y;
ctx.strokeStyle = x;
ctx.stroke();
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
.colortool div {
width: 15px;
height: 15px;
float: left;
margin-left: 2px;
}
.clear {
clear: both;
}
<!DOCTYPE HTML>
<html>
<body onload="init()">
<div class="canvasbody">
<canvas id="can" width="400" height="400" style="border:1px dotted #eee;"></canvas>
</div>
</body>
</html>
Here is you new JavaScript
var canvas, cnvHid, cnvRender, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
currShape = 'rectangle',
mouseIsDown = 0,
startX, endX, startY, endY,
dot_flag = false;
var x = "white",
y = 2;
function init() {
canvas = document.getElementById('can');
cnvHid = document.getElementById( "canHid" );
cnvRender = document.getElementById( "canRend" );
ctx = canvas.getContext("2d");
var imageObj = new Image(); //Canvas image Obj
imageObj.onload = function() {
ctx.drawImage(imageObj, 69, 50); //Load Image on canvas
renderAllCanvas();
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg'; //Load Image
w = canvas.width; // Canvas Width
h = canvas.height; // Canvas Height
//Check Shape to be draw
eventListener();
}
function eventListener(){
if(currShape=='rectangle'){
cnvRender.addEventListener("mousedown",function (e) {
mouseDown(e);
renderAllCanvas();
}, false);
cnvRender.addEventListener("mousemove",function (e){
mouseXY(e);
renderAllCanvas();
}, false);
cnvRender.addEventListener("mouseup", function (e){
mouseUp(e);
renderAllCanvas();
}, false);
}
}
function mouseUp(eve) {
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
if(currShape=='rectangle')
{
drawSquare( canvas ); //update on mouse-up
cnvHid.getContext( "2d" ).clearRect( 0, 0, cnvHid.width, cnvHid.height );
}
}
}
function mouseDown(eve) {
mouseIsDown = 1;
var pos = getMousePos(canvas, eve);
startX = endX = pos.x;
startY = endY = pos.y;
if(currShape=='rectangle')
{
drawSquare( canvas ); //update on mouse-up
}
}
function mouseXY(eve) {
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
drawSquare( cnvHid, true );
}
}
function drawSquare( cnv, clear ) {
var ctx = cnv.getContext( "2d" );
if( clear && clear === true ){
ctx.clearRect( 0, 0, cnv.width, cnv.height );
}
// creating a square
var w = endX - startX;
var h = endY - startY;
var offsetX = (w < 0) ? w : 0;
var offsetY = (h < 0) ? h : 0;
var width = Math.abs(w);
var height = Math.abs(h);
ctx.beginPath();
ctx.globalAlpha=0.7;
ctx.rect(startX + offsetX, startY + offsetY, width, height);
ctx.fillStyle = x;
ctx.fill();
ctx.lineWidth = y;
ctx.strokeStyle = x;
ctx.stroke();
ctx.closePath();
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
function renderAllCanvas(){
var cnxRender = cnvRender.getContext( "2d" );
cnxRender.drawImage(
canvas
,0,0
,cnvRender.width,cnvRender.height
);
cnxRender.drawImage(
cnvHid
,0,0
,cnvRender.width,cnvRender.height
);
}
And here is you new HTML
<!DOCTYPE HTML>
<html>
<body onload="init()">
<div class="canvasbody">
<canvas id="can" width="400" height="400" style="display: none;"></canvas>
<canvas id="canHid" width="400" height="400" style="display: none;"></canvas>
<canvas id="canRend" width="400" height="400" style="border:1px dotted #eee;"></canvas>
</div>
</body>
</html>
In some way, you would need to keep track on the changes you make to a shape you draw on the canvas. In your case, you would start by creating a very small rectangle and then scale it according to your mouse position during your dragmove.
Currently, you only have a function which draws an entirely new rectangle but does not take any previous "state" into consideration.
I found this blogpost which could be helpful. It doesn't explain scaling in particular but it could help with the basic concepts behind so I think this would be a good way for you to find a suitable solution.
Since we are finding the canvas tag in the DOM using it’s id and then setting the drawing context of the canvas to 2D. Two things is importent here is store the information as we draw the recatangle and a bolean to check user is drawing the rectangleor not.
You can reffer these links:Drawing a rectangle using click, mouse move, and click
Draw on HTML5 Canvas using a mouse
Check the js fiddle in the given link.
Hope this will help you..
Your current code has the redraw commented out on the mouse move, which would be required to update the canvas. However your code is also destroying the image the way the rectangle is being drawn. If you retain the image as shown below and redraw it on each frame before drawing the rectangle, it might have the desired effect.
var canvas, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
currShape = 'rectangle',
mouseIsDown = 0,
startX, endX, startY, endY,
dot_flag = false;
var x = "white",
y = 2,
image = null;
function init() {
canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
var imageObj = new Image(); //Canvas image Obj
imageObj.onload = function() {
image = imageObj;
ctx.drawImage(image, 69, 50); //Load Image on canvas
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg'; //Load Image
w = canvas.width; // Canvas Width
h = canvas.height; // Canvas Height
//Check Shape to be draw
eventListener();
}
function eventListener(){
if(currShape=='rectangle'){
canvas.addEventListener("mousedown",function (e) {
mouseDown(e);
}, false);
canvas.addEventListener("mousemove",function (e){
mouseXY(e);
}, false);
canvas.addEventListener("mouseup", function (e){
mouseUp(e);
}, false);
}
}
function mouseUp(eve) {
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
if(currShape=='rectangle')
{
drawSquare(); //update on mouse-up
}
}
}
function mouseDown(eve) {
mouseIsDown = 1;
var pos = getMousePos(canvas, eve);
startX = endX = pos.x;
startY = endY = pos.y;
if(currShape=='rectangle')
{
drawSquare(); //update on mouse-up
}
}
function mouseXY(eve) {
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
drawSquare();
}
}
function drawSquare() {
// draw background image
if(image) {
ctx.drawImage(image, 69, 50);
}
// creating a square
var w = endX - startX;
var h = endY - startY;
var offsetX = (w < 0) ? w : 0;
var offsetY = (h < 0) ? h : 0;
var width = Math.abs(w);
var height = Math.abs(h);
ctx.beginPath();
ctx.globalAlpha=0.7;
ctx.rect(startX + offsetX, startY + offsetY, width, height);
ctx.fillStyle = x;
ctx.fill();
ctx.lineWidth = y;
ctx.strokeStyle = x;
ctx.stroke();
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
.colortool div {
width: 15px;
height: 15px;
float: left;
margin-left: 2px;
}
.clear {
clear: both;
}
<!DOCTYPE HTML>
<html>
<body onload="init()">
<div class="canvasbody">
<canvas id="can" width="400" height="400" style="border:1px dotted #eee;"></canvas>
</div>
</body>
</html>

Categories