How to store boxes from canvas? - javascript

I have a canvas, which will display videos taken from file upload on the first layer, and the second layer allow rectangles to be drawn. As I am trying to annotate videos and not still images, I will need the annotations to be saved then cleared, and then redrawn again and again until the video is over. However, I have no clue how I should do so as I am relatively new to JavaScript.
This is the code I have for now for the drawing of the annotations:
// Drawing boxes
function handleMouseDown(e) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
console.log(mouseX, mouseY);
$("#downlog").html("Down: " + mouseX + " / " + mouseY);
// Put your mousedown stuff here
if (mouseIsDown) {
console.log('1');
canvas2.style.cursor = "crosshair";
mouseIsDown = false;
mouseIsUp = false;
console.log(mouseIsDown);
} else {
handleMouseUp();
}
mouseIsDown = false;
mouseIsUp = true;
}
function handleMouseUp(e) { // array? user input?
mouseIsDown = false;
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
/*if (mouseIsUp) {
console.log('2');*/
draw();
}
function draw() {
/* context2.clearRect(0, 0, canvas2.width, canvas2.height);*/
context2.beginPath();
context2.rect(startX, startY, mouseX - startX, mouseY - startY);
context2.strokeStyle = "limegreen";
context2.lineWidth = 2;
context2.stroke();
canvas2.style.cursor = "default";
}
$("#canvas2").mousedown(function(e) {
handleMouseDown(e);
});
$("#canvas2").mouseup(function(e) {
handleMouseUp(e);
});
function clearcanvas()
{
var canvas2 = document.getElementById('canvas2'),
context2 = canvas2.getContext("2d");
context2.clearRect(0, 0, canvas2.width, canvas2.height);
}
I will really appreciate any help, thank you!

