Scaling canvas shapes with 100% width canvas - javascript

I am trying to create an example of a canvas element with 100% width, containing a red square "border" rect. If I set the width of a canvas element in CSS to be 100%, it will successfully grow to fit the full width of the viewport, but the rect is blurred because CSS just stretches the canvas. This is demonstrated here:
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.strokeStyle = "red";
ctx.strokeRect(0, 0, 300, 150);
canvas {
width: 100%;
}
<canvas></canvas>
I can set the canvas height and width to be equal to clientWidth and clientHeight as demonstrated below, which means the canvas will not bet stretched, but now my canvas context dimensions are no longer 300 x 150, and I won't know what the actual dimensions are in advance. How can do my canvas drawing with predictable dimensions liek 300 x 150, but also scale the canvas element to be 100% width? Webgl has gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); which I believe solves this problem, does canvas have a similar approach, or do you need to scale all the of dimensions of your shapes to have the same scaling that is applied to the canvas element? e.g. multiply by clientWidth / 300 and clientHeight / 150?
const canvas = document.querySelector("canvas");
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
const ctx = canvas.getContext("2d");
ctx.strokeStyle = "red";
ctx.strokeRect(0, 0, 300, 150);
canvas {
width: 100%;
}
<canvas></canvas>

A good solution seems to be using the .scale() method on the canvas context as per below. This way you can work with whatever coordinate system you like in the canvas context.
const canvas = document.querySelector("canvas");
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
const ctx = canvas.getContext("2d");
ctx.scale(canvas.clientWidth / 300, canvas.clientHeight / 150);
ctx.strokeStyle = "red";
ctx.strokeRect(0, 0, 300, 150);
canvas {
width: 100%;
}
<canvas></canvas>

Related

How to Style Images in a canvas?

I'm using node-canvas and I was wonder how style an imported image in canvas similar to how you would an image in CSS.
For example, how would I crop a square image in canvas to a circle. In CSS, all you need to do is set border radius to 50%.
Well obviously you cannot use CSS in this case since CSS is applied to the DOM and not the the pixel based content of a Canvas element.
However the Canvas element has its own set of draw functions which allow to you replicate or at least approximate CSS rules.
Since you mentioned cropping an image to a circle I'll focus on this example. To achieve this effect you want to specify a clipping region before drawing the image. Every pixel outside of the clipped region will not be drawn. Effectively this will crop the image to the clipped region.
In code:
// Retrieve canvas and get context
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
// Save the context so we can undo the clipping region at a later time
context.save();
// Define the clipping region as an 360 degrees arc at point x and y
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
// Clip!
context.clip();
// Draw the image at imageX, imageY.
context.drawImage(image, imageX, imageY);
// Restore context to undo the clipping
context.restore();
I'd advice taking a look at this page to give you an idea of what you can do with the Canvas element and the 2D rendering context.
I don't know if this would work in node, However you can do this with canvas;
The simplest way of doing it is using, as you intended, border-radius:
canvas{border-radius:50%;}
An other way of doing it is by using the ctx.clip() method.
let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(125,120,100,0,2*Math.PI);
// you clip the context
ctx.clip();
let img = document.querySelector("#testImg");
ctx.drawImage(img, 0, 20);
<canvas width="250" height="240" >
<img id="testImg" src="theImage.jpg">
</canvas>
Yet an other way of doing it is by using ctx.globalCompositeOperation = "destination-atop"in this way:
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
let cw = canvas.width = 400,
cx = cw / 2;
let ch = canvas.height = 400,
cy = ch / 2;
ctx.globalCompositeOperation = "destination-atop";
let img = document.querySelector("#testImg");
ctx.drawImage(img, 0, 0);
ctx.beginPath();
ctx.fillStyle = "#f00";
ctx.arc(cx, cx, 100, 0, 2 * Math.PI);
ctx.fill();

Rotate an image and draw on canvas

I have been trying different ways to draw an image from a videostream of size 1920*1080 on a canvas of size 1080*1920. I want to rotate the video -90ยบ so it fits exactly on the canvas (not resizing the original video by shrinking and expanding). The following is what I tried:
canvas = document.createElement('canvas');
canvas.height = 1920;
canvas.width = 1080;
context = canvas.getContext('2d');
context.drawImage(videoSrc, 0, 0, 1080, 1920, 1080, -1920, 1080, 1920);
// I have been trying different combinations of above numbers
return canvas;
I haven't used context.rotate() or any other translation method as I don't want to rotate the canvas but just draw the video starting from a different position in the canvas. Maybe I'm wrong. Thanks for reading
You need to call to rotate() within your context prior to drawing your image. Like so:
canvas = document.createElement('canvas');
canvas.height = 1920;
canvas.width = 1080;
//Angle to rotate, negative for counter clockwise
degrees = 45;
context = canvas.getContext('2d');
//Rotation calculated in radians (hence the math).
context.rotate(degrees * Math.PI / 180);
context.drawImage(videoSrc, 0, 0, 1080, 1920, 1080, -1920, 1080, 1920);
//Reset rotation
context.resetTransform();
return canvas;

Cannot draw text in javascript

