How to rotate object in the canvas - javascript

I'm trying to rotate only one object in the canvas, not the whole canvas.
My code is as follows:
var canvas = document.getElementById('canvas');
var buttons = document.getElementById('buttons');
var img = document.getElementById('photo');
var ctx = canvas.getContext('2d');
var rect = {};
var drag = false;
var buttons_shown = false;
var angle = 10;
var rotate_angle = 0;
var original_source = img.src;
img.src = original_source;
function init() {
img.addEventListener('load', function(){
canvas.width = img.width;
canvas.height = img.height;
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
document.addEventListener("keydown", keyDownPressed, false);
});
}
function keyDownPressed(e) {
var keyCode = e.keyCode;
var left_arrow = 37;
var right_arrow = 39;
var up_arrow = 38;
var down_arrow = 40;
if(keyCode === left_arrow) {
onRotateLeft()
}
if(keyCode === right_arrow){
onRotateRight()
}
}
function mouseDown(e) {
rect.startX = e.offsetX;
rect.startY = e.offsetY;
drag = true;
buttons_shown = false;
buttons.classList.add("hide");
}
function mouseUp() { drag = false; buttons_shown = true; }
function onRemoveSelectionClick(e) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drag = false;
buttons_shown = false;
buttons.classList.add("hide");
}
function onRotateLeft(){
rotate_angle = rotate_angle - angle;
canvas.style.transform = 'rotate(' + rotate_angle + 'deg)';
}
function onRotateRight(){
rotate_angle = rotate_angle + angle;
canvas.style.transform = 'rotate(' + rotate_angle + 'deg)';
}
function mouseMove(e) {
if (drag) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
rect.w = (e.pageX - this.offsetLeft) - rect.startX;
rect.h = (e.pageY - this.offsetTop) - rect.startY;
ctx.shadowBlur = 5;
ctx.filter = 'blur(10px)';
ctx.fillRect(rect.startX, rect.startY, rect.w, rect.h);
ctx.strokeRect(rect.startX, rect.startY, rect.w, rect.h);
}else{
if(buttons_shown && buttons.classList.contains("hide")){
buttons.classList.remove("hide");
}
}
}
//
init();
.hide{
display: none !important;
}
canvas{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display:inline-block;
background-color: yellow;
}
<div style="position: relative; overflow: hidden;display:inline-block;">
<img id="photo" src="http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg"/>
<canvas id="canvas"></canvas>
</div>
<div id="buttons" class="hide">
<button onclick="onRotateLeft()">Rotate Left</button>
<button onclick="onRotateRight()">Rotate right</button><br />
<button onclick="onRemoveSelectionClick()">Remove Selection</button>
</div>
Thus, if an object is drawn, I show the buttons to rotate it left or right or to delete it. If I click on for example Rotate Left button, it executes the next code:
rotate_angle = rotate_angle - angle;
canvas.style.transform = 'rotate(' + rotate_angle + 'deg)';
But that rotates my whole canvas (yellow background) but I want to rotate only the object inside the canvas.
Any idea?

