Related
A few of my circle objects are not bouncing back, even though I have tried to take care of the edge cases.
I followed everything from here -
https://www.youtube.com/watch?v=yq2au9EfeRQ
I've tried different ways of passing the Window width and height and changing them in different ways using the radius:
var canvas = document.querySelector('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var iW = window.innerWidth;
var iH = window.innerHeight;
var c = canvas.getContext('2d');
function Circle(x, y, dx, dy, radius) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.radius = radius;
this.draw = function() {
c.beginPath();
c.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
c.strokeStyle = "orange";
c.stroke();
}
this.update = function() {
if (this.x + this.radius > iW || this.x - this.radius < 0) {
this.dx = ~this.dx;
}
if (this.y + this.radius > iH || this.y - this.radius < 0) {
this.dy = ~this.dy;
}
this.x += this.dx;
this.y += this.dy;
this.draw();
}
}
var circleArray = [];
for (var i = 0; i < 100; i++) {
var radius = 30;
var x = Math.random() * (iW - radius * 2) + radius;
var y = Math.random() * (iH - radius * 2) + radius;
var dx = Math.random() * 5;
var dy = Math.random() * 5;
circleArray.push(new Circle(x, y, dx, dy, radius));
}
function animate() {
requestAnimationFrame(animate);
c.clearRect(0, 0, iW, iH);
for (var i = 0; i < circleArray.length; i++) {
circleArray[i].update();
}
}
animate();
canvas { border : 1px solid black; }
body { margin :0; }
<canvas>abcd</canvas>
The circles are getting stuck and then are going out of the window after vibrating where they get stuck. They should bounce back but only a few are bouncing back. I am using brackets and also am getting an undefined error I don't know if that error is what is causing this problem.
You are not negating the dx and dy values. Instead you are flipping all their binary bits. But then note how ~(-1) === 0. This roughly explains the problem you see: circles that only move with -1 in either direction, will "bounce" to a move of 0 in that same direction. Consequently they are bouncing again on the next cycle, where they start moving with -1 again, ... and so they wiggle off the canvas.
So just use the minus operator:
this.dx = -this.dx;
this.dy = -this.dy;
I am trying to extend a line (from to points(X,Y)) to the end of the drawing area.
so far i found a couple of instructions on how to calculate the extension end point.
however i don't really get it done it works in one direction and breaks as soon as you reach over the middle point.
see attached code sample (the real product i am working on is in swift, but as it is not a programming language related issue, i ported it to javascript)
on the right side it seems to work, black line is the one the user selects, red one is the extension to the edge of canvas, going to the left side produces garbage.
var canvas = document.getElementById("myCanvas");
var endPoint = {
x: 200,
y: 200
};
function draw() {
//Demo only in final product user also can select the startpoint
startPoint = {
x: 150,
y: 150
}
screenMax = {
x: canvas.height,
y: canvas.width
}
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.moveTo(startPoint.x, startPoint.y);
ctx.lineTo(endPoint.x, endPoint.y);
ctx.strokeStyle = "#000000";
ctx.stroke();
//Extend line to end of canvas according to slope
var slope = 1.0
var extendedPoint = {
x: 0,
y: 0
}
if (endPoint.x != startPoint.x) {
slope = (endPoint.y - startPoint.y) / (endPoint.x - startPoint.x);
extendedPoint = {
x: screenMax.x,
y: slope * (screenMax.x - endPoint.x) + endPoint.y
}
} else {
slope = 0
extendedPoint.x = endPoint.x;
extendedPoint.y = screenMax.y;
}
console.log(endPoint);
//Draw the Extension
ctx.beginPath();
ctx.moveTo(endPoint.x, endPoint.y);
ctx.lineTo(extendedPoint.x, extendedPoint.y);
ctx.strokeStyle = "#FF0000";
ctx.stroke();
}
//initial draw
draw();
//handle Mouse dOwn
canvas.onmousedown = function(e) {
handleMouseDown(e);
}
// handle the mousedown event
//Set new endpoint
function handleMouseDown(e) {
mouseX = parseInt(e.clientX);
mouseY = parseInt(e.clientY);
endPoint = {
x: mouseX,
y: mouseY
}
draw();
}
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="300" height="300" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
</body>
</html>
This function may help, takes the line x1,y1 to x2,y2 and extends it to the border defined by left,top,right,bottom returning the intercept point as {x:?,y:?}
function toBorder(x1, y1, x2, y2, left, top, right, bottom){
var dx, dy, py, vx, vy;
vx = x2 - x1;
vy = y2 - y1;
dx = vx < 0 ? left : right;
dy = py = vy < 0 ? top : bottom;
if(vx === 0){
dx = x1;
}else if(vy === 0){
dy = y1;
}else{
dy = y1 + (vy / vx) * (dx - x1);
if(dy < top || dy > bottom){
dx = x1 + (vx / vy) * (py - y1);
dy = py;
}
}
return {x : dx, y : dy}
}
Slope approach is not universal - it cannot work with vertical lines (x0=x1).
I'd use parametric representation of ray (line)
x0 = startPoint.x
x1 = endPoint.x
y0 = startPoint.y
y1 = endPoint.y
dx = x1 - x0
dy = y1 - y0
x = x0 + dx * t
y = y0 + dy * t
Now check what border will be intersected first (with smaller t value)
//prerequisites: potential border positions
if dx > 0 then
bx = width
else
bx = 0
if dy > 0 then
by = height
else
bx = 0
//first check for horizontal/vertical lines
if dx = 0 then
return ix = x0, iy = by
if dy = 0 then
return iy = y0, ix = bx
//in general case find parameters of intersection with horizontal and vertical edge
tx = (bx - x0) / dx
ty = (by - y0) / dy
//and get intersection for smaller parameter value
if tx <= ty then
ix = bx
iy = y0 + tx * dy
else
iy = by
ix = x0 + ty * dx
return ix, iy
I am developing in html5's canvas element. I have the follwing code and it is draggable and resizable image. How can I turn it to rotatable by a anchor too? How can I provide live rotating by an anchor. I saw other codes samples, but do not know how to implement it.
Sampler Working:
http://jsfiddle.net/LAS8L/588/
<canvas id="canvas" width=350 height=350></canvas>
Javascript
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var isDown = false;
var pi2 = Math.PI * 2;
var resizerRadius = 8;
var rr = resizerRadius * resizerRadius;
var draggingResizer = {
x: 0,
y: 0
};
var imageX = 50;
var imageY = 50;
var imageWidth, imageHeight, imageRight, imageBottom;
var draggingImage = false;
var startX;
var startY;
var cx = canvas.width / 2;
var cy = canvas.height / 2;
var w;
var h;
var r = 0;
var img = new Image();
img.onload = function () {
imageWidth = img.width;
imageHeight = img.height;
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight
draw(true, false);
}
img.src = "https://dl.dropboxusercontent.com/u/139992952/stackoverflow/facesSmall.png";
function draw(withAnchors, withBorders) {
// clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw the image
ctx.drawImage(img, 0, 0, img.width, img.height, imageX, imageY, imageWidth, imageHeight);
// optionally draw the draggable anchors
if (withAnchors) {
drawDragAnchor(imageX, imageY);
drawDragAnchor(imageRight, imageY);
drawDragAnchor(imageRight, imageBottom);
drawDragAnchor(imageX, imageBottom);
}
// optionally draw the connecting anchor lines
if (withBorders) {
ctx.beginPath();
ctx.moveTo(imageX, imageY);
ctx.lineTo(imageRight, imageY);
ctx.lineTo(imageRight, imageBottom);
ctx.lineTo(imageX, imageBottom);
ctx.closePath();
ctx.stroke();
}
}
function drawDragAnchor(x, y) {
ctx.beginPath();
ctx.arc(x, y, resizerRadius, 0, pi2, false);
ctx.closePath();
ctx.fill();
}
function anchorHitTest(x, y) {
var dx, dy;
// top-left
dx = x - imageX;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (0);
}
// top-right
dx = x - imageRight;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (1);
}
// bottom-right
dx = x - imageRight;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (2);
}
// bottom-left
dx = x - imageX;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (3);
}
return (-1);
}
function desenhe() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawRotationHandle(true);
drawRect();
}
function drawRect() {
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(r);
ctx.drawImage(img, 0, 0, img.width, img.height, -imageWidth, -imageheight, w, h);
// ctx.fillStyle="yellow";
// ctx.fillRect(-w/2,-h/2,w,h);
ctx.restore();
}
function drawRotationHandle(withFill) {
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(r);
ctx.beginPath();
ctx.moveTo(0, -1);
ctx.lineTo(imageWidth + 20, -1);
ctx.lineTo(imageWidth + 20, -7);
ctx.lineTo(imageWidth + 30, -7);
ctx.lineTo(imageWidth + 30, 7);
ctx.lineTo(imageWidth + 20, 7);
ctx.lineTo(imageWidth + 20, 1);
ctx.lineTo(0, 1);
ctx.closePath();
if (withFill) {
ctx.fillStyle = "blue";
ctx.fill();
}
ctx.restore();
}
function hitImage(x, y) {
return (x > imageX && x < imageX + imageWidth && y > imageY && y < imageY + imageHeight);
}
function handleMouseDown(e) {
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
draggingResizer = anchorHitTest(startX, startY);
draggingImage = draggingResizer < 0 && hitImage(startX, startY);
}
function handleMouseUp(e) {
draggingResizer = -1;
draggingImage = false;
draw(true, false);
}
function handleMouseOut(e) {
handleMouseUp(e);
}
function handleMouseMove(e) {
if (draggingResizer > -1) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// resize the image
switch (draggingResizer) {
case 0:
//top-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageY = mouseY;
imageHeight = imageBottom - mouseY;
break;
case 1:
//top-right
imageY = mouseY;
imageWidth = mouseX - imageX;
imageHeight = imageBottom - mouseY;
break;
case 2:
//bottom-right
imageWidth = mouseX - imageX;
imageHeight = mouseY - imageY;
break;
case 3:
//bottom-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageHeight = mouseY - imageY;
break;
}
if(imageWidth<25){imageWidth=25;}
if(imageHeight<25){imageHeight=25;}
// set the image right and bottom
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight;
// redraw the image with resizing anchors
draw(true, true);
} else if (draggingImage) {
imageClick = false;
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// move the image by the amount of the latest drag
var dx = mouseX - startX;
var dy = mouseY - startY;
imageX += dx;
imageY += dy;
imageRight += dx;
imageBottom += dy;
// reset the startXY for next time
startX = mouseX;
startY = mouseY;
// redraw the image with border
draw(false, true);
}
}
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function (e) {
handleMouseOut(e);
});
I would like to work this way: http://jsfiddle.net/m1erickson/QqwKR/ but I don't know how merge the code. Can somebody help me?
Here is a function the will set the transform to scale rotate and translate an rectangle or anything.
function setTransform(ctx,x,y,scale,rotate){
var xdx = Math.cos(rotate) * scale; // create the x axis
var xdy = Math.sin(rotate) * scale;
ctx.setTransform(xdx, xdy, - xdy, xdx, x, y);
}
The canvas transform is set after that. Now just draw the object in its local space coords.
Eg draw at center of canvas double scale and 45deg rotation
setTransform(ctx,canvas.width/2,canvas.height/2,2,Math.PI /4);
ctx.strokeRect(-100,-100,200,200);
You will notice that the coordinates are negative. This is because I want the center of the box to be at the center of the canvas. If I wanted the top left of the box to be at the center
ctx.strokeRect(0,0,200,200);
or the bottom right
ctx.strokeRect(-200,-200,200,200);
Back to the centered box I can move it anywhere
setTransform(
ctx,
Math.random() * canvas.width, // random x pos
Math.random() * canvas.height, // random y pos
Math.random() * 10 + 0.1, // random scale
Math.random() * Math.PI * 2 // random rotation
);
The transform is random but I do not need to care I can still draw the box in local coordinates.
ctx.strokeRect(-100,-100,200,200);
And it will be draw where ever the transform has set it to.
Using ctx.setTransform saves the hassle of using save and restore.
If at any stage you need to return to the default transform
ctx.setTransform(1,0,0,1,0,0);
The problem you will next face is that the mouse coordinates are in canvas coordinates while the object is in its local space. You need to convert the mouse coordinates into the local object coordinates.
This is done by multiplying the mouse coordinates by the inverse of the matrix. A bit of maths here.
function getMouseLocal(mousex,mouseY,x,y,scale,rot){
var xdx = Math.cos(rotate) * scale; // create the x axis
var xdy = Math.sin(rotate) * scale;
// get the cross product of the two axies
var cross = xdx * xdx - xdy * -xdy;
// or
var cross = Math.pow(xdx,2) + Math.pow(xdy,2);
// then create the inverted axies
var ixdx = xdx / cross; // create inverted x axis
var ixdy = -xdy / cross;
var iydx = xdy / cross; // create inverted y axis
var iydy = xdx / cross;
// now remove the origin from the mouse coords
mouseX -= x;
mouseY -= y;
// multiply by the invers matrix
var localMouseX = mouseX * ixdx + mouseY * iydx;
var localMouseY = mouseX * ixdy + mouseY * iydy;
// and return the result
return {x : localMouseX, y : localMouseY};
}
Now you have the mouse coordinates in the local space. If you need to find out if the mouse is inside the box you
setTransform(ctx,100,100,2,Math.PI/4);
ctx.strokeRect(-100,-100,200,200);
var localMouse= getMouseLocal(mouseX,mouseY,100,100,2,Math.PI/4);
if(localMouse.x > -100 && localMouse.x < -100 + 200 && localMouse.y > -100 && localMouse.y < -100 + 200){
// mouse is inside the box
}
That should give you what you need.
UPDATE
I forgot you want to scale both x and y.. So below are the modified functions for scaling both X and Y axies
// sx and sy are scale x and y
function setTransform(ctx,x,y,sx,sy,rotate){
var xdx = Math.cos(rotate); // create the x axis
var xdy = Math.sin(rotate);
ctx.setTransform(xdx * sx, xdy * sx, - xdy * sy, xdx * sy, x, y);
}
And getting the mouse to local
function getMouseLocal(mousex,mouseY,x,y,sx,sy,rot){
var xdx = Math.cos(rotate); // create the x axis
var xdy = Math.sin(rotate);
// get the cross product of the two axies
var cross = xdx * sx * xdx * sy - xdy *sx * -xdy * sy;
// or
// this shortcut does not work now.
// var cross = Math.pow(xdx,2) + Math.pow(xdy,2);
// then create the inverted axies
var ixdx = (xdx * sy) / cross; // create inverted x axis
var ixdy = (-xdy * sx) / cross;
var iydx = (xdy * sy) / cross; // create inverted y axis
var iydy = (xdx * sx) / cross;
// now remove the origin from the mouse coords
mouseX -= x;
mouseY -= y;
// multiply by the invers matrix
var localMouseX = mouseX * ixdx + mouseY * iydx;
var localMouseY = mouseX * ixdy + mouseY * iydy;
// and return the result
return {x : localMouseX, y : localMouseY};
}
I'm using a HTML canvas to allow a user to edit (move, resize and rotate) an image on bottle to create their own custom one - similar to how a t-shirt designer would work.
It all works (there's a slight issue with the rotate though) up until you resize the screen. Because the canvas is horizontally centred on my page, when you reduce the size (or increase) from the initial load of the page - the canvas thinks the image on is still in its original place. Meaning that you cannot click the image to move it around, you have to click to the right or left (depending on how the screen is resized).
I think there's an issue with the maths, perhaps to do with the window or canvas offset not being updated when you resize the screen, but I cannot work out what the problem is.
Example: https://jsfiddle.net/mpsx1xnj/
The code is as follows:
<div id="design-canvas">
<canvas id="bottleCanvas" width="400" height="600"></canvas>
<center><canvas id="printableCanvas" width="71" height="245"></canvas></center>
<center><canvas id="editorCanvas" width="400" height="600"></canvas></center>
<p class="tooltip">Guidelines show the printable area on the bottle.</p>
</div>
var canvas = document.getElementById("editorCanvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#editorCanvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var isDown = false;
var pi2 = Math.PI * 2;
var resizerRadius = 4;
var rr = resizerRadius * resizerRadius;
var draggingResizer = {
x: 0,
y: 0
};
var imageX = 0;
var imageY;
var imageWidth, imageHeight, imageRight, imageBottom;
var draggingImage = false;
var startX;
var startY;
var ratio;
var img = new Image();
img.crossOrigin='anonymous';
img.onload = function () {
ratio = img.width / img.height;
imageWidth = 71;
imageHeight = imageWidth / ratio;
imageY = (245-imageHeight)/2;
if (imageHeight > 245) {
imageHeight = 245;
imageWidth = imageHeight * ratio;
imageY = 0;
}
imageX = ((canvas.width-imageWidth)/2);
imageY = ((canvas.height-imageHeight)/2);
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight;
draw(true, false);
}
//img.src='https://dl.dropboxusercontent.com/u/139992952/multple/leftarrow.png';
function draw(withAnchors, withBorders) {
// clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw the image
ctx.drawImage(img, 0, 0, img.width, img.height, imageX, imageY, imageWidth, imageHeight);
// optionally draw the draggable anchors
if (withAnchors) {
drawDragAnchor(imageX, imageY);
drawDragAnchor(imageRight, imageY);
drawDragAnchor(imageRight, imageBottom);
drawDragAnchor(imageX, imageBottom);
}
// optionally draw the connecting anchor lines
if (withBorders) {
ctx.beginPath();
ctx.moveTo(imageX, imageY);
ctx.lineTo(imageRight, imageY);
ctx.lineTo(imageRight, imageBottom);
ctx.lineTo(imageX, imageBottom);
ctx.closePath();
ctx.stroke();
}
}
function drawDragAnchor(x, y) {
ctx.beginPath();
ctx.arc(x, y, resizerRadius, 0, pi2, false);
ctx.closePath();
ctx.fill();
}
function anchorHitTest(x, y) {
var dx, dy;
// top-left
dx = x - imageX;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (0);
}
// top-right
dx = x - imageRight;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (1);
}
// bottom-right
dx = x - imageRight;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (2);
}
// bottom-left
dx = x - imageX;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (3);
}
return (-1);
}
function hitImage(x, y) {
return (x > imageX && x < imageX + imageWidth && y > imageY && y < imageY + imageHeight);
}
function handleMouseDown(e) {
offsetX = offsetX + window.pageXOffset;
offsetY = offsetY + window.pageYOffset;
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
draggingResizer = anchorHitTest(startX, startY);
draggingImage = draggingResizer < 0 && hitImage(startX, startY);
}
function handleMouseUp(e) {
draggingResizer = -1;
draggingImage = false;
draw(true, false);
}
function handleMouseOut(e) {
handleMouseUp(e);
}
function handleMouseMove(e) {
if (draggingResizer > -1) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// resize the image
switch (draggingResizer) {
case 0:
//top-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageY = mouseY;
imageHeight = imageBottom - mouseY;
break;
case 1:
//top-right
imageY = mouseY;
imageWidth = mouseX - imageX;
imageHeight = imageWidth/ratio; //imageBottom - mouseY;
break;
case 2:
//bottom-right
imageWidth = mouseX - imageX;
imageHeight = mouseY - imageY;
break;
case 3:
//bottom-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageHeight = mouseY - imageY;
break;
}
if(imageWidth<25){imageWidth=25;}
if(imageHeight<25){imageHeight=25;}
// set the image right and bottom
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight;
// redraw the image with resizing anchors
draw(true, true);
} else if (draggingImage) {
imageClick = false;
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// move the image by the amount of the latest drag
var dx = mouseX - startX;
var dy = mouseY - startY;
imageX += dx;
imageY += dy;
imageRight += dx;
imageBottom += dy;
// reset the startXY for next time
startX = mouseX;
startY = mouseY;
// redraw the image with border
draw(false, true);
}
}
$("#editorCanvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#editorCanvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#editorCanvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#editorCanvas").mouseout(function (e) {
handleMouseOut(e);
});
function rotate(rotationPointX,rotationPointY,degreeRotation){
// Create an second in-memory canvas:
var mCanvas=document.createElement('canvas');
mCanvas.width=canvas.width;
mCanvas.height=canvas.height;
var mctx=mCanvas.getContext('2d');
// Draw your canvas onto the second canvas
mctx.drawImage(canvas,0,0);
// Clear your main canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
// Rotate the main canvas
// set the rotation point as center of the canvas
// (but you can set any rotation point you desire)
ctx.translate(rotationPointX,rotationPointY);
// rotate by 90 degrees (==PI/2)
var radians=degreeRotation/180*Math.PI;
ctx.rotate(radians);
// Draw the second canvas back to the (now rotated) main canvas:
ctx.drawImage(mCanvas,-canvas.width/2,-canvas.height/2);
// clean up -- unrotate and untranslate
ctx.rotate(-radians);
ctx.translate(-canvas.width/2,-canvas.height/2);
}
$(window).on("resize scroll",function(e) {
offsetX = win.left;
offsetY = canvasOffset.top;
imageWidth = 71;
imageHeight = imageWidth / ratio;
imageY = (245-imageHeight)/2;
if (imageHeight > 245) {
imageHeight = 245;
imageWidth = imageHeight * ratio;
imageY = 0;
}
imageX = ((canvas.width-imageWidth)/2);
imageY = ((canvas.height-imageHeight)/2);
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight;
draw(true, false);
});
$('#rotate').click(function(){
rotate((imageX + (canvas.width/2)),(imageY + (canvas.height/2,90)));
});
So my question is how would I fix this issue, so that resizing the window causes no issue?
If i understand you correctly...
Here's a solution: jsFiddle
the width and height attributes of the canvas determine the width or height of the canvas's coordinate system - the page resizing only updates css properties (to make it responsive) which means your fixed width/height attrs always stay the same, even after a resize.
so on page resize
$('canvas#editorCanvas').attr('width', $('#design-canvas').width() );
$('canvas#editorCanvas').attr('height', $('#design-canvas').height() );
make the container responsive using max-height, max-width and setting height/width to 100%
I am making a simple HTML5 Canvas drawing app where a circle is placed at a x and y position each time the mouse moves. The (quite common but unsolved) problem is: when the mouse is moved very fast (as in faster than the mouse move events are triggered), you end up with space in between the circles.
I have used Bresenham's line algorithm to somewhat successfully draw circles between the gaps. However, I have encountered another problem: when the color is one of translucency I get an unintentional fade-to-darker effect.
Here's an example:
I don't understand why this is happening. How would you properly interpolate between two points using Bresenham's line algorithm? Or some other algorithm?
Here's my code: http://jsfiddle.net/E5NBs/
var x = null;
var y = null;
var prevX = null;
var prevY = null;
var spacing = 3;
var drawing = false;
var size = 5;
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
function createFlow(x1, y1, x2, y2, callback) {
var dx = x2 - x1;
var sx = 1;
var dy = y2 - y1;
var sy = 1;
var space = 0;
if (dx < 0) {
sx = -1;
dx = -dx;
}
if (dy < 0) {
sy = -1;
dy = -dy;
}
dx = dx << 1;
dy = dy << 1;
if (dy < dx) {
var fraction = dy - (dx >> 1);
while (x1 != x2) {
if (fraction >= 0) {
y1 += sy;
fraction -= dx;
}
fraction += dy;
x1 += sx;
if (space == spacing) {
callback(x1, y1);
space = 0;
} else {
space += 1;
}
}
} else {
var fraction = dx - (dy >> 1);
while (y1 != y2) {
if (fraction >= 0) {
x1 += sx;
fraction -= dy;
}
fraction += dx;
y1 += sy;
if (space == spacing) {
callback(x1, y1);
space = 0;
} else {
space += 1;
}
}
}
callback(x1, y1);
}
context.fillStyle = '#FFFFFF';
context.fillRect(0, 0, 500, 400);
canvas.onmousemove = function(event) {
x = parseInt(this.offsetLeft);
y = parseInt(this.offsetTop);
if (this.offsetParent != null) {
x += parseInt(this.offsetParent.offsetLeft);
y += parseInt(this.offsetParent.offsetTop);
}
if (navigator.appVersion.indexOf('MSIE') != -1) {
x = (event.clientX + document.body.scrollLeft) - x;
y = (event.clientY + document.body.scrollTop) - y;
} else {
x = event.pageX - x;
y = event.pageY - y;
}
context.beginPath();
if (drawing == true) {
if (((x - prevX) >= spacing || (y - prevY) >= spacing) || (prevX - x) >= spacing || (prevY - y) >= spacing) {
createFlow(x, y, prevX, prevY, function(x, y) {
context.fillStyle = 'rgba(0, 0, 0, 0.1)';
context.arc(x, y, size, 0, 2 * Math.PI, false);
context.fill();
});
prevX = x, prevY = y;
}
} else {
prevX = x, prevY = y;
}
};
canvas.onmousedown = function() {
drawing = true;
};
canvas.onmouseup = function() {
drawing = false;
};
HTML Canvas supports fractional / floating point coordinates, so using an algorithm for integer coordinate based pixel canvas is not necessary and could be considered even counter-productive.
A simple, generic solution would be something along these lines:
when mouse_down:
x = mouse_x
y = mouse_y
draw_circle(x, y)
while mouse_down:
when mouse_moved:
xp = mouse_x
yp = mouse_y
if (x != xp or y != yp):
dir = atan2(yp - y, xp - x)
dist = sqrt(pow(xp - x, 2) + pow(yp - y, 2))
while (dist > 0):
x = x + cos(dir)
y = y + sin(dir)
draw_circle(x, y)
dist = dist - 1
That is, whenever the mouse is moved to a location different from the location of the last circle drawn, walk towards the new location with steps having distance one.
If I understand well, you want to have rgba(0, 0, 0, 0.1) on every point. If so, then you can clear the point before drawing new one.
// this is bad way to clear the point, just I don't know canvas so well
context.fillStyle = 'rgba(255, 255, 255, 1)';
context.arc(x, y, size, 0, 2 * Math.PI, false);
context.fill();
context.fillStyle = 'rgba(0, 0, 0, 0.1)';
context.arc(x, y, size, 0, 2 * Math.PI, false);
context.fill();
I've figured it out.
"context.beginPath();" needed to be in the createFlow callback function like so:
createFlow(x, y, prevX, prevY, function(x, y) {
context.beginPath();
context.fillStyle = 'rgba(0, 0, 0, 0.1)';
context.arc(x, y, size, 0, 2 * Math.PI, false);
context.fill();
});