How to mirror and reverse a movement of a canvas object? - javascript

So I have two objects. SquareA and SquareB. SquareA follows the movement of the cursor. Now I want to make SquareB mirror the movement of SquareA but in reverse.
Example:
SquareA goes left, SquareB goes right.
SquareA goes down, SquareB goes up.
I currently have this code to make squareB follow squareA
// update squareA to mouse
squareA.x = mouseX - (squareB.width * .5);
squareA.y = mouseY - (squareB.height * .5);
// update squareB to squareA
squareB.x = squareA.x;
squareB.y = squareA.y - (squareA.height * 2);
But I can't think of a way to reverse squareB's movement.
Here's the pen for the problem
https://codepen.io/ricjonsu098/pen/xxZrvZP?editors=0010

Full solution:
// create a canvas to work with
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
// style canvas
canvas.id = "canvas";
canvas.width = 400;
canvas.height = 400;
canvas.setAttribute("style", "border: 1px solid black;");
// get 2D context
var context = canvas.getContext('2d');
var squareA = {x:10, y:30, width: 25, height: 25 };
var squareB = {x:10, y:30, width: 25, height: 25 };
// place holders for mouse x,y position
var mouseX = 0;
var mouseY = 0;
var centerX = canvas.width/2;
var centerY = canvas.height/2;
// Render Loop
function update() {
// update squareA to mouse
squareA.x = mouseX - (squareB.width * .5);
squareA.y = mouseY - (squareB.height * .5);
// update squareB to squareA
squareB.x = centerX - (squareA.x - centerX);
squareB.y = centerY - (squareA.y - centerY);
// clear the canvas
canvas.width = canvas.width;
// draw first rectangle
context.fillStyle = "blue";
context.fillRect (squareA.x,squareA.y,squareA.width,squareA.height);
// draw second rectangle
context.fillStyle = "green";
context.fillRect (squareB.x,squareB.y,squareB.width,squareB.height);
}
// update mouse position
canvas.onmousemove = function(e) {
mouseX = e.offsetX;
mouseY = e.offsetY;
update();
}
Note that I got rid of the interval. You can just update whne the mouse moves.

I hope this helps, 400 is canvas size
// update squareA to mouse
squareA.x = mouseX;
squareA.y = mouseY;
// update squareB to squareA
squareB.x = 400 - squareA.x;
squareB.y = 400 - squareA.y;

Related

how to draw lines simultaneously show x & y coordinators on top of mouse pointer using canvas and javascript