Use canvas transform not CSS transform.
You need to apply the transform in the canvas when you render the rectangle.
The snippet is a copy of your code with some changes.
The rendering is done via requestAnimationFrame so as not to have needless renders when the mouse moves.
A global flag update is set to true whenever there is need to update the canvas.
An array of rectangles is used to store each rectangle.
The rectangle object also stores its rotation rect.rotate so that each rectangle has an independent rotation.
The global variable rect holds the current rectangle.
Events change the global rect object and set the update = true flag, they do not do any rendering.
The rectangle is rotated about its center
Canvas context ctx.rotate uses radians not degrees
See code for more info.
var canvas = document.getElementById('canvas');
var buttons = document.getElementById('buttons');
var img = document.getElementById('photo');
var ctx = canvas.getContext('2d');
var rect = {};
var drag = false;
var buttons_shown = false;
var angle = 10 * (Math.PI / 180) ;
var rotate_angle = 0;
var update = true; // when true updates canvas
var original_source = img.src;
img.src = original_source;
function init() {
img.addEventListener('load', function(){
canvas.width = img.width;
canvas.height = img.height;
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
document.addEventListener("keydown", keyDownPressed, false);
});
// start the rendering loop
requestAnimationFrame(updateCanvas);
}
// main render loop only updates if update is true
function updateCanvas(){
if(update){
drawCanvas();
update = false;
}
requestAnimationFrame(updateCanvas);
}
// array of rectangles
const rectangles = [];
// adds a rectangle
function addRectangle(rect){
rectangles.push(rect);
}
// draws a rectangle with rotation
function drawRect(rect){
ctx.setTransform(1,0,0,1,rect.startX + rect.w / 2, rect.startY + rect.h / 2);
ctx.rotate(rect.rotate);
ctx.beginPath();
ctx.rect(-rect.w/2, -rect.h/2, rect.w, rect.h);
ctx.fill();
ctx.stroke();
}
// clears canvas sets filters and draws rectangles
function drawCanvas(){
// restore the default transform as rectangle rendering does not restore the transform.
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.shadowBlur = 5;
ctx.filter = 'blur(10px)';
rectangles.forEach(drawRect);
}
function keyDownPressed(e) {
var keyCode = e.keyCode;
var left_arrow = 37;
var right_arrow = 39;
var up_arrow = 38;
var down_arrow = 40;
if(keyCode === left_arrow) {
onRotateLeft()
}
if(keyCode === right_arrow){
onRotateRight()
}
}
// create new rect add to array
function mouseDown(e) {
rect = {
startX : e.offsetX,
startY : e.offsetY,
w : 1,
h : 1,
rotate : 0,
};
drag = true;
buttons_shown = false;
buttons.classList.add("hide");
addRectangle(rect);
update = true;
}
function mouseUp() { drag = false; buttons_shown = true; update = true; }
// removes top rectangle and sets next down as current or if none then hides controls
function onRemoveSelectionClick(e) {
rectangles.pop();
if(rectangles.length === 0){
drag = false;
buttons_shown = false;
buttons.classList.add("hide");
}else{
rect = rectangles[rectangles.length -1];
}
update = true;
}
// rotate current rectangle
function onRotateLeft(){
rect.rotate -= angle;
update = true;
}
function onRotateRight(){
rect.rotate += angle;
update = true;
}
function mouseMove(e) {
if (drag) {
rect.w = (e.pageX - this.offsetLeft) - rect.startX;
rect.h = (e.pageY - this.offsetTop) - rect.startY;
update = true;
}else{
if(buttons_shown && buttons.classList.contains("hide")){
buttons.classList.remove("hide");
}
}
}
//
init();
.hide{
display: none !important;
}
canvas{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display:inline-block;
background-color: yellow;
}
<div style="position: relative; overflow: hidden;display:inline-block;">
<img id="photo" src="http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg"/>
<canvas id="canvas"></canvas>
</div>
<div id="buttons" class="hide">
<button onclick="onRotateLeft()">Rotate Left</button>
<button onclick="onRotateRight()">Rotate right</button><br />
<button onclick="onRemoveSelectionClick()">Remove Selection</button>
</div>

You will need a separate canvas for the object; draw the object on this separate canvas and then, depending on what you actually intend to do, you can either:
Draw the auxiliary canvas' contents on the main one using context.rotate() combined with context.drawImage();
Overlay one canvas on top of another using CSS.
Then again, perhaps you could just use context.rotate() then draw on the main canvas as cited in: HTML5 Canvas Rotate Image

Related

canvas with mouse that moves ball

