Drawing on Canvas with image - javascript

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%;

Related

I'm making a drawing based web-app and I'm using HTML Canvas to handle the drawing, however the drawing is offset to the right a lot?

const map = document.getElementById('map')
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
const grid = document.getElementById('grid')
function resize() {
canvas.width = map.offsetWidth
canvas.height = map.offsetHeight
ctx.width = map.offsetWidth
ctx.height = map.offsetHeight
}
resize();
grid.appendChild(canvas)
canvas.style.gridColumn = 2
canvas.style.gridRow = 1
let pos = { x: 0, y: 0 };
window.addEventListener('resize', resize);
document.addEventListener('mousemove', draw);
document.addEventListener('mousedown', setPosition);
document.addEventListener('mouseenter', setPosition);
function setPosition(e) {
pos.x = e.clientX;
pos.y = e.clientY;
}
function draw(e) {
if (e.buttons !== 1) return;
ctx.beginPath();
ctx.lineWidth = 5;
ctx.lineCap = 'round';
ctx.strokeStyle = '#c0392b';
ctx.moveTo(pos.x, pos.y);
setPosition(e);
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
}
Heres the code that generates the canvas relative to the size of a picture and allows the user to draw on the canvas. I've looked over another StackOverflow post with the same problem but no relevant answers. I know that the cause of the problem is that the canvas is stretched from it's standard proportion of 300 x 150 and is drawing at the correct position mathematically but not physically. How do I fix this?

Mouse Position Off In HTML5 Canvas?

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

Fade out effect for line in HTML5 canvas with background image

I'm currently working on an HTML canvas example that fades out a line after it is drawn on a canvas, though my question is: how do I attain this while using a background image?
Live Demo (current code in a link at the bottom of this post)
CSS:
canvas {
background-image: url("https://zgab33vy595fw5zq-zippykid.netdna-ssl.com/wp-content/uploads/2018/02/PluralsightandSO.jpg");
background-size: 100% 100%;
}
JavaScript:
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
painting = false,
lastX = 0,
lastY = 0;
canvas.width = canvas.height = 600;
canvas.onmousedown = function (e) {
if (!painting) {
painting = true;
} else {
painting = false;
}
lastX = e.pageX - this.offsetLeft;
lastY = e.pageY - this.offsetTop;
};
canvas.onmousemove = function (e) {
if (painting) {
mouseX = e.pageX - this.offsetLeft;
mouseY = e.pageY - this.offsetTop;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(mouseX, mouseY);
ctx.stroke();
lastX = mouseX;
lastY = mouseY;
}
}
function fadeOut() {
ctx.fillStyle = "rgba(255,255,255,0.3)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
setTimeout(fadeOut,100);
}
fadeOut();
I realize fillRect is filling the entire canvas with the fillStyle so I assumed I could add the image to the canvas instead, but as you can tell, the animation is not the same by using this code instead:
var image = new Image();
image.src = "https://zgab33vy595fw5zq-zippykid.netdna-ssl.com/wp-content/uploads/2018/02/PluralsightandSO.jpg"
ctx.drawImage(image, 0, 0);
Current Live Demo (after changes described above) - it's too rigid and doesn't have as long of a tail
Any thoughts?
You're drawing a 30% transparent square to get the 'fading' effect:
ctx.fillStyle = "rgba(255,255,255,0.3)";
So you need to draw the PNG transparently as well
canvas.onmousemove = function (e) {
if (painting) {
// set line alpha to 1
ctx.globalAlpha = 1.0;
// your paint code here
}
}
function fadeOut() {
var image = new Image();
// set image alpha to 0.3
ctx.globalAlpha = 0.3;
// your draw image code here
}
By the way, you don't need to create the new image every time!
Example
You need to specify width and height:
ctx.drawImage(image, 0, 0, 600, 600);

HTML5: whiteboard dimension?

I'm creating a simple whiteboard using html5 canvas.
I need to give the canvas a width and height. This causes the whiteboard to not work properly.
If I remove the width and height from the canvas, it works fine!
This is my code:
var myCanvas = document.getElementById("myCanvas");
var ctx = myCanvas.getContext("2d");
// Fill Window Width and Height
myCanvas.width = window.innerWidth;
myCanvas.height = window.innerHeight;
// Set Background Color
ctx.fillStyle="#fff";
ctx.fillRect(0,0,myCanvas.width,myCanvas.height);
// Mouse Event Handlers
if(myCanvas){
var isDown = false;
var canvasX, canvasY;
ctx.lineWidth = 5;
$(myCanvas)
.mousedown(function(e){
isDown = true;
ctx.beginPath();
canvasX = e.pageX - myCanvas.offsetLeft;
canvasY = e.pageY - myCanvas.offsetTop;
ctx.moveTo(canvasX, canvasY);
})
.mousemove(function(e){
if(isDown !== false) {
canvasX = e.pageX - myCanvas.offsetLeft;
canvasY = e.pageY - myCanvas.offsetTop;
ctx.lineTo(canvasX, canvasY);
ctx.strokeStyle = "#000";
ctx.stroke();
}
})
.mouseup(function(e){
isDown = false;
ctx.closePath();
});
}
// Touch Events Handlers
draw = {
started: false,
start: function(evt) {
ctx.beginPath();
ctx.moveTo(
evt.touches[0].pageX,
evt.touches[0].pageY
);
this.started = true;
},
move: function(evt) {
if (this.started) {
ctx.lineTo(
evt.touches[0].pageX,
evt.touches[0].pageY
);
ctx.strokeStyle = "#000";
ctx.lineWidth = 5;
ctx.stroke();
}
},
end: function(evt) {
this.started = false;
}
};
// Touch Events
myCanvas.addEventListener('touchstart', draw.start, false);
myCanvas.addEventListener('touchend', draw.end, false);
myCanvas.addEventListener('touchmove', draw.move, false);
// Disable Page Move
document.body.addEventListener('touchmove',function(evt){
evt.preventDefault();
},false);
#myCanvas{
width:90%;
height:200px;
border:solid 1px #c8def0;
border-radius:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="myCanvas">
Sorry, your browser does not support HTML5 canvas technology.
</canvas>
basically, when I run the above code, the mouse doesn't go all the way down the canvas but if I remove the canvas width and height, it works fine.
Could someone please advice on this issue?
Thanks in advance.