draw lines while mouseDown and simultaneously show x & y coordinators on top of mouse pointer while MouseMove using canvas and javascript.
Here x & y coordinators are continuously drawing on top of mouse pointer while MouseMove. Then I am unable Draw Lines while MouseDown since i am using ctxTemp.clearRect(0,0,canvasTemp.width,canvasTemp.height);
if i am not using ctxTemp.clearRect(0,0,canvasTemp.width,canvasTemp.height); then x & y coordinators are continuously drawing on top of mouse pointer while MouseMove.
thanks is advance.
Double buffer
It is a common task to render addition guides (coordinates, widgets, etc...) on the canvas while creating content.
Using a single canvas this become problematic as you are overwriting the content by clearing, or the just painting the guides .
The solution is to use an additional (or more) canvas to separate the content from the guides.
Example
The example shows how this is done.
A second canvas is created call drawing. It matches the size of the canvas on the page.
The mouse draws the stroke to the second canvas.
The main update function draws the second canvas onto the main canvas and then draws the mouse position in a box over that.
As you can not draw outside the canvas some additional code is needed when drawing the mouse position to prevent it from going outside the canvas.
requestAnimationFrame(update);
const ctx = canvas.getContext("2d");
var w = canvas.width, h = canvas.height;
const drawing = createImage(w, h); // create canvas to hold drawing
const pointQueue = []; // holds points when mouse button down
drawing.ctx.lineWidth = 4;
drawing.ctx.strokeStyle = "#F00";
drawing.ctx.lineJoin = "round";
drawing.ctx.lineCap = "round";
ctx.font = "16px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
/* add mouse listeners */
const bounds = canvas.getBoundingClientRect();
const mouse = {x: 0, y: 0, button: false}, events = ["down", "up", "move"];
events.forEach(name => document.addEventListener("mouse" + name, mouseEvents));
function drawMousePos(ctx) {
const text = "X: " + mouse.x.toFixed(0) + " Y: " + mouse.y.toFixed(0);
const width = ctx.measureText(text).width + 8;
var x = mouse.x, y = mouse.y - 18;
if (x + width / 2 > w) { x = w - width / 2 }
if (x - width / 2 < 0) { x = width / 2 }
if (y - 10 < 0) { y = 10 }
if (y + 10 > h) { y = h - 10 }
ctx.fillStyle = "#EEC8";
ctx.fillRect(x - width / 2, y - 12, width , 20);
ctx.strokeRect(x - width / 2, y - 12, width, 20);
ctx.fillStyle = "#000C";
ctx.fillText(text, x, y);
}
function drawPen(ctx) {
if (pointQueue.length >= 2) {
ctx.beginPath();
ctx.moveTo(...pointQueue.shift());
while (pointQueue.length > (mouse.button ? 1 : 0)) { ctx.lineTo(...pointQueue.shift()) }
pointQueue.length && ctx.lineTo(...pointQueue[0]);
ctx.stroke();
}
}
function update(){
if (pointQueue.length) {
drawPen(drawing.ctx);
ctx.clearRect(0, 0, w, h);
ctx.drawImage(drawing, 0, 0);
pointQueue.length && drawMousePos(ctx);
canvas.style.cursor = "none";
} else { canvas.style.cursor = "crosshair" }
requestAnimationFrame(update);
}
function createImage(w, h){
const can = document.createElement("canvas");
can.width = w;
can.height = h;
can.ctx = can.getContext("2d");
return can;
}
function mouseEvents(e){
mouse.x = e.pageX - bounds.left - 2; // offset by 2 pixels for canvas border
mouse.y = e.pageY - bounds.top - 2;
if (e.type === "mousedown") { mouse.button = true }
if (mouse.button) { pointQueue.push([mouse.x , mouse.y]) }
if (e.type === "mouseup") { mouse.button = false }
}
canvas {
border : 2px solid black;
cursor: crosshair;
}
Click drag mouse to draw<br>
<canvas id="canvas" width="512" height="256"></canvas>
you could try binding a div or a span to your mouse and attach it an eventListener like 'mousemove', in this div you could have two spans like
<div id='mouseCoord" style="position: absolute; top:0,left:0">
<span id='mouseX'><span>
<span id='mouseY'><span>
</div>
The div #mouseCoord would have an absolute position, and on mouse move, you could update his top/left position
const mouseDiv = document.getElementById('mouseCoord')
const mouseX = document.getElementById('mouseX')
const mouseY = document.getElementById('mouseY')
mouseDiv.addEventListener('mousemove', e => {
mouseDiv.setAttribute('style', `left: ${e.offsetX};top: ${e.offsetY}`)
mouseY.innerText = `y: ${e.offsetY}`
mouseY.innerText = `x: ${e.offsetX}`
})
With this in place, you could add some mouse events to control when you want to display the coordinate like only when the mouse is moving etc ...
I hope this can helps

Pan around the canvas within bounds smoothly