Please read the comments. I hope my code is clear enough.
let c = document.getElementById("canvas");
let ctx = c.getContext("2d");
// the array of all rectangles
let rectsRy = [];
// the actual rectangle, the one that is beeing drawn
let o={};
// a variable to store the mouse position
let m = {},
// a variable to store the point where you begin to draw the rectangle
start = {};
// a boolean
let isDrawing = false;
function handleMouseDown(e) {
start = oMousePos(c, e);
isDrawing = true;
//console.log(start.x, start.y);
c.style.cursor = "crosshair";
}
function handleMouseMove(e) {
if(isDrawing){
m = oMousePos(c, e);
draw();
}
}
function handleMouseUp(e) { // array? user input?
c.style.cursor = "default";
isDrawing = false;
// push a new rectangle into the rects array
rectsRy.push({x:o.x,y:o.y,w:o.w,h:o.h});
}
function draw() {
o.x = start.x;
o.y = start.y;
o.w = m.x - start.x;
o.h = m.y - start.y;
clearcanvas();
// draw all the rectangles saved in the rectsRy
rectsRy.map(r => {drawRect(r)})
// draw the actual rectangle
drawRect(o);
}
c.addEventListener("mousedown", handleMouseDown);
c.addEventListener("mousemove", handleMouseMove);
c.addEventListener("mouseup", handleMouseUp);
function clearcanvas(){
ctx.clearRect(0, 0, c.width, c.height);
}
function drawRect(o){
ctx.strokeStyle = "limegreen";
ctx.lineWidth = 2;
ctx.beginPath(o);
ctx.rect(o.x,o.y,o.w,o.h);
ctx.stroke();
}
// a function to detect the mouse position
// the function returns an object
function oMousePos(canvas, evt) {
let ClientRect = canvas.getBoundingClientRect();
return {
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
}
}
canvas{border:1px solid #d9d9d9;}
<canvas id="canvas" width="600" height="300">

Related

Javascript - Need to get x and y coordinates only from the stroke of a SVG path?

I have a canvas in which, is drawn an element svg (example a circle), the user is responsible for drawing with the mouse through this figure, I save the dots x and y drawn by the user in an array, but I dont know how to get the dots only from svg stroke.
My problem is:
Using isPointInStroke() I can see if the point is in the stroke but If I don't have the total points array of the stroke, it's impossible to know if the user has drawn 100% of the SVG figure. In the previous way if the user draws half of the drawing but correctly, it would give me 100% success.
function init() {
canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
w = canvas.width;
h = canvas.height;
var svgPathCirculo=" M125,200a75,75 0 1,0 150,0a75,75 0 1,0 -150,0";
var circulo = new Path2D(svgPathCirculo);
ctx.lineWidth = 5;
ctx.setLineDash([5, 15]);
ctx.stroke(circulo);
// Just example to check if it works
if(ctx.isPointInStroke(circulo, 125, 200)){
ctx.arc(200,200,3,0,2*Math.PI);
ctx.fill();
};
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);
}
I use the canvas to draw on it and svg to display predefined shapes for the user to follow as a template while drawing (such as drawing booklets for young children).
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;
if(!arrayCoordenadas.includes({x:currX,y:currY})){
arrayCoordenadas.push({x:currX,y:currY});
}
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;
if(!arrayCoordenadas.includes({x:currX,y:currY})){
arrayCoordenadas.push({x:currX,y:currY});
}
draw();
}
}
}
I need to know each of the x and y coordinates of the svg stroke path.
Example: Example of what I mean
I've added a function to detect the mouse position in the canvas and now currX became curr.x ... etc
If you are using Path2Dthis is how you detect if a point {x,y} is in the stroke:
ctx.isPointInStroke(the_path, x, y)
Next comes my code. The user can draw only inside the stroke.
Now the code is working but I don't think you may know if the user has drawn 100% of the SVG figure. You may push the points inside the array of points and calculate the length of the path, and compare it with the length of the circle, but I don't think this would do.
let prev = {},
curr = {};
let flag = false;
let circulo;
function init() {
canvas = document.getElementById("can");
ctx = canvas.getContext("2d");
w = canvas.width = 400;
h = canvas.height = 400;
var svgPathCirculo = "M125,200a75,75 0 1,0 150,0a75,75 0 1,0 -150,0";
circulo = new Path2D(svgPathCirculo);
ctx.lineWidth =10;
ctx.setLineDash([5, 15]);
ctx.stroke(circulo);
canvas.addEventListener("mousemove", move, false);
canvas.addEventListener("mousedown", down, false);
canvas.addEventListener("mouseup", up, false);
canvas.addEventListener("mouseout", up, false);
}
function draw(prev, curr, trazado) {
ctx.setLineDash([]); //unset linedash
ctx.lineCap = "round";
ctx.strokeStyle = "gold"
ctx.lineWidth =5;
if (
ctx.isPointInStroke(trazado, curr.x, curr.y) &&
ctx.isPointInStroke(trazado, prev.x, prev.y)
) {
ctx.beginPath();
ctx.moveTo(prev.x, prev.y);
ctx.lineTo(curr.x, curr.y);
ctx.stroke();
}
}
function down(e) {
prev = oMousePos(canvas, e);
curr = oMousePos(canvas, e);
flag = true;
}
function up(e) {
flag = false;
}
function move(e) {
if (flag) {
curr = oMousePos(canvas, e);
draw(prev, curr, circulo);
prev = { x: curr.x, y: curr.y };
}
}
function oMousePos(canvas, evt) {
var ClientRect = canvas.getBoundingClientRect();
return {
//objeto
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
};
}
init();
canvas{border:1px solid}
<canvas id="can"></canvas>

Drawing multiple boxes on canvas

