Related
I have 2 canvases, one uses HTML attributes width and height to size it, the other uses CSS:
<canvas id="compteur1" width="300" height="300" onmousedown="compteurClick(this.id);"></canvas>
<canvas id="compteur2" style="width: 300px; height: 300px;" onmousedown="compteurClick(this.id);"></canvas>
Compteur1 displays like it should, but not compteur2. The content is drawn using JavaScript on a 300x300 canvas.
Why is there a display difference?
It seems that the width and height attributes determine the width or height of the canvas’s coordinate system, whereas the CSS properties just determine the size of the box in which it will be shown.
This is explained in the HTML specification:
The canvas element has two attributes to control the size of the element’s bitmap: width and height. These attributes, when specified, must have values that are valid non-negative integers. The rules for parsing non-negative integers must be used to obtain their numeric values. If an attribute is missing, or if parsing its value returns an error, then the default value must be used instead. The width attribute defaults to 300, and the height attribute defaults to 150.
To set the width and height on a canvas, you may use:
canvasObject.setAttribute('width', '150');
canvasObject.setAttribute('height', '300');
For <canvas> elements, the CSS rules for width and height set the actual size of the canvas element that will be drawn to the page. On the other hand, the HTML attributes of width and height set the size of the coordinate system or 'grid' that the canvas API will use.
For example, consider this (jsfiddle):
var ctx = document.getElementById('canvas1').getContext('2d');
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 30, 30);
var ctx2 = document.getElementById('canvas2').getContext('2d');
ctx2.fillStyle = "red";
ctx2.fillRect(10, 10, 30, 30);
canvas {
border: 1px solid black;
}
<canvas id="canvas1" style="width: 50px; height: 100px;" height="50" width="100"></canvas>
<canvas id="canvas2" style="width: 100px; height: 100px;" height="50" width="100"></canvas>
Both have had the same thing drawn on them relative to the internal coordinates of the canvas element. But in the second canvas, the red rectangle will be twice as wide because the canvas as a whole is being stretched across a bigger area by the CSS rules.
Note: If the CSS rules for width and/or height aren't specified then the browser will use the HTML attributes to size the element such that 1 unit of these values equals 1px on the page. If these attributes aren't specified then they will default to a width of 300 and a height of 150.
The canvas will be stretched if you set the width and height in your CSS. If you want to dynamically manipulate the dimension of the canvas you have to use JavaScript like so:
canvas = document.getElementById('canv');
canvas.setAttribute('width', '438');
canvas.setAttribute('height', '462');
The browser uses the css width and height, but the canvas element scales based on the canvas width and height. In javascript, read the css width and height and set the canvas width and height to that.
var myCanvas = $('#TheMainCanvas');
myCanvas[0].width = myCanvas.width();
myCanvas[0].height = myCanvas.height();
Shannimal correction
var el = $('#mycanvas');
el.attr('width', parseInt(el.css('width')))
el.attr('height', parseInt(el.css('height')))
Canvas renders image by buffer, so when you specify the width and height HTML attributes the buffer size and length changes, but when you use CSS, the buffer's size is unchanged. Making the image stretched.
Using HTML sizing.
Size of canvas is changed -> buffer size is changed -> rendered
Using CSS sizing
Size of canvas is changed -> rendered
Since the buffer length is kept unchanged, when the context renders the image,
the image is displayed in resized canvas (but rendered in unchanged buffer).
CSS sets the width and height of the canvas element so it affects the coordinate space leaving everything drawn skewed
Here's my way on how to set the width and height with Vanilla JavaScript
canvas.width = numberForWidth
canvas.height = numberForHeight
I believe CSS has much better machinery for specifying the size of the canvas and CSS must decide styling, not JavaScript or HTML. Having said that, setting width and height in HTML is important for working around the issue with canvas.
CSS has !important rule that allows to override other styling rules for the property, including those in HTML. Usually, its usage is frowned upon but here the use is a legitimate hack.
In Rust module for WebAssembly you can do the following:
fn update_buffer(canvas: &HtmlCanvasElement) {
canvas.set_width(canvas.client_width() as u32);
canvas.set_height(canvas.client_height() as u32);
}
//..
#[wasm_bindgen(start)]
pub fn start() -> Result<(), JsValue> {
// ...
let canvas: Rc<_> = document
.query_selector("canvas")
.unwrap()
.unwrap()
.dyn_into::<HtmlCanvasElement>()
.unwrap()
.into();
update_buffer(&canvas);
// ...
// create resizing handler for window
{
let on_resize = Closure::<dyn FnMut(_)>::new(move |_event: Event| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
// ...
window.add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())?;
on_resize.forget();
}
}
There we update the canvas buffer once the WASM module is loaded and then whenever the window is resized. We do it by manually specifying width and height of canvas as values of clientWidth and clientHeight. Maybe there are better ways to update the buffer but I believe this solution is better than those suggested by #SamB, #CoderNaveed, #Anthony Gedeon, #Bluerain, #Ben Jackson, #Manolo, #XaviGuardia, #Russel Harkins, and #fermar because
The element is styled by CSS, not HTML.
Unlike elem.style.width & elem.style.height trick used by #Manolo or its JQuery equivalent used by #XaviGuardia, it will work for canvas whose size is specified by usage as flex or grid item.
Unlike the solution by #Russel Harkings, this also handles resizing. Though I like his answer because it is really clean and easy.
WASM is the future! Haha :D
P.S. there's a ton of .unwrap() because Rust explicitly handles possible failures.
P.P.S.
{
let on_resize = Closure::<dyn FnMut(_)>::new(move |_event: Event| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
// ...
window.add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())?;
on_resize.forget();
}
can be done much cleaner with better libraries. E.g.
add_resize_handler(&window, move |e: ResizeEvent| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
})
If you want a dynamic behaviour based on, e.g. CSS media queries, don't use canvas width and height attributes. Use CSS rules and then, before getting the canvas rendering context, assign to width and height attributes the CSS width and height styles:
var elem = document.getElementById("mycanvas");
elem.width = elem.style.width;
elem.height = elem.style.height;
var ctx1 = elem.getContext("2d");
...
I have 2 canvases, one uses HTML attributes width and height to size it, the other uses CSS:
<canvas id="compteur1" width="300" height="300" onmousedown="compteurClick(this.id);"></canvas>
<canvas id="compteur2" style="width: 300px; height: 300px;" onmousedown="compteurClick(this.id);"></canvas>
Compteur1 displays like it should, but not compteur2. The content is drawn using JavaScript on a 300x300 canvas.
Why is there a display difference?
It seems that the width and height attributes determine the width or height of the canvas’s coordinate system, whereas the CSS properties just determine the size of the box in which it will be shown.
This is explained in the HTML specification:
The canvas element has two attributes to control the size of the element’s bitmap: width and height. These attributes, when specified, must have values that are valid non-negative integers. The rules for parsing non-negative integers must be used to obtain their numeric values. If an attribute is missing, or if parsing its value returns an error, then the default value must be used instead. The width attribute defaults to 300, and the height attribute defaults to 150.
To set the width and height on a canvas, you may use:
canvasObject.setAttribute('width', '150');
canvasObject.setAttribute('height', '300');
For <canvas> elements, the CSS rules for width and height set the actual size of the canvas element that will be drawn to the page. On the other hand, the HTML attributes of width and height set the size of the coordinate system or 'grid' that the canvas API will use.
For example, consider this (jsfiddle):
var ctx = document.getElementById('canvas1').getContext('2d');
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 30, 30);
var ctx2 = document.getElementById('canvas2').getContext('2d');
ctx2.fillStyle = "red";
ctx2.fillRect(10, 10, 30, 30);
canvas {
border: 1px solid black;
}
<canvas id="canvas1" style="width: 50px; height: 100px;" height="50" width="100"></canvas>
<canvas id="canvas2" style="width: 100px; height: 100px;" height="50" width="100"></canvas>
Both have had the same thing drawn on them relative to the internal coordinates of the canvas element. But in the second canvas, the red rectangle will be twice as wide because the canvas as a whole is being stretched across a bigger area by the CSS rules.
Note: If the CSS rules for width and/or height aren't specified then the browser will use the HTML attributes to size the element such that 1 unit of these values equals 1px on the page. If these attributes aren't specified then they will default to a width of 300 and a height of 150.
The canvas will be stretched if you set the width and height in your CSS. If you want to dynamically manipulate the dimension of the canvas you have to use JavaScript like so:
canvas = document.getElementById('canv');
canvas.setAttribute('width', '438');
canvas.setAttribute('height', '462');
The browser uses the css width and height, but the canvas element scales based on the canvas width and height. In javascript, read the css width and height and set the canvas width and height to that.
var myCanvas = $('#TheMainCanvas');
myCanvas[0].width = myCanvas.width();
myCanvas[0].height = myCanvas.height();
Shannimal correction
var el = $('#mycanvas');
el.attr('width', parseInt(el.css('width')))
el.attr('height', parseInt(el.css('height')))
Canvas renders image by buffer, so when you specify the width and height HTML attributes the buffer size and length changes, but when you use CSS, the buffer's size is unchanged. Making the image stretched.
Using HTML sizing.
Size of canvas is changed -> buffer size is changed -> rendered
Using CSS sizing
Size of canvas is changed -> rendered
Since the buffer length is kept unchanged, when the context renders the image,
the image is displayed in resized canvas (but rendered in unchanged buffer).
CSS sets the width and height of the canvas element so it affects the coordinate space leaving everything drawn skewed
Here's my way on how to set the width and height with Vanilla JavaScript
canvas.width = numberForWidth
canvas.height = numberForHeight
I believe CSS has much better machinery for specifying the size of the canvas and CSS must decide styling, not JavaScript or HTML. Having said that, setting width and height in HTML is important for working around the issue with canvas.
CSS has !important rule that allows to override other styling rules for the property, including those in HTML. Usually, its usage is frowned upon but here the use is a legitimate hack.
In Rust module for WebAssembly you can do the following:
fn update_buffer(canvas: &HtmlCanvasElement) {
canvas.set_width(canvas.client_width() as u32);
canvas.set_height(canvas.client_height() as u32);
}
//..
#[wasm_bindgen(start)]
pub fn start() -> Result<(), JsValue> {
// ...
let canvas: Rc<_> = document
.query_selector("canvas")
.unwrap()
.unwrap()
.dyn_into::<HtmlCanvasElement>()
.unwrap()
.into();
update_buffer(&canvas);
// ...
// create resizing handler for window
{
let on_resize = Closure::<dyn FnMut(_)>::new(move |_event: Event| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
// ...
window.add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())?;
on_resize.forget();
}
}
There we update the canvas buffer once the WASM module is loaded and then whenever the window is resized. We do it by manually specifying width and height of canvas as values of clientWidth and clientHeight. Maybe there are better ways to update the buffer but I believe this solution is better than those suggested by #SamB, #CoderNaveed, #Anthony Gedeon, #Bluerain, #Ben Jackson, #Manolo, #XaviGuardia, #Russel Harkins, and #fermar because
The element is styled by CSS, not HTML.
Unlike elem.style.width & elem.style.height trick used by #Manolo or its JQuery equivalent used by #XaviGuardia, it will work for canvas whose size is specified by usage as flex or grid item.
Unlike the solution by #Russel Harkings, this also handles resizing. Though I like his answer because it is really clean and easy.
WASM is the future! Haha :D
P.S. there's a ton of .unwrap() because Rust explicitly handles possible failures.
P.P.S.
{
let on_resize = Closure::<dyn FnMut(_)>::new(move |_event: Event| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
// ...
window.add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())?;
on_resize.forget();
}
can be done much cleaner with better libraries. E.g.
add_resize_handler(&window, move |e: ResizeEvent| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
})
If you want a dynamic behaviour based on, e.g. CSS media queries, don't use canvas width and height attributes. Use CSS rules and then, before getting the canvas rendering context, assign to width and height attributes the CSS width and height styles:
var elem = document.getElementById("mycanvas");
elem.width = elem.style.width;
elem.height = elem.style.height;
var ctx1 = elem.getContext("2d");
...
I have 2 canvases, one uses HTML attributes width and height to size it, the other uses CSS:
<canvas id="compteur1" width="300" height="300" onmousedown="compteurClick(this.id);"></canvas>
<canvas id="compteur2" style="width: 300px; height: 300px;" onmousedown="compteurClick(this.id);"></canvas>
Compteur1 displays like it should, but not compteur2. The content is drawn using JavaScript on a 300x300 canvas.
Why is there a display difference?
It seems that the width and height attributes determine the width or height of the canvas’s coordinate system, whereas the CSS properties just determine the size of the box in which it will be shown.
This is explained in the HTML specification:
The canvas element has two attributes to control the size of the element’s bitmap: width and height. These attributes, when specified, must have values that are valid non-negative integers. The rules for parsing non-negative integers must be used to obtain their numeric values. If an attribute is missing, or if parsing its value returns an error, then the default value must be used instead. The width attribute defaults to 300, and the height attribute defaults to 150.
To set the width and height on a canvas, you may use:
canvasObject.setAttribute('width', '150');
canvasObject.setAttribute('height', '300');
For <canvas> elements, the CSS rules for width and height set the actual size of the canvas element that will be drawn to the page. On the other hand, the HTML attributes of width and height set the size of the coordinate system or 'grid' that the canvas API will use.
For example, consider this (jsfiddle):
var ctx = document.getElementById('canvas1').getContext('2d');
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 30, 30);
var ctx2 = document.getElementById('canvas2').getContext('2d');
ctx2.fillStyle = "red";
ctx2.fillRect(10, 10, 30, 30);
canvas {
border: 1px solid black;
}
<canvas id="canvas1" style="width: 50px; height: 100px;" height="50" width="100"></canvas>
<canvas id="canvas2" style="width: 100px; height: 100px;" height="50" width="100"></canvas>
Both have had the same thing drawn on them relative to the internal coordinates of the canvas element. But in the second canvas, the red rectangle will be twice as wide because the canvas as a whole is being stretched across a bigger area by the CSS rules.
Note: If the CSS rules for width and/or height aren't specified then the browser will use the HTML attributes to size the element such that 1 unit of these values equals 1px on the page. If these attributes aren't specified then they will default to a width of 300 and a height of 150.
The canvas will be stretched if you set the width and height in your CSS. If you want to dynamically manipulate the dimension of the canvas you have to use JavaScript like so:
canvas = document.getElementById('canv');
canvas.setAttribute('width', '438');
canvas.setAttribute('height', '462');
The browser uses the css width and height, but the canvas element scales based on the canvas width and height. In javascript, read the css width and height and set the canvas width and height to that.
var myCanvas = $('#TheMainCanvas');
myCanvas[0].width = myCanvas.width();
myCanvas[0].height = myCanvas.height();
Shannimal correction
var el = $('#mycanvas');
el.attr('width', parseInt(el.css('width')))
el.attr('height', parseInt(el.css('height')))
Canvas renders image by buffer, so when you specify the width and height HTML attributes the buffer size and length changes, but when you use CSS, the buffer's size is unchanged. Making the image stretched.
Using HTML sizing.
Size of canvas is changed -> buffer size is changed -> rendered
Using CSS sizing
Size of canvas is changed -> rendered
Since the buffer length is kept unchanged, when the context renders the image,
the image is displayed in resized canvas (but rendered in unchanged buffer).
CSS sets the width and height of the canvas element so it affects the coordinate space leaving everything drawn skewed
Here's my way on how to set the width and height with Vanilla JavaScript
canvas.width = numberForWidth
canvas.height = numberForHeight
I believe CSS has much better machinery for specifying the size of the canvas and CSS must decide styling, not JavaScript or HTML. Having said that, setting width and height in HTML is important for working around the issue with canvas.
CSS has !important rule that allows to override other styling rules for the property, including those in HTML. Usually, its usage is frowned upon but here the use is a legitimate hack.
In Rust module for WebAssembly you can do the following:
fn update_buffer(canvas: &HtmlCanvasElement) {
canvas.set_width(canvas.client_width() as u32);
canvas.set_height(canvas.client_height() as u32);
}
//..
#[wasm_bindgen(start)]
pub fn start() -> Result<(), JsValue> {
// ...
let canvas: Rc<_> = document
.query_selector("canvas")
.unwrap()
.unwrap()
.dyn_into::<HtmlCanvasElement>()
.unwrap()
.into();
update_buffer(&canvas);
// ...
// create resizing handler for window
{
let on_resize = Closure::<dyn FnMut(_)>::new(move |_event: Event| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
// ...
window.add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())?;
on_resize.forget();
}
}
There we update the canvas buffer once the WASM module is loaded and then whenever the window is resized. We do it by manually specifying width and height of canvas as values of clientWidth and clientHeight. Maybe there are better ways to update the buffer but I believe this solution is better than those suggested by #SamB, #CoderNaveed, #Anthony Gedeon, #Bluerain, #Ben Jackson, #Manolo, #XaviGuardia, #Russel Harkins, and #fermar because
The element is styled by CSS, not HTML.
Unlike elem.style.width & elem.style.height trick used by #Manolo or its JQuery equivalent used by #XaviGuardia, it will work for canvas whose size is specified by usage as flex or grid item.
Unlike the solution by #Russel Harkings, this also handles resizing. Though I like his answer because it is really clean and easy.
WASM is the future! Haha :D
P.S. there's a ton of .unwrap() because Rust explicitly handles possible failures.
P.P.S.
{
let on_resize = Closure::<dyn FnMut(_)>::new(move |_event: Event| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
// ...
window.add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())?;
on_resize.forget();
}
can be done much cleaner with better libraries. E.g.
add_resize_handler(&window, move |e: ResizeEvent| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
})
If you want a dynamic behaviour based on, e.g. CSS media queries, don't use canvas width and height attributes. Use CSS rules and then, before getting the canvas rendering context, assign to width and height attributes the CSS width and height styles:
var elem = document.getElementById("mycanvas");
elem.width = elem.style.width;
elem.height = elem.style.height;
var ctx1 = elem.getContext("2d");
...
I'm having a problem with loading image into canvas - the image is somehow scaled.
Background: I've got several canvases on my web page, I want to load images into them. When constructing, I'm not sure about the dimension, because the size depends on the screen size.
So I create div and canvas, use css to have it in the size that I want it to have and print an image onto the canvas. There would couple more things to do with the image (i.e. decide based on the ratio if I need to center it vertically or horizontally), but those are not really important at this point. The problem is that the image is rendered "zoomed".
Example: the javascript piece is here:
$("canvas").each(function() {
var context = $(this)[0].getContext('2d');
var img = new Image;
img.src = 'http://i67.tinypic.com/n38zdv.jpg';
$(img).load(function() {
context.drawImage(this, 0, 0);
});
//img will print 400 (correct, thats the width of the img)
//canvas will print based on the screen size (correct)
//img displayed in the canvas shows 300px out of 400px, it's zoomed (not correct)
$(this).parent().append(
'img width: '+img.width+
', canvas width: '+$(this).width());
});
I put the whole example with HTML and CSS to https://jsfiddle.net/7zdrfe58/11/.
I'm trying on Mac. Safari and Chrome work the same (i.e. with the zoom).
I would very appreciate help with this!! Thanks a lot
drawImage lets you specify the width and height of the image. You can get the canvas width like so:
$("canvas").each(function() {
var canvas = this;
var context = canvas.getContext('2d');
var img = new Image;
img.src = 'http://i67.tinypic.com/n38zdv.jpg';
$(img).load(function() {
context.drawImage(this, 0, 0, canvas.width, canvas.height);
});
});
Check out your working code here:
https://jsfiddle.net/ucxdLsq9/
The documentation of the drawImage signatures can be found here:
https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/drawImage
Give proper width and height to drawImage.
context.drawImage(this, 0, 0 ,300 ,160);
Updated Fiddle
When using the HTML5 drag and drop API, it would appears though the .width property on has no impact on the width of an image being used as an icon for dragging. Take this fiddle for example: http://jsfiddle.net/cnAHv/7/. You can set dragIcon.width to anything you want, and it will not change the actual width of the icon.
Most of the resources on the web seem to arbitrarily set dragIcon.width to 100. Is this just a matter of people copying eachother's code without checking functionality?
So...
Is the width property on an image variable actually something that setDragImage() will accept?
If not, how would you set the width of the icon without manually changing sizing the image in a program like photoshop?
When you use an <img> in setDragImage Javascript will just use the actual image bitmap data, ignoring other attributes like width. Check the specs.
However if you do something like this:
function handleDragStart(e) {
var dragIcon = document.createElement('img');
dragIcon.src = 'http://jsfiddle.net/favicon.png';
dragIcon.width = '100';
var div = document.createElement('div');
div.appendChild(dragIcon);
document.querySelector('body').appendChild(div);
e.dataTransfer.setDragImage(div, -10, -10);
}
http://jsfiddle.net/cnAHv/9/
You will see the drag shadow now contains the bigger image. It occurs because when we use other visible HTML elements (that's why I appended the DIV to the body), the browser will use its rendered view as a drag image.
This answer might be a bit late but you can also use a canvas to scale your original image.
function handleDragStart(e) {
var dragIcon = document.createElement('img');
dragIcon.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAD///+l2Z/dAAAAM0lEQVR4nGP4/5/h/1+G/58ZDrAz3D/McH8yw83NDDeNGe4Ug9C9zwz3gVLMDA/A6P9/AFGGFyjOXZtQAAAAAElFTkSuQmCC';
var width = 100;
var height = width * (3/4); // The height must be set explicitly. I'm assuming the image is 4:3 for this example
var c = document.createElement("canvas");
c.width = width;
c.height = height;
var ctx = c.getContext('2d');
ctx.drawImage(dragIcon,0,0,width,height);
dragIcon.src = c.toDataURL();
e.dataTransfer.setDragImage(dragIcon, -10, -10);
}
http://jsfiddle.net/cnAHv/138/
The only downside to this is that the canvas may be tainted if the image doesn't come from the same origin. More on tainted canvases here