Canvas растягивается при использовании CSS, но обычно со свойствами "width" / "height"
У меня есть 2 холста, один использует атрибуты HTML width
а также height
чтобы определить его размер, другой использует 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 отображается так, как должно, но не compteur2. Контент рисуется с использованием JavaScript на холсте размером 300x300.
Почему разница в отображении?
10 ответов
Кажется, что width
а также height
атрибуты определяют ширину или высоту системы координат холста, тогда как свойства CSS просто определяют размер поля, в котором он будет отображаться.
Это объясняется по адресу http://www.whatwg.org/html (требуется JS) или http://www.whatwg.org/c (вероятно, будет кушать ваш компьютер):
canvas
Элемент имеет два атрибута для управления размером растрового изображения элемента:width
а такжеheight
, Эти атрибуты, если они указаны, должны иметь значения, которые являются действительными неотрицательными целыми числами. Правила для анализа неотрицательных целых чисел должны использоваться для получения их числовых значений. Если атрибут отсутствует или анализ его значения возвращает ошибку, то вместо этого должно использоваться значение по умолчанию.width
атрибут по умолчанию равен 300, аheight
атрибут по умолчанию равен 150.
Чтобы установить width
а также height
вам нужно, вы можете использовать
canvasObject.setAttribute('width', '475');
За <canvas>
элементы, правила CSS для width
а также height
установите фактический размер элемента canvas, который будет отображаться на странице. С другой стороны, атрибуты HTML width
а также height
установите размер системы координат или "сетки", которую будет использовать API Canvas.
Например, рассмотрим это ( 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>
На обоих нарисовано одно и то же относительно внутренних координат элемента canvas. Но на втором холсте красный прямоугольник будет в два раза шире, потому что холст в целом растягивается по большей площади по правилам CSS.
Примечание: если правила CSS для width
и / или height
не указываются, тогда браузер будет использовать атрибуты HTML для определения размера элемента таким образом, чтобы 1 единица этих значений равнялась 1 пикселю на странице. Если эти атрибуты не указаны, по умолчанию они width
из 300
и height
из 150
,
Холст будет растянут, если вы установите ширину и высоту в своем CSS. Если вы хотите динамически манипулировать размером холста, вы должны использовать JavaScript следующим образом:
canvas = document.getElementById('canv');
canvas.setAttribute('width', '438');
canvas.setAttribute('height', '462');
Браузер использует ширину и высоту CSS, но элемент холста масштабируется в зависимости от ширины и высоты холста. В javascript прочитайте ширину и высоту css и установите ширину и высоту холста.
var myCanvas = $('#TheMainCanvas');
myCanvas[0].width = myCanvas.width();
myCanvas[0].height = myCanvas.height();
Шеннимальная коррекция
var el = $('#mycanvas');
el.attr('width', parseInt(el.css('width')))
el.attr('height', parseInt(el.css('height')))
холст отображает изображение по буферу, поэтому, когда вы указываете атрибуты html ширины и высоты, размер и длина буфера изменяются, но когда вы используете css, размер буфера не изменяется. делая изображение растянутым.
Использование размера html.
размер холста изменен -> размер буфера изменен -> визуализирован
Использование css sizing
размер холста изменен -> визуализирован
поскольку длина буфера остается неизменной, когда контекст визуализирует изображение, изображение отображается на холсте с измененным размером (но визуализируется в неизмененном буфере) .
CSS устанавливает ширину и высоту элемента холста, поэтому он влияет на пространство координат, оставляя все нарисованное перекошенным.
Вот мой способ установки ширины и высоты с помощью Vanilla JavaScript
canvas.width = numberForWidth
canvas.height = numberForHeight
Если вы хотите динамическое поведение, основанное, например, на медиазапросах CSS, не используйте атрибуты width и height. Используйте правила CSS, а затем, прежде чем получить контекст визуализации холста, присвойте атрибутам width и height стили CSS width и height:
var elem = document.getElementById("mycanvas");
elem.width = elem.style.width;
elem.height = elem.style.height;
var ctx1 = elem.getContext("2d");
...
Я считаю, что в CSS есть гораздо лучший механизм для указания размера холста, и именно CSS должен определять стиль, а не JavaScript или HTML. Сказав это, установка ширины и высоты в HTML важна для решения проблемы с холстом.
CSS имеет!important
правило, которое позволяет переопределить другие правила стиля для свойства, в том числе в HTML. Обычно его использование не одобряется, но здесь это использование является законным взломом.
В модуле Rust для WebAssembly вы можете сделать следующее:
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();
}
}
Там мы обновляем буфер холста после загрузки модуля WASM, а затем всякий раз, когда изменяется размер окна. Мы делаем это, указав вручнуюwidth
иheight
холста как значенияclientWidth
иclientHeight
. Возможно, есть лучшие способы обновить буфер, но я считаю, что это решение лучше, чем те, которые предложены @SamB, @CoderNaveed, @Anthony Gedeon, @Bluerain, @Ben Jackson, @Manolo, @XaviGuardia, @Russel Harkins и @fermar. потому что
- Элемент оформлен с помощью CSS, а не HTML.
- В отличие от
elem.style.width
&elem.style.height
трюк, используемый @Manolo или его эквивалент JQuery, используемый @XaviGuardia, он будет работать дляcanvas
размер которого определяется использованием какflex
илиgrid
элемент. - В отличие от решения @Russel Harkings, это также обрабатывает изменение размера. Хотя мне нравится его ответ, потому что он действительно чистый и простой.
- WASM - это будущее! Ха-ха :D
PS есть тонна.unwrap()
потому что Rust явно обрабатывает возможные сбои.
PPS
{
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();
}
можно сделать намного чище с лучшими библиотеками. Например
add_resize_handler(&window, move |e: ResizeEvent| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
})