أعتقد أنه كان يجب على الجميع أن يواجهوا مثل هذه الحاجة عند تعلم اللوحة القماشية أو استخدام اللوحة القماشية في تطوير المشروع: لتنفيذ أداة لوحة الرسم التي يمكن كتابتها.
حسنًا، أعتقد أنه بالنسبة للأطفال الأكثر دراية بالقماش، يمكن القيام بذلك باستخدام بضع عشرات من أسطر التعليمات البرمجية فقط. العرض التوضيحي التالي هو مثال بسيط:
<!DOCTYPE html><html><head> <title>عرض لوحة الرسم</title> <style type=text/css> Canvas { border: 1px blue Solid } </style></head><body> <canvas id=canvas width=800 height=500></canvas> <script type=text/javascript> Let isDown = false; document.querySelector('#canvas'); const ctx = Canvas.getContext('2d'); // تعيين لون الخط ctx.strokeStyle = 'red'; .lineCap = 'round'; Canvas.addEventListener('mousedown', down, false); move, false); Canvas.addEventListener('mouseup', up, false); move(evt) { if (!isDown) return; const endPoint = getPos(evt); drawLine(beginPoint, endPoint); beginPoint }; up(evt) { if (!isDown) return; const endPoint = getPos(evt); drawLine(beginPoint, endPoint); beginPoint = null; false } function getPos(evt) { return { x: evt.clientX, y: evt.clientY } } function drawLine(beginPoint, endPoint) { ctx.beginPath(); ctx.moveTo(beginPoint.x, beginPoint.y); ctx.lineTo(endPoint.x, endPoint.y); >
منطق التنفيذ الخاص به بسيط جدًا أيضًا:
mousedown
و mouseup
و mousemove
، ونقوم أيضًا بإنشاء متغير isDown
؛mousedown
)، اضبط isDown
على true
، وعندما يضع المستخدم الماوس لأسفل ( mouseup
)، اضبطه على false
. وتتمثل ميزة ذلك في أنه يمكنه تحديد ما إذا كان المستخدم في حالة رسم حاليًا ;mousemove
إذا وفقط إذا كانت isDown
true
(أي في حالة الكتابة)، سيتم توصيل النقطة الحالية ورسمها بالنقطة السابقة من خلال طريقة lineTo
الخاصة بالتابع. قماش؛من خلال الخطوات المذكورة أعلاه، يمكننا تحقيق وظيفة لوحة الرسم الأساسية، ومع ذلك، فإن الأمور ليست بهذه البساطة. أحذية الأطفال الحذرة قد تجد مشكلة خطيرة للغاية - الخطوط المرسومة بهذه الطريقة خشنة وليست سلسة بما فيه الكفاية، وكلما أسرعت. ارسم، كلما كان الإحساس بالخطوط المكسورة أقوى. يظهر الأداء أدناه:
لماذا يحدث هذا؟ تحليل المشكلةالأسباب الرئيسية لهذه الظاهرة هي:
نقوم بتوصيل النقاط باستخدام طريقة lineTo
من القماش. ما يربط بين نقطتين متجاورتين هو خط مستقيم، وليس منحنى، لذلك فإن ما يتم رسمه بهذه الطريقة هو خط متعدد؛
نظرًا لقلة تكرار جمع أحداث mousemove
في المتصفح، يعلم الجميع أنه أثناء mousemove
، يجمع المتصفح إحداثيات الماوس الحالي كل فترة زمنية قصيرة، لذلك، كلما تحرك الماوس بشكل أسرع، كلما كانت المسافة بين النقطتين المتجاورتين اللتين تم جمعهما أبعد بعيدًا، كلما كان الشعور بالخطوط القابلة للطي أكثر وضوحًا؛
هناك بالفعل طرق لرسم منحنيات ناعمة. إذا كان lineTo
غير موثوق به، فيمكننا استخدام واجهة برمجة تطبيقات رسم أخرى من اللوحة القماشية - quadraticCurveTo
، والتي تُستخدم لرسم منحنيات Bezier التربيعية.
منحنى بيزير التربيعي
quadraticCurveTo(cp1x, cp1y, x, y)
يتطلب استدعاء الأسلوب quadraticCurveTo
أربعة معلمات cp1x
و cp1y
تصف نقاط التحكم، بينما x
و y
هما نقطتا النهاية للمنحنى:
يمكن العثور على مزيد من المعلومات التفصيلية على MDN
بما أننا نريد استخدام منحنى بيزيير، فمن الواضح أن بياناتنا ليست كافية لوصف منحنى بيزيير التربيعي بشكل كامل، نحتاج إلى: نقطة البداية، ونقطة التحكم، ونقطة النهاية.
هناك خوارزمية ذكية جدًا يمكنها مساعدتنا في الحصول على هذه المعلومات
خوارزمية للحصول على نقاط بيزيير الرئيسية من الدرجة الثانيةليس من الصعب فهم هذه الخوارزمية، واسمحوا لي أن أقدم مثالاً مباشرًا:
لنفترض أننا جمعنا ما مجموعه 6 إحداثيات الماوس في اللوحة، وهي A, B, C, D, E, F
؛ خذ النقاط الثلاث السابقة A, B, C
، واحسب نقطة المنتصف B1
لـ B
و C
، واستخدم A
هي نقطة البداية، B
هي نقطة التحكم، B1
هي نقطة النهاية. استخدم quadraticCurveTo
لرسم مقطع منحنى Bezier من الدرجة الثانية؛
بعد ذلك، احسب نقطة المنتصف C1
بين النقطتين C
و D
، واستمر في رسم المنحنى بحيث تكون B1
نقطة البداية، C
كنقطة التحكم، و C1
كنقطة النهاية؛
يستمر الرسم عن طريق القياس. عند الوصول إلى النقطة الأخيرة F
، ينتهي منحنى بيزيير بـ D1
، نقطة المنتصف لـ D
و E
، كنقطة البداية، E
كنقطة التحكم، و F
كنقطة النهاية.
حسنًا، الخوارزمية على هذا النحو، ثم سنقوم بترقية الكود الحالي بناءً على هذه الخوارزمية:
Let isDown = false;let point = [];let beginPoint = null;const Canvas = document.querySelector('#canvas');const ctx = Canvas.getContext('2d');// تعيين لون الخط ctx.strokeStyle = 'أحمر';ctx.lineWidth = 1;ctx.lineJoin = 'round';ctx.lineCap = 'round';canvas.addEventListener('mousedown', down, false);canvas.addEventListener('mousemove', move, false);canvas.addEventListener('mouseup', up, false);canvas.addEventListener('mouseout' , up, false); function down(evt) { isDown = true; Points.push({x, y}); beginPoint = {x, y};} function move(evt) { if (!isDown) return; const { x, y} = getPos(evt); x, y}); if (points.length > 3) { const lastTwoPoints = point.slice(-2); x: (lastTwoPoints[0].x + lastTwoPoints[1].x) / 2, y: (lastTwoPoints[0].y + lastTwoPoints[1].y) / 2, } drawLine(beginPoint, controlPoint, endPoint); beginPoint = endPoint }}function up(evt) { if (!isDown) return const { x, y } = getPos(evt); point.push({x, y}); if (points.length > 3) { const lastTwoPoints = point.slice(-2); , controlPoint, endPoint); } beginPoint = null = false; evt.clientX, y: evt.clientY }}function drawLine(beginPoint, controlPoint, endPoint) { ctx.beginPath(); ctx.moveTo(beginPoint.x, beginPoint.y); y, endPoint.x, endPoint.y); ctx.stroke(); ctx.ClosePath();}
على أساس الأصل، أنشأنا points
متغيرة لحفظ النقاط التي مر بها الماوس في حدث mousemove
السابق، وفقًا لهذه الخوارزمية، يستغرق رسم منحنى بيزيير من الدرجة الثانية 3 نقاط على الأقل، لذلك لدينا فقط يبدأ الرسم points
فقط عندما يكون عدد النقاط أكبر من 3. المعالجة اللاحقة هي تمامًا نفس هذه الخوارزمية، لذا لن أخوض في التفاصيل هنا.
بعد تحديث الكود، أصبح منحنىنا أكثر سلاسة، كما هو موضح في الشكل أدناه:
تنتهي هذه المقالة هنا، أتمنى أن تستمتعوا جميعًا بالرسم على القماش ~ نراكم في المرة القادمة :)
إذا كنت مهتمًا بأحذية الأطفال، يمكنك النقر هنا لمتابعة مدونتي، وسيتم نشر أي منشورات مدونة جديدة ومثيرة للاهتمام هنا في أقرب وقت ممكن ~
ما ورد أعلاه هو المحتوى الكامل لهذه المقالة وآمل أن يكون مفيدًا لدراسة الجميع وآمل أيضًا أن يدعم الجميع شبكة VeVb Wulin.