Рисование точки на холсте HTML5

Рисование строки на холсте HTML5 довольно просто, используя функции context.moveTo() и context.lineTo().

Я не совсем уверен, можно ли нарисовать точку, то есть цвет одного пикселя. Функция lineTo не будет рисовать одну пиксельную линию (очевидно).

Есть ли способ сделать это?

Ответ 1

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

ctx.fillRect(10,10,1,1); // fill in the pixel at (10,10)

Ответ 2

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

var canvas = document.getElementById("myCanvas");
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var ctx = canvas.getContext("2d");
var canvasData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);

// That how you define the value of a pixel //
function drawPixel (x, y, r, g, b, a) {
    var index = (x + y * canvasWidth) * 4;

    canvasData.data[index + 0] = r;
    canvasData.data[index + 1] = g;
    canvasData.data[index + 2] = b;
    canvasData.data[index + 3] = a;
}

// That how you update the canvas, so that your //
// modification are taken in consideration //
function updateCanvas() {
    ctx.putImageData(canvasData, 0, 0);
}

Чем вы можете использовать его таким образом:

drawPixel(1, 1, 255, 0, 0, 255);
drawPixel(1, 2, 255, 0, 0, 255);
drawPixel(1, 3, 255, 0, 0, 255);
updateCanvas();

Для получения дополнительной информации вы можете взглянуть на это сообщение в блоге Mozilla: http://hacks.mozilla.org/2009/06/pushing-pixels-with-canvas/

Ответ 3

Кажется странным, но тем не менее HTML5 поддерживает рисование линий, кругов, прямоугольников и многих других основных фигур, у него нет ничего подходящего для рисования основной точки. Единственный способ сделать это - имитировать точку с тем, что у вас есть.

Итак, в основном есть 3 возможных решения:

  • точка рисования в виде строки
  • точка рисования как многоугольник
  • точка рисования в виде круга

У каждого из них есть свои недостатки.


Линия

function point(x, y, canvas){
  canvas.beginPath();
  canvas.moveTo(x, y);
  canvas.lineTo(x+1, y+1);
  canvas.stroke();
}

Имейте в виду, что мы тянемся к юго-восточному направлению, и если это край, может возникнуть проблема. Но вы также можете рисовать в любом другом направлении.


Прямоугольник

function point(x, y, canvas){
  canvas.strokeRect(x,y,1,1);
}

или быстрее, используя fillRect, потому что движок визуализации просто заполнит один пиксель.

function point(x, y, canvas){
  canvas.fillRect(x,y,1,1);
}

круг

Одна из проблем с кругами заключается в том, что двигателю сложнее отображать их

function point(x, y, canvas){
  canvas.beginPath();
  canvas.arc(x, y, 1, 0, 2 * Math.PI, true);
  canvas.stroke();
}

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

function point(x, y, canvas){
  canvas.beginPath();
  canvas.arc(x, y, 1, 0, 2 * Math.PI, true);
  canvas.fill();
}

Проблемы со всеми этими решениями:

  • Трудно отслеживать все точки, которые вы собираетесь нарисовать.
  • когда вы увеличиваете масштаб изображения, он выглядит уродливым.

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

Ответ 4

В моем Firefox этот трюк работает:

function SetPixel(canvas, x, y)
{
  canvas.beginPath();
  canvas.moveTo(x, y);
  canvas.lineTo(x+0.4, y+0.4);
  canvas.stroke();
}

Небольшое смещение не отображается на экране, но заставляет механизм рендеринга фактически нарисовать точку.

Ответ 5

Вышеупомянутое утверждение: "Если вы планируете рисовать много пикселей, гораздо эффективнее использовать данные изображения на холсте для рисования пикселов", кажется, совершенно неверно - по крайней мере, с Chrome 31.0.1650.57 м или в зависимости от вашего определения "много пикселей". Я бы предпочел прокомментировать прямо на соответствующую запись, но, к сожалению, у меня еще не хватает точек stackoverflow:

Я думаю, что я рисую "много пикселей", и поэтому я сначала внимательно следил за соответствующими советами. Позже я изменил свою реализацию на простой ctx.fillRect(..) для каждой нарисованной точки, см. http://www.wothke.ch/webgl_orbittrap/Orbittrap.htm

Интересно, что глупая реализация ctx.fillRect() в моем примере фактически по крайней мере в два раза быстрее, чем метод двойной буферизации на основе ImageData.

По крайней мере, для моего сценария кажется, что встроенная ctx.getImageData/ctx.putImageData на самом деле невероятно медленная. (Было бы интересно узнать процент пикселей, которые нужно коснуться до того, как подход на основе ImageData может взять на себя инициативу.)

Заключение: если вам нужно оптимизировать производительность, вам нужно профилировать свой код и действовать на ВАШИХ результатах.

Ответ 6

Это должно выполнить задание

//get a reference to the canvas
var ctx = $('#canvas')[0].getContext("2d");

//draw a dot
ctx.beginPath();
ctx.arc(20, 20, 10, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();