Как изменить размер элемента холста HTML?

У меня есть элемент холста, статически определенный в HTML с шириной и высотой. Если я попытаюсь использовать JavaScript для динамического изменения его размера (установив новую ширину и высоту - либо в атрибутах холста, либо через свойства стиля), я получаю следующую ошибку в Firefox:

uncaught exception: [Exception... "Illegal operation on WrappedNative prototype object" nsresult: "0x8057000c (NS_ERROR_XPC_BAD_OP_ON_WN_PROTO)" location: "JS frame :: file:///home/russh/Desktop/test.html :: onclick :: line 1" data: no]

Можно ли изменить размер этого элемента или мне нужно уничтожить его и создать новый элемент на лету?

На самом деле сообщение об ошибке выглядит так, как если бы вы пытались напрямую изменить свойство width или heightHTMLCanvasElement.prototype. Я понятия не имею, как это могло произойти случайно.

Robert 24.12.2012 03:00

Взгляните на мою реализацию: stackoverflow.com/a/23128583/1265753

karaxuna 17.04.2014 12:51
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
52
2
171 043
7

Ответы 7

Вы не опубликовали свой код, и я подозреваю, что вы делаете что-то не так. можно изменить размер, назначив атрибуты ширины и высоты с помощью чисел:

canvasNode.width  = 200; // in pixels
canvasNode.height = 100; // in pixels

По крайней мере, у меня это работает. Убедитесь, что вы не назначаете строки (например, «2 см», «3 дюйма» или «2,5 пикселя») и не путаетесь со стилями.

На самом деле это общедоступная информация - все об этом вы можете прочитать в спецификация холста HTML - она ​​очень маленькая и необычайно информативная. Это весь интерфейс DOM:

interface HTMLCanvasElement : HTMLElement {
           attribute unsigned long width;
           attribute unsigned long height;

  DOMString toDataURL();
  DOMString toDataURL(in DOMString type, [Variadic] in any args);

  DOMObject getContext(in DOMString contextId);
};

Как видите, он определяет 2 атрибута width и height, и оба они - unsigned long.

Примечание: при изменении размера холста кажется, что холст очищается (по крайней мере, в хроме).

RobKohr 31.08.2011 17:50

да. Я согласен. Есть ли способ изменить размер холста, а также изменить размер (масштабирование) изображений внутри него?

Alexis 11.08.2012 07:30

Было бы полезно опубликовать пример использования этого на jsfiddle.

Anderson Green 17.12.2012 00:12

@Alexis Изменение стиля меняет масштаб. Итак, canvas.style.width = "700px"; изменит его масштаб, но canvas.width = 700; не будет.

Joseph Lennox 29.04.2014 21:45

@JosephLennox Это очень полезно знать. Вы сэкономили мне массу умственных усилий, упомянув об этом.

Daniel Kaplan 22.05.2014 05:51

Да, спасибо, @JosephLennox. В jquery $ ('# canvas'). Width (500) будет масштабироваться, а $ ('# canvas') [0] .width = 500 не будет масштабироваться. Я делал то же самое и без вашего комментария решил бы навсегда.

ChrisPhoenix 20.02.2015 05:07

Он не просто сбрасывает холст, он делает это асинхронно. Таким образом, перерисовка в той же функции, что и изменение размера, не имеет никакого эффекта. Код перерисовки должен быть заключен в setTimeout(() => { ... }, 0). Сюда входят такие вещи, как lineWidth = ....

AndreKR 18.05.2018 07:53

Это сработало для меня только сейчас:

<canvas id = "c" height = "100" width = "100" style = "border:1px solid red"></canvas>
<script>
var c = document.getElementById('c');
alert(c.height + ' ' + c.width);
c.height = 200;
c.width = 200;
alert(c.height + ' ' + c.width);
</script>

У меня была такая же проблема, как и у вас, но я узнал о методе toDataURL, который оказался полезным.

Суть его в том, чтобы превратить ваш текущий холст в dataURL, изменить размер холста, а затем нарисовать то, что у вас было, обратно на холст из сохраненного вами dataURL.

Итак, вот мой код:

