Rotate functionality is not working on onmousedown? - javascript

So I am following this code to implement rotate function in my paint program:
http://jsfiddle.net/QqwKR/412/
However, the image img doesn't load up and instead a yellow filled rectangle shows up.
Also when I add the rotate function, the code stops working:
function rotate() {
flag = 4;
var img = new Image();
img.onload = function () {
w = img.width / 2;
h = img.height / 2;
draw();
}
img.src = "https://image.flaticon.com/teams/new/1-freepik.jpg";
}
In html I add the following:
<button onclick="rotate()" style="height:100px;width:100px;">rotate</button>
Any ideas why this is happening?

A big yellow rectangle shows up because you draw a big yellow rectangle over the image. Copied from the code:
function drawRect() {
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(r);
ctx.drawImage(img, 0, 0, img.width, img.height, -w / 2, -h / 2, w, h);
ctx.fillStyle="yellow";
ctx.fillRect(-w/2,-h/2,w,h); // <-- Here.
ctx.restore();
}
If you remove those two lines, the handle works just fine.
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 cx = canvas.width / 2;
var cy = canvas.height / 2;
var w;
var h;
var r = 0;
var img = new Image();
img.onload = function () {
w = img.width / 2;
h = img.height / 2;
draw();
}
img.src = "https://image.flaticon.com/teams/new/1-freepik.jpg";
function draw() {
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, -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(w / 2 + 20, -1);
ctx.lineTo(w / 2 + 20, -7);
ctx.lineTo(w / 2 + 30, -7);
ctx.lineTo(w / 2 + 30, 7);
ctx.lineTo(w / 2 + 20, 7);
ctx.lineTo(w / 2 + 20, 1);
ctx.lineTo(0, 1);
ctx.closePath();
if (withFill) {
ctx.fillStyle = "blue";
ctx.fill();
}
ctx.restore();
}
function handleMouseDown(e) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
drawRotationHandle(false);
isDown = ctx.isPointInPath(mouseX, mouseY);
// console.log(isDown);
}
function handleMouseUp(e) {
isDown = false;
}
function handleMouseOut(e) {
isDown = false;
}
function handleMouseMove(e) {
if (!isDown) {
return;
}
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
var dx = mouseX - cx;
var dy = mouseY - cy;
var angle = Math.atan2(dy, dx);
r = angle;
draw();
}
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function (e) {
handleMouseOut(e);
});
body {
background-color: ivory;
}
#canvas {
border:1px solid red;
}
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<p>Rotate by dragging blue rotation handle</p>
<canvas id="canvas" width=300 height=300></canvas>
Regarding the button and the rotate function, I have no idea what you want to achieve with that.

Related

Canvas Arrowhead

