How to draw canvas elements in the right positions? - javascript

I am using javascript to draw a rectangle around DOM elements in a website.
The problem is that the rectangles are drawn in the wrong positions.
I know that canvas, work like a real canvas so you have to "predraw" everything before filling the canvas, otherwise the elements will be on top of each other, in the orders you drew them.
That's why I'm defining canvas, and context outside of the loop.
This is my code:
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.globalAlpha = 0.5;
//Set canvas width/height
canvas.style.width='100%';
canvas.style.height='100%';
//Set canvas drawing area width/height
canvas.width = document.width;
canvas.height = document.height;
//Position canvas
canvas.style.position='absolute';
canvas.style.left=0;
canvas.style.top=0;
canvas.style.zIndex=100000;
canvas.style.pointerEvents='none'; //Make sure you can click 'through' the canvas
document.body.appendChild(canvas); //Append canvas to body element
var listingsRect = Array.prototype.map.call(document.querySelectorAll('.rc'), function(e) {
return e.getBoundingClientRect();
});
listingsRect.forEach(function(listingRect) {
var x = listingRect.left;
var y = listingRect.top;
var width = listingRect.width;
var height = listingRect.height;
//Draw rectangle
context.rect(x, y, width, height);
context.fillStyle = 'yellow';
context.fill();
});
However, when I change
canvas.width and canvas.height to window.innerWidth and window.innerHeight respectively, then canvas draws the rectangles in the right positions, however it only draws them in the visible area of the website (obviously).
Can somebody tell me what's wrong with my code?
Here's a JS bin:
http://jsbin.com/elUToGO/1

The x,y in context.rect(x,y,width,height) are relative to the canvas element not to the browser window.
So if your canvas element is absolutely positioned at 50,75 and you want a rect at window position 110,125 you would draw your rect like this:
context.rect( 110-50, 125-75, width, height );
A few other things:
If you set the canvas element width/height and then position absolutely, you don't need canvas.style.width/height.
document.width/height are deprecated (& not supported in IE) . Use this instead:
//Set canvas drawing area width/height
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
When setting style.left/top, you might want to pass a string with "px" in case you later set >0.
canvas.style.left="0px";
canvas.style.top="0px";
.pointerEvents='none' is supported in most browsers (but not in IE<11)

Related

HTML Canvas fillRect fill 25% of window-height

I'm trying to learn how to use HTML's Canvas and it's properties.
Now I'm trying to draw a ground and a sky, and I want the sky to be 75% of screens height and ground to be 25%.
This was easy using a div, and style it with CSS or JavaScript CSS Query. Now that I'm on a Canvas, I can't figure out how to set the fillRect properties...
My code:
var windowHeight = $(window).height();
var windowWidth = $(window).width();
var skyHeight = windowHeight - (windowHeight * 0.25);
var groundHeight = windowHeight - (windowHeight * 0.75);
ctx = gameCanvas.getContext("2d");
ctx.fillStyle="green";
ctx.fillRect(0,0,windowWidth,windowHeight);
ctx.fillStyle="cyan";
ctx.fillRect(0,0,windowWidth,skyHeight);
Also: if I try using i.e.
ctx.fillStyle="cyan";
ctx.fillRect(0,0,30,30);
This draws a perfect square on top of the green "ground"-background, but if I change to i.e.
ctx.fillRect(0,0,200,200);
it will fill my entire height of the screen, and more than 50% of my screen-width.
According to http://www.w3schools.com/tags/canvas_fillstyle.asp canvas fillrect are using pixels, but 200 x 200 pixels should definitely NOT fill my entire screen height. :/
Where's the part where you tell canvas what its dimensions are? Just like any other HTML media element that you need to be of a specific size (video, image), you need to tell it what its width and height is if you want reliably sized content (if you don't, by convention the canvas will be sized 300 x 150px). And because we're setting the number of pixels we can draw on, this is not "purely cosmetic" like CSS, we have to do it properly:
var cvs = document.querySelector("canvas");
// if you didn't use <canvas width="..." height="...">, we need this:
cvs.width = 800;
cvs.height = 400;
And then you can do your drawing:
var ctx = cvs.getContext("2d");
ctx.fillStyle = "green";
ctx.fillRect(0,0.75*cvs.height, cvs.width,0.25*cvs.height);
ctx.fillStyle = "lightblue";
ctx.fillRect(0,0, cvs.width, 0.75*cvs.height);
See http://jsbin.com/tejiqixeji/edit?html,js,output