Most other solutions I have found relate to images as the bounds and work through css, and I can't get them to work with a canvas.
I want to create the bounds by defining an arbitrary percent size of the canvas (e.g 2x - twice the size) that expands from the center of the canvas and then have the canvas view (red) move/pan around within the bounds (green) by mouse hovering inside the canvas - that it moves to all corners of the bounds from the center of the canvas.
like this behavior in terms of the direction with panning
http://jsfiddle.net/georgedyer/XWnUA/2/
Additionally, I would like
the solution to work with a responsive canvas sizes rather than fixed canvas sizes
the panning to be smooth using easing such as CubicInOut easing
to detect the mouse hover inside the circle drawn. Might have to change the coordinate from screen to world to get it to work properly. But maybe theirs an easier way?
formulas
Here's my attempt at figuring out the formulas to get it working! I'll just focus on just one axis (x-axis) from left to right of the mouse, but the same formulas should apply to the y-axis.
First I get the "percentX" of the mouse along the width. If the "percentX" is 0 then the "newX" for the pan will be the value of the leftSide, else if it's 1 then it'll be the rightSide of the boundsBorder (green). So the "percentX" determines which side of the boundsBorder/limit the canvas view will extend/move to.
Only problem is that this doesn't work. So my formula must be wrong. The mouse inside the circle event is also inaccurate because of my canvas translate. Combining everything together is difficult to figure out!
Code
<html>
<head>
<meta charset="UTF-8">
<title>Panning</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
body {
background: #eee;
padding: 20px 0;
}
.canvas-container {
height: 400px;
width: 100%;
margin-bottom: 40px;
border-radius: 10px;
background: #fff;
overflow: hidden;
}
canvas {
width: 100%;
height: inherit;
}
.container {
width: 60%;
margin: 0 auto;
}
</style>
</head>
<body>
<!-- CANVAS -->
<div class="container">
<div class="canvas-container">
<canvas id="canvas"></canvas>
</div>
</div>
<!-- SCRIPT -->
<script type="text/javascript">
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var width = canvas.width = canvas.clientWidth;
var height = canvas.height = canvas.clientHeight;
var panX = 0, panY = 0;
var scaleBorderFactor = 2; /* scale factor for the bounds */
var mouse = {
x: 0,
y: 0
}
function Circle(x, y, radius, color){
this.x = x;
this.y = y;
this.radius = radius;
this.color = color;
this.draw = function(ctx){
ctx.beginPath();
ctx.arc(this.x,this.y,this.radius,0,Math.PI*2,false);
ctx.fillStyle = this.color;
ctx.fill();
ctx.closePath();
}
}
/* Rect Stroke Borders for visual reference */
function RectBorder(x, y, w, h, c){
this.x = x;
this.y = y;
this.width = w;
this.height = h;
this.color = c;
this.draw = function(ctx){
ctx.strokeStyle = this.color;
ctx.lineWidth = 2;
ctx.strokeRect(this.x, this.y, this.width, this.height);
};
/* Draw rect from a center point */
this.drawAtCenter = function(ctx){
ctx.strokeStyle = this.color;
ctx.lineWidth = 2;
ctx.strokeRect(this.x, this.y, this.width, this.height);
};
this.toString = function(){
console.log("x: "+this.x+", y: "+this.y+", w: "+this.width+", h: "+this.height+", color = "+this.color);
}
}
function getMousePos(canvas, event) {
var rect = canvas.getBoundingClientRect();
return {
x: (event.clientX - rect.left),
y: (event.clientY - rect.top)
};
}
function insideCircle(circle, mouse){
var dist = Math.sqrt(Math.pow(circle.x - mouse.x,2) + Math.pow(circle.y - mouse.y,2));
console.log(circle.radius+", d = "+dist)
return dist <= circle.radius;
}
function lerp(start, end, percent){
return start*(1 - percent) + percent*end;
}
/* t: current time, b: beginning value, c: change in value, d: duration */
function easeInOutCubic(t, b, c, d) {
if ((t/=d/2) < 1) return c/2*t*t*t + b;
return c/2*((t-=2)*t*t + 2) + b;
}
var canvasBorder = new RectBorder(0,0,canvas.width,canvas.height,'red');
var boundsBorder = new RectBorder(-(canvas.width*scaleBorderFactor - canvas.width)/2,-(canvas.height*scaleBorderFactor - canvas.height)/2,canvas.width*scaleBorderFactor,canvas.height*scaleBorderFactor,'green');
var circle = new Circle(200,200,40,'blue');
/* Draw Update */
update();
function update(){
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
width = canvas.width = canvas.clientWidth;
height = canvas.height = canvas.clientHeight;
ctx.clearRect(0,0,width,height);
ctx.save();
/* MOUSE */
percentX = (mouse.x / width);
percentY = (mouse.y / height);
/* the 2 sides of boundsBorder */
var leftSide = (width*scaleBorderFactor - width)/2 - width;
var rightSide = (width*scaleBorderFactor - width)/2 + width;
var topSide = (height*scaleBorderFactor - height)/2 - width;
var bottomSide = (height*scaleBorderFactor - height)/2 + height;
newX = rightSide * percentX + leftSide * (1 - percentX);
newY = bottomSide * percentY + topSide * (1 - percentY);
/* maybe use easeInOutCubic for better smoothness */
panX = lerp(-newX, mouse.x, 0.1);
panY = lerp(-newY, mouse.y, 0.1);
if (insideCircle(circle, mouse)){
circle.color = "pink";
} else {
circle.color = "blue";
}
ctx.translate(panX,panY);
/* Draw both borders only for reference */
canvasBorder.draw(ctx);
boundsBorder.drawAtCenter(ctx);
/* Draw Circle */
circle.draw(ctx);
ctx.restore();
requestAnimationFrame(update);
}
/* Events */
function mousemove(e) {
mouse = getMousePos(canvas, e);
}
/* Event Listeners */
canvas.addEventListener('mousemove', mousemove);
</script>
</body>
</html>
EDIT
I have managed to get the pan functionality to work. I just realized that all I need to do is offset by the positive and negative "widthGap"(see picture below) amount when panning. So it goes from positive "widthGap" (moves to the rght) to negative "widthGap" (moves to the left) when the "percentX" changes value like mentioned previously.
To get the smooth movement, I instead applied the lerp to the "percentX" values.
The code below is what should be replaced from the previous code above. It also shows the new variables I defined, which will make some of the variables from the previous code redundant.
UPDATED Code
var canvasBorder = new RectBorder(0,0,canvas.width,canvas.height,'red');
/* widthGap is the new leftSide formula.
* it is the gap differance between border and canvas
*/
var widthGap = (canvas.width*scaleBorderFactor - canvas.width)/2;
var heightGap = (canvas.height*scaleBorderFactor - canvas.height)/2;
var boundsBorder = new RectBorder(-widthGap,-heightGap,canvas.width+widthGap*2,canvas.height+heightGap*2,'green');
var circle = new Circle(200,200,40,'blue');
/* Draw Update */
update();
var newPercentX = 0, newPercentY = 0;
var percentX = 0, percentY = 0;
function update(){
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
width = canvas.width = canvas.clientWidth;
height = canvas.height = canvas.clientHeight;
ctx.clearRect(0,0,width,height);
ctx.save();
newPercentX = (mouse.x / width);
newPercentY = (mouse.y / height);
/* MOUSE */
percentX = lerp(percentX,newPercentX,0.05);
percentY = lerp(percentY,newPercentY,0.05);
panX = (widthGap) * percentX + (-widthGap) * (1 - percentX);
panY = (heightGap) * percentY + (-heightGap) * (1 - percentY);
ctx.translate(-panX,-panY);
if (insideCircle(circle, mouse)){
circle.color = "pink";
} else {
circle.color = "blue";
}
/* Draw both borders only for reference */
canvasBorder.draw(ctx);
boundsBorder.drawAtCenter(ctx);
/* Draw Circle */
circle.draw(ctx);
ctx.restore();
requestAnimationFrame(update);
}