I have a mouse image and a cheese image with line in-between. Works fine. Does nothing except look good.
I added a ball that follows the user mouse and it cleared all my images. I tried to add layers(I am a total newbie).
I want the mouse user to be able to lead just the ball on top of the mouse image to the cheese. After I get that working, I will have the cheese turn into a separate image.
The mouse user can lead the ball anywhere. It does not have to just be on the line in-between the two images.
<!DOCTYPE html>
<title>Mouse Event</title>
<style>
canvas {
border: #333 10px solid;
}
</style>
<div style = "position: relative;">
<canvas id = "layer1" width="600px" height="600px"
style="position: absolute; left: 0; top: 0; z-index: 0;></canvas>
<canvas id = "layer2" width="600px" height="600px"
style="position: absolute; left: 0; top: 0; z-index: 1;></canvas>
<script>
var canvas1 = document.querySelector("#layer1");
var context = canvas1.getContext("2d");
//Get the mouse position
//First, listen for the mouse event & call setMousePosition
//This function assigns the current horizontal and vertical mouse
//position to the mouseX,Y properties, it relies on the clientX
//and Y properties that the MouseEvent-based event arument object provides
var canvasPos = getPosition(canvas);
var mouseX = 500;
var mouseY = 500;
canvas1.addEventListener("mousemove", setMousePosition, false);
function setMousePosition(e) {
mouseX = e.clientX - canvasPos.x;//now stores the position returned by the getPosition function
mouseY = e.clientY - canvasPos.y;
}
function update() {
context.clearRect(0, 0, canvas.width, canvas.height);//clears earlier positions
context.beginPath();
context.arc(mouseX, mouseY, 50, 0, 2 * Math.PI, true);
context.fillStyle = "LightSeaGreen";
context.lineWidth = 5;
context.strokeStyle = "yellow";
context.fill();
context.stroke();
requestAnimationFrame(update);
}
//Get the Exact Mouse Position
function getPosition(el) {
var xPosition = 0;
var yPosition = 0;
while (el) {
xPosition += (el.offsetLeft - el.scrollLeft + el.clientLeft);
yPosition += (el.offsetTop - el.scrollTop + el.clientTop);
el = el.offsetParent;
}
return {
x: xPosition,
y: yPosition
};
}
update();
var canvas2 = document.querySelector("#layer2");
var context = canvas2.getContext("2d");
//draw connecting line
context.moveTo(30,30);
context.bezierCurveTo(-50,600, 500, 0, 300,500);
context.lineWidth = 15;
context.strokeStyle = "teal";
context.stroke();
context.fillStyle = "#ff6600";
context.font = "bold 35px 'Book Antiqua'";
context.fillText("Help Me", 300,100);
context.fillText("find the cheese,", 300, 135);
context.fillText("Please!", 300, 170);
//load cheeseImage
var cheeseImage = new Image();
cheeseImage.src = "images/transparentCheese.png";
cheeseImage.addEventListener("load", loadImage, false);
//load mouse image
var mouseImage = new Image();
mouseImage.src = "images/mouse.png";
mouseImage.addEventListener("load", loadImage, false);
function loadImage(e) {
context.drawImage(cheeseImage,10,10);
context.drawImage(mouseImage,210,400);
}
</script>
</div>
[mouse][1]cheese
The images are gone because the update function clears the canvas each frame of the animation (context.clearRect), but you want the canvas to clear so don't delete that.
You need to put all the code to draw the things you would like on the canvas inside the update function, or functions the update code calls.
Also its best to wait until both images have loaded before calling the update() function for the first time.
I have modified your code and added some comments, hopefully it makes sense...
function update() {
context.clearRect(0, 0, canvas.width, canvas.height);//clears earlier positions
context.beginPath();
context.arc(mouseX, mouseY, 50, 0, 2 * Math.PI, true);
context.fillStyle = "LightSeaGreen";
context.lineWidth = 5;
context.strokeStyle = "yellow";
context.fill();
context.stroke();
// Call functions to draw text and images on the canvas.
drawText();
drawCheese();
drawMouse();
requestAnimationFrame(update);
}
//Get the Exact Mouse Position
function getPosition(el) {
var xPosition = 0;
var yPosition = 0;
while (el) {
xPosition += (el.offsetLeft - el.scrollLeft + el.clientLeft);
yPosition += (el.offsetTop - el.scrollTop + el.clientTop);
el = el.offsetParent;
}
return {
x: xPosition,
y: yPosition
};
}
var canvas2 = document.querySelector("#layer2");
var context = canvas2.getContext("2d");
function drawText() {
//draw connecting line
context.moveTo(30,30);
context.bezierCurveTo(-50,600, 500, 0, 300,500);
context.lineWidth = 15;
context.strokeStyle = "teal";
context.stroke();
context.fillStyle = "#ff6600";
context.font = "bold 35px 'Book Antiqua'";
context.fillText("Help Me", 300,100);
context.fillText("find the cheese,", 300, 135);
context.fillText("Please!", 300, 170);
}
// Draw cheese image on canvas
function drawCheese() {
context.drawImage(cheeseImage,10,10);
}
// Draw mouse image on canvas.
function drawMouse() {
context.drawImage(mouseImage,210,400);
}
//load cheeseImage
var cheeseImage = new Image();
cheeseImage.src = "images/transparentCheese.png";
cheeseImage.addEventListener("load", loadImage, false);
//load mouse image
var mouseImage = new Image();
mouseImage.src = "images/mouse.png";
mouseImage.addEventListener("load", loadImage, false);
var imagesLoaded = 0;
// Called when image is loaded.
function loadImage(e) {
// Increment the number of images loaded
imagesLoaded += 1;
// If both images have loaded call the update function for the first time.
if (imagesLoaded == 2) {
update();
}
}

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.