Canvas doesn't draw IE 11

I have a canvas code to draw a signature. The code works perfectly fine with chrome and Firefox but does not draw at all on IE 11.
My canvas is:
<canvas id="signitureCanvas" style="border: 3px solid #000; cursor:crosshair; background-color:white;"></canvas>
My code is as below:
var canvas = document.getElementById('signitureCanvas');
var ctx = canvas.getContext('2d');
var canvasWidth = 200;
var canvasLength = 120;
canvas.width = canvasWidth;
canvas.height = canvasLength;
var canvasx = $(canvas).offset().left;
var canvasy = $(canvas).offset().top;
var last_mousex = last_mousey = 0;
var mousex = mousey = 0;
var mousedown = false;
var tooltype = 'draw';
//Mousedown
$(canvas).on('mousedown', function (e) {
last_mousex = mousex = parseInt(e.clientX - canvasx);
last_mousey = 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.beginPath();
if (tooltype == 'draw') {
ctx.globalCompositeOperation = 'source-over';
ctx.strokeStyle = 'black';
ctx.lineWidth = 3;
} else {
ctx.globalCompositeOperation = 'destination-out';
ctx.lineWidth = 10;
}
ctx.moveTo(last_mousex, last_mousey);
ctx.lineTo(mousex, mousey);
ctx.lineJoin = ctx.lineCap = 'round';
ctx.stroke();
}
last_mousex = mousex;
last_mousey = mousey;
});
function ClearCanvas() {
var canvas = document.getElementById('signitureCanvas');
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
Is IE 11 in particular having problems?
Edit:
I figured out the problem is with my Iframe:
When height and width are set to 300 everything works fine:
<embed id="fred" type="application/pdf" style="border:1px solid #666CCC" title="PDF in an i-Frame" src="#Model.FilePath" frameborder="1" scrolling="yes" height="300" width="300" />
When I set it to 1000, it won't work:
<embed id="fred" type="application/pdf" style="border:1px solid #666CCC" title="PDF in an i-Frame" src="#Model.FilePath" frameborder="1" scrolling="yes" height="1000" width="1000" />
I believe it's something with the offset but I can't figure how to fix it.
any help?
For further knowledge to whom might ask:
I have found this piece of code that works on all browsers, layerX and layerY are different for firefox browsers:
var canvas = document.getElementById('signitureCanvas');
var ctx = canvas.getContext('2d');
var canvasWidth = 200;
var canvasLength = 120;
canvas.width = canvasWidth;
canvas.height = canvasLength;
var x = 0;
var y = 0;
function tool_pencil() {
var tool = this;
this.started = false;
// This is called when you start holding down the mouse button
// This starts the pencil drawing
this.mousedown = function (ev) {
ctx.beginPath();
ctx.strokeStyle = 'black';
ctx.lineWidth = 3;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.moveTo(x, y);
tool.started = true;
};
// This function is called every time you move the mouse. Obviously, it only
// draws if the tool.started state is set to true (when you are holding down
// the mouse button)
this.mousemove = function (ev) {
if (tool.started) {
ctx.lineTo(x, y);
ctx.stroke();
}
};
// This is called when you release the mouse button
this.mouseup = function (ev) {
if (tool.started) {
tool.mousemove(ev);
tool.started = false;
}
};
}
// The general-purpose event handler. This function just determines
// the mouse position relative to the <canvas> element
function ev_canvas(ev) {
// Firefox
if (ev.offsetX || ev.offsetX == 0) {
x = ev.offsetX;
y = ev.offsetY;
// Opera
} else if (ev.layerX || ev.layerX == 0) {
x = ev.layerX;
y = ev.layerX;
}
// Call the event handler of the tool
var func = tool[ev.type];
if (func) {
func(ev);
}
}
function ClearCanvas() {
var canvas = document.getElementById('signitureCanvas');
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
}

Categories