I am trying to display simple text on the screen via update() and setInterval() functions, but it's not working. Note that I create a canvas on which I want the text to be displayed. Please , check the code below.
var canvas, canvasContext;
window.onload = function() {
canvas = document.getElementById('theCanvas');
canvasContext = canvas.getContext('2d');
var fps = 30;
setInterval(update, 1000 / fps);
}
function update() {
drawText();
}
function drawText() {
canvasContext.fillStyle = 'black';
canvasContext.font = 'bold 40px Monospace';
canvasContext.fillText('POC ......', 150, 150);
}
#canvasHolder {
position: absolute;
left: 0px;
top: 0px;
}
#theCanvas {
background-color: lightgreen;
width: 100pc;
height: 100pc;
}
<div id="canvasHolder">
<canvas id="theCanvas"></canvas>
</div>
The issue is that the canvas is being stretched to fill the element. Both the canvas itself and the canvas element have a size. If you don't specify the size of the canvas (you haven't), it defaults to 300x150. When the size of the element and the canvas don't match, the canvas content is scaled to fit into the element.. So the text is being drawn, it's just really big; scroll to the right and down and you'll find it.
My guess is that you meant for the canvas and the element to be the same size. If so, you need to set the size of the canvas. You can do that with width and height attributes on the canvas element, but those values will be in pixels, not picas as in your CSS. So we do it dynamically by getting the computed width and height of the element (because they'll come back to us in pixels), and then setting those values for the width and height attributes of the canvas:
// Set the canvas size to match the element size
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
Updated snippet:
var canvas, canvasContext;
window.onload = function() {
canvas = document.getElementById('theCanvas');
// Set the canvas size to match the element size
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
canvasContext = canvas.getContext('2d');
canvasContext.canvas.width = canvas.width;
canvasContext.canvas.height = canvas.height;
var fps = 30;
setInterval(update, 1000 / fps);
};
function update() {
drawText();
}
function drawText() {
canvasContext.fillStyle = 'black';
canvasContext.font = 'bold 40px Monospace';
canvasContext.fillText('POC ......', 150, 150);
}
#canvasHolder {
position: absolute;
left: 0px;
top: 0px;
}
#theCanvas {
background-color: lightgreen;
width: 100pc;
height: 100pc;
}
<div id="canvasHolder">
<canvas id="theCanvas"></canvas>
</div>
Note that right now, you're just redrawing it at the same location every time, but I assume moving it was your next task...
The text is already rendered but if you want to animate your text then you have to change your draw function because each time you are drawing your text in the same position -
function drawText() {
canvasContext.fillStyle = 'black';
canvasContext.font = 'bold 40px Monospace';
canvasContext.fillText('POC ......', 150, 150); //here you have given the fixed position.
}
and you have to clear your canvas before rendering your text in new position-
please refer -
How to clear the canvas for redrawing

Canvas ImageData don't get more than 102,000 values?

I am getting pixels values from an image using canvas. The image size is 170*170 pixels. Here is my code:
var canvas = document.createElement("canvas");
canvas.style.width = img.width;
canvas.style.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
var pixelData = canvas.getContext('2d').getImageData(0, 0, img.width, img.height).data;
It works well, I have values in pixelData, until I reach pixelData[102000]... I've test it with a white image, and all the values from pixelData[0] to pixelData[101999] are 255, but then it is 0 until the end...
Somebody sees why? Maybe this is about canvas width and height?
Your canvas size is not what you think it is.
You are only setting the size of the canvas element not the canvas bitmap:
canvas.style.width = img.width;
canvas.style.height = img.height;
This means your bitmap is actually 300 x 150 pixels in size, the default size, and you're just scaling that to the size of the image (since it's all white you won't be able to detect this so easily).
Since your image is 170 x 170 pixels you will only paint part of the canvas leaving the rest to default RGBA value [0,0,0,0].
In order to properly set the size of the canvas you must edit the above mentioned lines to be:
canvas.width = img.width;
canvas.height = img.height;

text is grainy/blurry when drawing text on a canvas via onload

If I try to draw text to my canvas at the onload event, the text shows up blurry. I draw to the same canvas later via a button click from another function and it's fine. But if I call this function from the button, it's still blurry. Can anybody see something wrong in this code?
window.onload = initCanvasRender;
function initCanvasRender() {
var c = document.getElementById("canvas");
var ctx = c.getContext('2d');
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillStyle = 'black';
ctx.font = '20px Times New Roman';
ctx.fillText('hello...', c.width/2, c.height/2);
}
There may be some problem with the
ctx.fillText('hello...', c.width/2, c.height/2);
Because if you for example set width of the canvas with css then c.width and c.height will be the default size for the canvas which is, 300x150 and not the size defined in css. Try to set two variables for the width and height that are global for your application. E.g
var canvasWidth = 400;
var canvasHeight = 200;
c.width = canvasWidth;
c.height = canvasHeight;
/* ... */
and then later in your code you can use canvasWidth and canvasWeight:
ctx.fillText('hello...', canvasWidth/2, canvasHeight/2);
Take a look at this test: http://jsfiddle.net/EsQfb/7/ it's important to use use the canvas.width and not canvas.style.width in your case.
Take a look at this for more information about this: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#attr-canvas-width

Categories