I was following this MDN tutorial:
https://developer.mozilla.org/es/docs/Games/Workflows/Famoso_juego_2D_usando_JavaScript_puro/Mueve_la_bola
And I was wondering how could we control the ball's movement using mouse movement event.
I have seen that mousemove works with textarea and some inputs:
https://developer.mozilla.org/en-US/docs/Web/Events/mousemove
I thought if we could put a textarea behind the canvas, we could detect the event, get the mouse's position and let the user change the ball's movement with mouse movement.
I have read:
Dynamically resize textarea width and height to contain text
So I tried:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Juego</title>
<style>
* {
padding: 0;
margin: 0;
}
canvas {
background: #eee;
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<textarea name="ta" id="ta" cols="30" rows="10"></textarea>
<canvas id="myCanvas" width="480" height="320"></canvas>
<script>
const textarea = document.getElementById('ta');
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
textarea.style.height = canvas.height;
textarea.style.width = canvas.width;
let x = canvas.width / 2;
let y = canvas.height - 30;
const dx = 2;
const dy = -2;
let drawBall = function () {
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
};
function draw(e) {
console.log(e);
ctx.clearRect(0,0,canvas.width,canvas.height);
drawBall();
x += dx;
y += dy;
}
setInterval(draw, 10);
canvas.addEventListener('mousemove', draw);
</script>
</body>
</html>
The expected output would be to have the textarea using canvas' width and height, and being behind it; however it is smaller and put on top left:
Thank you for your help.
you don't need the textarea to capture the event, and it'll be complicated because the canvas will be on top and the textarea will never know the mouse is moving on top of it, and to make the ball moving with the mouse, you have to passe the x and y of the mouse to the draw(); while it's moving function
here's a fiddle : https://jsfiddle.net/vqdyLx5u/22/
let canvas = document.getElementById('myCanvas');
let ctx = canvas.getContext('2d');
function drawBall(x, y) {
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function draw(x, y) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBall(x, y);
}
draw(canvas.height / 2 , canvas.width / 2); // initial draw
canvas.addEventListener('mousemove', function(e) {
draw(e.pageX, e.pageY); // the coordinates of the mouse
});
* {
padding: 0;
margin: 0;
}
canvas {
background: #eee;
display: block;
margin: 0 auto;
}
<canvas id="myCanvas" width="480" height="320"></canvas>
Related
I'm trying to let users draw rectangles on a canvas using the mouse and i've been able to get it to work to some extent.The users can draw the rectangles using the mouse but it only shows after the mouseup event but i also want the users to also see the rectangles while drawing it on mousemove event. How can i achieve this and at the same time let users draw multiple rectangles which currently works but i want them to see it while drawing the rectangles.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
#container {
/*background-color: lime;*/
width: 150px;
height: 150px;
cursor: pointer;
}
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
#heatmapContainer {
border: 1px solid red;
}
</style>
</head>
<body>
<div class="heatmapWrapper">
<div id="heatmapContainer" style="height: 4205px; width: 1278px">
<div id="heatmap1" class="heatmapTile" style="height: 4205px; position: relative">
<canvas id="myCanvas" class="heatmap-canvas" width="1278" height="4205" style="position: absolute; left: 0px; top: 0px"></canvas>
</div>
</div>
</div>
<script>
var canvas = document.getElementById('myCanvas'),
elemLeft = canvas.offsetLeft,
elemTop = canvas.offsetTop,
context = canvas.getContext('2d');
let start = {};
var mouseDown = false;
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect(),
scaleX = canvas.width / rect.width,
scaleY = canvas.height / rect.height;
return {
x: (evt.clientX - rect.left) * scaleX,
y: (evt.clientY - rect.top) * scaleY,
};
}
function startRect(e) {
start = getMousePos(canvas, e);
mouseDown = true;
}
window.addEventListener('mousedown', startRect);
function endRect(e) {
let {
x,
y
} = getMousePos(canvas, e);
context.strokeStyle = 'blue';
context.strokeRect(start.x, start.y, x - start.x, y - start.y);
mouseDown = false;
}
function drawSquare(e) {
if (!mouseDown) return;
// creating a square
var width = Math.abs(start.x - canvas.getBoundingClientRect().offsetLeft);
var height = Math.abs(start.y - canvas.getBoundingClientRect().offsetLeft);
context.beginPath();
context.rect(start.x, start.y, width, height);
context.strokeStyle = 'blue';
context.stroke();
}
window.addEventListener('mouseup', endRect);
window.addEventListener('mousemove', drawSquare);
/**End Drawing a rectangle on the canvas **/
</script>
</body>
</html>
We need to make something different, instead of drawing on the fly we need to add the rectangles to an array, then clean the canvas and draw them on demand, that way we can also draw additional elements, on the sample below I draw a red rectangle while moving and blue ones once we release the mouse
var canvas = document.getElementById('myCanvas')
var context = canvas.getContext('2d')
let start = {}
let rects = [{x: 9, y: 9, width: 50, height: 30}]
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect()
return {
x: (evt.clientX - rect.left) * canvas.width / rect.width,
y: (evt.clientY - rect.top) * canvas.height / rect.height,
};
}
function startRect(e) {
start = getMousePos(canvas, e);
}
function endRect(e) {
let { x, y } = getMousePos(canvas, e)
rects.push({x: start.x, y: start.y, width: x - start.x, height: y - start.y})
start = {}
draw()
}
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height)
rects.forEach(rect => {
context.beginPath();
context.rect(rect.x, rect.y, rect.width, rect.height);
context.strokeStyle = 'blue';
context.stroke();
});
}
function drawMove(e) {
if (start.x) {
draw()
let { x, y } = getMousePos(canvas, e)
context.beginPath();
context.rect(start.x, start.y, x - start.x, y - start.y);
context.strokeStyle = 'red';
context.stroke();
context.beginPath();
context.arc(start.x, start.y, 5, 0, 2 * Math.PI);
context.fill();
context.beginPath();
context.arc(x, y, 5, 0, 2 * Math.PI);
context.fill();
}
}
draw()
window.addEventListener('mouseup', endRect)
window.addEventListener('mousedown', startRect)
window.addEventListener('mousemove', drawMove)
canvas { border: solid }
<canvas id="myCanvas" width="400" height="400"></canvas>
I'm trying to have an image on my website become saturated at the same location the mouse is. When the mouse moves the saturation effect goes with it, and the area previously hovered over becomes grayscale again. I'm thinking this effect could be accomplished using saturate(), however I haven't had any success with it. Additionally, I would like the effect to be circular without hard edges similar to this.
Example of what it would look like (orange arrow indicating where the mouse is).
Any help or insight would be appreciated, thanks!
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content= "width=device-width, initial-scale=1.0" />
</head>
<script>
const size = 250;
var radius = 30;
var rad = Math.PI / 180;
var canvas = document.querySelector("canvas")
var ctx = canvas.getContext("2d");
canvas.width = size;
canvas.height = size;
var image = new Image();
image.onload = demo
image.src = "https://picsum.photos/250"
function draw_circle(x, y, radius) {
ctx.clearRect(0, 0, size, size);
ctx.drawImage(image, 0, 0); // image to change
ctx.globalCompositeOperation = "saturation";
ctx.beginPath();
ctx.fillStyle = "hsl(0,100%,50%)"; // saturation at 100%
ctx.arc(x, y, radius, 0, 360 * rad, false);
ctx.fill()
ctx.closePath();
ctx.globalCompositeOperation = "source-over"; // restore default comp
}
function demo() {
ctx.drawImage(image, 0, 0); // image to change
canvas.addEventListener('mousemove', function(ev) {
var cx = ev.offsetX
var cy = ev.offsetY
draw_circle(cx, cy, radius)
})
}
</script>
<canvas></canvas>
</html>
Using a canvas we can try. Here's a start inspired by How can I adjust the huse, saturation, and lightness of in image in HTML5 Canvas?.
const size = 250;
var radius = 30;
var rad = Math.PI / 180;
var canvas = document.querySelector("canvas")
var ctx = canvas.getContext("2d");
canvas.width = size;
canvas.height = size;
var image = new Image();
image.onload = demo
image.src = "https://picsum.photos/250"
function draw_circle(x, y, radius) {
ctx.clearRect(0, 0, size, size);
ctx.drawImage(image, 0, 0); // image to change
ctx.globalCompositeOperation = "saturation";
ctx.beginPath();
ctx.fillStyle = "hsl(0,100%,50%)"; // saturation at 100%
ctx.arc(x, y, radius, 0, 360 * rad, false);
ctx.fill()
ctx.closePath();
ctx.globalCompositeOperation = "source-over"; // restore default comp
}
function demo() {
ctx.drawImage(image, 0, 0); // image to change
canvas.addEventListener('mousemove', function(ev) {
var cx = ev.offsetX
var cy = ev.offsetY
draw_circle(cx, cy, radius)
})
}
<canvas></canvas>
This is a simple answer (change the logic of the program as you want):
<!DOCTYPE html>
<html>
<head>
<style>
div.relative {
position: relative;
width: 200px;
height: 150px;
}
.image {
width: 100%;
height: 100%;
}
</style>
<script>
const width = 50;
const height = 50;
function create() {
const element = document.createElement("div");
element.id = "filtered";
element.style.width = `${width}px`;
element.style.height = `${height}px`;
element.style.borderRadius = "50%";
element.style.position = "absolute";
element.style.backgroundColor = "red";
element.style.opacity = "0.2";
element.style.zIndex = "2";
return element;
}
function changePos(e) {
x = e.clientX;
y = e.clientY;
let element = document.getElementById("filtered");
if (!element) {
element = create();
document.getElementById("focusArea").appendChild(element);
}
element.style.left = `${x - width / 2}px`;
element.style.top = `${y - height / 2}px`;
}
function removeElement() {
if (document.getElementById("filtered")) {
document.getElementById("filtered").remove();
}
}
</script>
</head>
<body>
<div
id="focusArea"
onmouseleave="removeElement()"
onmousemove="changePos(event)"
class="relative"
>
<img
src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/b6/Image_created_with_a_mobile_phone.png/800px-Image_created_with_a_mobile_phone.png"
class="image"
/>
</div>
</body>
</html>
I'm working on an app that allows the user to select an image and define a custom clipping region for that image. The user can place blue dots on the canvas containing the image, which will represent the clipping path. These points are stored in the coordinates array. This is the function that clips the image to the selected area:
function crop()
{
ctx.beginPath();
ctx.moveTo(coordinates[0].x, coordinates[0].y);
for(let i=1; i<coordinates.length; i++)
{
ctx.lineTo(coordinates[i].x, coordinates[i].y);
}
ctx.lineTo(coordinates[0].x, coordinates[0].y);
ctx.stroke();
ctx.save();
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.restore();
ctx.clip();
//redraw the image in the cropped area
let pattern = ctx.createPattern(image, "repeat");
ctx.fillStyle = pattern;
ctx.fill();
ctx.closePath();
}
This works perfectly fine when I let the image keep its natural dimensions (in this case 1200x600):
But if I give the image max-height and max-width properties, each set to 80vmin, the cropping stops working correctly:
Instead of cropping the image around the eye area, like in the previous image, it clips a different part of the image to the selected area.
I suspect createPattern is for some reason not loading the image properly, with its updated dimensions. So I tried passing it a new canvas object (which is basically a copy of the canvas I'm working on in its original form, with the resized image painted on and nothing else) instead of the image itself, but that didn't seem to work either, I was getting the same result. Is there anything else I could try?
Update: here is a JSFiddle containing the whole code
const image = document.getElementById("pic");
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
//draw the image on the canvas
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0, 0, image.width, image.height);
//get mouse coordinates
let coordinates = [];
canvas.onclick = function clickEvent(e)
{
let rect = e.target.getBoundingClientRect();
let x = e.clientX - rect.left;
let y = e.clientY - rect.top;
let point = {
"x": x,
"y": y
};
coordinates.push(point);
ctx.fillStyle = "blue";
ctx.fillRect(x, y, 10, 10);
}
//debugging
console.log(coordinates);
//crop the image
function crop()
{
ctx.beginPath();
ctx.moveTo(coordinates[0].x, coordinates[0].y);
for(let i=1; i<coordinates.length; i++)
{
ctx.lineTo(coordinates[i].x, coordinates[i].y);
}
ctx.lineTo(coordinates[0].x, coordinates[0].y);
ctx.stroke();
ctx.save();
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.restore();
ctx.clip();
//redraw the image in the cropped area
let pattern = ctx.createPattern(image, "repeat");
ctx.fillStyle = pattern;
ctx.fill();
ctx.closePath();
}
function save()
{
let newCanvas = document.getElementById('canvas2');
//get new dimensions
let top = canvas.height;
let left = canvas.width;
let right = -canvas.width;
let bottom = -canvas.height;
for(let i=0; i<coordinates.length; i++)
{
if(coordinates[i].y < top)
top = coordinates[i].y;
if(coordinates[i].x < left)
left = coordinates[i].x;
if(coordinates[i].x > right)
right = coordinates[i].x;
if(coordinates[i].y > bottom)
bottom = coordinates[i].y;
}
newCanvas.width = right-left;
newCanvas.height = bottom-top;
//save the new image
newCanvas.getContext("2d").drawImage(canvas, left, top, newCanvas.width, newCanvas.height, 0, 0, newCanvas.width, newCanvas.height);
let downloadLink = document.createElement("a");
downloadLink.download = "crop.png";
downloadLink.href = newCanvas.toDataURL("image/png");
downloadLink.click();
}
h1 {
color: blue;
margin-bottom: 0px;
margin-top: 0px;
}
.image-div img {
max-width: 80vmin;
max-height: 80vmin;
border: 1px solid black;
}
.canvas-div {
margin-top: 240px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test</title>
</head>
<body>
<h1>Image:</h1>
<div class="image-div">
<img id="pic" src="https://icatcare.org/app/uploads/2018/07/Helping-your-new-cat-or-kitten-settle-in-1.png">
</div>
<div class="canvas-div">
<h1>Canvas:</h1>
<canvas id="canvas" style="border: 1px solid blue;"></canvas>
</div>
<!-- for exporting the final result -->
<canvas id="canvas2" style="display: none;"></canvas>
<button onclick="crop()">Crop</button>
<button onclick="save()">Save</button>
<br><br><br>
<!-- script -->
<script src="script.js"></script>
</body>
</html>
Before reading the explanation try the following:
ctx.beginPath();
ctx.moveTo(coordinates[0].x, coordinates[0].y);
for(let i=1; i<coordinates.length; i++)
{
ctx.lineTo(coordinates[i].x, coordinates[i].y);
}
ctx.lineTo(coordinates[0].x, coordinates[0].y);
ctx.stroke();
ctx.closePath();
ctx.clip();
ctx.save();
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.restore();
You will see that it does an invert cropping, that is, it clears the points you want to not clear and preserves the points you wanted to clear. So, to solve your problem, assuming that the crop will be a convex shape, you need the following:
get all the lines involved
create a polygon of the "outside" of the polygons
clear
Since you can have many different types of shapes and they can be convex or concave alike, it would be far-fetched for the purpose of a stackoverflow answer to implement the full logic, but this is how you can do it relatively easily:
Make sure that the lines are continuous, so if you draw the lines by hand from coordinates[0] to coordinates1 and then coordinates1 to coordinates[2], etc. then you will end up drawing the correct polygon (so each line between coordinates[i-1] and coordinates[i]) is a side of your polygon rather than a diagonal.
moveTo coordinates[0] and have a lineto for all coordinates, almost like you did, except for the very last one. So, you are effectively almost drawing the polygon except the very last line.
continue with lineto to a side of the canvas (careful though, not to cross the internal of the polygon) and then to all the edges of the canvas (the corners), so you are effectively defining a polygon that's a. outside your polygon b. ends at your last coordinate c. does not include your last line
clear
moveTo your penultimate coordinate, lineTo your last coordinate and then proceed with lineTo calls to draw the
The snippet below is a proof-of-concept that is a good starting point, but it is not a proper solution yet.
const image = document.getElementById("pic");
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
//draw the image on the canvas
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0, 0, image.width, image.height);
//get mouse coordinates
let coordinates = [];
canvas.onclick = function clickEvent(e)
{
let rect = e.target.getBoundingClientRect();
let x = e.clientX - rect.left;
let y = e.clientY - rect.top;
let point = {
"x": x,
"y": y
};
coordinates.push(point);
ctx.fillStyle = "blue";
ctx.fillRect(x, y, 10, 10);
}
//debugging
console.log(coordinates);
//crop the image
function crop()
{
ctx.beginPath();
for(let i=0; i<coordinates.length - 1; i++)
{
ctx.lineTo(coordinates[i].x, coordinates[i].y);
}
ctx.lineTo(canvas.width, canvas.height);
ctx.lineTo(canvas.width, 0);
ctx.lineTo(0, 0);
ctx.lineTo(0, canvas.height);
ctx.lineTo(coordinates[0].x, coordinates[0].y);
ctx.stroke();
ctx.closePath();
ctx.clip();
ctx.save();
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.restore();
}
function save()
{
let newCanvas = document.getElementById('canvas2');
//get new dimensions
let top = canvas.height;
let left = canvas.width;
let right = -canvas.width;
let bottom = -canvas.height;
for(let i=0; i<coordinates.length; i++)
{
if(coordinates[i].y < top)
top = coordinates[i].y;
if(coordinates[i].x < left)
left = coordinates[i].x;
if(coordinates[i].x > right)
right = coordinates[i].x;
if(coordinates[i].y > bottom)
bottom = coordinates[i].y;
}
newCanvas.width = right-left;
newCanvas.height = bottom-top;
//save the new image
newCanvas.getContext("2d").drawImage(canvas, left, top, newCanvas.width, newCanvas.height, 0, 0, newCanvas.width, newCanvas.height);
let downloadLink = document.createElement("a");
downloadLink.download = "crop.png";
downloadLink.href = newCanvas.toDataURL("image/png");
downloadLink.click();
}
h1 {
color: blue;
margin-bottom: 0px;
margin-top: 0px;
}
.image-div img {
max-width: 80vmin;
max-height: 80vmin;
border: 1px solid black;
}
.canvas-div {
margin-top: 240px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test</title>
</head>
<body>
<h1>Image:</h1>
<div class="image-div">
<img id="pic" src="https://icatcare.org/app/uploads/2018/07/Helping-your-new-cat-or-kitten-settle-in-1.png">
</div>
<div class="canvas-div">
<h1>Canvas:</h1>
<canvas id="canvas" style="border: 1px solid blue;"></canvas>
</div>
<!-- for exporting the final result -->
<canvas id="canvas2" style="display: none;"></canvas>
<button onclick="crop()">Crop</button>
<button onclick="save()">Save</button>
<br><br><br>
<!-- script -->
<script src="script.js"></script>
</body>
</html>
I am trying to make a simple game. The green block is my game character. I used a the keydown event to make my character able to move right and left. When I hold down the right or left arrow key, the character keeps on accelerating. If you start by tapping the right or left arrow key, you will see that the space interval between where the character was and where it is increases as you click more. How can I make my character move at a constant speed with constant space intervals.
//variables
var canvas = document.getElementById("canvas");
var draw = canvas.getContext("2d");
var characterx = 20;
var charactery = window.innerHeight - 60;
var dx = 0.01;
var dy = 0.01;
//canvas size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
//main game function
function run() {
//loops the function
requestAnimationFrame(run);
//clears the screen
draw.clearRect(0, 0, canvas.width, canvas.height)
//draws the ground
draw.beginPath();
draw.fillStyle = "#823819";
draw.fillRect(0, canvas.height - 20, canvas.width, 20);
draw.fill();
draw.closePath();
//draws the main character
draw.beginPath();
draw.fillStyle = "#128522";
draw.fillRect(characterx, charactery, 40, 40);
draw.fill();
draw.closePath();
//key evevnts
window.addEventListener("keydown",function(event) {
if(event.keyCode == 39) {
characterx += dx;
}
});
window.addEventListener("keydown",function(event) {
if(event.keyCode == 37) {
characterx -= dx;
}
});
};
run();
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<style type="text/css">
body {
margin: 0;
overflow: hidden;
}
canvas {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
Your event listeners should be added outside of your game loop.
Currently you are adding an extra listener for each keypress on every frame, meaning that on the first frame you will move dx * 1 for a keypress, but on frame 100 you will move dx * 100 for a single keypress.
This is also why your dx value had to be so low - I've increased it in the sample below, but you can adjust it as needed.
//variables
var canvas = document.getElementById("canvas");
var draw = canvas.getContext("2d");
var characterx = 20;
var charactery = window.innerHeight - 60;
var dx = 3.0;
var dy = 3.0;
//canvas size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
//key evevnts
window.addEventListener("keydown",function(event) {
if(event.keyCode == 39) {
characterx += dx;
}
});
window.addEventListener("keydown",function(event) {
if(event.keyCode == 37) {
characterx -= dx;
}
});
//main game function
function run() {
//loops the function
requestAnimationFrame(run);
//clears the screen
draw.clearRect(0, 0, canvas.width, canvas.height)
//draws the ground
draw.beginPath();
draw.fillStyle = "#823819";
draw.fillRect(0, canvas.height - 20, canvas.width, 20);
draw.fill();
draw.closePath();
//draws the main character
draw.beginPath();
draw.fillStyle = "#128522";
draw.fillRect(characterx, charactery, 40, 40);
draw.fill();
draw.closePath();
};
run();
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<style type="text/css">
body {
margin: 0;
overflow: hidden;
}
canvas {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
Im trying to make so when you click on a canvas, there comes a circle at the mouse's cordinates.
When i click the canvas the circle appears maybe 300 pixels to low.
I tried changing from pageX/Y, clientX/Y and screenX/Y.
<canvas id="canvas" class="canvas" width="300px" height="200px" style="border: 1px solid #000; Padding-bottom: 100px;">
</canvas>
<script>
window.onload = function()
{
var canvas = document.getElementById("canvas");
addEventListener("mousedown", drawCircle)
}
function drawCircle(event)
{
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
x = event.pageX
y = event.pageY
ctx.fillStyle = "red";
ctx.beginPath();
ctx.arc(x, y, 50, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill()
}
</script>
I expect the circle to appear at the mouse's cordinates.
You need to account for the position of the canvas itself. it looks like your code assumes the canvas is always in the top left of the screen.
There is also some issues with your canvas element. The width and height should just be numbers (no "px" required). The bottom padding is making the bottom half of the canvas inaccessible.
window.onload = function() {
var canvas = document.getElementById("canvas");
addEventListener("mousedown", drawCircle)
}
function drawCircle(event) {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var rect = canvas.getBoundingClientRect();
x = event.clientX - rect.left;
y = event.clientY - rect.top;
ctx.fillStyle = "red";
ctx.beginPath();
ctx.arc(x, y, 50, 0, 2 * Math.PI, true);
ctx.stroke();
ctx.fill()
}
<canvas id="canvas" class="canvas" width="300" height="200" style="border: 1px solid #000;">
</canvas>
Possibly being offset by other elements on the page around the canvas. Try something like this to get x/y relative to canvas:
<canvas id="canvas" class="canvas"></canvas>
<script>
window.onload = function () {
var canvas = document.getElementById("canvas");
canvas.width = 300;
canvas.height = 200;
addEventListener("mousedown", drawCircle)
}
function drawCircle(event) {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var rect = canvas.getBoundingClientRect();
x = (event.clientX - rect.left)
y = (event.clientY - rect.top)
//x = event.pageX
//y = event.pageY
ctx.fillStyle = "red";
ctx.beginPath();
ctx.arc(x, y, 50, 0, 2 * Math.PI);
ctx.stroke();
ctx.fill()
}
</script>
https://jsfiddle.net/1z5modk2/1/
Instead of using pageX and pageY, use offsetX and offsetY
https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/offsetX