width and height in canvas are not accurate

I'm trying to draw a canvas with width x*100px and height y*100px
var x=6,y=5;
var canvas = document.getElementById('game');
var ctx = canvas.getContext('2d');
canvas.style.width=(100*x)+"px";
canvas.style.height=(100*y)+"px";
for(var i=0;i<x;i++)
for(var j=0;j<y;j++)
{
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect (i*100, j*100, 100, 100);
ctx.fillStyle = "rgb(0,0,0)";
ctx.strokeRect(i*100, j*100, 100, 100);
}
jsfiddle
but it looks like the width and height of each tile in the grid are not 100 px, Why is that? and how can I set the width of each tile exactly to 100px?
Use this instead:
canvas.width=(100*x);
canvas.height=(100*y);
It seems a bit strange, but canvas is one element type that does not use CSS styling for its width and height. The number of available physical pixels is very relevant to the way that it draws, so it can't be left as a transient, derived CSS value (ie, width: calc(300vw - 100% - 20px);). That said, it's usually a good idea to have width/height change on a browser resize if you're making the web page responsive.

Getting wrong canvas height

I get a wrong canvas height. Whats wrong here?
I made a fiddle: http://jsfiddle.net/hbcz6/
HTML:
<div id="app">
<div id="percent" class="animated"></div>
<canvas></canvas>
</div>
Javascript:
var canvas = document.getElementsByTagName("canvas")[0];
var context = canvas.getContext('2d');
var x = canvas.width / 2;
console.log("canvas X: ", x);
var y = canvas.height / 2;
console.log("canvas y: ", y);
Please have a look to your console.
As you are not setting the size of the canvas element its bitmap will default to 300 x 150 pixels. If you use CSS rules then the element will be stretched but the bitmap will, stay at the same size just scaled to fit the size of the element (just like an image would).
Here is how to dynamically fit a canvas element inside a parent element settings its size properly:
First, remove the width and height from the CSS rule:
#app canvas {
border:2px solid red;
}
Then use getComputedStyle to get the parent element's dimension in pixels:
var cs = getComputedStyle(app),
width = parseInt(cs.getPropertyValue('width'), 10);
height = parseInt(cs.getPropertyValue('height'), 10);
The parseInt will remove the px at the end - now simply use those for the canvas element:
canvas.width = width;
canvas.height = height;
Working fiddle here
You aren't setting the canvas's dimensions. Using CSS to style it only affects the rendered result, it does not affect the underlying canvas that is being drawn on. In this case, it is using the default sizes, and then stretching it to cover the container.

HTML canvas - drawing disappear on resizing

