why do figures appear distorted on canvas? - javascript

I'm playing around with html5 canvas, and I have came across some strange behaviour. I'm doing pretty basic animation based on these three steps:
I call update() function inside wich I change x and y of the objects.
I clear the canvas with this line of code this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
I redraw all the elements.
This is how I draw the figures:
// drawing a circle
function drawCircle(x,y) {
var rad = 5;
ctx.beginPath();
ctx.arc(x, y, rad, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
}
// and a rect
function drawRect(x, y,) {
var width = 60,
height = 10;
ctx.fillRect(x, y, width, height);
}
Now I expect my rectangle to be 60px width and 10px height. I've added a div after the <canvas> tag and set its width and height to 60px and 10px respectively in order to illustrate the discrepancy. As you can see on the picture, obviously my rectangle isn't 60х10. The same apply to the circle. What am I missing here?
here is fiddle

Set the size of the canvas using it's width and height attributes (for tag) or properties (in JS):
<canvas id="..." width=400 height=400></canvas>
in JS:
canvasEl.width = 400;
canvasEl.height = 400;
Don't use CSS as that only affects the canvas element but not its bitmap (consider canvas as an image). The default size of a canvas is 300 x 150 pixels. If you don't change that size it will be stretched to the size you set using CSS. This is why we in general don't recommend using CSS (there are special cases though where CSS is necessary such as print situations, non 1:1 pixel aspect ratios and so forth).

Probably it's because you styled your canvas to a costum with/height. A canvas' default width/height is 150*300 and if you do not scale well you obtain such result as you found.
drawImage(image, x, y, width, height)
This adds the width and height parameters, which indicate the size to which to
scale the image when drawing it onto the canvas.
So to be short you have to scale your drawings.
the Canvas element on MDN
Canvas drawing on MDN

Related

How to "paint" on an image on Canvas?

I want to use an image like this on canvas:
The user will "paint and fill" the image, but not on top of the outline.
The problem is:
If I put behind the canvas, the paint will cover the outline.
If I put over the canvas the image block canvas interaction.
Can you help me guys?
Use compositing mode "destination-over" to draw behind existing content (from image, vectors etc.). It's necessary that the existing content provide an alpha channel or composition won't work. If there is no alpha-channel you can convert inverse luma / matte (the white) to alpha channel.
// a quick-n-dirty demo
var ctx = c.getContext("2d");
ctx.lineWidth = 10;
ctx.moveTo(100, 0); ctx.lineTo(150, 150); ctx.stroke();
ctx.fillStyle = "#09f";
// KEY: composite mode -
ctx.globalCompositeOperation = "destination-over";
// draw behind the line
c.onmousemove = function(e) {
ctx.fillRect(e.clientX - 10, e.clientY - 10, 20, 20);
};
body {margin:0}
canvas {border:#777 solid 1px}
<canvas id="c"></canvas>
Here is the example of drawImage function. You can draw any preloaded image onto canvas. You can also try to place the <img> overlay in front of the canvas and disable mouse events for it using pointer-events: none CSS property.

how do make the radius of the circle responsive in canvas element?

I have a canvas element in which I have drawn a circle. How do I give the responsiveness to the canvas element?
If the width of the browser changes I need to change the radius by some amount, if the height of the browser changes I need to change the radius by some amount.
For that how do I need to calculate the changing ratio?
var canvasWidthRatio = currentDivWidth / initialDivWidth;
var canvasHeightRatio = currentHeight / initialDivHeight;
radius = (I need something here)
It appears you're letting the canvas resize based on its div container. That can introduce a problem.
If you resize the canvas's CSS using different percentages for width & height then the canvas content will distort--it will stretch.
To avoid distortion you must resize the canvas width & height proportionally (by the same percentage). The proportionally resized canvas will not necessarily fill the new div size as it did before.
An alternative:
Resize the canvas element itself & use the scaling transformation to redraw your content
This way you won't need to recalculate your circle's radius or position. You can use the exact same drawing commands that were originally used to draw your circle. The canvas's built-in scaling will do all the recalculations for you!
Get a reference to your canvas & your div container and save the original div size
var divcontainer=document.getElementById('mydiv');
var canvas=document.getElementById('mycanvas');
var context=canvas.getContext('2d');
var originalWidth=divcontainer.width;
var originalHeight=divcontainer.height;
Resize the canvas element to the new div size.
var newWidth=divcontainer.width;
var newHeight=divcontainer.height;
// Notes:
// Resizing the canvas element will clear its content
// This alternative allows the canvas to resize disproportionately
canvas.width=newWidth;
canvas.height=newHeight;
Use context scaling to automatically resize the canvas. Any redrawn content will scale automatically using the same original drawing commands.
// calculate the scaling percentage necessary such that
// new content will fit on the canvas
var scaleFactor=Math.min((newWidth/originalWidth),(newHeight/originalHeight));
// scale the canvas
context.scale(scaleFactor);
// now redraw all content (your circle) using their original sizes & coordinates
// unscale the canvas
// (scaling is cumulative, so this cleans up for the next resizing)
context.scale(-scaleFactor);
try this
var radius = 10; // set default radius to start with
var radiusX = Math.min(currentDivWidth , radius); // set horizontal radius to be atleast as wide as width of div
var radiusY = Math.min(currentDivHeight , radius); // set vertical radius to be atleast as high as height of div
radius = Math.min(radiusX, radiusY); // now set the radius of the circle equal to the minimum of the two values so that it is a perfect circle
context.arc(0, 0, radius, 0, 2*Math.PI, false); // use new radius to draw a brand new circle
try using like this:
radius = Math.min(radiusX, radiusY);// here radiusX and radiusY will be currentDivWidth,currentDivHeight resp.
context.arc(0, 0, radius, 0, 2*Math.PI);
see a better description here:http://www.w3schools.com/tags/canvas_arc.asp

Canvas roulette wheel - using background images as each slice

I have a roulette wheel created with HTML5 canvas and currently each slice is a plain color generated by using the fillStyle(), beginPath(), stroke(), then fill() methods.
I would like to use images that that crop appropriately in the shape of the slice, but I'm not sure how to implement this using drawImage().
Here's the jsfiddle
http://jsfiddle.net/pyD2q/2/
Any help or resources is appreciated.
Instead of filling the color in you can use it as a clipping mask instead. For each arc, set clip, draw the image and repeat.
Something like this (untested):
for (i = 0; i < s.members.length; i++) {
angle = s.startAngle + i * s.arc;
ctx.beginPath();
ctx.arc(s.width / 2, s.height / 2, s.outsideRadius, angle, angle + s.arc, false);
ctx.arc(s.width / 2, s.height / 2, s.insideRadius, angle + s.arc, angle, true);
ctx.save(); /// store current clip-state
ctx.clip(); /// set current arc as clipping mask
ctx.drawImage(someImageArray[i], x, y, width, height);
ctx.restore(); /// restore clip-state
ctx.stroke(); /// stroke arc
}
You will of course also need to place the images correctly relative to the section and if you want to rotate the image you would need to rotate it at this point.
In that regard I would recommend creating this wheel on an off-screen canvas. This way you only need to draw the off-screen canvas into the main canvas rotated and what have you (saves you the trouble of calculating each angle as well and the performance will be better).

Drawing image on canvas - larger than real

I want to draw an image from jpg file on canvas.
My code:
var canvas = document.getElementById('my_canvas');
var ctx = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
ctx.drawImage(imageObj, 0, 0);
};
imageObj.src = 'img/my_image.jpg';
The problem is that the image on canvas is much bigger than in file. Why? How can I draw image real size?
UPDATE:
result: http://jsfiddle.net/AJK2t/
This is your problem:
<canvas style="width: 700px; height: 400px;" id="konf"></canvas>
You are setting the visual size of your canvas, but not the number of pixels. Consequently the browser is scaling the canvas pixels up.
The simplest fix is:
<canvas width="700" height="400" id="konf"></canvas>
The width and height parameters control the number of pixels in the canvas. With no CSS styling, the default visual size of the canvas will also be this size, resulting in one canvas pixel per screen pixel (assuming you have not zoomed the web browser).
Copy/pasting from my answer to a related question:
Think about what happens if you have a JPG that is 32x32 (it has exactly 1024 total pixels) but specify via CSS that it should appear as width:800px; height:16px. The same thing applies to HTML Canvas:
The width and height attributes of the canvas element itself decide how many pixels you can draw on. If you don't specify the height and width of the canvas element, then per the specs:
"the width attribute defaults to 300, and the height attribute defaults to 150."
The width and height CSS properties control the size that the element displays on screen. If the CSS dimensions are not set, the intrinsic size of the element is used for layout.
If you specify in CSS a different size than the actual dimensions of the canvas it must be stretched and squashed by the browser as necessary for display. You can see an example of this here: http://jsfiddle.net/9bheb/5/
Working Example: http://jsfiddle.net/jzF5R/
In order to scale an image you need to provide the scaled width and height you want to ctx.drawImage():
// x, y, width, height
ctx.drawImage(imageObj, 0, 0, 100, 50);
Maintain original image size:
ctx.drawImage(imageObj, 0, 0, imageObj.width, imageObj.height);
Keep canvas from overflowing off the page:
ctx.canvas.width = document.body.clientWidth;
You can easily scale the image width and height to 70% of original:
ctx.drawImage(imageObj, 0, 0, imageObj.width * 0.7, imageObj.height * 0.7);
To display a MJPEG stream on a canvas (or something else) without define the width and the height of the canvas in HTML, so only using CSS to get a responsive canvas and fit with the page, I use that:
//get size from CSS
var sizeWidth = context.canvas.clientWidth;
var sizeHeight = context.canvas.clientHeight;
//here the solution, it replaces HTML width="" height=""
canvas.width = sizeWidth;
canvas.height = sizeHeight;
...........
context.drawImage(imageObj, 0, 0, imageObj.width, imageObj.height, 0, 0, sizeWidth, sizeHeight);
The picture is entirely contained in the canvas whatever the size of the canvas (the rate between height and width is not kept but it doesn't matter, an height:auto; in css can fix that).
Et voilà !

Adding a Border Dynamically to an Image on an HTML5 Canvas

I've got a canvas that includes images, I'm re-drawing 1 pixel lower each time to give the effect of falling. I've got the images in an array and I just place them 1 pixel lower without recreating the image.
Is it possible to add a border dynamically to images that reach a certain point and if so, how?
Yes, all you have to do is draw a path outside the image and call ctx.stroke() to make the border.
So say the image has the coordinates x and y, with a width and height of w and h, you just do:
ctx.rect(x, y, w, h);
ctx.stroke();
Want a different colored border?
ctx.strokeStyle = 'blue';
Thicker?
ctx.lineWidth = 5;
If you know your images' size and location and as you draw them you probably do, You can use the .rect canvas method to draw a rectangle around the image.

Categories

Resources