Scribing a cicrular line in Canvas

I am attempting to mouse-drag a dot around the outer perimeter of a large circle and have that dot appear to scribe a thick line around the outer perimeter behind itself. I can get everything to work except scribing the outer line behind the dot. I have researched many ideas and tried many of my own but the line still produces "spotted" results. Here is an image to show what I'm attempting.
MounseDrag Scribed Line
Thank you for taking the time to read my question. :-)
<script type="text/javascript">
var canvas1 = document.getElementById("canvas1"),
canvas2 = document.getElementById("canvas2"),
c1 = canvas1.getContext("2d"),
c2 = canvas2.getContext("2d"),
dot = 7,
started = false,
width = 350,
height = 350,
radians = 0,
cRad = 165, // Circle Radius
cord = {mX:0, mY:0, csX:0, snY:0, x:0, y:0},
init = function(){
cord.mX = 0;
cord.mY = 0;
cord.csX = width /2 + cRad;
cord.snY = height /2;
cord.x = width /2;
cord.y = height /2;
};
init();
canvas1.width = width;
canvas1.height = height;
canvas2.width = width;
canvas2.height = height;
canvas1.addEventListener("mousemove", function(event) {
cord.mX = event.clientX - canvas1.offsetLeft;
cord.mY = event.clientY - canvas1.offsetTop;
});
canvas1.addEventListener("mousedown", function(event) {
if (started) {
started = false;
} else {
started = true;
render();
};
});
function update() {
radians = Math.atan2(cord.mY - width/2, cord.mX - height/2);
cord.csX = width/2 - Math.cos(radians) * cRad * -1;
cord.snY = height/2 - Math.sin(radians) * cRad * -1;
};
function outerTheta() {
c2.beginPath();
c2.arc(cord.csX, cord.snY, 3, 0, Math.PI * 2);
c2.closePath();
c2.fillStyle = "#000";
c2.fill();
};
function render() {
c1.clearRect(0, 0, width, height);
c1.beginPath();
c1.moveTo(cord.x, cord.y);
c1.lineTo(cord.csX, cord.snY);
c1.lineWidth = 3;
c1.strokeStyle = "#000";
c1.stroke();
c1.beginPath(); //<---------------------------------- Drag-Dot
c1.arc(cord.csX, cord.snY, dot, 0, Math.PI * 2);
c1.closePath();
c1.fillStyle = "#000";
c1.fill();
if(started){
update();
outerTheta();
requestAnimationFrame(render);
};
};
render();
</script>
The browser is not able to cycle the animation as quickly as the mouse is moving. If you move the mouse slowly, then the dots that are drawn in each animation cycle overlap and the circle has a solid line. If you move the mouse quickly, then the dots do not overlap and you get "spotting".
If you pay close attention to the way drawing programs work, you will see that the "pen" tool draws a continuous line. If you move the mouse quickly while using the tool, the continuous line is made up of line segments that stretch from each point that the computer was able to capture while your mouse was moving quickly.
I modified your program so that a line segment stretches between each captured point during the animation cycle:
https://jsfiddle.net/17hvw5pp
var canvas1 = document.getElementById("canvas1"),
canvas2 = document.getElementById("canvas2"),
c1 = canvas1.getContext("2d"),
c2 = canvas2.getContext("2d"),
dot = 7,
started = false,
width = 350,
height = 350,
radians = 0,
cRad = 165, // Circle Radius
cord = {mX:0, mY:0, csX:0, snY:0, x:0, y:0},
init = function(){
cord.mX = 0;
cord.mY = 0;
cord.csX = width /2 + cRad;
cord.snY = height /2;
cord.lastCSX = cord.csX;
cord.lastSNY = cord.snY;
cord.x = width /2;
cord.y = height /2;
};
canvas1.style.position="absolute";
canvas2.style.position="absolute";
init();
canvas1.width = width;
canvas1.height = height;
canvas2.width = width;
canvas2.height = height;
canvas1.addEventListener("mousemove", function(event) {
cord.mX = event.clientX - canvas1.offsetLeft;
cord.mY = event.clientY - canvas1.offsetTop;
});
canvas1.addEventListener("mousedown", function(event) {
if (started) {
started = false;
} else {
started = true;
render();
};
});
function update() {
radians = Math.atan2(cord.mY - width/2, cord.mX - height/2);
cord.csX = width/2 - Math.cos(radians) * cRad * -1;
cord.snY = height/2 - Math.sin(radians) * cRad * -1;
};
function outerTheta() {
//draw a line from the last known coordinate to the new known coordinate
c2.beginPath();
c2.moveTo(cord.lastCSX, cord.lastSNY);
c2.lineTo(cord.csX, cord.snY);
c2.lineWidth=5;
c2.strokeStyle="#000";
c2.stroke();
cord.lastCSX = cord.csX;
cord.lastSNY = cord.snY;
c2.beginPath();
c2.arc(cord.csX, cord.snY, 3, 0, Math.PI * 2);
c2.closePath();
c2.fillStyle = "#000";
c2.fill();
};
function render() {
c1.clearRect(0, 0, width, height);
c1.beginPath();
c1.moveTo(cord.x, cord.y);
c1.lineTo(cord.csX, cord.snY);
c1.lineWidth = 3;
c1.strokeStyle = "#000";
c1.stroke();
c1.beginPath(); //<---------------------------------- Drag-Dot
c1.arc(cord.csX, cord.snY, dot, 0, Math.PI * 2);
c1.closePath();
c1.fillStyle = "#000";
c1.fill();
if(started){
update();
outerTheta();
requestAnimationFrame(render);
};
};
render();
This works better, but not perfectly: If you move the mouse quickly, the line segment will become a chord across the circle and this ruins the effect.
I attempted to modify the program to draw an arc between the two known points:
https://jsfiddle.net/17hvw5pp/1/
You can see that this implementation is also not ideal because the arc function becomes confused about which direction to draw the partial circle based on just two radians coordinates. Using quaternion math will solve this problem for you.
https://en.wikipedia.org/wiki/Quaternion
But that may be more complication that you want to introduce into this project.

