في مشروع حديث، أرغب في تنفيذ لوحة رسم على شكل بكسل، حيث يمكن مسح شبكات البكسل الصغيرة، وتغيير لون تحديدات الإطار، ويمكن مسح الرسومات المختلفة. قد يبدو مثل هذا المشروع الصغير بسيطًا، ولكنه يحتوي على الكثير أشياء.
ارسم شبكة بكسلدعونا أولاً نحدد فئة شبكة البكسل
Pixel = function (option) { this.x = option.x; this.y = option.y; this.shape = option.shape;
يمثل x وy إحداثيات النقطة المركزية. لقد قمت بذلك في البداية.
createPath: الوظيفة (ctx) {if (this.shape === 'circle') {this.createCircle(ctx);} else if (this.shape === 'rect') {this.createRect(ctx);} آخر {this.createCircle(ctx);}}، createCircle: الوظيفة (ctx) {var radius = this.size / 2;ctx.arc(this.x,this.y,radius,0,Math.PI*2);},createRect: function (ctx) {var point = this.getPoints(); , 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();}
ثم قم بإنشاء شبكة البكسل على دفعات عبر حلقة:
لـ (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) { فار بكسل = بكسل جديد({x: i,y: j,shape: 'circle'})box.push(pixel);}}// الرسم الدفعي console.time('time');ctx.beginPath();for (var c = 0; c < box.length; c++) {var دائرة = مربع [ج]؛ctx.moveTo(circle.x + 3, Circle.y);circle.createPath(ctx);}ctx. ClosePath();ctx.stroke();console.timeEnd('time');
يمكنك أن ترى أن كفاءة العرض هذه سريعة جدًا، وأن حالة اللوحة القماشية تتغير بأقل قدر ممكن، لأنه في كل مرة يتم فيها تغيير حالة السياق، سيتم إعادة رسم اللوحة القماشية، وهذه الحالة هي حالة عالمية.
تفاعل شبكة البكسلمتطلب المشروع هو أنه يمكن مسح وحدات البكسل عن طريق الضغط على الماوس وتحريكه على اللوحة القماشية، ويحتوي هذا على نقطتين معرفيتين، إحداهما تتعلق بكيفية الحصول على شبكة البكسل على مسار حركة الماوس، والثانية تتعلق بمشاكل الأداء، بسبب. احتياجاتنا الشرط هو رسم 80000 نقطة، ناهيك عن أي شيء آخر، فمجرد التكرار سيستغرق عشرات أو مئات المللي ثانية، ناهيك عن الرسم والعرض. لننظر إلى السؤال الأول أولاً:
احصل على الشبكة أسفل مسار حركة الماوسعند رؤية هذه المشكلة، يمكننا بسهولة التفكير في كتابة دالة للحصول على موضع الماوس من خلال موضع الماوس الذي يحتوي على الشبكة، ثم إعادة تحديث حساب الموضع في كل مرة يتحرك فيها هذا المتطلب يمكن تحقيقه، ولكن إذا تحرك الماوس، فمن المستحيل القيام بذلك بسرعة، ويمكن حساب موضع كل نقطة، وسيكون التأثير غير متناسق. دعونا نغير تفكيرنا، يمكننا أن نعرف بوضوح نقاط البداية والنهاية للمسار الذي يمر به الماوس، ونتخيل مسار الرسم بأكمله كقطعة خطية، ثم تصبح المشكلة خوارزمية لتقاطع قطعة الخط مع الخط الأصلي المقطع هو سمك الفرشاة والمسار الذي يمر عبره مقطع الخط هي مسارات حركة الماوس، والدوائر التي تتقاطع معها هي الشبكات التي تحتاج إلى تغيير. يتم تحويله إلى كود كما يلي:
وظيفة sqr(x) { return x * x } وظيفة dist2(p1, p2) { return sqr(p1.x - p2.x) + sqr(p1.y - p2.y) } وظيفة 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); (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) + offset; var minY = Math.min(vy, wy) - offset; ||.px > maxX) && (py < minY || py > maxY)) { return Number.MAX_VALUE } return Math.sqrt(distToSegmentSquared(p, الخامس، ث))؛ }
لن يتم توضيح المنطق المحدد. يمكن للقراء قراءة الكود بأنفسهم. ثم، من خلال الحصول على الشبكة المتقاطعة، وحذف البيانات الموجودة في المربع، وعرضها مرة أخرى، يمكنك رؤية التأثير.
بنفس الطريقة، يمكننا إنشاء تأثير صبغ، وبعد ذلك يمكننا تنفيذ عرض توضيحي صغير للوحة رسم البكسل القماشية. ومع ذلك، لإنشاء تأثير الصباغة، يجب عليك استخدام طريقة الرسم الأولى. يجب أن يكون كل بكسل كائنًا، لأن حالة كل كائن مستقلة، ومع ذلك، لا داعي للقلق بشأن الأداء، ولا يوجد الكثير من البكسلات لن يكون هناك أي شعور بالتأخر. التأثير تقريبًا كما يلي:
لقد كنت كسولًا بعض الشيء مؤخرًا، لذا سأترك الأمر على هذا النحو في الوقت الحالي، وسيكون لدي الوقت لإضافة وظيفة لتحميل الصور وتقسيم الصور ووظائف التصدير لاحقًا.
ما ورد أعلاه هو المحتوى الكامل لهذه المقالة وآمل أن يكون مفيدًا لدراسة الجميع وآمل أيضًا أن يدعم الجميع شبكة VeVb Wulin.