$(document).ready(function () {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
rect = {},
drag = false;
function init() {
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
}
function mouseDown(e) {
rect.startX = e.pageX - this.offsetLeft;
rect.startY = e.pageY - this.offsetTop;
drag = true;
}
function mouseUp() {
drag = false;
}
function mouseMove(e) {
if (drag) {
rect.w = (e.pageX - this.offsetLeft) - rect.startX;
rect.h = (e.pageY - this.offsetTop) - rect.startY;
ctx.clearRect(0, 0, canvas.width, canvas.height);
draw();
}
}
function draw() {
ctx.fillRect(rect.startX, rect.startY, rect.w, rect.h);
}
init();
});
This is what i have so far but when i create another rectangle the last one is automatically erased.
I need to crate multiple rectangles and make them drag able inside canvas.
Using drawOldShapes() method, you can persist the old rectangles.
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
// ctx.globalAlpha = 0.5;
rect = {},
drag = false;
var rectStartXArray = new Array() ;
var rectStartYArray = new Array() ;
var rectWArray = new Array() ;
var rectHArray = new Array() ;
function init() {
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
}
function mouseDown(e) {
rect.startX = e.pageX - this.offsetLeft;
rect.startY = e.pageY - this.offsetTop;
drag = true;
}
function mouseUp() {
rectStartXArray[rectStartXArray.length] = rect.startX;
rectStartYArray[rectStartYArray.length] = rect.startY;
rectWArray[rectWArray.length] = rect.w;
rectHArray[rectHArray.length] = rect.h;
drag = false;
}
function mouseMove(e) {
if (drag) {
rect.w = (e.pageX - this.offsetLeft) - rect.startX;
rect.h = (e.pageY - this.offsetTop) - rect.startY;
ctx.clearRect(0, 0, canvas.width, canvas.height);
draw();
}
drawOldShapes();
}
function draw() {
ctx.beginPath();
ctx.rect(rect.startX, rect.startY, rect.w, rect.h);
ctx.stroke();
}
function drawOldShapes(){
for(var i=0;i<rectStartXArray.length;i++)
{
if(rectStartXArray[i]!= rect.startX && rectStartYArray[i] != rect.startY && rectWArray[i] != rect.w && rectHArray[i] != rect.h)
{
ctx.beginPath();
ctx.rect(rectStartXArray[i], rectStartYArray[i], rectWArray[i], rectHArray[i]);
ctx.stroke();
}
}
}
init();
I guess you need to store each rectangle in an array and each time draw() is called you need to draw all of them.
something like:
rects = [];
rect = null;
//onmouse down:
rect = { x1 : <value from Mouse>,y1: <value from Mouse>,x2 : 0 ,y2 : 0 };
//onmouse up
rect.x2 = <value from Mouse>;
rect.y2 = <value from Mouse>;
rects.push( rect );
rect = null;
//draw
for( var i = 0; i < rects.length; i++ ) {
//drawing each rectangle
}
That is just kind of suggestion to approach. Next to the coordinates you can also store information about fill-color, stroke-width and -style and so on.
Good luck!
Related
I want to draw a simple circle on a canvas using mouse events, but what I am getting is partial circles, half circles, and sometimes a full one. The rectangle is working fine.Picture of resulting partial circles is attached.enter image description here
Code is
function draw() {
if (circ == 1)
{
context.beginPath();
context.arc(rect.startX, rect.startY, rect.w, rect.h, Math.PI * 2, false);
context.stroke();
}
}
function mouseDownrect(e) {
rect.startX = (e.layerX - this.offsetLeft);
rect.startY = e.layerY - this.offsetTop;
drag = true;
}
function mouseUprect() {
draw();
rect.w = 0;
rect.h = 0;
drag = false;
}
function mouseMoverect(e) {
if (drag == true) {
rect.w = (e.layerX - this.offsetLeft) - rect.startX;
rect.h = (e.layerY - this.offsetTop) - rect.startY;
}
}
function rectangle() {
color = 'black';
rectan = 1;
circ = 0;
pen = 0;
canvas.addEventListener('mousedown', mouseDownrect, false);
canvas.addEventListener('mouseup', mouseUprect, false);
canvas.addEventListener('mousemove', mouseMoverect, false);
}
function Circle()
{
color = 'black';
circ = 1;
rectan = 0;
pen = 0;
canvas.addEventListener('mousedown', mouseDownrect, false);
canvas.addEventListener('mouseup', mouseUprect, false);
canvas.addEventListener('mousemove', mouseMoverect, false);
}
The fourth argument in arc() is the starting ANGLE. So you want 0 to Math.PI * 2 for a full circle.
context.arc(rect.startX, rect.startY, rect.w, 0, Math.PI * 2, false);
Also, the 3rd argument is the RADIUS, and i don't know what you want that to be.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var rect = {};
var drag = false;
make_base();
init();
function make_base() {
base_image = new Image();
base_image.src = 'https://www.w3schools.com/css/img_fjords.jpg';
base_image.onload = function() {
context.drawImage(base_image, 0, 0, 800, 500);
}
}
function writeMessage(canvas, message) {
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(base_image, 0, 0, 800, 500);
context.font = '12pt Calibri';
context.fillStyle = 'red';
context.fillText(message, 25, 25);
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
function init() {
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
}
function mouseDown(e) {
rect.startX = e.pageX - this.offsetLeft;
rect.startY = e.pageY - this.offsetTop;
drag = true;
}
function mouseUp() {
drag = false;
}
function mouseMove(e) {
if(drag) {
rect.w = (e.pageX - this.offsetLeft) - rect.startX;
rect.h = (e.pageY - this.offsetTop) - rect.startY ;
context.clearRect(rect.startX, rect.startY, rect.w, rect.h);
draw();
}
}
function draw() {
context.lineWidth="1";
context.strokeStyle = "blue";
context.beginPath();
context.rect(rect.startX, rect.startY, rect.w, rect.h);
context.stroke();
context.closePath();
}
<canvas id="myCanvas" width="800" height="500" style="border:1px solid #000000;">
</canvas>
Now I can draw multi rectangle on image using mouse.
However, it will be white?
How to draw a rectangle more like select a area?
Best practice.
Rendering
You should never render from mouse or other UI events as they are not synced to the display. This can result in unpleasant shearing and flickering and also cause needless rendering that may only be partially or not at all seen, chewing power and battery life for no reason.
If you are regularly updating elements in the DOM (not just canvas) use render loop called via requestAnimationFrame. This ensures you only present DOM content that can be seen.
Lost input
When getting mouse input that is intended to be dragged you should listen to the document's mouse events rather than the element's. This allows you to follow the dragged input when it moves of the element and page. If you do not do this the drag can get locked if the user drags of the element/page and releases the mouse button.
Both the other answers fail to handle this correctly.
Constants and style
Use constants (const) wherever possible. They are block scoped and help to reduce bugs (though this is arguable).
Get used to adding "use strict"; top the top of your code, it will help you reduce and spot bugs early. Do not add "use strict" once you have completed the code unless you do full testing cycle as it will/may break what was once working code.
Though best practice do not define naming styles it does mean that you use a naming style consistently. If you choose snake case (snake_case) then use it throughout the code, if you choose camel case (camelCase) then only use that. You remember variable as the words, trying to remember which style you used for a variable will slow you down and can result in bugs.
"use strict";
requestAnimationFrame(mainLoop);
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
const storedRects = [];
const baseImage = loadImage("https://www.w3schools.com/css/img_fjords.jpg");
var refresh = true;
const rect = (() => {
var x1, y1, x2, y2;
var show = false;
function fix() {
rect.x = Math.min(x1, x2);
rect.y = Math.min(y1, y2);
rect.w = Math.max(x1, x2) - Math.min(x1, x2);
rect.h = Math.max(y1, y2) - Math.min(y1, y2);
}
function draw(ctx) { ctx.strokeRect(this.x, this.y, this.w, this.h) }
const rect = {x : 0, y : 0, w : 0, h : 0, draw};
const API = {
restart(point) {
x2 = x1 = point.x;
y2 = y1 = point.y;
fix();
show = true;
},
update(point) {
x2 = point.x;
y2 = point.y;
fix();
show = true;
},
toRect() {
show = false;
return Object.assign({}, rect);
},
draw(ctx) {
if (show) { rect.draw(ctx) }
},
show : false,
}
return API;
})();
function loadImage(url) {
const image = new Image();
image.src = url;
image.onload = () => refresh = true;
return image;
}
const mouse = {
button : false,
x : 0,
y : 0,
down : false,
up : false,
element : null,
event(e) {
const m = mouse;
m.bounds = m.element.getBoundingClientRect();
m.x = e.pageX - m.bounds.left - scrollX;
m.y = e.pageY - m.bounds.top - scrollY;
const prevButton = m.button;
m.button = e.type === "mousedown" ? true : e.type === "mouseup" ? false : mouse.button;
if (!prevButton && m.button) { m.down = true }
if (prevButton && !m.button) { m.up = true }
},
start(element) {
mouse.element = element;
"down,up,move".split(",").forEach(name => document.addEventListener("mouse" + name, mouse.event));
}
}
mouse.start(canvas);
function draw() {
ctx.drawImage(baseImage, 0, 0, ctx.canvas.width, ctx.canvas.width);
ctx.lineWidth = 1;
ctx.strokeStyle = "yellow";
storedRects.forEach(rect => rect.draw(ctx));
ctx.strokeStyle = "red";
rect.draw(ctx);
}
function mainLoop() {
if (refresh || mouse.down || mouse.up || mouse.button) {
refresh = false;
if (mouse.down) {
mouse.down = false;
rect.restart(mouse);
} else if (mouse.button) {
rect.update(mouse);
} else if (mouse.up) {
mouse.up = false;
rect.update(mouse);
storedRects.push(rect.toRect());
}
draw();
}
requestAnimationFrame(mainLoop)
}
<canvas id="myCanvas" width="800" height="500" title = "click and drag to add rectangles" style="border:1px solid #000000;cursor:crosshair"></canvas>
Heavily inspired by #Blindman67's excellent answer, this solution accepts touch events as well as mouse events, which I required for my own use.
The idea of the API Object was maintained but called "RectangleMaker".
Animation frames are only requested on the move event.
I found it hard to follow the signature mouse object run through the mainLoop loop function so I pulled that apart into three functions: "start", "move" and "stop". Events are added individually for each event type.
There are a few extra bits:
The code is invoked via a constructor so as to allow many canvases on a page.
Rectangle can preloaded, rectangle can be returned.
function AnnotateImage (canvas) {
const canvasContext = canvas.getContext('2d');
const rectangleMaker = new RectangleMaker(canvasContext);
const mouseObj = { x: 0, y: 0 };
let dragAction = false;
const img1 = new Image();
img1.src = canvas.toDataURL();
attachEvents(canvas);
let rectangles = [];
this.returnRectangles = () => {
return rectangles;
};
this.loadRectangles = (rects) => {
rectangles = rects;
rectangleMaker.drawRectangles();
return this;
};
function RectangleMaker (canvasContext) {
let x1, y1, x2, y2;
const finishedRectangle = { x: 0, y: 0, w: 0, h: 0 };
function makeFinishedRectangle () {
finishedRectangle.x = Math.min(x1, x2);
finishedRectangle.y = Math.min(y1, y2);
finishedRectangle.w = Math.max(x1, x2) - Math.min(x1, x2);
finishedRectangle.h = Math.max(y1, y2) - Math.min(y1, y2);
}
this.setFirstPoint = (point) => {
return setFirstPoint(point);
};
function setFirstPoint (point) {
x2 = x1 = point.x;
y2 = y1 = point.y;
makeFinishedRectangle();
}
this.setSecondPoint = (point) => {
return setSecondPoint(point);
};
function setSecondPoint (point) {
x2 = point.x;
y2 = point.y;
makeFinishedRectangle();
}
this.saveLocal = () => {
const rect = Object.assign({}, finishedRectangle);
rectangles.push(rect);
};
this.getRectangleToSave = () => {
return getRectangleToSave();
};
function getRectangleToSave () {
return Object.assign({}, finishedRectangle);
}
this.drawRectangles = () => {
return drawRectangles();
};
function drawRectangles () {
if (rectangles && rectangles.length > 0) {
rectangles.forEach((rectangle) => {
canvasContext.strokeRect(rectangle.x, rectangle.y, rectangle.w, rectangle.h);
});
}
}
}
function attachEvents (canvas) {
canvas.addEventListener('mousedown', (e) => {
start(e);
});
canvas.addEventListener('touchstart', (e) => {
start(e);
});
function start (e) {
const bounds = canvas.getBoundingClientRect();
mouseObj.x = (e.type.includes('mouse')) ? e.pageX - bounds.left - scrollX : e.targetTouches[0].pageX - bounds.left - scrollX;
mouseObj.y = (e.type.includes('mouse')) ? e.pageY - bounds.top - scrollY : e.targetTouches[0].pageY - bounds.top - scrollY;
rectangleMaker.setFirstPoint(mouseObj);
dragAction = true;
}
canvas.addEventListener('mousemove', (e) => {
move(e);
});
canvas.addEventListener('touchmove', (e) => {
move(e);
});
function move (e) {
e.preventDefault();
if (dragAction) {
// const prior = rectangleMaker.getRectangleToSave();
// canvasContext.strokeRect(prior.x, prior.y, prior.w, prior.h);
const bounds = canvas.getBoundingClientRect();
mouseObj.x = (e.type.includes('mouse')) ? e.pageX - bounds.left - scrollX : e.targetTouches[0].pageX - bounds.left - scrollX;
mouseObj.y = (e.type.includes('mouse')) ? e.pageY - bounds.top - scrollY : e.targetTouches[0].pageY - bounds.top - scrollY;
rectangleMaker.setSecondPoint(mouseObj);
const newRect = rectangleMaker.getRectangleToSave();
window.requestAnimationFrame(() => {
canvasContext.drawImage(img1, 0, 0);
rectangleMaker.drawRectangles();
canvasContext.strokeRect(newRect.x, newRect.y, newRect.w, newRect.h);
});
}
}
canvas.addEventListener('mouseup', (e) => {
stop(e);
});
canvas.addEventListener('touchend', (e) => {
stop(e);
});
function stop (e) {
dragAction = false;
const bounds = canvas.getBoundingClientRect();
mouseObj.x = (e.type.includes('mouse')) ? e.pageX - bounds.left - scrollX : e.changedTouches[0].pageX - bounds.left - scrollX;
mouseObj.y = (e.type.includes('mouse')) ? e.pageY - bounds.top - scrollY : e.changedTouches[0].pageY - bounds.top - scrollY;
rectangleMaker.setSecondPoint(mouseObj);
rectangleMaker.saveLocal();
rectangleMaker.drawRectangles();
}
}
}
/**
* #description code to load the canvas and call the Annotate constructor
*/
const canvas = document.querySelector('canvas');
loadImageFromlink(canvas).then(() => {
const annotate = new AnnotateImage(canvas);
});
function loadImageFromlink (canvas) {
const promise = new Promise((resolve, reject)=>{
const ctx = canvas.getContext('2d');
const img = new Image();
img.src = canvas.dataset.src;
img.crossOrigin = 'Anonymous';
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
resolve('loaded');
};
});
return promise;
}
<canvas data-src="https://www.gannett-cdn.com/-mm-/dcd88fe5876fd549823feb35af14c0ae9f0885b6/c=0-25-492-303/local/-/media/Phoenix/None/2014/10/17/635491415661570024-garfi8.PNG?width=492&height=277&fit=crop&format=pjpg&auto=webp"></canvas>
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>
I have a simple paint canvas html5. Its can draw through a selection option some shapes like lines, circles, rectangles, polygon, but now i want to make all draws draggable if possible resizable, without 3 part library only pure JS.
var canvas,
context,
dragStartLocation,
snapshot;
dragdrop = false;
isDrag = false;
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
function getCanvasCoordinates(event) {
var x = event.clientX - canvas.getBoundingClientRect().left;
y = event.clientY - canvas.getBoundingClientRect().top;
return {x: x, y: y};
}
function takeSnapshot() {
snapshot = context.getImageData(0, 0, canvas.width, canvas.height);
}
function restoreSnapshot() {
context.putImageData(snapshot, 0, 0);
}
function drawLine(position) {
context.beginPath();
context.moveTo(dragStartLocation.x, dragStartLocation.y);
context.lineTo(position.x, position.y );
context.stroke();
}
function drawRect(position) {
context.beginPath();
//context.moveTo(dragStartLocation.x, dragStartLocation.y);
context.fillRect(position.x, position.y, dragStartLocation.x - position.x, dragStartLocation.y - position.y);
//context.stroke();
}
function drawCircle(position) {
var radius = Math.sqrt(Math.pow((dragStartLocation.x - position.x), 2) + Math.pow((dragStartLocation.y - position.y), 2));
context.beginPath();
context.arc(dragStartLocation.x, dragStartLocation.y, radius, 0, 2 * Math.PI, false);
}
/*
function drawPolygon(position, sides, angle) {
var coordinates = [],
radius = Math.sqrt(Math.pow((dragStartLocation.x - position.x), 2) + Math.pow((dragStartLocation.y - position.y), 2)),
index = 0;
for (index = 0; index < sides; index++) {
coordinates.push({x: dragStartLocation.x + radius * Math.cos(angle), y: dragStartLocation.y - radius * Math.sin(angle)});
angle += (2 * Math.PI) / sides;
}
context.beginPath();
context.moveTo(coordinates[0].x, coordinates[0].y);
for (index = 1; index < sides; index++) {
context.lineTo(coordinates[index].x, coordinates[index].y);
}
context.closePath();
}*/
function draw(position) {
var fillBox = document.getElementById("fillBox"),
shape = document.querySelector('#tools option:checked').value,
/*polygonSides = document.getElementById("polygonSides").value,
polygonAngle = document.getElementById("polygonAngle").value,*/
lineCap = document.querySelector('input[type="radio"][name="lineCap"]:checked').value;
/*composition = document.querySelector('input[type="radio"][name="composition"]:checked').value;*/
context.lineCap = lineCap;
/*context.globalCompositeOperation = composition;*/
if (shape === "circle") {
drawCircle(position);
}
if (shape === "line") {
drawLine(position);
}
if (shape === "rect") {
drawRect(position);
}
if (shape === "polygon") {
drawPolygon(position, polygonSides, polygonAngle * (Math.PI / 180));
}
if (shape !== "line") {
if (fillBox.checked) {
context.fill();
} else {
context.stroke();
}
}
}
function dragStart(event) {
dragging = true;
dragStartLocation = getCanvasCoordinates(event);
takeSnapshot();
}
function drag(event) {
var position;
if (dragging === true) {
restoreSnapshot();
position = getCanvasCoordinates(event);
draw(position);
}
}
function dragStop(event) {
dragging = false;
restoreSnapshot();
var position = getCanvasCoordinates(event);
draw(position);
}
function changeLineWidth() {
context.lineWidth = this.value;
event.stopPropagation();
}
function changeFillStyle() {
context.fillStyle = this.value;
event.stopPropagation();
}
function changeStrokeStyle() {
context.strokeStyle = this.value;
event.stopPropagation();
}
function changeBackgroundColor() {
context.save();
context.fillStyle = document.getElementById("backgroundColor").value;
context.fillRect(0, 0, canvas.width, canvas.height);
context.restore();
}
function eraseCanvas() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
function init() {
canvas = document.getElementById("canvas");
context = canvas.getContext('2d');
var lineWidth = document.getElementById("lineWidth"),
fillColor = document.getElementById("fillColor"),
strokeColor = document.getElementById("strokeColor"),
//canvasColor = document.getElementById("backgroundColor"),
clearCanvas = document.getElementById("clearCanvas");
//saveCanvas = document.getElementById("saveCanvas");
context.strokeStyle = strokeColor.value;
context.fillStyle = fillColor.value;
context.lineWidth = lineWidth.value;
/*window.addEventListener('resize', resizeCanvas, false);
window.addEventListener('orientationchange', resizeCanvas, false);
resizeCanvas();*/
canvas.addEventListener('mousedown', dragStart, false);
canvas.addEventListener('mousemove', drag, false);
canvas.addEventListener('mouseup', dragStop, false);
lineWidth.addEventListener("input", changeLineWidth, false);
fillColor.addEventListener("input", changeFillStyle, false);
strokeColor.addEventListener("input", changeStrokeStyle, false);
//canvasColor.addEventListener("input", changeBackgroundColor, false);
clearCanvas.addEventListener("click", eraseCanvas, false);
//saveCanvas.addEventListener("click", salvaCanvas, false);
}
window.addEventListener('load', init, false);
It is an essential feature of canvas that it stores only the raster image formed as a result of all the draw operations. This why canvas is fast and memory efficient.
The downside is that you have to erase the affected rectangle on the canvas (or the whole canvas in the worst case) and redraw all the shapes that need to be resized, moved, etc. The canvas does not store them as objects, so your JS code must take care of storing, modifying and re-drawing them on the canvas. The effort is substantial unless you use some third party library.
The alternative is to use SVG-like features of HTML5 instead of canvas: <line>, <path>, <rect>, etc. They are kept as objects by the browser and accessible via DOM. This is a totally different approach, however, and requires a full rewrite of your code.
I am currently working on an application where I draw a rectangle on a canvas. I can draw the rectangle perfectly but then when I try to change the movement of the mouse to make the rectangle smaller there are trails that are left behind. How do I clear these trails when I make the rectangle's size smaller? below is my JavaScript code that I used. Thanks in advance.
function drawSquare() {
// creating a square
var w = lastX - startX;
var h = lastY - startY;
var offsetX = (w < 0) ? w : 0;
var offsetY = (h < 0) ? h : 0;
var width = Math.abs(w);
var height = Math.abs(h);
context.beginPath();
context.rect(startX + offsetX, startY + offsetY, width, height);
context.fillStyle = "gold";
context.fill();
context.lineWidth = 1;
context.strokeStyle = 'red';
context.stroke();
canvas.style.cursor = "default";
}
function getMousePos(canvas, e) {
var rect = canvas.getBoundingClientRect();
return {
x: e.pageX - canvas.offsetLeft,
y: e.pageY - canvas.offsetTop,
};
}
function handleMouseDown(e) {
// get mouse coordinates
mouseX = parseInt(e.pageX - offsetX);
mouseY = parseInt(e.pageY - offsetY);
// set the starting drag position
lastX = mouseX;
lastY = mouseY;
isDown = true;
if (isChecBoxClicked == true) {
mouseIsDown = 1;
startX = lastX;
startY = lastY;
var pos = getMousePos(canvas, e);
startX = lastX = pos.x;
startY = lastY = pos.y;
drawSquare();
}
else {
canvas.style.cursor = "default";
}
}
function handleMouseUp(e) {
// clear the dragging flag
isDown = false;
canvas.style.cursor = "default";
// get mouse coordinates
mouseX = parseInt(e.pageX - offsetX);
mouseY = parseInt(e.pageY - offsetY);
// set the starting drag position
lastX = mouseX;
lastY = mouseY;
if (isChecBoxClicked == true)
{
canvas.style.cursor = "crosshair";
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, e);
lastX = pos.x;
lastY = pos.y;
drawSquare();
}
}
}
function handleMouseMove(e) {
// if we're not dragging, exit
if (!isDown) {
return;
}
//if (defaultval == 1) {
// return;
//}
if (isChecBoxClicked == true) {
canvas.style.cursor = "crosshair";
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, e);
lastX = pos.x;
lastY = pos.y;
drawSquare();
}
}
}
A canvas doesn't clear itself. At least not a 2D context, like you are using. If you keep drawing on it, the new graphics is placed on top of the old. You need to explicitly clear it:
context.clearRect(0, 0, canvas.width, canvas.height);
You will probably have to clear your canvas. If you are only drawing a square you will have to do that in the drawSquare function. If you are drawing multiple things you will have to do it in a higher function that redraws multiple things.
For clearing the whole canvas, you can use the following code:
context.clearRect ( 0 , 0 , canvas.width, canvas.height );
There are also a lot of canvas libraries that will manage this for you and optimize the areas redrawn (they might only clear a part of the canvas, so there are less pixels redrawn)