Рисование точки на холсте HTML5 [дубликат]
этот вопрос уже есть ответ здесь:
рисование линии на холсте HTML5 довольно просто с помощью context.moveTo()
и context.lineTo()
функции.
Я не совсем уверен, можно ли нарисовать точку, т. е. цвет a один пиксель. Функция lineTo не будет рисовать одну пиксельную линию (очевидно).
есть ли способ сделать это?
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 может взять на себя инициативу..)
Вывод: Если вам нужно оптимизировать производительность, вы должны профилировать свой код и действовать по своим выводам..