var oldCanvas = canvas.toDataURL("image/png");
var img = new Image();
img.src = oldCanvas;
img.onload = function (){
    canvas.height += 100;
    ctx.drawImage(img, 0, 0);
}

ctx.getImageData () и ctx.putImageData () имеют меньший вес и предназначены для этой задачи.

fuzzyTew 28.07.2013 05:40

@fuzzyTew Я почти уверен, что использование getImageData() и putImageData() будет эффективным, но будет копировать пиксель за пикселем, таким образом, не масштабируя старые данные изображения, тогда как использование drawImage() допускает масштабирование.

snapfractalpop 21.06.2014 17:52

Зачем использовать toDataUrl? Это вызывает ненужное преобразование данных (raw => png). Вместо этого вы можете использовать drawImage дважды.

Tomáš Zato - Reinstate Monica 30.11.2014 23:42

Вот мои усилия, чтобы дать более полный ответ (основанный на ответе @john).

Первоначальная проблема, с которой я столкнулся, заключалась в изменении ширины и высоты узла холста (с использованием стилей), в результате чего содержимое просто «увеличивалось» или «уменьшалось». Это не был желаемый эффект.

Предположим, вы хотите нарисовать два прямоугольника произвольного размера на холсте размером 100 на 100 пикселей.

<canvas width = "100" height = "100"></canvas>

Чтобы прямоугольники не превышали размер холста и, следовательно, не были видны, необходимо убедиться, что холст достаточно большой.

var $canvas = $('canvas'),
    oldCanvas,
    context = $canvas[0].getContext('2d');

function drawRects(x, y, width, height)
{
  if (($canvas.width() < x+width) || $canvas.height() < y+height)
  {
    oldCanvas = $canvas[0].toDataURL("image/png")
    $canvas[0].width = x+width;
    $canvas[0].height = y+height;

    var img = new Image();
    img.src = oldCanvas;
    img.onload = function (){
      context.drawImage(img, 0, 0);
    };
  }
  context.strokeRect(x, y, width, height);
}


drawRects(5,5, 10, 10);
drawRects(15,15, 20, 20);
drawRects(35,35, 40, 40);
drawRects(75, 75, 80, 80);

Наконец, вот jsfiddle для этого: http://jsfiddle.net/Rka6D/4/.

Обратите внимание, что если ваш холст объявлен статически, вы должны использовать атрибуты width и height, а не стиль, например., это будет работать:

<canvas id = "c" height = "100" width = "100" style = "border:1px"></canvas>
<script>
    document.getElementById('c').width = 200;
</script>

Но это нет будет работать:

<canvas id = "c" style = "width: 100px; height: 100px; border:1px"></canvas>
<script>
    document.getElementById('c').width = 200;
</script>

С прототипами может быть сложно работать, и из части ошибки _PROTO кажется, что ваша ошибка вызвана, скажем, HTMLCanvasElement.prototype.width, возможно, попыткой изменить размер всех холстов сразу.

В качестве предложения, если вы пытаетесь изменить размер нескольких полотен одновременно, вы можете попробовать:

<canvas></canvas>
<canvas></canvas>
<canvas></canvas>
<script type = "text/javascript">
    ...
</script>

В JavaScript вместо вызова прототипа попробуйте следующее:

$$ = function(){
    return document.querySelectorAll.apply(document,arguments);
}
for(var i in $$('canvas')){
    canvas = $$('canvas')[i];
    canvas.width = canvas.width+100;
    canvas.height = canvas.height+100;
}

Это изменит размер всех полотен, добавив к их размеру 100 пикселей, как показано в этот пример.


Hope this helped.
<div id = "canvasdiv" style = "margin: 5px; height: 100%; width: 100%;">
    <canvas id = "mycanvas" style = "border: 1px solid red;"></canvas>
</div>
<script>
$(function(){
    InitContext();
});
function InitContext()
{
var $canvasDiv = $('#canvasdiv');

var canvas = document.getElementById("mycanvas");
canvas.height = $canvasDiv.innerHeight();
canvas.width = $canvasDiv.innerWidth();
}
</script>

Другие вопросы по теме