I have created a basic shape in HTML canvas element which works fine.
The problem occurs when I resize the canvas, all the drawing in the canvas disappears. Is this the normal behavior? or is there a function that can be used to stop this?
One way to fix this could be to call drawing function again on canvas resize however this may not be very efficient if there is huge content to be drawn.
What's the best way?
Here is the link to sample code https://gist.github.com/2983915
You need to redraw the scene when you resize.
setting the width or height of a canvas, even if you are setting it to the same value as before, not only clears the canvas but resets the entire canvas context. Any set properties (fillStyle, lineWidth, the clipping region, etc) will also be reset.
If you do not have the ability to redraw the scene from whatever data structures you might have representing the canvas, you can always save the entire canvas itself by drawing it to an in-memory canvas, setting the original width, and drawing the in-memory canvas back to the original canvas.
Here's a really quick example of saving the canvas bitmap and putting it back after a resize:
http://jsfiddle.net/simonsarris/weMbr/
Everytime you resize the canvas it will reset itself to transparant black, as defined in the spec.
You will either have to:
redraw when you resize the canvas, or,
don't resize the canvas
One another way is to use the debounce if you are concerned with the performance.
It doesnt resize or redraw every position you are dragging. But it will resize only when the it is resized.
// Assume canvas is in scope
addEventListener.("resize", debouncedResize );
// debounce timeout handle
var debounceTimeoutHandle;
// The debounce time in ms (1/1000th second)
const DEBOUNCE_TIME = 100;
// Resize function
function debouncedResize () {
clearTimeout(debounceTimeoutHandle); // Clears any pending debounce events
// Schedule a canvas resize
debounceTimeoutHandle = setTimeout(resizeCanvas, DEBOUNCE_TIME);
}
// canvas resize function
function resizeCanvas () { ... resize and redraw ... }
I had the same problem. Try following code
var wrapper = document.getElementById("signature-pad");
var canvas = wrapper.querySelector("canvas");
var ratio = Math.max(window.devicePixelRatio || 1, 1);
canvas.width = canvas.offsetWidth * ratio;
canvas.height = canvas.offsetHeight * ratio;
It keeps the drawing as it is
One thing that worked for me was to use requestAnimationFrame().
let height = window.innerHeight;
let width = window.innerWidth;
function handleWindowResize() {
height = window.innerHeight;
width = window.innerWidth;
}
function render() {
// Draw your fun shapes here
// ...
// Keep this on the bottom
requestAnimationFrame(render);
}
// Canvas being defined at the top of the file.
function init() {
ctx = canvas.getContext("2d");
render();
}
I had the same problem when I had to resize the canvas to adjust it to the screen.
But I solved it with this code:
var c = document.getElementById('canvas');
ctx = c.getContext('2d');
ctx.fillRect(0,0,20,20);
// Save canvas settings
ctx.save();
// Save canvas context
var dataURL = c.toDataURL('image/jpeg');
// Resize canvas
c.width = 50;
c.height = 50;
// Restore canvas context
var img = document.createElement('img');
img.src = dataURL;
img.onload=function(){
ctx.drawImage(img,20,20);
}
// Restote canvas settings
ctx.restore();
<canvas id=canvas width=40 height=40></canvas>
I also met this problem.but after a experiment, I found that Resizing the canvas element will automatically clear all drawings off the canvas!
just try the code below
<canvas id = 'canvas'></canvas>
<script>
var canvas1 = document.getElementById('canvas')
console.log('canvas size',canvas1.width, canvas1.height)
var ctx = canvas1.getContext('2d')
ctx.font = 'Bold 48px Arial'
var f = ctx.font
canvas1.width = 480
var f1 = ctx.font
alert(f === f1) //false
</script>

Html Canvas Resizing And Coordinate Space

Note: I'm using Google Chrome
Currently I have this test page
http://www.evecakes.com/doodles/canvas_size_issue.htm
It should draw a rectangle right below the mouse cursor, but there are some really weird scaling issues which is causing it to draw at a varying offset. I think it's because the canvas coordinate space is not increasing along with its html size. Is there a way to increase that coordinate space size?
Here's the javascript function
$('#mapc').mousemove(function (event) {
var canvas = $('#mapc');
var ctx = canvas[0].getContext('2d');
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect(event.clientX, event.clientY, 55, 50);
document.title = event.clientX + " --- " + event.clientY;
});
Set the width and height HTML attributes of the canvas. Right now, it's assuming its default width and the CSS is just stretching it, and it appears as if it is scaling.
A side-note, you can use this in the mousemove event - it is a reference to #mapc element, so you won't have to query the DOM on every mouse move.
var offset = $('#mapc').offset();
$('#mapc').mousemove(function (event) {
var ctx = this.getContext('2d');
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect(event.pageX - offset.left, event.pageY - offset.top, 1, 1);
});

Categories

Resources