Adjust canvas background in Javascript

I'm trying to drawn a rect on canvas, but I want that canvas has lightly transparent background, but that drawn rect has no background.
What I will is something as follows:
I have code as follows:
var canvas = document.getElementById('canvas');
var img = document.getElementById('photo');
var ctx = canvas.getContext('2d');
var rect = {};
var drag = false;
var update = true; // when true updates canvas
var original_source = img.src;
img.src = original_source;
function init() {
img.addEventListener('load', function(){
canvas.width = img.width;
canvas.height = img.height;
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
});
// start the rendering loop
requestAnimationFrame(updateCanvas);
}
// main render loop only updates if update is true
function updateCanvas(){
if(update){
drawCanvas();
update = false;
}
requestAnimationFrame(updateCanvas);
}
// draws a rectangle with rotation
function drawRect(){
ctx.setTransform(1,0,0,1,rect.startX + rect.w / 2, rect.startY + rect.h / 2);
ctx.rotate(rect.rotate);
ctx.beginPath();
ctx.rect(-rect.w/2, -rect.h/2, rect.w, rect.h);
/* ctx.fill(); */
ctx.stroke();
}
// clears canvas sets filters and draws rectangles
function drawCanvas(){
// restore the default transform as rectangle rendering does not restore the transform.
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawRect()
}
// create new rect add to array
function mouseDown(e) {
rect = {
startX : e.offsetX,
startY : e.offsetY,
w : 1,
h : 1,
rotate : 0,
};
drag = true;
}
function mouseUp() { drag = false; buttons_shown = true; update = true; }
function mouseMove(e) {
if (drag) {
rect.w = (e.pageX - this.offsetLeft) - rect.startX;
rect.h = (e.pageY - this.offsetTop) - rect.startY;
update = true;
}
}
init();
.hide{
display: none !important;
}
canvas{
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display:inline-block;
background:rgba(0,0,0,0.3);
}
<div style="position: relative; overflow: hidden;display:inline-block;">
<img id="photo" src="http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg"/>
<canvas id="canvas"></canvas>
</div>
<div id="buttons" class="hide"></div>
In my example I set the background of the canvas to what I will but I cannot remove that background for the drawn rect, it has the same color as the canvas.
Here is the fiddle.
Any idea how to solve it?
This could be achieved in several ways (compositing, clip-path...) but the easiest for such a simple path is probably to use the "evenodd" fill-rule parameter of fill() method which will allow us to draw this rectangle with a hole.
The process is simply to draw a first rect the size of the canvas, then, in the same path declaration, draw your own smaller rectangle. The fill-rule will then exclude this smaller inner rectangle from the bigger one.
function drawRect() {
ctx.beginPath(); // a single path
// the big rectangle, covering the whole canvas
ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height);
// your smaller, inner rectangle
ctx.setTransform(1, 0, 0, 1, rect.startX + rect.w / 2, rect.startY + rect.h / 2);
ctx.rotate(rect.rotate);
ctx.rect(-rect.w / 2, -rect.h / 2, rect.w, rect.h);
// set the fill-rule to evenodd
ctx.fill('evenodd');
// stroke
// start a new Path declaration
ctx.beginPath
// redraw only the small rect
ctx.rect(-rect.w / 2, -rect.h / 2, rect.w, rect.h);
ctx.stroke();
}
var canvas = document.getElementById('canvas');
var img = document.getElementById('photo');
var ctx = canvas.getContext('2d');
var rect = {};
var drag = false;
var update = true; // when true updates canvas
var original_source = img.src;
img.src = original_source;
function init() {
img.addEventListener('load', function() {
canvas.width = img.width;
canvas.height = img.height;
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
// set our context's styles here
ctx.fillStyle = 'rgba(0,0,0,.5)';
ctx.strokeStyle = 'white';
ctx.lineWidth = 2;
});
// start the rendering loop
requestAnimationFrame(updateCanvas);
}
// main render loop only updates if update is true
function updateCanvas() {
if (update) {
drawCanvas();
update = false;
}
requestAnimationFrame(updateCanvas);
}
// draws a rectangle with rotation
// clears canvas sets filters and draws rectangles
function drawCanvas() {
// restore the default transform as rectangle rendering does not restore the transform.
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawRect()
}
// create new rect add to array
function mouseDown(e) {
rect = {
startX: e.offsetX,
startY: e.offsetY,
w: 1,
h: 1,
rotate: 0,
};
drag = true;
}
function mouseUp() {
drag = false;
buttons_shown = true;
update = true;
}
function mouseMove(e) {
if (drag) {
rect.w = (e.pageX - this.offsetLeft) - rect.startX;
rect.h = (e.pageY - this.offsetTop) - rect.startY;
update = true;
}
}
init();
.hide {
display: none !important;
}
canvas {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: inline-block;
background: rgba(0, 0, 0, 0.3);
}
<div style="position: relative; overflow: hidden;display:inline-block;">
<img id="photo" src="http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg" />
<canvas id="canvas"></canvas>
</div>
<div id="buttons" class="hide"></div>
Try filling your rect before calling ctx.stroke(), like this:
ctx.fillStyle = "rgba(255, 255, 255, 0.3)";
ctx.fill();
This will produce similar effect to what you have shown in your question. Now the inside of rectangle has both css and fillStyle effect, so it's not ideal - for even better effect you would have to fill outside of rect with desired style instead of setting background in css.
first, draw a full canvas with semi-transparent background, like
ctx.fillStyle = 'rgba(32, 32, 32, 0.7)';
ctx.fillRect(0, 0, width, height);
Then just clear your rectangular form this canvas
ctx.clearRect(x, y, mini_width, mini_height);

