I have this simple code for drawing with mouse in canvas. But if I try to style the canvas, like altering the width or centering, the pointer and line drawn get separated. How do I solve this?
JavaScript:
var el = document.getElementById('canvas');
var ctx = el.getContext('2d');
var isDrawing;
el.onmousedown = function(e) {
isDrawing = true;
ctx.moveTo(e.clientX, e.clientY);
};
el.onmousemove = function(e) {
if (isDrawing) {
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
}
};
el.onmouseup = function() {
isDrawing = false;
};
HTML:
CSS:
canvas {
border: 2px solid #ccc;
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
width: 800px;
}
Here's a Fiddle
NEVER set canvas's width / height using css. It's really a bad idea. Always use the native width / height property of the canvas.
Also, you should probably be using e.offsetX and e.offsetY to get the x and y coordinates of the mouse.
Here's a working fiddle
Related
I'm trying to add an overlay using canvas. It needs to disable clicks so all elements above the overlay should be unclickable, except the element that I send to openOverlay function.
In addition, there is a button that I want to make it clickable. This button is sent to openOverlay function.
How can I do it?
This is my code:
https://codepen.io/anon/pen/QQqQae
The button needs to be clickable but not the div
I tried something like: ctx.clearRect in order to cut the piece that is found above the button:
function openOverlay(elem) {
var loc = elem.getBoundingClientRect();
var canvas = document.createElement("canvas");
canvas.className = "highlight";
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.clearRect(loc.left - padding, loc.top - padding, loc.width + padding * 2, loc.height + padding * 2);
document.body.appendChild(canvas);
window.overlayCanvas = canvas;
}
Set z-index for "canvas" to -1 :
canvas{
z-index: -1;
}
But, the above method will make all the elements in the canvas clickable.
So, you can set the following style on the button to make it clickable :
button{
position: absolute; //or, relative
left: 0px;
top: 0px;
z-index: 2;
}
All the other elements in the canvas won't be clickable unless they have position absolute (or, relative) and higher z-index.
First, ctx.clearRect doesn't really have any effect on the mouse click event.
In the future, you may be able to use canvas hit regions, but they have limited support for now. See MDN AddHitRegion
But for now, you can put any button that is supposed to be clickable at a higher z-index than the overlay and give it either relative or absolute positioning.
function openOverlay(elem) {
var canvas = document.createElement("canvas");
canvas.className = "highlight";
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.zIndex = 100;
var ctx = canvas.getContext("2d");
ctx.fillRect(4, 4, 300, 150);
elem.classList.add("clickable");
document.body.appendChild(canvas);
window.overlayCanvas = canvas;
}
var element= document.getElementById("button1")
openOverlay(element)
body{
background-color: grey;
}
.clickable{
position: relative;
z-index:200;
}
canvas{
z-index: 100;
position: absolute;
display: block;
top: 0;
left: 0;
background-color:blue;
opacity: 0.6;
}
<button id="button1" onclick="window.alert('Clicked button1')">Click Me</button>
<button id="button2" onclick="window.alert('Clicked button 2')">Don't Click Me</button>
Is there any way to allow a user to draw on top of a board of divs and allow the drawing to float on top, but for the divs below to still be selectable?
Using html5 canvas (react-sketch), you can of course superimpose a canvas object on top of a page of divs, but then the underlying divs are covered by the (transparent) canvas, and though viewable, cannot be selected.
Is there any simple way around this?
It's doable but you will invite several challenges that in my opinion is simply not worth it.
Example of this:
var ctx = c.getContext("2d"), rect = c.getBoundingClientRect(), isDown = false;
c.width = rect.width;
c.height = rect.height;
// canvas interaction when no divs are in the way
window.onmouseup = window.onmousedown = function(e) {isDown = e.type === "mousedown"};
window.onmousemove = function(e) {
if (isDown) ctx.fillRect(e.clientX, e.clientY, 2, 2);
};
#c {
position:fixed;
left:0;
top:0;
width:100vw;
height:100vh;
pointer-events:none;
}
div {
padding:10px;
border:1px solid #999;
width:200px;
margin-bottom:9px;
}
<div>Hello</div>
<div>There</div>
<canvas id=c></canvas>
As you can see, sure, we can interact and select divs below the canvas, but we are still drawing to the canvas and so forth.
If I may suggest a different approach, it would be to have a modus switch so that when you activate interactive mode using a switch/button in the UI, only interaction with canvas is allowed, and of course, vica versa when mode is switched off.
The mode button could be attached to a hotkey, middle mouse-button and so forth.
var ctx = c.getContext("2d"), rect = c.getBoundingClientRect(), isDown = false;
var drawMode = false;
c.width = rect.width;
c.height = rect.height;
window.onmouseup = c.onmousedown = function(e) {isDown = e.type === "mousedown"};
// only draw if we are in interactive mode
c.onmousemove = function(e) {
if (drawMode && isDown) ctx.fillRect(e.clientX, e.clientY, 2, 2);
};
// toggle mode
document.querySelector("button").onclick = function() {
this.classList.toggle("selected");
c.classList.toggle("active");
drawMode = !drawMode;
};
#c {
position:fixed;
left:0;
top:0;
width:100vw;
height:100vh;
pointer-events:none;
}
#c.active {
pointer-events:auto;
}
div {
padding:10px;
border:1px solid #999;
width:200px;
margin-bottom:9px;
}
button {
position:fixed;
right:7px;
top:7px;
opacity:0.5;
transition:opacity 0.2s;
background:#9f9;
border:1px solid #000;
padding:7px;
}
button:hover {opacity:1}
button.selected {background:#fc0}
<div>Hello</div>
<div>There</div>
<canvas id=c></canvas>
<button>Interactive mode</button>
<p>Click button in upper right corner to activate interactive drawing on canvas</p>
I want to display the mouse's x position on canvas as mouse moves. Can someone please tell why the text is so big and blurry and also is there any way to achieve the transparency between these two canvases
<body style="margin: 0; padding: 0; height: 100%; width: 100%; overflow: hidden;">
<canvas id="myCanvas" style="display: block; height: 100%; width: 100%;">
Your browser does not support the HTML5 canvas tag.</canvas> <canvas id="temp">
Your browser does not support the HTML5 canvas tag.</canvas>
<script type="text/javascript">
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var hgap = 0;
var vgap = 0;
var rows, cols;
var annotation_x = 1;
var row = 0; var col = 0;
//ctx.font = "14px Arial";
var t = document.getElementById("temp");
tctx = t.getContext("2d");
// tctx.lineWidth = 10;
tctx.lineJoin = 'round';
tctx.lineCap = 'round';
tctx.strokStyle = 'red';
var mouse = { x: 0, y: 0 };
c.addEventListener('mousemove', function (evt) {
// tctx.clearRect(0, 0, c.width, c.height);
ctx.clearRect(0, 0, c.width, c.height);
mouse.x = evt.pageX;
mouse.y = evt.pageY;
ctx.fillText(mouse.x, 10, 10);
}, false);
</script>
</body>
The problem isn't due to having two canvas.
The problem is that you scale your canvas using CSS, but you don't modify its number of pixels (height and width attributes). Then, the result is blurry.
If you don't scale it with CSS, the result is fine: Demo
Alternatively, you can try using image-rendering CSS property (e.g. crisp-edges, demo)
You can also modify height and width attributes when the browser is resized (resize event), and redraw the canvas.
<canvas id="myCanvas" style="display: block; height: 100%; width: 100%;">
^ You shouldn't scale a canvas element with CSS unless you want it's contents to be interpolated. Consider a 300x125px image, which you've scaled to the width and height of the browser window - the image will become blurry.
If you wish to have a full-screen canvas you need to scale it with JS:
var c = document.getElementById("myCanvas");
c.width = window.innerWidth;
c.height = window.innerHeight;
..or with HTML:
<canvas width="1920" height="1080"></canvas>
I'm currently learning canvas touch event function,I 'm able to draw line on the canvas, now I want to get the x and y coordinates when I draw any lines and show on the screen.please help and teach me how to get the x and y values, thank You!
here is the coding
<!DOCTYPE html>
<html><head>
<style>
#contain {
width: 500px;
height: 120px;
top : 15px;
margin: 0 auto;
position: relative;
}
</style>
<script>
var canvas;
var ctx;
var lastPt=null;
var letsdraw = false;
var offX = 10, offY = 20;
function init() {
var touchzone = document.getElementById("layer1");
touchzone.addEventListener("touchmove", draw, false);
touchzone.addEventListener("touchend", end, false);
ctx = touchzone.getContext("2d");
}
function draw(e) {
e.preventDefault();
if (lastPt != null) {
ctx.beginPath();
ctx.moveTo(lastPt.x, lastPt.y);
ctx.lineTo(e.touches[0].pageX - offX,
e.touches[0].pageY - offY);
ctx.stroke();
}
lastPt = {
x: e.touches[0].pageX - offX,
y: e.touches[0].pageY - offY
};
}
function end(e) {
var touchzone = document.getElementById("layer1");
e.preventDefault();
// Terminate touch path
lastPt = null;
}
function clear_canvas_width ()
{
var s = document.getElementById ("layer1");
var w = s.width;
s.width = 10;
s.width = w;
}
</script>
</head>
<body onload="init()">
<div id="contain">
<canvas id="layer1" width="450" height="440"
style="position: absolute; left: 0; top: 0;z-index:0; border: 1px solid #ccc;"></canvas>
</div>
</body>
</html>
Still not entirely confident I understand your question.
In the code you posted, you are already obtaining coordinates using e.touches[0].pageX/Y. The main problem with that is that the pageX/Y values are relative to the page origin. You are then subtracting fixed offX/Y in your code to try and convert these to canvas-relative coordinates. Right idea, wrong values. You need to subtract off the position of the canvas element which can be obtained by summing the offsetX/Y values as you traverse the tree upward using the offsetParent reference.
Something like:
offX=0;offY=0;
node = document.getElementById ("layer1");
do {
offX += node.offsetX;
offY += node.offsetY;
node = node.offsetParent;
} while(node);
should give you a better value for offX and offY.
If you just want to locate the actual drawing at the end, it would be easiest just to track a bounding box while the user draws.
I'm trying to draw a rectangle by dragging mouse, basically follow this tutorial.
However, I found that if I specify the canvas dimension in px, it will not work. In contrast, if I use this html, this works fine:
<!DOCTYPE html>
<html>
<head>
<title>drag a rectangle</title>
<style>
#cvs {
width: 500;
height: 500;
border: 1px solid #666;
}
</style>
<script src="jquery-1.9.0.js"></script>
</head>
<body>
<canvas id="cvs"></canvas>
<script src="main.js"></script>
</body>
</html>
And this js:
$(document).ready(function() {
var canvas = document.getElementById('cvs');
var ctx = canvas.getContext('2d');
var rect = {};
var drag = false;
var mouseDown = function(e) {
rect.startX = e.pageX - this.offsetLeft;
rect.startY = e.pageY - this.offsetTop;
console.log(rect.startX + ' ' + rect.startY);
drag = true;
};
var mouseUp = function(e) {
drag = false;
};
var draw = function() {
ctx.fillRect(rect.startX, rect.startY, rect.w, rect.h);
};
var mouseMove = function(e) {
if (drag) {
rect.w = (e.pageX - this.offsetLeft) - rect.startX;
rect.h = (e.pageY - this.offsetTop) - rect.startY;
console.log(rect.w + ' ' + rect.h);
ctx.clearRect(0, 0, canvas.width, canvas.height);
draw();
}
};
function init() {
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
}
init();
});
It works fine. However, if I specify the dimension in px, i.e.,
#cvs {
width: 500px;
height: 500px;
border: 1px solid #666;
}
The mouse location and the rectangle no longer align. Also, the dimension in the viewport is also different. I suppose it's a fundamental question, but what is the difference between specify the px or not? And how does that influence my drag rectangle behavior?
Tested locally on the latest Chrome.
To set the size of your canvas, use the canvas element attributes width and height.
<canvas width="400" height="300">Not supported</canvas>
When the page loads the canvas size is set to it's width and height. If style.width and/or style.height are set, the canvas will scale to fit the dimensions specified in these styles.
Here is an example.
So now about your question. As I wrote above when you set style.width and style.height as:
#cvs {
width: 500px;
height: 500px;
border: 1px solid #666;
}
The width and height will apply and the canvas will scale it's size, so the point with coordinates (x, y) won't appear where you expect. For example, if you try to draw a point with coordinates (500, 500) you probably won't see it at all, because simply your canvas coordinate system's dimensions are less than that. When you don't specify px you simply don't provide valid width and height and your style does not apply correctly so your canvas is not scaled and everything works as you expect.