最近のプロジェクトでは、小さなピクセル グリッドを消去したり、フレーム選択の色を変更したり、さまざまなグラフィックを消去したりできる、ピクセル スタイルの描画ボードを実装したいと考えています。このような小さなプロジェクトは単純に見えるかもしれませんが、多くの機能が含まれています。もの。
ピクセルグリッドを描画するまずピクセルグリッドクラスを定義しましょう
ピクセル = 関数 (オプション) { this.x = option.x; this.y = option.shape; this.size = option.size 8;}
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) {var Points = this.getPoints(); point.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.drawingStyle=this.drawingStyle;ctx.fillStyle=this.fillStyle;ctx.beginPath();this.createPath(ctx); ctx.ストローク();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 ピクセル = 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 Circle = box[c];ctx.moveTo(circle.x + 3, Circle.y);circle.createPath(ctx);}ctx.closePath();ctx.ストローク();console.timeEnd('time');
このレンダリング効率は非常に高速であり、コンテキストの状態が変更されるたびにキャンバスが再描画され、この状態はグローバルな状態であるため、キャンバスの状態の変更は最小限であることがわかります。
ピクセルグリッドのインタラクションプロジェクトの要件は、キャンバス上でマウスを押して移動することでピクセルを消去できることです。これには 2 つの知識ポイントが含まれます。1 つはマウスの移動パス上のピクセル グリッドを取得する方法であり、2 つ目はパフォーマンスの問題です。私たちのニーズ 要件は 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) は 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) + オフセット; || px > maxX) && (py < minY || py > maxY)) { return Number.MAX_VALUE } return Math.sqrt(distToSegmentSquared(p, v、w));
特定のロジックについては詳しく説明しません。読者は自分でコードを読むことができます。次に、交差するグリッドを取得し、ボックス内のデータを削除し、再度レンダリングすると、効果が確認できます。
同様に、染色効果を作成し、キャンバス ピクセル描画ボードの小さなデモを実装できます。ただし、染色効果を作成するには、各ピクセルが独立しているため、最初の描画方法を使用する必要があります。ただし、ピクセルの数はそれほど多くありません。基本的にラグ感はありません。効果は大まかに以下のような感じです。
最近少し怠けているので、今はこのままにしておきます。後で写真をアップロードしたり、写真をモザイク化したり、エクスポートしたりする機能を追加します。
以上がこの記事の全内容です。皆様の学習のお役に立てれば幸いです。また、VeVb Wulin Network をご支援いただければ幸いです。