Moving a canvas from left to right is not smooth and fast

I want to move one canvas on top of another. when top canvas moves the base canvas displays its x and y. The event initially starts at mouse down. so press mouse and start moving the canvas moves smoothly from right to left but not left to right.
http://jsfiddle.net/happyomi/23PL3/3/
<head>
<style type="text/css">
body, html {
margin: 0;
}
canvas {
position: absolute;
/* top: 0;
left: 0;*/
}
#temp {
background-color: pink;
}
</style>
</head>
<body style="margin: 0; padding: 0; height: 100%; width: 100%; overflow: hidden;">
<canvas id="myCanvas" style="display: block;">
Your browser does not support the HTML5 canvas tag.
</canvas>
<canvas id="temp" style="position: relative">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script type="text/javascript">
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var hgap = 0;
var vgap = 0;
var rows, cols;
var annotation_x = 1;
var row = 0; var col = 0;
//ctx.font = "14px Arial";
c.width = $(document).width();
c.height = $(document).height();
var t = document.getElementById("temp");
tctx = t.getContext("2d");
// tctx.lineWidth = 10;
tctx.lineJoin = 'round';
tctx.lineCap = 'round';
tctx.strokStyle = 'red';
var mouse = { x: 0, y: 0 };
c.addEventListener('mousemove', function (evt) {
mouse.x = evt.pageX;
mouse.y = evt.pageY;
}, false);
c.addEventListener('mousedown', function (evt) {
// tctx.clearRect(0, 0, c.width, c.height);
evt.preventDefault();
ctx.clearRect(0, 0, c.width, c.height);
tctx.clearRect(0, 0, c.width, c.height);
mouse.x = evt.pageX;
mouse.y = evt.pageY;
t.style.left = mouse.x + "px";
t.style.top = mouse.y + "px";
t.style.position = "absolute";
str = "x=" + mouse.x + " y=" + mouse.y;
ctx.fillText(str, 10, 10);
c.addEventListener('mousemove', onPaint, false);
}, false);
var onPaint = function () {
ctx.clearRect(0, 0, c.width, c.height);
tctx.clearRect(0, 0, t.width, t.height);
t.style.left = mouse.x + "px";
t.style.top = mouse.y + "px";
t.style.position = "absolute";
str = "x=" + mouse.x + " y=" + mouse.y;
ctx.fillText(str, 10, 10);
}
c.addEventListener('mouseup', function () {
c.removeEventListener('mousemove', onPaint, false);
}, false);
</script>
</body>
Heres A good Starting point for ya :) it does what your looking for. jsFiddle
/* Main Canvas */
var main = document.getElementById('main');
main.width = window.innerWidth;
main.height = window.innerHeight;
var mainCtx = main.getContext('2d');
var mainFill = '#000';
mainCtx.fillStyle = mainFill;
mainCtx.rect(0,0,main.width,main.height);
mainCtx.fill();
/* secondary canvas */
var cv = document.createElement('canvas');
cv.style.position = 'absolute';
cv.width = '200';
cv.height = '100';
cv.style.left = '0px';
cv.style.top = '0px';
var ctx = cv.getContext('2d');
var fillRect = '#ccc';
var fillText = '#000';
ctx.fillStyle = fillRect;
ctx.rect(0,0,cv.width,cv.height);
ctx.fill();
//draw this canvas to main canvas
mainCtx.drawImage(cv,parseInt(cv.style.left),parseInt(cv.style.top));
var isHolding = false;
var mDown = function(e)
{
isHolding = true;
main.addEventListener('mousemove',mMove);
}
var mMove = function(e)
{
console.log('moving');
if(isHolding)
{
var xPos = e.pageX;
var yPos = e.pageY;
cv.style.left = (xPos-(cv.width/2))+'px';
cv.style.top = (yPos-(cv.height/2))+'px';
cv.width = cv.width; //clears canvas
ctx.fillStyle = fillRect;
ctx.rect(0,0,cv.width,cv.height);
ctx.fill();
ctx.fillStyle = fillText;
ctx.fillText('x: '+e.pageX,10,10);
ctx.fillText('y: '+e.pageY,50,10);
//draw temp canvas to main canvas
this.width = this.width;
mainCtx.fillStyle = mainFill;
mainCtx.rect(0,0,main.width,main.height);
mainCtx.fill();
mainCtx.drawImage(cv,parseInt(cv.style.left),parseInt(cv.style.top));
}
}
var mUp = function(e)
{
isHolding = false;
main.removeEventListener('mousemove',mMove);
}
main.addEventListener('mousedown',mDown);
main.addEventListener('mouseup',mUp);
also it gets rid of the move event when not being used which will help have less event dispatches in memory and help with performance.

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