В недавнем проекте я хочу реализовать доску для рисования в пиксельном стиле, где можно стирать мелкие пиксельные сетки, менять цвет выделенных рамок и стирать различную графику. Такой небольшой проект может показаться простым, но он содержит много элементов. вещи.
Рисуем пиксельную сеткуДавайте сначала определим класс пиксельной сетки.
Пиксель = функция (опция) { this.x = option.x; this.y = option.shape; this.size = option.size ||
x и y представляют координаты центральной точки. Это то, что я сделал вначале.
createPath: function (ctx) {if (this.shape === 'circle') {this.createCircle(ctx);} else if (this.shape === 'rect') {this.createRect(ctx);} else {this.createCircle(ctx);}},createCircle: function (ctx) {var radius = this.size / 2;ctx.arc(this.x,this.y,radius,0,Math.PI*2);},createRect: function (ctx) {varpoints = this.getPoints();points.forEach(function (point) , i) { ctx[i == 0 ? 'moveTo': 'lineTo'](point.x, point.y); }) ctx.lineTo(points[0].x, точки[0].y);},
Пиксельная сетка поддерживает круги и прямоугольники. После определения пути он рисуется.
ничья: функция (ctx) {ctx.save();ctx.lineWidth=this.lineWidth;ctx.strokeStyle=this.strokeStyle;ctx.fillStyle=this.fillStyle;ctx.beginPath();this.createPath(ctx); ctx.stroke();if(this.isFill){ctx.fill();}ctx.restore();}
Затем создайте пиксельную сетку партиями с помощью цикла:
for (var i = StepX + .5; i < Canvas.width; i+=stepX) {for (var j = StepY + .5; j < Canvas.height; j+=stepY) {var Pixel = New Pixel({x : i,y: j,shape: 'circle'})box.push(pixel);pixel.draw(ctx);}}
Кажется, это идеально, но есть огромный недостаток: каждый раз, когда пиксель отрисовывается, он возвращается в контекст, и состояние холста каждый раз меняется. Это приведет к снижению производительности рендеринга, поскольку их много. пикселей. Если холст относительно большой, производительность вызывает беспокойство, и на чертежной доске выполняются некоторые операции. Нецелесообразно так часто менять состояние холста.
Поэтому правильный подход: мы должны определить все пути, и лучше всего рисовать их на холсте сразу пачками;
//Определяем положение пикселя for (var i = StepX + .5; i < Canvas.width; i+=stepX) {for (var j = StepY + .5; j < Canvas.height; j+=stepY) { var пиксель = новый пиксель({x: i,y: j,shape: 'circle'})box.push(pixel);}}//Пакетное рисование console.time('time');ctx.beginPath();for (var c = 0; c < box.length; c++) {var круг = box[c];ctx.moveTo(circle.x + 3, Circle.y);circle.createPath(ctx);}ctx.closePath();ctx.stroke();console.timeEnd('time');
Вы можете видеть, что эта эффективность рендеринга очень быстрая, а состояние холста меняется как можно меньше, потому что каждый раз, когда состояние контекста изменяется, холст будет перерисовываться, и это состояние является глобальным.
Взаимодействие с пиксельной сеткойТребование проекта заключается в том, что пиксели можно стирать, нажимая и перемещая мышь по холсту. Это содержит два пункта знаний: один — о том, как получить пиксельную сетку на пути движения мыши, а второй — проблемы с производительностью из-за. Наши потребности Требуется отрисовать 80 000 точек, не говоря уже о чем-то другом, просто цикл займет десятки или сотни миллисекунд, не говоря уже о рисовании и рендеринге. Давайте сначала разберемся с первым вопросом:
Получите сетку под траекторией движения мыши.Видя эту проблему, мы можем легко подумать о написании функции, которая будет определять положение мыши по положению мыши, содержащей сетку, а затем повторно обновлять вычисление позиции каждый раз, когда она перемещается. Таким образом, требование выполняется. можно выполнить, но при наведении курсора мыши сделать это быстро невозможно. Положение каждой точки можно вычислить, и эффект будет неоднозначным. Давайте изменим наше мышление. Мы можем четко знать начальную и конечную точки пути, который проходит мышь. Мы представляем себе весь путь рисования как отрезок линии. Тогда проблемой становится алгоритм пересечения отрезка линии с оригиналом. сегмент — это Толщина кисти и путь, по которому проходит отрезок линии, — это пути движения мыши, а пересекающиеся с ними окружности — это сетки, которые необходимо изменить. Преобразование в код выглядит следующим образом:
function sqr(x) { return x * x } function dist2(p1, p2) { return sqr(p1.x - p2.x) + sqr(p1.y - p2.y) } function distToSegmentSquared(p, v, w ) { var l2 = dist2(v, w); if (l2 == 0) return dist2(p, v); ((px - vx) * (wx - vx) + (py - vy) * (wy - vy)) / l2; if (t < 0) return dist2(p, v); if (t > 1) return dist2; (p, w); return dist2(p, { x: vx + t * (wx - vx), y: vy + t * (wy - vy) }/** * @description Вычислить, пересекает ли отрезок линии окружность* @param {x: num, y: num} p центр окружности* @param {x: num, y: num} v начальная точка отрезка* @param {x : num, y: num } w конечная точка сегмента линии*/ function distToSegment(p, v, w) { var offset = pathHeight; var minX = Math.min(vx, wx) - смещение; var maxX = Math.max(vx, wx) + смещение; var minY = Math.min(vy, wy) - смещение; var maxY = Math.max(vy, wy) + смещение, если ((px < minX; || px > maxX) && (py < minY || py > maxY)) { return Number.MAX_VALUE } return Math.sqrt(distToSegmentSquared(p, в, ш));
Конкретная логика не будет подробно описана. Читатели смогут прочитать код самостоятельно. Затем, получив пересекающуюся сетку, удалите данные в поле и отрендерите ее снова, вы увидите эффект.
Таким же образом мы можем создать эффект окрашивания, а затем реализовать небольшую демонстрацию пиксельной доски для рисования холста. Однако для создания эффекта окрашивания необходимо использовать первый метод рисования. Каждый пиксель должен быть объектом, поскольку состояние каждого объекта независимо. Однако не нужно беспокоиться о производительности. в принципе не будет ощущения задержки. Эффект примерно следующий:
В последнее время я немного ленился, поэтому оставлю пока так. У меня будет время добавить функцию загрузки картинок, пикселизировать картинки и функции экспорта.
Выше приведено все содержание этой статьи. Я надеюсь, что она будет полезна для изучения всеми. Я также надеюсь, что все поддержат сеть VeVb Wulin.