I am attempting to locate the coordinates of the mouse on a canvas element of an HTML5 page.
I create the canvas to be a certain height and width, for example 700x700. When I mouse over the canvas, I want to be able to know the X,Y of the mouse. This works fine, until I stretch my canvas using CSS in the HTML file...
Here is my javascript file:
function Sprite(path)
{
this.img = new Image();
this.img.onload = loaded;
this.img.src = path;
function loaded()
{
console.log("Loaded picture");
}
}
function drawSprite(sprite, ctx)
{
console.log("drawing picture");
ctx.drawImage(sprite.img,10,10);
}
//------------------------------------------
function Game()
{
this.canvas = document.createElement("canvas");
document.body.appendChild(this.canvas);
this.canvas.width = 700;
this.canvas.height = 700;
this.context = this.canvas.getContext("2d");
var ctx = this.context;
ctx.canvas.addEventListener('mousemove', function(event){
var mouseX = event.clientX - ctx.canvas.offsetLeft;
var mouseY = event.clientY - ctx.canvas.offsetTop;
var status = document.getElementById("coords");
status.innerHTML = mouseX+" | "+mouseY;
});
this.objects = new Array();
this.objects.push(new Sprite("dog.png"));
}
function drawGame(g)
{
console.log("I'm here");
for(var i=0;i<g.objects.length;i++)
{
drawSprite(g.objects[i], g.context);
}
}
function drawLine(g)
{
g.context.moveTo(0,0);
g.context.lineTo(100,100);
g.context.stroke();
}
//------------------
window.addEventListener('load',function(event){startgame();});
var globalGame;
function startgame()
{
globalGame = new Game();
drawGame(globalGame);
drawLine(globalGame);
}
Here is my HTML File
<html>
<head>
<script src="functions.js"></script>
<style>
canvas
{
width:90%;
height:90%;
}
</style>
</head>
<body>
<h1 id="coords">0 | 0</h1>
</body>
<html>
The mouse coordinates are in display pixels. To convert that to canvas coordinates, you'll need to scale them accordingly.
One way of doing this is:
const canvasX = mouseX * canvas.width / canvas.clientWidth;
const canvasY = mouseY * canvas.height / canvas.clientHeight;
as shown in this example:
const status = document.getElementById("coords");
const canvas = document.createElement("canvas");
canvas.width = 700;
canvas.height = 700;
document.body.appendChild(canvas);
canvas.addEventListener('mousemove', event => {
const mouseX = event.clientX - canvas.offsetLeft;
const mouseY = event.clientY - canvas.offsetTop;
// scale mouse coordinates to canvas coordinates
const canvasX = mouseX * canvas.width / canvas.clientWidth;
const canvasY = mouseY * canvas.height / canvas.clientHeight;
status.innerHTML = `${mouseX} | ${mouseY}<br>${canvasX} | ${canvasY}`;
});
canvas {
width:250px;
height:250px;
background-color:#f0f;
}
<div id="coords">??? | ???<br>??? | ???</div>
Related
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 have the following code that allows the user to upload an image which gets put into a canvas, but once it has been drawn I want users to be able to rotate the image with the click of a button, but I don't know how to re-access the image object to be able to rotate the canvas. The code below is what works:
onFilePicked (e) {
const files = e.target.files;
for (let file of files) {
if(file !== undefined) {
let image = {
thumbnail: '/img/spinner.gif'
};
this.images.push(image);
this.loadImage(file, image);
}
}
},
loadImage(file, image) {
const fr = new FileReader();
fr.readAsDataURL(file);
fr.addEventListener('load', () => {
var img = new Image();
img.src = fr.result;
img.onload = () => {
image.thumbnail = this.resizeImage(img, 400, 300);
image.large = this.resizeImage(img, 1280, 960);
}
})
},
resizeImage(origImg, maxWidth, maxHeight) {
let scale = 1;
if (origImg.width > maxWidth) {
scale = maxWidth / origImg.width;
}
if (origImg.height > maxHeight) {
let scale2 = maxHeight / origImg.height;
if (scale2 < scale) scale = scale2;
}
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = origImg.width * scale;
canvas.height= origImg.height * scale;
ctx.drawImage(origImg, 0, 0, canvas.width, canvas.height);
return canvas.toDataURL("image/jpeg");
},
And seen below is the function I built out to rotate the image- it works in that if I replace the code inside of the resizeImage function with the code below that the image is drawn in a way that is rotated correctly, but I don't know how to access the origImg object to be able to redraw the canvas in a separate function.
rotateImage(origImg, maxWidth, maxHeight){
let scale = 1;
if (origImg.width > maxWidth) {
scale = maxWidth / origImg.width;
}
if (origImg.height > maxHeight) {
let scale2 = maxHeight / origImg.height;
if (scale2 < scale) scale = scale2;
}
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = origImg.height * scale;
canvas.height= origImg.width * scale;
ctx.translate(canvas.width, 0);
ctx.rotate(90 * Math.PI / 180);
ctx.drawImage(origImg, 0, 0, canvas.height, canvas.width);
return canvas.toDataURL("image/jpeg");
},
Running this function as-is triggers the following console error:
Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLImageElement or SVGImageElement or HTMLVideoElement or HTMLCanvasElement or ImageBitmap or OffscreenCanvas)'
How do I get/reuse the origImg object from the resizeImage function so I can use it in the rotateImage function?
you can try with this code:
var myCanvas = document.getElementById('my_canvas_id');
var ctx = myCanvas.getContext('2d');
var img = new Image;
img.onload = function(){
ctx.drawImage(origImg,0,0); // Or at whatever offset you like
};
And apply your code insede onload function of img and finally transform img source to date URL
Try this code, based on one file picker, two buttons. The first one resize image and the second one rotete the image
function resizeImg()
{
var oPicker = document.getElementById('avatar');
var oImage = document.getElementById('imgOut');
var file = oPicker.files[0];
const fr = new FileReader();
fr.readAsDataURL(file);
fr.addEventListener('load', () => {
var img = new Image();
img.src = fr.result;
img.onload = () => {
oImage.thumbnail = this.resizeImage(img, 400, 300);
oImage.src = this.resizeImage(img, 1280, 960);
}
})
}
function rotateImg()
{
var imgOut = document.getElementById('imgOut');
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
let scale = 1;
canvas.width = imgOut.height * scale;
canvas.height= imgOut.width * scale;
ctx.translate(canvas.width, 0);
ctx.rotate(90 * Math.PI / 180);
ctx.drawImage(imgOut, 0, 0, canvas.height, canvas.width);
imgOut.src = canvas.toDataURL("image/jpeg");
}
function resizeImage(origImg, maxWidth, maxHeight) {
let scale = 1;
if (origImg.width > maxWidth) {
scale = maxWidth / origImg.width;
}
if (origImg.height > maxHeight) {
let scale2 = maxHeight / origImg.height;
if (scale2 < scale) scale = scale2;
}
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
canvas.width = origImg.width * scale;
canvas.height= origImg.height * scale;
ctx.drawImage(origImg, 0, 0, canvas.width, canvas.height);
return canvas.toDataURL("image/jpeg");
}
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Image test</h1>
<img src="" id="imgOut" />
<label for="avatar">Choose a profile picture:</label>
<input type="file" id="avatar" name="avatar" accept="image/png, image/jpeg">
<input type="button" id="resImg" onclick="resizeImg()" value="Resize" />
<input type="button" id="rotImg" onclick="rotateImg()" value="Rotate" />
</body>
</html>
As you have a part in onFilePicked() where you store something about the images:
let image = {
thumbnail: '/img/spinner.gif'
};
this.images.push(image);
and later update the same objects in loadImage() (well, an event handler in it) as
image.thumbnail = this.resizeImage(img, 400, 300);
image.large = this.resizeImage(img, 1280, 960);
It could be simply extended to
image.original = img;
image.thumbnail = this.resizeImage(img, 400, 300);
image.large = this.resizeImage(img, 1280, 960);
Starting from this point, the objects in your images array would have an original field, storing the original, non-resized variant of the image.
I want to resize the canvas field like paint app in javascript how can I do ?
My html file is :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="paint.css">
<title>Paint</title>
</head>
<body>
<canvas id="canvas" style="border: solid 1px black">Your Browser does not support Canvas, please upgrade</canvas>
<script src="paint.js"></script>
</body>
</html>
Thanks !
It turned out to be a bit more complex.
Resizing the canvas clears it, therefore you need to do it this way:
create a new canvas
assign the dimensions
draw the old canvas over the new canvas
replace the old canvas with the new canvas
//Base canvas and dimensions
var canvas = document.body.appendChild(document.createElement("canvas"));
var width = canvas.height = canvas.width = 400;
var height = width;
var ctx = canvas.getContext("2d");
//Drawing variables
var lastPosition = null;
var drawing = false;
//Drawing functionality
function startDraw() {
drawing = true;
}
canvas.onmousedown = startDraw;
function stopDraw() {
drawing = false;
}
canvas.onmouseup = stopDraw;
canvas.onmouseleave = stopDraw;
function mouseMove(evt) {
var pos = {
x: evt.offsetX,
y: evt.offsetY
};
if (lastPosition !== null && drawing === true) {
ctx.beginPath();
ctx.moveTo(lastPosition.x, lastPosition.y);
ctx.lineTo(pos.x, pos.y);
ctx.closePath();
ctx.stroke();
}
lastPosition = pos;
}
canvas.onmousemove = mouseMove;
//Resizer functions
var resizerX = document.body.appendChild(document.createElement("button"));
resizerX.innerHTML = "Resize X";
resizerX.onclick = function() {
var newValue = null;
while (isNaN(newValue) || newValue < 10) {
newValue = parseInt(prompt("Insert new width", width.toString()));
}
var c = document.createElement("canvas");
width = newValue;
c.width = width;
c.height = height;
ctx = c.getContext("2d");
ctx.drawImage(canvas, 0, 0);
canvas.parentNode.replaceChild(c, canvas);
canvas = c;
canvas.onmousedown = startDraw;
canvas.onmouseup = stopDraw;
canvas.onmouseleave = stopDraw;
canvas.onmousemove = mouseMove;
};
var resizerY = document.body.appendChild(document.createElement("button"));
resizerY.innerHTML = "Resize Y";
resizerY.onclick = function() {
var newValue = null;
while (isNaN(newValue) || newValue < 10) {
newValue = parseInt(prompt("Insert new height", height.toString()));
}
var c = document.createElement("canvas");
height = newValue;
c.width = width;
c.height = height;
ctx = c.getContext("2d");
ctx.drawImage(canvas, 0, 0);
canvas.parentNode.replaceChild(c, canvas);
canvas = c;
canvas.onmousedown = startDraw;
canvas.onmouseup = stopDraw;
canvas.onmouseleave = stopDraw;
canvas.onmousemove = mouseMove;
};
canvas {
background-color: #eee
}
I have a drawing interface which the drawings need to be saved at 1280x720px. However, I want the canvas to be able to be scalable in relation to that aspect ratio. A problem is that when I draw, the start of the path is not on the cursor.
I've looked everywhere and cannot find a solution. Here is the javascript:
var clearButton = document.getElementById('doodle-bin');
var canvascontainer = document.getElementById('doodle-canvas-container');
var canvas = document.getElementById('doodle-canvas');
var context = canvas.getContext('2d');
var radius = (document.getElementById('doodle-canvas-container').clientWidth + document.getElementById('doodle-canvas-container').clientHeight)/150;
var dragging = false;
context.mozImageSmoothingEnabled = false;
context.imageSmoothingEnabled = false;
canvas.width = 1280;
canvas.height = 720;
canvas.style.width = '100%';
canvas.style.height = '100%';
/* CLEAR CANVAS */
function clearCanvas() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
clearButton.addEventListener('click', clearCanvas);
var putPoint = function (e) {
if (dragging) {
context.lineTo(e.offsetX, e.offsetY);
context.lineWidth = radius * 2;
context.stroke();
context.beginPath();
context.arc(e.offsetX, e.offsetY, radius, 0, Math.PI * 2);
context.fill();
context.beginPath();
context.moveTo(e.offsetX, e.offsetY);
}
};
var engage = function (e) {
dragging = true;
putPoint(e);
};
var disengage = function () {
dragging = false;
context.beginPath();
};
canvas.addEventListener('mousedown', engage);
canvas.addEventListener('mousemove', putPoint);
canvas.addEventListener('mouseup', disengage);
document.addEventListener('mouseup', disengage);
canvas.addEventListener('contextmenu', disengage);
Use the following function to get the proper mouse position even if the canvas is re-scaled. This will resolve the path start issue.
function getMouesPosition(e) {
var mouseX = e.offsetX * canvas.width / canvas.clientWidth | 0;
var mouseY = e.offsetY * canvas.height / canvas.clientHeight | 0;
return {x: mouseX, y: mouseY};
}
var clearButton = document.getElementById('doodle-bin');
var canvascontainer = document.getElementById('doodle-canvas-container');
var canvas = document.getElementById('doodle-canvas');
var context = canvas.getContext('2d');
var radius = (document.getElementById('doodle-canvas-container').clientWidth + document.getElementById('doodle-canvas-container').clientHeight) / 150;
var dragging = false;
context.mozImageSmoothingEnabled = false;
context.imageSmoothingEnabled = false;
canvas.width = 1280;
canvas.height = 720;
canvas.style.width = '100%';
canvas.style.height = '100%';
/* CLEAR CANVAS */
function clearCanvas() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
clearButton.addEventListener('click', clearCanvas);
function getMouesPosition(e) {
var mouseX = e.offsetX * canvas.width / canvas.clientWidth | 0;
var mouseY = e.offsetY * canvas.height / canvas.clientHeight | 0;
return {x: mouseX, y: mouseY};
}
var putPoint = function (e) {
if (dragging) {
context.lineTo(getMouesPosition(e).x, getMouesPosition(e).y);
context.lineWidth = radius * 2;
context.stroke();
context.beginPath();
context.arc(getMouesPosition(e).x, getMouesPosition(e).y, radius, 0, Math.PI * 2);
context.fill();
context.beginPath();
context.moveTo(getMouesPosition(e).x, getMouesPosition(e).y);
}
};
var engage = function (e) {
dragging = true;
putPoint(e);
};
var disengage = function () {
dragging = false;
context.beginPath();
};
canvas.addEventListener('mousedown', engage);
canvas.addEventListener('mousemove', putPoint);
canvas.addEventListener('mouseup', disengage);
document.addEventListener('mouseup', disengage);
canvas.addEventListener('contextmenu', disengage);
body{margin:0;overflow:hidden}canvas{border:1px solid #ccc}
<button id="doodle-bin">Clear</button>
<div id="doodle-canvas-container">
<canvas id="doodle-canvas"></canvas>
</div>
I am attempting to locate the coordinates of the mouse on a canvas element of an HTML5 page.
I create the canvas to be a certain height and width, for example 700x700. When I mouse over the canvas, I want to be able to know the X,Y of the mouse. This works fine, until I stretch my canvas using CSS in the HTML file...
Here is my javascript file:
function Sprite(path)
{
this.img = new Image();
this.img.onload = loaded;
this.img.src = path;
function loaded()
{
console.log("Loaded picture");
}
}
function drawSprite(sprite, ctx)
{
console.log("drawing picture");
ctx.drawImage(sprite.img,10,10);
}
//------------------------------------------
function Game()
{
this.canvas = document.createElement("canvas");
document.body.appendChild(this.canvas);
this.canvas.width = 700;
this.canvas.height = 700;
this.context = this.canvas.getContext("2d");
var ctx = this.context;
ctx.canvas.addEventListener('mousemove', function(event){
var mouseX = event.clientX - ctx.canvas.offsetLeft;
var mouseY = event.clientY - ctx.canvas.offsetTop;
var status = document.getElementById("coords");
status.innerHTML = mouseX+" | "+mouseY;
});
this.objects = new Array();
this.objects.push(new Sprite("dog.png"));
}
function drawGame(g)
{
console.log("I'm here");
for(var i=0;i<g.objects.length;i++)
{
drawSprite(g.objects[i], g.context);
}
}
function drawLine(g)
{
g.context.moveTo(0,0);
g.context.lineTo(100,100);
g.context.stroke();
}
//------------------
window.addEventListener('load',function(event){startgame();});
var globalGame;
function startgame()
{
globalGame = new Game();
drawGame(globalGame);
drawLine(globalGame);
}
Here is my HTML File
<html>
<head>
<script src="functions.js"></script>
<style>
canvas
{
width:90%;
height:90%;
}
</style>
</head>
<body>
<h1 id="coords">0 | 0</h1>
</body>
<html>
The mouse coordinates are in display pixels. To convert that to canvas coordinates, you'll need to scale them accordingly.
One way of doing this is:
const canvasX = mouseX * canvas.width / canvas.clientWidth;
const canvasY = mouseY * canvas.height / canvas.clientHeight;
as shown in this example:
const status = document.getElementById("coords");
const canvas = document.createElement("canvas");
canvas.width = 700;
canvas.height = 700;
document.body.appendChild(canvas);
canvas.addEventListener('mousemove', event => {
const mouseX = event.clientX - canvas.offsetLeft;
const mouseY = event.clientY - canvas.offsetTop;
// scale mouse coordinates to canvas coordinates
const canvasX = mouseX * canvas.width / canvas.clientWidth;
const canvasY = mouseY * canvas.height / canvas.clientHeight;
status.innerHTML = `${mouseX} | ${mouseY}<br>${canvasX} | ${canvasY}`;
});
canvas {
width:250px;
height:250px;
background-color:#f0f;
}
<div id="coords">??? | ???<br>??? | ???</div>