Рисование точки на холсте HTML5 [дубликат]


этот вопрос уже есть ответ здесь:

рисование линии на холсте HTML5 довольно просто с помощью context.moveTo() и context.lineTo() функции.

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

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

6 93

6 ответов:

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

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

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

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's 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's 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/

это кажется странным, но тем не менее 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 здесь с сравнительными тестами

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

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

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

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

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

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

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

Вывод: Если вам нужно оптимизировать производительность, вы должны профилировать свой код и действовать по своим выводам..

Это должно сделать задание

//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();