Before I edited my code to create the boxes as objects and push them into an array, I could draw multiple boxes on the canvas and all of them would show up at once (until I cleared the canvas). However, now only one box shows up on the canvas at once, and when I draw another box, the previous box would be removed (although they would still be created as an object and pushed into the array). How do I edit my code so that I can draw multiple boxes onto the canvas and have them all show up together, until I clear the canvas?
Code:
const annotation = {
xcoordi: 0,
ycoordi: 0,
width: 0,
height: 0,
printCoordinates: function () {
console.log(`X: ${this.xcoordi}px, Y: ${this.ycoordi}px, Width: ${this.width}px, Height: ${this.height}px`);
}
};
//the array of all rectangles
let boundingBoxes = [];
// the actual rectangle, the one that is being drawn
let o={};
// a variable to store the mouse position
let m = {},
// a variable to store the point where you begin to draw the rectangle
start = {};
// a boolean
let isDrawing = false;
function handleMouseDown(e) {
start = oMousePos(canvas2, e);
isDrawing = true;
//console.log(start.x, start.y);
canvas2.style.cursor = "crosshair";
}
function handleMouseMove(e) {
if(isDrawing){
m = oMousePos(canvas2, e);
draw();
}
}
function handleMouseUp(e) {
canvas2.style.cursor = "default";
isDrawing = false;
const box = Object.create(annotation);
box.xcoordi = o.x;
box.ycoordi = o.y;
box.width = o.w;
box.height = o.h;
boundingBoxes.push(box);
draw();
box.printCoordinates();
console.log(boundingBoxes)
}
function draw() {
o.x = start.x; // start position of x
o.y = start.y; // start position of y
o.w = m.x - start.x; // width
o.h = m.y - start.y; // height
clearcanvas();
// draw all the rectangles saved in the rectsRy
boundingBoxes.map(r => {drawRect(r)})
// draw the actual rectangle
drawRect(o);
}
canvas2.addEventListener("mousedown", handleMouseDown);
canvas2.addEventListener("mousemove", handleMouseMove);
canvas2.addEventListener("mouseup", handleMouseUp);
function savecanvas(){
context2.clearRect(0, 0, canvas2.width, canvas2.height);
var savedBoxes = boundingBoxes.slice(0);
console.log(savedBoxes); // ok
}
function resetcanvas(){
context2.clearRect(0, 0, canvas2.width, canvas2.height);
boundingBoxes.length = 0;
console.log(boundingBoxes); // ok
}
function drawRect(o){
context2.strokeStyle = "limegreen";
context2.lineWidth = 2;
context2.beginPath(o);
context2.rect(o.x,o.y,o.w,o.h);
context2.stroke();
}
// Function to detect the mouse position
function oMousePos(canvas2, evt) {
let ClientRect = canvas2.getBoundingClientRect();
return {
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
}
}
Any help is really appreciated, thank you!
You have 2 errors:
in your code you are using a clearcanvas(); function which is not defined. I've replaced it with context2.clearRect(0, 0, canvas2.width, canvas2.height);
and this is more important: the object you save has these properties: xcoordi, ycoordi, width, height, BUT in drawRect(o) you are using x, y, w, h to draw the rect, but x, y, w, h are undefined, and thus no rect is drawn.
Please check my code:
const canvas2 = document.getElementById("canvas");
const context2 = canvas.getContext("2d");
const annotation = {
x: 0,
y: 0,
w: 0,
h: 0,
printCoordinates: function () {
console.log(`X: ${this.x}px, Y: ${this.y}px, Width: ${this.w}px, Height: ${this.h}px`);
}
};
//the array of all rectangles
let boundingBoxes = [];
// the actual rectangle, the one that is being drawn
let o={};
// a variable to store the mouse position
let m = {},
// a variable to store the point where you begin to draw the rectangle
start = {};
// a boolean
let isDrawing = false;
function handleMouseDown(e) {
start = oMousePos(canvas2, e);
isDrawing = true;
//console.log(start.x, start.y);
canvas2.style.cursor = "crosshair";
}
function handleMouseMove(e) {
if(isDrawing){
m = oMousePos(canvas2, e);
draw();
}
}
function handleMouseUp(e) {
canvas2.style.cursor = "default";
isDrawing = false;
const box = Object.create(annotation);
box.x = o.x;
box.y = o.y;
box.w = o.w;
box.h = o.h;
boundingBoxes.push(box);
draw();
box.printCoordinates();
console.log(boundingBoxes)
}
function draw() {
o.x = start.x; // start position of x
o.y = start.y; // start position of y
o.w = m.x - start.x; // width
o.h = m.y - start.y; // height
//clearcanvas();
context2.clearRect(0, 0, canvas2.width, canvas2.height);//////***********
// draw all the rectangles saved in the rectsRy
boundingBoxes.map(r => {drawRect(r)})
// draw the actual rectangle
drawRect(o);
}
canvas2.addEventListener("mousedown", handleMouseDown);
canvas2.addEventListener("mousemove", handleMouseMove);
canvas2.addEventListener("mouseup", handleMouseUp);
function savecanvas(){
context2.clearRect(0, 0, canvas2.width, canvas2.height);
var savedBoxes = boundingBoxes.slice(0);
console.log(savedBoxes); // ok
}
function resetcanvas(){
context2.clearRect(0, 0, canvas2.width, canvas2.height);
boundingBoxes.length = 0;
console.log(boundingBoxes); // ok
}
function drawRect(o){
context2.strokeStyle = "limegreen";
context2.lineWidth = 2;
context2.beginPath(o);
context2.rect(o.x,o.y,o.w,o.h);
context2.stroke();
}
// Function to detect the mouse position
function oMousePos(canvas2, evt) {
let ClientRect = canvas2.getBoundingClientRect();
return {
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
}
}
canvas{border:1px solid;}
<canvas id="canvas"></canvas>
void function() {
"use strict";
// Variables
var canvasWidth = 180;
var canvasHeight = 160;
var canvas = null;
var ctx = null;
var rectangles = [];
var isDrawing = false;
var mouseStartX = 0.0;
var mouseStartY = 0.0;
var mouseEndX = 0.0;
var mouseEndY = 0.0;
// Functions
// Constructor function (called with 'new')
function Rectangle(x,y,width,height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
function draw() {
ctx.fillStyle = "black";
ctx.fillRect(0,0,canvasWidth,canvasHeight);
ctx.strokeStyle = "limegreen";
ctx.lineWidth = 2;
ctx.beginPath();
for (var i = 0; i < rectangles.length; ++i) {
var rectangle = rectangles[i];
ctx.rect(
rectangle.x,
rectangle.y,
rectangle.width,
rectangle.height
);
}
ctx.stroke();
}
function getMousePosition(e) {
if (canvas && e) {
var bounds = canvas.getBoundingClientRect();
return [
e.clientX - bounds.left,
e.clientY - bounds.top
];
} else {
return [
0.0,
0.0
];
}
}
// Event Handlers
window.onmousedown = function(e) {
if (!isDrawing) {
isDrawing = true;
// Destructuring Assignment
[mouseStartX,mouseStartY] = getMousePosition(e);
canvas.style.cursor = "crosshair";
}
}
window.onmouseup = function(e) {
if (isDrawing) {
isDrawing = false;
// Destructuring Assignment
[mouseEndX,mouseEndY] = getMousePosition(e);
rectangles.push(
new Rectangle(
mouseStartX,
mouseStartY,
mouseEndX - mouseStartX,
mouseEndY - mouseStartY
)
);
draw();
canvas.style.cursor = "default";
}
}
window.onmousemove = function(e) {
if (isDrawing) {
// Destructuring Assignment
[mouseEndX,mouseEndY] = getMousePosition(e);
draw();
ctx.strokeStyle = "darkred";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.rect(
mouseStartX,
mouseStartY,
mouseEndX - mouseStartX,
mouseEndY - mouseStartY
);
ctx.stroke();
}
}
// Runs when the page loads
window.onload = function() {
canvas = document.getElementById("canvas");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
ctx = canvas.getContext("2d");
draw();
}
}();
canvas {
display: block;
margin: auto;
border: solid 2px black;
border-radius: 10px;
}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<canvas id="canvas"></canvas>
</body>
</html>

How to draw rectangle in canvas which is already in pdf.js

am using pdf.js here am rendering my pdf in canvas,
My code is:
<div id="viewerContainer" tabindex="0">
<div id="viewer" class="pdfViewer"></div>
</div>
The above canvas is generating through viewer.js
Now I am trying to draw rectangle on my pdf, but its not showing my rectangle,
My script is in below:
<script type="text/javascript">
var canvas, context, startX, endX, startY, endY;
var mouseIsDown = 0;
function init() {
canvas = document.getElementById("page1");
context = canvas.getContext("2d");
canvas.addEventListener("mousedown", mouseDown, false);
canvas.addEventListener("mousemove", mouseXY, false);
canvas.addEventListener("mouseup", mouseUp, false);
}
function mouseUp() {
if (mouseIsDown !== 0) {
mouseIsDown = 0;
drawSquare(); //update on mouse-up
}
}
function mouseDown() {
mouseIsDown = 1;
startX = endX = event.clientX - canvas.offsetLeft; //remember to subtract
startY = endY = event.clientY - canvas.offsetTop; //canvas offset
drawSquare(); //update
}
function mouseXY(eve) {
if (mouseIsDown !== 0) {
if (!eve) {
var eve = event;
}
endX = event.pageX - canvas.offsetLeft;
endY = event.pageY - canvas.offsetTop;
drawSquare();
}
}
function drawSquare() {
// creating a square
var width = Math.abs(startX - endX);
var height = Math.abs(startY - endY);
context.clearRect(0, 0, context.width, context.height);
//or use fillRect if you use a bg color
context.beginPath();
context.rect(startX, startY, width, height);
context.fillStyle = "yellow";
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'black';
context.stroke();
}
</script>
viwer.js code:
var canvasWrapper = document.createElement('div');
canvasWrapper.style.width = div.style.width;
canvasWrapper.style.height = div.style.height;
canvasWrapper.classList.add('canvasWrapper');
if (this.annotationLayer && this.annotationLayer.div) {
div.insertBefore(canvasWrapper, this.annotationLayer.div);
} else {
div.appendChild(canvasWrapper);
}
var textLayer = null;
if (this.textLayerFactory) {
var textLayerDiv = document.createElement('div');
textLayerDiv.className = 'textLayer';
textLayerDiv.style.width = canvasWrapper.style.width;
textLayerDiv.style.height = canvasWrapper.style.height;
if (this.annotationLayer && this.annotationLayer.div) {
div.insertBefore(textLayerDiv, this.annotationLayer.div);
} else {
div.appendChild(textLayerDiv);
}
textLayer = this.textLayerFactory.createTextLayerBuilder(textLayerDiv, this.id - 1, this.viewport, this.enhanceTextSelection);
}
var viewport = this.viewport;
var canvas = document.createElement('canvas');
canvas.id = this.renderingId;
canvas.setAttribute('hidden', 'hidden');
var isCanvasHidden = true;
var showCanvas = function showCanvas() {
if (isCanvasHidden) {
canvas.removeAttribute('hidden');
isCanvasHidden = false;
}
};
canvasWrapper.appendChild(canvas);
Is there any mistake in my code? I have searched many source but I could not able to find the correct one. Kindly help me in this issue.

Multi canvas drawing issue

I am building a paint tool application.I am using two canvases. One for loading a background image and one for do the painting. Painting canvas is placed over the other one. I used two canvases because i don't want the eraser tool to take effect on the image. On my code y position drawn by the application is not always accurate. In most cases the line is drawn higher than the actual drawn path.
var baseCanvas,baseContext,canvasObj,context;
var lastX,lastY,mouseX,mouseY;
var isMouseDown = false;
var mode = "pen";
$(window).load(function()
{
baseCanvas = document.getElementById("imageCanvas");
baseContext = baseCanvas.getContext("2d");
baseContext.strokeStyle = 'Black';
baseContext.fillStyle = "skyBlue";
baseContext.lineWidth = 5;
baseContext.fillRect(0, 0, baseCanvas.width, baseCanvas.height);
canvasObj = document.getElementById("drawingCanvas");
context = canvasObj.getContext("2d");
context.strokeStyle = 'Black';
context.lineCap = "round";
context.lineJoin = "round";
context.lineWidth = 2;
function handleMouseDown(e) {
mouseX = parseInt(e.clientX - $('#drawingCanvas').offset().left);
mouseY = parseInt(e.clientY - $('#drawingCanvas').offset().top);
lastX = mouseX;
lastY = mouseY;
isMouseDown = true;
}
function handleMouseUp(e) {
mouseX = parseInt(e.clientX - $('#drawingCanvas').offset().left);
mouseY = parseInt(e.clientY - $('#drawingCanvas').offset().top);
isMouseDown = false;
}
function handleMouseOut(e) {
mouseX = parseInt(e.clientX - $('#drawingCanvas').offset().left);
mouseY = parseInt(e.clientY - $('#drawingCanvas').offset().top);
isMouseDown = false;
}
function handleMouseMove(e) {
mouseX = parseInt(e.clientX - $('#drawingCanvas').offset().left);
mouseY = parseInt(e.clientY - $('#drawingCanvas').offset().top);
if (isMouseDown) {
context.beginPath();
if (mode == 'pen') {
context.globalCompositeOperation = "source-over";
context.moveTo(lastX, lastY);
context.lineTo(mouseX, mouseY);
context.stroke();
} else {
context.globalCompositeOperation = "destination-out";
context.arc(lastX, lastY, 5, 0, Math.PI * 2, false);
context.fill();
}
lastX = mouseX;
lastY = mouseY;
}
}
$(document).on('mousedown',$("#drawingCanvas"),function (e) {
handleMouseDown(e);
});
$(document).on('mousemove',$("#drawingCanvas"),function (e) {
handleMouseMove(e);
});
$(document).on('mouseup',$("#drawingCanvas"),function (e) {
handleMouseUp(e);
});
$(document).on('mouseout',$("#drawingCanvas"),function (e) {
handleMouseOut(e);
});
});
function setCanvas(imageFile)
{
var base_image = new Image();
base_image.src = window.URL.createObjectURL(imageFile[0]);
baseContext.save();
baseContext.clearRect(0, 0, baseCanvas.width, baseCanvas.height);
baseContext.beginPath();
base_image.onload = function()
{
baseContext.drawImage(base_image,0,0, $('#imageCanvas').width(), $('#imageCanvas').height());
baseContext.restore();
}
}
If you scroll the browser window, you need to adjust for that scrolling.
Here's how:
var scrollAdjustment=$("html,body").scrollTop();
mouseY+=scrollAdjustment;
And if you scroll horizontally, you would need to adjust for horizontal scrolling too.
BTW, since the canvas offset doesn't change, you could pre-calculate the canvas offsets one time instead of calculating it each time in your event handlers.
In your setup up top:
var canvasOffset=$("#drawingCanvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
And in your event handlers:
var scrollAdjustment=$("html,body").scrollTop();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY+scrollAdjustment);
Provided you are using the clientX, clientY properties of your mouse events, and that you hooked the events on the window, you should getBoundingClientRect on your canvas to know its top and left position, then substract them.
https://developer.mozilla.org/en-US/docs/Web/API/element.getBoundingClientRect
Rq : You might think also about hooking the events on the canvas.

Drawing a rectangle on Canvas

I am trying to create a simple canvas program where the user can consistently create new shapes. This one is just a basic rectangle creator (I am hoping to expand it more to circles, lines, and maybe even other stuff). Right now though I have created something that is working in a really weird way.
<html>
<head>
<meta chartset="utf-8">
<title>Dragging a square</title>
<script type="text/javascript">
var canvas, context, startX, endX, startY, endY;
var mouseIsDown = 0;
function init() {
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
canvas.addEventListener("mousedown", mouseDown, false);
canvas.addEventListener("mousemove", mouseXY, false);
document.body.addEventListener("mouseup", mouseUp, false);
}
function mouseUp() {
mouseIsDown = 0;
//mouseXY();
}
function mouseDown() {
mouseIsDown = 1;
startX = event.clientX;
startY = event.clientY;
mouseXY();
}
function mouseXY(eve) {
if (!eve) {
var eve = event;
}
endX = event.pageX - canvas.offsetLeft;
endY = event.pageY - canvas.offsetTop;
drawSquare();
}
function drawSquare() {
// creating a square
var width = Math.abs(startX - endX);
var height = Math.abs(startY - endY);
context.beginPath();
context.rect(startX, startY, width, height);
context.fillStyle = "yellow";
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'black';
context.stroke();
}
</script>
</head>
<body onload="init()">
<canvas id="canvas" width="400" height="400" style="border: 1px solid black; cursor: pointer;"></canvas>
</body>
</html>
Sorry about the slightly weird formatting when I copy and pasted my code. I think the problem is my mouseXY function. What I want is the user to click somewhere on the canvas a drag the mouse to create a rectangle, when the user lets go that is the end of that operation and they can create a whole new rectangle right after. At this point the program kind of just lets me click and create a new rectangle but if I let go of the mouse button it doesn't stop, in fact I have to click again to make it stop which then creates a new rectangle. I am still very new to this and I am having a lot of trouble with this, I will continue to work on this and if I figure it out I will let the site know. Thank you and have a great day!
Well I got this to work (thanks to #Ken) but now I am trying to solve a new problem. I want to be able to put multiple rectangles on the canvas. I created a function that represents the Rectangle and then created a draw function within the rectangle function to draw out a rectangle. I created a new function called addShape() that ideally creates the rectangle object and pushes into an array called square and drawShapes() that is supposed to erase everything on the canvas and redraws everything. Here is what I have so far:
<html>
<head>
<meta chartset="utf-8">
<title>Dragging a square</title>
<script type="text/javascript">
function Rectangle(canvas, x, y, width, height,color) {
//this.context = canvas.getContext("2d");
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = color;
this.draw = function() {
this.context.globalAlpha = 0.85;
this.context.beginPath();
this.context.rect(this.x, this.y, this.width, this.height);
this.context.fillStyle = this.color;
this.context.strokeStyle = "black";
this.context.lineWidth = 1;
this.context.fill();
this.context.stroke();
};
};
// hold the canvas and context variable, as well as the
// starting point of X and Y and the end ones
var canvas, context, startX, endX, startY, endY;
var mouseIsDown = 0;
// An array that holds all the squares
var squares = [];
window.onload = function() {
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
canvas.addEventListener("mousedown", mouseDown, false);
canvas.addEventListener("mousemove", mouseXY, false);
canvas.addEventListener("mouseup", mouseUp, false);
}
function mouseUp(eve) {
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
//Square(); //update on mouse-up
addShape(); // Update on mouse-up
}
}
function mouseDown(eve) {
mouseIsDown = 1;
var pos = getMousePos(canvas, eve);
startX = endX = pos.x;
startY = endY = pos.y;
// Square(); //update
addShape();
}
function mouseXY(eve) {
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
//Square();
addShape();
}
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
function addShape() {
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);
var s = new Rectangle(startX + offsetX, startY + offsetY, width, height, "yellow");
squares.push(s);
// Update the display
drawShapes();
}
function drawShapes() {
context.clearRect(0,0,canvas.width,canvas.height);
for (var i = 0; i < squares.length; i++) {
var shape = squares[i];
shape.draw();
};
}
function clearCanvas() {
squares = [];
drawShapes();
}
</script>
</head>
<body onload="addShape()">
<canvas id="canvas" width="400" height="400" style="border: 1px solid black; cursor: pointer;"></canvas><br>
<button onclick="clearCanvas()">Clear Canvas</button>
</body>
</html>
I am pretty sure I broke the original code... thank you for any help!
You need to modify a couple of things in the code: (edit: there are many issues with this code. I went through some of them inline here, but haven't tested. If you put it in a fiddle it's easier for us to check)..
Fiddle
When mouse down occur initialize both start and end points. Call a common draw function that is not dependent on the event itself:
function mouseDown(eve) {
mouseIsDown = 1;
var pos = getMousePos(canvas, eve);
startX = endX = pos.x;
startY = endY = pos.y;
drawSquare(); //update
}
At mouse up, only register if isMouseDown is true, else this function will handle all incoming up-events (as you have attatched it to document, which is correct - window could have been used too):
function mouseUp(eve) {
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
drawSquare(); //update on mouse-up
}
}
Only draw if mouseisdown is true:
function mouseXY(eve) {
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
drawSquare();
}
}
In addition you will need to clear the previous area of the rectangle before drawing a new or else it won't show when you draw a bigger rectangle and then move the mouse back to draw a smaller one.
For simplicity you can do:
function drawSquare() {
// creating a square
var width = Math.abs(startX - endX);
var height = Math.abs(startY - endY);
context.clearRect(0, 0, context.width, context.height);
//or use fillRect if you use a bg color
context.beginPath();
context.rect(startX, startY, width, height);
context.fillStyle = "yellow";
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'black';
context.stroke();
}
Use this for mouse position:
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}

Categories

Resources