Mouse cursor doesn't match with canvas

I have question: when I'm drawing a line in canvas, it seems the mouse position doesn't match with the canvas position, so whenever I draw, there is some distance between my cursor and the drawing line .. please help me with this problem, here is my code :
$(document).ready(function(){
context = document.getElementById('canvasInAPerfectWorld').getContext("2d");
$('#canvasInAPerfectWorld').mousedown(function(e){
var mouseX = e.pageX - this.offsetLeft;
var mouseY = e.pageY - this.offsetTop;
paint = true;
addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
redraw();
});
$('#canvasInAPerfectWorld').mousemove(function(e){
if(paint){
addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop, true);
redraw();
}
});
$('#canvasInAPerfectWorld').mouseup(function(e){
paint = false;
});
$('#canvasInAPerfectWorld').mouseleave(function(e){
paint = false;
});
});
var clickX = new Array();
var clickY = new Array();
var clickDrag = new Array();
var paint;
function addClick(x, y, dragging)
{
clickX.push(x);
clickY.push(y);
clickDrag.push(dragging);
}
function clear_canvas(){
//alert('masuk claear');
context.clearRect(0,0,context.canvas.width,context.canvas.height);
}
function redraw(){
context.strokeStyle = "#df4b26";
context.lineJoin = "round";
context.lineWidth = 5;
for(var i=0; i < clickX.length; i++) {
context.beginPath();
if(clickDrag[i] && i){
context.moveTo(clickX[i-1], clickY[i-1]);
}else{
context.moveTo(clickX[i]-1, clickY[i]);
}
context.lineTo(clickX[i], clickY[i]);
context.closePath();
context.stroke();
}
}
Inside your mouse event handlers, this refers to the window object and your this.offsetLeft is undefined.
You can use getBoundingClientRect to get the bounds of your canvas element:
// get a reference to your canvas element at the start of your app
var canvas=document.getElementById('canvasInAPerfectWorld');
// example mousedown handler
// get the current canvas offsets using getBoundingClientRect
var BB=canvas.getBoundingClientRect();
var offsetX=BB.left;
var offsetY=BB.top;
// calculate the current mouse position relative to the canvas
// using e.client and the offsets calculated above
var mouseX=parseInt(e.clientX-offsetX);
var mouseY=parseInt(e.clientY-offsetY);
If you canvas does not reposition relative to the viewport, you can get the offsets once at the start of your app so they don't need to be recalculated every time inside the mouse handler.
You could follow the solution in markE's answer (also found here).
Or you could do the following if your layout allows
Set canvas element to position relative
Use layerX and layerY to read the mouse position
This approach gives a little simpler code.
Both methods will be affected by padding and border thickness (they need to be subtracted if any is used). If you want border/padding it's better to wrap the canvas in a div and then style the div instead.
Example using relative positioned canvas
var c = document.querySelector("canvas"),
ctx = c.getContext("2d");
ctx.font = "bold 16px sans-serif";
c.onmousemove = function(e) {
var x = e.layerX,
y = e.layerY;
ctx.clearRect(0, 0, 300, 20);
ctx.fillText("x: " + x + ", y: " + y, 10, 16);
};
div {padding:20px}
canvas {background:#eee; position:relative}
<div><div><canvas></canvas></div></div>
Example using getBoundingClientRect()
var c = document.querySelector("canvas"),
ctx = c.getContext("2d");
ctx.font = "bold 16px sans-serif";
c.onmousemove = function(e) {
var rect = this.getBoundingClientRect(),
x = e.clientX - rect.left,
y = e.clientY - rect.top;
ctx.clearRect(0, 0, 300, 20);
ctx.fillText("x: " + x + ", y: " + y, 10, 16);
};
div {padding:20px}
canvas {background:#eee; position:relative}
<div><div><canvas></canvas></div></div>

DIV changing shape unexpectedly

I'm trying to draw a circle in a canvas to match the dimensions of a div. I can't understand what's wrong here (aside from the bad style), as the result is an ellipsis, which looks like the canvas size has been stretched after the drawing (JSFiddle here):
$(document).ready(function() {
scrH = $(window).height();
scrW = $(window).width();
// place map
$('body').append("<div id='pagUserStart_map1' style='border:5px solid red;'></div>");
var map = $("#pagUserStart_map1");
map.css("width", scrW - 60 + "px");
map.css("height", map.css("width"));
map.css("top", scrH / 2 - map.height()/2);
map.css("left", (scrW - map.width()) / 2);
map.css("position", "absolute");
map.css("margin", "0 auto");
map.css("border-radius", "50%");
map.css("z-index", "100");
//place canvas
$('body').append("<canvas id='canvas1'></canvas>");
var canvas = $("#canvas1");
canvas.width(map.width());
canvas.height(canvas.width());
canvas.css("position", "absolute");
canvas.position({
my: "center",
at: "center",
of: map
});
canvas = document.getElementById("canvas1");
// draw circle in canvas
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height /2 ;
var radius = 50;
context.beginPath();
context.arc(centerX, centerY, 50, 0, 2 * Math.PI, false);
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.shadowBlur = 10;
context.shadowColor = '#656565';
context.lineWidth = 10;
context.strokeStyle = '#B8CADE';
context.stroke();
});
I understand that something goes wrong between when I use JQuery to reference 'canvas1' and when I use getElementById. But why? It seems like the code is not executed sequentially. I've lost a few hours googling around and playing with the code... I really need your help.
You need to set Canvas size correctly:
canvas.attr('width', map.width());
canvas.attr('height', map.height());
And you will recieve this:
http://i.stack.imgur.com/5UsGQ.png
Set the canvas element width instead of the canvas css width:
// draw circle in canvas
canvas = document.getElementById("canvas1");
canvas.width=map.width();
canvas.height=map.height();
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height /2 ;
var radius = 50;
Simple change your absolute position to fixed.
Like this
$(document).ready(function() {
scrH = $(window).height();
scrW = $(window).width();
// place map
$('body').append("<div id='pagUserStart_map1' style='border:5px solid red;'></div>");
var map = $("#pagUserStart_map1");
map.css("width", scrW - 60 + "px");
map.css("height", map.css("width"));
map.css("top", scrH / 2 - map.height()/2);
map.css("left", (scrW - map.width()) / 2);
map.css("position", "fixed");
map.css("margin", "0 auto");
map.css("border-radius", "50%");
map.css("z-index", "100");
//place canvas
$('body').append("<canvas id='canvas1'></canvas>");
var canvas = $("#canvas1");
canvas.width(map.width());
canvas.height(canvas.width());
canvas.css("position", "fixed");
canvas.position({
my: "center",
at: "center",
of: map
});

Categories

Resources