Please look at the code for Canvas arrowhead why the arrowhead disappears every time you draw a new line. And how can I fix it? sorry for my english thank you
I want this section to be used to draw matching lines. But I have a problem with arrowheads. I hope someone can help me with a problem I'm not good at and can't find a solution.
https://jsfiddle.net/liptonkingza/4vn3uyb9/1/
Code
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var storedLines = [];
var startX = 0;
var startY = 0;
var isDown;
ctx.strokeStyle = "orange";
ctx.lineWidth = 3;
$("#canvas").mousedown(function(e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function(e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function(e) {
handleMouseUp(e);
});
$("#clear").click(function() {
storedLines.length = 0;
redrawStoredLines();
});
function handleMouseDown(e) {
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
isDown = true;
startX = mouseX;
startY = mouseY;
}
function arrow (p1, p2, size) {
var angle = Math.atan2((p2.y - p1.y) , (p2.x - p1.x));
var hyp = Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
ctx.save();
ctx.translate(p1.x, p1.y);
ctx.rotate(angle);
// line
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(hyp - size, 0);
ctx.stroke();
// triangle
ctx.fillStyle = 'orange';
ctx.beginPath();
ctx.lineTo(hyp - size, size);
ctx.lineTo(hyp, 0);
ctx.lineTo(hyp - size, -size);
ctx.fill();
ctx.restore();
}
function handleMouseMove(e) {
if (!isDown) {
return;
}
redrawStoredLines();
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
// draw the current line
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(mouseX, mouseY);
arrow({x: startX, y: startY}, {x: mouseX, y: mouseY}, 10);
ctx.stroke();
}
function handleMouseUp(e) {
isDown = false;
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
storedLines.push({
x1: startX,
y1: startY,
x2: mouseX,
y2: mouseY
});
redrawStoredLines();
arrow({x: startX, y: startY}, {x: mouseX, y: mouseY}, 10);
}
function redrawStoredLines() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (storedLines.length == 0) {
return;
}
// redraw each stored line
for (var i = 0; i < storedLines.length; i++) {
ctx.beginPath();
ctx.moveTo(storedLines[i].x1, storedLines[i].y1);
ctx.lineTo(storedLines[i].x2, storedLines[i].y2);
ctx.stroke();
}
}
body {
background-color: ivory;
padding: 10px;
}
canvas {
border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Drag to draw lines</p>
<canvas id="canvas" width=300 height=300></canvas>
<br/>
<button id="clear">Clear Canvas</button>
Your redrawStoredLines function is only drawing lines and not including the arrow.
Replace this:
function redrawStoredLines() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (storedLines.length == 0) {
return;
}
// redraw each stored line
for (var i = 0; i < storedLines.length; i++) {
ctx.beginPath();
ctx.moveTo(storedLines[i].x1, storedLines[i].y1);
ctx.lineTo(storedLines[i].x2, storedLines[i].y2);
ctx.stroke();
}
}
With:
function redrawStoredLines() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (storedLines.length == 0) {
return;
}
// redraw each stored line
for (var i = 0; i < storedLines.length; i++) {
arrow({x: storedLines[i].x1, y: storedLines[i].y1}, {x: storedLines[i].x2, y: storedLines[i].y2}, 10);
}
}
See it in action...
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var storedLines = [];
var startX = 0;
var startY = 0;
var isDown;
ctx.strokeStyle = "orange";
ctx.lineWidth = 3;
$("#canvas").mousedown(function(e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function(e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function(e) {
handleMouseUp(e);
});
$("#clear").click(function() {
storedLines.length = 0;
redrawStoredLines();
});
function handleMouseDown(e) {
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
isDown = true;
startX = mouseX;
startY = mouseY;
}
function arrow (p1, p2, size) {
var angle = Math.atan2((p2.y - p1.y) , (p2.x - p1.x));
var hyp = Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
ctx.save();
ctx.translate(p1.x, p1.y);
ctx.rotate(angle);
// line
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(hyp - size, 0);
ctx.stroke();
// triangle
ctx.fillStyle = 'orange';
ctx.beginPath();
ctx.lineTo(hyp - size, size);
ctx.lineTo(hyp, 0);
ctx.lineTo(hyp - size, -size);
ctx.fill();
ctx.restore();
}
function handleMouseMove(e) {
if (!isDown) {
return;
}
redrawStoredLines();
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
// draw the current line
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(mouseX, mouseY);
arrow({x: startX, y: startY}, {x: mouseX, y: mouseY}, 10);
ctx.stroke();
}
function handleMouseUp(e) {
isDown = false;
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
storedLines.push({
x1: startX,
y1: startY,
x2: mouseX,
y2: mouseY
});
redrawStoredLines();
arrow({x: startX, y: startY}, {x: mouseX, y: mouseY}, 10);
}
function redrawStoredLines() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (storedLines.length == 0) {
return;
}
// redraw each stored line
for (var i = 0; i < storedLines.length; i++) {
arrow({x: storedLines[i].x1, y: storedLines[i].y1}, {x: storedLines[i].x2, y: storedLines[i].y2}, 10);
}
}
body {
background-color: ivory;
padding: 10px;
}
canvas {
border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Drag to draw lines</p>
<canvas id="canvas" width=300 height=300></canvas>
<br/>
<button id="clear">Clear Canvas</button>

JavaScript canvas moving element to target coordinates

I'm trying to move an element (with its own starting coordinates) to a custom position on the canvas.
How can I make it move to the new position directly (following a straight line)?
<html>
<head></head>
<body>
<canvas id="canvas" width="600px" height="600px"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var mouseX, mouseY;
document.addEventListener("click", function (e) {
mouseX = e.clientX;
mouseY = e.clientY;
console.log(mouseX, mouseY)
})
function background() {
ctx.fillStyle = "#505050";
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
var ball = {
x: 100,
y: 100,
draw: function () {
ctx.fillStyle = "#F00000";
ctx.beginPath();
ctx.arc(this.x, this.y, 30, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
}
}
setInterval(function () {
background();
ball.draw()
//example
if (mouseX > ball.x)
ball.x++;
if (mouseY > ball.y)
ball.y++;
}, 1000 / 60)
</script>
</body>
</html>
The thing under //example can work only for pure left/right/up/down/diagonal movement, but doesn't work as intended for custom locations other than those.
I want it to always travel directly to a custom location, following a straight line.
You should work with dx and dy to figure out how far to move each direction on each render. I also recommend to use window.requestAnimationFrame to call draw on each frame. You can also set stepWidthFactor relative to the distance.
<canvas id="canvas" width="600px" height="600px"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var stepWidthFactor = 200;
var mouseX, mouseY;
function background() {
ctx.fillStyle = "#505050";
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
var ball = {
x: 100,
y: 100,
dx: 0,
dy: 0,
draw: function () {
ctx.fillStyle = "#F00000";
ctx.beginPath();
ctx.arc(this.x, this.y, 30, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
}
}
function draw() {
background();
ball.draw();
var shouldMove = Math.abs(ball.x - mouseX) > 1 || Math.abs(ball.y - mouseY) > 1;
if(shouldMove) {
ball.x += ball.dx;
ball.y += ball.dy;
} else {
ball.dx = 0;
ball.dy = 0;
}
window.requestAnimationFrame(draw)
}
document.addEventListener("click", function (e) {
mouseX = e.clientX;
mouseY = e.clientY;
ball.dx = (ball.x - mouseX) / stepWidthFactor * -1;
ball.dy = (ball.y - mouseY) / stepWidthFactor * -1;
})
draw();
</script>

How to draw parallel rectangles with rubber-band in canvas

I am trying to draw a group of shapes using canvas.
I have referenced below SO threads:
Draw a parallel line
How to draw parallel line using three.js?
but not able to figure out how to calculate points for the rectangles parallel in as we stretch the line.
Any reference for stretching shapes with canvas is appreciated.
//Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//Variables
var canvasx = $(canvas).offset().left;
var canvasy = $(canvas).offset().top;
var last_mousex = last_mousey = 0;
var mousex = mousey = 0;
var mousedown = false;
// grid parameters
var gridSpacing = 20; // pixels
var gridWidth = 1;
//var gridColor = "#f1f1f1";
var gridColor = "lightgray";
/** */
var originX = 0;
/** */
var originY = 0;
drawGrid();
//Mousedown
$(canvas).on('mousedown', function(e) {
last_mousex = parseInt(e.clientX-canvasx);
last_mousey = parseInt(e.clientY-canvasy);
mousedown = true;
});
//Mouseup
$(canvas).on('mouseup', function(e) {
mousedown = false;
});
//Mousemove
$(canvas).on('mousemove', function(e) {
mousex = parseInt(e.clientX-canvasx);
mousey = parseInt(e.clientY-canvasy);
if(mousedown) {
ctx.clearRect(0,0,canvas.width,canvas.height); //clear canvas
drawGrid();
ctx.setLineDash([5, 15]);
ctx.beginPath();
ctx.moveTo(last_mousex,last_mousey);
ctx.lineTo(mousex,mousey);
//ctx.lineTo(mousex,mousey);
ctx.strokeStyle = 'blue';
ctx.lineDashOffset = 2;
ctx.lineWidth = 5;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.stroke();
startx = last_mousex;
starty = last_mousey;
drawPolygon([last_mousex, mousex, mousex, last_mousex, last_mousex],
[last_mousey-10, mousey-10, mousey-60, last_mousey-60],true, 'gray', false, 'black', 2);
drawPolygon([last_mousex, mousex, mousex, last_mousex, last_mousex],
[last_mousey+10, mousey+10, mousey+60, last_mousey+60],true, 'gray', false, 'black', 2);
}
//Output
$('#output').html('current: '+mousex+', '+mousey+'<br/>last: '+last_mousex+', '+last_mousey+'<br/>mousedown: '+mousedown);
});
/** */
function drawLine(startX, startY, endX, endY, width, color) {
// width is an integer
// color is a hex string, i.e. #ff0000
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.stroke();
}
function drawPolygon(xArr, yArr, fill, fillColor, stroke, strokeColor, strokeWidth) {
// fillColor is a hex string, i.e. #ff0000
fill = fill || false;
stroke = stroke || false;
ctx.beginPath();
ctx.moveTo(xArr[0], yArr[0]);
for (var i = 1; i < xArr.length; i++) {
ctx.lineTo(xArr[i], yArr[i]);
}
ctx.closePath();
if (fill) {
ctx.fillStyle = fillColor;
ctx.fill();
}
if (stroke) {
ctx.lineWidth = strokeWidth;
ctx.strokeStyle = strokeColor;
ctx.stroke();
}
//console.log(xArr);
//console.log(yArr);
}
/** returns n where -gridSize/2 < n <= gridSize/2 */
function calculateGridOffset(n) {
if (n >= 0) {
return (n + gridSpacing / 2.0) % gridSpacing - gridSpacing / 2.0;
} else {
return (n - gridSpacing / 2.0) % gridSpacing + gridSpacing / 2.0;
}
}
/** */
function drawGrid() {
var offsetX = calculateGridOffset(-originX);
var offsetY = calculateGridOffset(-originY);
var width = canvas.width;
var height = canvas.height;
for (var x = 0; x <= (width / gridSpacing); x++) {
drawLine(gridSpacing * x + offsetX, 0, gridSpacing * x + offsetX, height, gridWidth, gridColor);
}
for (var y = 0; y <= (height / gridSpacing); y++) {
drawLine(0, gridSpacing * y + offsetY, width, gridSpacing * y + offsetY, gridWidth, gridColor);
}
}
canvas {
cursor: crosshair;
border: 1px solid #000000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="800" height="500"></canvas>
<div id="output"></div>
I'm guessing this is what you wanted.
Instead of trying to manually draw your line rotated, instead, move the origin of the canvas to the start of the line,
// save the canvas state
ctx.save();
// move origin to start of line
ctx.translate(last_mousex, last_mousey);
then rotate the origin so it points toward the end of the line in the positive X direction
// compute direction of line from start to end
const dx = mousex - last_mousex;
const dy = mousey - last_mousey;
const angle = Math.atan2(dy, dx);
// rotate to point to end of line
ctx.rotate(angle);
then compute the length of the line from the start to the end
// compute length of line
const length = Math.sqrt(dx * dx + dy * dy);
and just draw an arrow in the positive x direction of that length
ctx.setLineDash([5, 15]);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(length, 0);
ctx.strokeStyle = 'blue';
ctx.lineDashOffset = 2;
ctx.lineWidth = 5;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.stroke();
drawPolygon([0, length, length, 0, 0],
[-10, -10, -60, -60],true, 'gray', false, 'black', 2);
drawPolygon([0, length, length, 0, 0],
[+10, +10, +60, +60],true, 'gray', false, 'black', 2);
// restore the canvas state
ctx.restore();
while we're at it your code for calculating the mouse position didn't work if the page is scrolled. This will get the mouse position relative to the pixels in the canvas.
const rect = canvas.getBoundingClientRect();
mousex = (e.clientX - rect.left) * canvas.width / canvas.clientWidth;
mousey = (e.clientY - rect.top ) * canvas.height / canvas.clientHeight;
//Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//Variables
var last_mousex = last_mousey = 0;
var mousex = mousey = 0;
var mousedown = false;
// grid parameters
var gridSpacing = 20; // pixels
var gridWidth = 1;
//var gridColor = "#f1f1f1";
var gridColor = "lightgray";
/** */
var originX = 0;
/** */
var originY = 0;
drawGrid();
//Mousedown
$(canvas).on('mousedown', function(e) {
const rect = canvas.getBoundingClientRect();
last_mousex = (e.clientX - rect.left) * canvas.width / canvas.clientWidth;
last_mousey = (e.clientY - rect.top ) * canvas.height / canvas.clientHeight;
mousedown = true;
});
//Mouseup
$(canvas).on('mouseup', function(e) {
mousedown = false;
});
//Mousemove
$(canvas).on('mousemove', function(e) {
const rect = canvas.getBoundingClientRect();
mousex = (e.clientX - rect.left) * canvas.width / canvas.clientWidth;
mousey = (e.clientY - rect.top ) * canvas.height / canvas.clientHeight;
if(mousedown) {
ctx.clearRect(0,0,canvas.width,canvas.height); //clear canvas
drawGrid();
// save the canvas state
ctx.save();
// move origin to start of line
ctx.translate(last_mousex, last_mousey);
// compute direction of line from start to end
const dx = mousex - last_mousex;
const dy = mousey - last_mousey;
const angle = Math.atan2(dy, dx);
// rotate to point to end of line
ctx.rotate(angle);
// compute length of line
const length = Math.sqrt(dx * dx + dy * dy);
ctx.setLineDash([5, 15]);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(length, 0);
ctx.strokeStyle = 'blue';
ctx.lineDashOffset = 2;
ctx.lineWidth = 5;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.stroke();
drawPolygon([0, length, length, 0, 0],
[-10, -10, -60, -60],true, 'gray', false, 'black', 2);
drawPolygon([0, length, length, 0, 0],
[+10, +10, +60, +60],true, 'gray', false, 'black', 2);
// restore the canvas state
ctx.restore();
}
//Output
$('#output').html('current: '+mousex+', '+mousey+'<br/>last: '+last_mousex+', '+last_mousey+'<br/>mousedown: '+mousedown);
});
/** */
function drawLine(startX, startY, endX, endY, width, color) {
// width is an integer
// color is a hex string, i.e. #ff0000
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.stroke();
}
function drawPolygon(xArr, yArr, fill, fillColor, stroke, strokeColor, strokeWidth) {
// fillColor is a hex string, i.e. #ff0000
fill = fill || false;
stroke = stroke || false;
ctx.beginPath();
ctx.moveTo(xArr[0], yArr[0]);
for (var i = 1; i < xArr.length; i++) {
ctx.lineTo(xArr[i], yArr[i]);
}
ctx.closePath();
if (fill) {
ctx.fillStyle = fillColor;
ctx.fill();
}
if (stroke) {
ctx.lineWidth = strokeWidth;
ctx.strokeStyle = strokeColor;
ctx.stroke();
}
//console.log(xArr);
//console.log(yArr);
}
/** returns n where -gridSize/2 < n <= gridSize/2 */
function calculateGridOffset(n) {
if (n >= 0) {
return (n + gridSpacing / 2.0) % gridSpacing - gridSpacing / 2.0;
} else {
return (n - gridSpacing / 2.0) % gridSpacing + gridSpacing / 2.0;
}
}
/** */
function drawGrid() {
var offsetX = calculateGridOffset(-originX);
var offsetY = calculateGridOffset(-originY);
var width = canvas.width;
var height = canvas.height;
for (var x = 0; x <= (width / gridSpacing); x++) {
drawLine(gridSpacing * x + offsetX, 0, gridSpacing * x + offsetX, height, gridWidth, gridColor);
}
for (var y = 0; y <= (height / gridSpacing); y++) {
drawLine(0, gridSpacing * y + offsetY, width, gridSpacing * y + offsetY, gridWidth, gridColor);
}
}
canvas {
cursor: crosshair;
border: 1px solid #000000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="800" height="500"></canvas>
<div id="output"></div>

Using arc to create a circle in javascript

I am creating a canvas dynamically and then drawing a circle.
However, as shown, the circle appears stretched and offset:
var max = 50;
var canvas = document.createElement('canvas');
canvas.id = "mazecanvas";
var size = (document.documentElement.clientWidth / 100) * max;
canvas.style.width = size + "px";
canvas.style.height = size + "px";
canvas.style.position = "absolute";
canvas.style.left = size / 2 + "px";
canvas.style.top = (document.documentElement.clientHeight / 2) - (size / 2) + "px";
document.body.appendChild(canvas);
var x, y;
var ctx = canvas.getContext('2d');
function circle() {
ctx.globalCompositeOperation = "destination-in";
ctx.beginPath();
console.log(x, y);
ctx.arc(x, y, 10, 0, 2 * Math.PI, false);
ctx.closePath();
ctx.fill();
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
canvas.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(canvas, evt);
x = mousePos.x;
y = mousePos.y;
}, false);
function draw() {
ctx.globalCompositeOperation = "source-over";
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < max; i++) {
for (var j = 0; j < max; j++) {
ctx.fillStyle = 'rgb(' + Math.floor(255 - 5.5 * i) + ',' + Math.floor(255 - 5.5 * j) + ',0)';
ctx.fillRect(j * (canvas.width / max), i * (canvas.height / max), canvas.width / max, canvas.height / max);
}
}
circle();
setTimeout(draw, 10);
}
draw();
I do not understand what I am doing wrong, I know it is to do with the canvas creation as when I remove it, and replace it with a static one, the problem is gone:
var max = 50;
var canvas = document.getElementById('canvas');
var x, y;
var ctx = canvas.getContext('2d');
function circle() {
ctx.globalCompositeOperation = "destination-in";
ctx.beginPath();
console.log(x, y);
ctx.arc(x, y, 10, 0, 2 * Math.PI, false);
ctx.closePath();
ctx.fill();
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
canvas.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(canvas, evt);
x = mousePos.x;
y = mousePos.y;
}, false);
function draw() {
ctx.globalCompositeOperation = "source-over";
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < max; i++) {
for (var j = 0; j < max; j++) {
ctx.fillStyle = 'rgb(' + Math.floor(255 - 5.5 * i) + ',' + Math.floor(255 - 5.5 * j) + ',0)';
ctx.fillRect(j * (canvas.width / max), i * (canvas.height / max), canvas.width / max, canvas.height / max);
}
}
circle();
setTimeout(draw, 10);
}
draw();
<canvas id="canvas"></canvas>
Setting the canvas's CSS style will stretch and squish the pixels. That's why your circle becomes an oval.
Instead, set the canvas element's width and height. This actually adds (or removes) pixels to the canvas to become the specified size. This will keep your circle circular. ;-)
canvas.width=500; // no need to add "px"
canvas.height=400;

Scaling with rotating image using html5 canvas

I have using scaling and rotation of images using mouse dragging separately. but i need to combine both the operations.
Please refer jsfiddle files for your understanding.
Scaling - http://jsfiddle.net/QqwKR/74/
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 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 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;
}
// enforce minimum dimensions of 25x25
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);
});
Rotating - http://jsfiddle.net/m1erickson/QqwKR/
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 cx = canvas.width / 2;
var cy = canvas.height / 2;
var w;
var h;
var r = 0;
var img = new Image();
img.onload = function () {
w = img.width / 2;
h = img.height / 2;
draw();
}
img.src = "https://dl.dropboxusercontent.com/u/139992952/stackoverflow/facesSmall.png";
function draw() {
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, -w / 2, -h / 2, 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(w / 2 + 20, -1);
ctx.lineTo(w / 2 + 20, -7);
ctx.lineTo(w / 2 + 30, -7);
ctx.lineTo(w / 2 + 30, 7);
ctx.lineTo(w / 2 + 20, 7);
ctx.lineTo(w / 2 + 20, 1);
ctx.lineTo(0, 1);
ctx.closePath();
if (withFill) {
ctx.fillStyle = "blue";
ctx.fill();
}
ctx.restore();
}
function handleMouseDown(e) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
drawRotationHandle(false);
isDown = ctx.isPointInPath(mouseX, mouseY);
console.log(isDown);
}
function handleMouseUp(e) {
isDown = false;
}
function handleMouseOut(e) {
isDown = false;
}
function handleMouseMove(e) {
if (!isDown) {
return;
}
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
var dx = mouseX - cx;
var dy = mouseY - cy;
var angle = Math.atan2(dy, dx);
r = angle;
draw();
}
$("#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 need to work scaling with rotation of image. ie) Four anchor points with rotating handle

Categories