I have tried a few solutions on SO but they didn't work for my setup. For some reason the mouse position is off on my canvas. I have pasted my HTML and JS below for reference.
The mouse works fine when the canvas size matches the window size, but I need it to work well when it is smaller or bigger too. How can I do this?
HTML
<canvas id="canvas"></canvas>
JS
window.addEventListener('load', () => {
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
// canvas.height = window.innerHeight;
// canvas.width = window.innerWidth;
canvas.height = 540;
canvas.width = 960;
// canvas.height = canvas.offsetHeight;
// canvas.width = canvas.offsetWidth;
let painting = false;
var gradient = ctx.createLinearGradient(0, 0, 170, 0);
gradient.addColorStop("0", "magenta");
gradient.addColorStop("0.5", "blue");
gradient.addColorStop("1.0", "red");
function windowSize() {
// canvas.height = window.innerHeight;
// canvas.width = window.innerWidth;
// canvas.height = 540;
// canvas.width = 960;
// canvas.height = canvas.offsetHeight;
// canvas.width = canvas.offsetWidth;
}
function startPosition(e) {
painting = true;
draw(e);
}
function finishedPosition() {
painting = false;
ctx.beginPath();
}
function draw(e) {
if(!painting) return;
ctx.lineWidth = lineSize;
ctx.lineCap = "round";
ctx.strokeStyle = color;
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(e.clientX, e.clientY);
}
var lineSize = 5;
var color = "Black";
// Event Listeners
canvas.addEventListener('mousedown', startPosition);
canvas.addEventListener('mouseup', finishedPosition);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('touchstart', startPosition);
canvas.addEventListener('touchend', finishedPosition);
canvas.addEventListener('touchmove', draw);
// window.addEventListener('resize', windowSize);
});
The accepted solution here solved my problem. I hope this helps someone else in the future, as it did not appear high in search results.
Real mouse position in canvas
Related
const canvas = document.getElementById("canvas");
canvas.width = window.innerWidth = 750;
canvas.height = 600;
var context = canvas.getContext("2d");
context.fillStyle = "white";
context.fillReact(0, 0, canvas.width, canvas.height);
let draw_color = "black";
let draw_width = "2";
let is_drawing = false;
canvas.addEventListener("touchstart", start, false);
canvas.addEventListener("touchmove", draw, false);
canvas.addEventListener("mousedown", start, false);
canvas.addEventListener("mousemove", draw, false);
function start(event) {
is_drawing = true;
context.beginPath();
context.moveTo(event.clientX = canvas.offsetLeft, event.clientY = canvas.offsetTop);
event.preventDefault();
}
function draw(event) {
if (is_drawing) {
context.beginPath();
context.moveTo(event.clientX = canvas.offsetLeft, event.clientY = canvas.offsetTop);
context.strokeStyle = draw_color;
context.lineWidth = draw_width;
context.lineCap = "round";
context.lineJoin = "round";
context.stroke();
}
}
I did everything right yet it is showing context.fillReact is not a function, it should have draw a line on moving the cursor but it is not doing anything just showing the error.
As far as I know, canvas element's context object does not have any fillReact method in it. Maybe you mean fillRect?
I'm looking for a solution to freehand draw a line with a gradient in canvas like this:
I already found this, but the gradient seems to be 'locked' on the background and is not following the line.
window.addEventListener('load', ()=>{
resize(); // Resizes the canvas once the window loads
document.addEventListener('mousedown', startPainting);
document.addEventListener('mouseup', stopPainting);
document.addEventListener('mousemove', sketch);
window.addEventListener('resize', resize);
});
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
function resize(){
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
}
let coord = {x:0 , y:0};
let paint = false;
function getPosition(event){
coord.x = event.clientX - canvas.offsetLeft;
coord.y = event.clientY - canvas.offsetTop;
}
function startPainting(event){
paint = true;
getPosition(event);
}
function stopPainting(){
paint = false;
}
function sketch(event){
if (!paint) return;
ctx.beginPath();
ctx.lineWidth = 5;
ctx.lineCap = 'round';
var gradient = ctx.createLinearGradient(0, 0, 200, 0);
gradient.addColorStop(0.00, 'grey');
gradient.addColorStop(1 / 2, 'white');
gradient.addColorStop(1.00, 'grey');
ctx.strokeStyle = gradient;
ctx.moveTo(coord.x, coord.y);
getPosition(event);
ctx.lineTo(coord.x , coord.y);
ctx.stroke();
}
Can somebody help me please?
I found a way to do it:
var context = canvas.getContext("2d");
context.strokeStyle = '#000000';
context.fillStyle = '#000000';
context.beginPath();
context.moveTo(10, 10);
context.lineTo(50, 10);
context.lineWidth = 2;
context.stroke();
context.beginPath();
context.lineWidth = 15;
context.moveTo(10, 30);
context.lineTo(50, 30);
context.stroke();
context.beginPath();
context.moveTo(10, 50);
context.lineTo(50, 50);
context.lineWidth = 2;
context.stroke();
Where I reconstructed the gradient with multiple lines and a blur on those lines.
When I load the page, the canvas loads and fills the background as white. But, when I click and drag in the canvas, it wont draw for me.
window.addEventListener("load", () => {
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
canvas.height = 200;
canvas.width = window.innerWidth;
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, canvas.width, canvas.height);
let painting = false;
function startPosition(e) {
painting = true;
draw(e);
}
function endPosition() {
painting = false;
ctx.beginPath();
}
function draw(e) {
if (!painting) return;
ctx.lineWidth = 7;
ctx.lineCap = "round";
ctx.strokeStyle = "black";
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(e.clientX, e.clientY);
}
//Event Listeners
canvas.addEventListener("mousedown", startPosition);
canvas.addEventListener("mouseup", endPosition);
canvas.addEventListener("mousemove", draw);
})
<canvas id='canvas'></canvas>
I have a video element playing a mp4 video.
When clicking the screenshot button, it draws the current video frame on the canvas. I would then like to draw on top of the canvas.
My problem is that I can't get the cursor to align with the drawing coordinates. I have a suspicion that this is because of the way I'm setting the height and the width of the canvas to be able to draw the video frame correctly.
Minimal repro:
https://codepen.io/stiba/pen/KEBRdy
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var video = document.getElementById('vid');
canvas.addEventListener('mousedown', mouseDown);
canvas.addEventListener('mouseup', mouseUp);
canvas.addEventListener('mousemove', mouseMove);
var isDrawing = false;
var prevX = 0;
var prevY = 0;
var currX = 0;
var currY = 0;
function buttonClick() {
console.log('Clicked!');
var height = video.videoHeight;
var width = video.videoWidth;
canvas.width = width;
canvas.height = height;
ctx.fillRect(0, 0, width, height);
ctx.drawImage(video, 0, 0, width, height);
}
function setCoordinates(e) {
prevX = currX;
prevY = currY;
var boundingClientRect = e.target.getBoundingClientRect();
var left = boundingClientRect.left;
var top = boundingClientRect.top;
currX = e.clientX - left;
currY = e.clientY - top;
}
function mouseDown(e) {
setCoordinates(e);
isDrawing = true;
}
function mouseUp(e) {
isDrawing = false;
}
function mouseMove(e) {
if (!isDrawing) {
return;
}
setCoordinates(e);
draw();
}
function draw() {
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(currX, currY);
ctx.strokeStyle = "red";
ctx.lineWidth = 2;
ctx.stroke();
ctx.closePath();
}
Removing the css styles from your canvas will fix the issue. If you need your canvas to be larger use canvas.width and canvas.height properties. Using css to control your canvas size will only increase the html element size but not the drawing surface(pixels).
css to be removed:
flex: 1;
width: 100%;
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>