تقنية

مسار Canvas: لماذا يعاد تلوين خط رسمته سابقا؟

لوحات تجربتنا الثلاث: خطان أزرقان في A، خطان أحمران في B، وعلوي أحمر وسفلي أزرق في C.
ألوان مراكز الخطوط بعد الرسم الثاني في ثلاث لوحات مستقلة؛ كل لوحة بدأت بعلوي أحمر.

قد يعيد stroke رسم خط سابق لأن المسار الحالي ما زال يحتويه. الرسم لا يفرغ ذلك المسار، والمسار نفسه خارج حالة الرسم التي تحفظها save. [3]

الخلاصة السريعة

  • في اختبارنا صار الخطان أزرقين عندما أبقينا المسار السابق.
  • أعادت restore اللون الأحمر في المقارنة، لكنها لم تعزل الخط الثاني.
  • تفرغ beginPath قائمة المسارات الفرعية. [1]
  • بقي الخط الأول أحمر في فرع العزل، وصار الثاني أزرق.

خط أول نعرف لونه وموضعه

أنشأنا ثلاث لوحات مستقلة، عرض كل منها 120 وارتفاعها 100. رسمنا في كل لوحة خطا أفقيا من الموضع 20 إلى 100 عند الارتفاع 25، بسماكة 8 ولون أحمر. أعطيناه الاسم العلوي لأننا سنضيف خطا آخر عند الارتفاع 75. الأبعاد اختيارات تعليمية ثابتة.

بعد الرسم الأول فحصنا منتصف الخط عند النقطة 60 و25. كانت قنوات اللون أحمر 255، أخضر صفرا، أزرق صفرا، وقيمة قناة ألفا 255. لم نستنتج اللون من اسم متغير؛ قرأنا البكسل نفسه. لم نستورد صورة ولم نستخدم خطا متدرجا أو حافة لتقرير النتيجة.

ثم فصلنا الخطوات التالية إلى ثلاثة فروع. بدأ كل فرع من لوحة جديدة أعادت الرسم الأول نفسه، حتى لا يرث فرع نتيجة الفرع السابق. علامة الفرع هنا اسم للاختبار، وليست وضعا جاهزا داخل المتصفح.

الفرع A: اللون الجديد يصل إلى الخطين

في الفرع persistent غيرنا strokeStyle إلى الأزرق، ثم أضفنا من 20 إلى 100 خطا عند الارتفاع 75. استدعينا stroke مرة ثانية من دون beginPath بين الخطين. قرأنا بعدها منتصف كل خط، فكان كلاهما أزرق: قنوات اللون صفر وصفر و255، والقناة الأخيرة 255.

لم يتغير موضع الخط العلوي ولا اسم اللوحة. الذي أضفناه قبل الرسم الثاني هو خط آخر وإعداد لون آخر. قارن اللقطتين: كان العلوي أحمر بعد الاستدعاء الأول، وصار أزرق بعد الثاني. هذه المقارنة الزمنية داخل الفرع تمنع اعتبار الأزرق لونه منذ البداية.

الفرع B: رجع اللون ولم ترجع قائمة أقدم

تحفظ save حالة الرسم، ومنها strokeStyle وسماكة الخط، وتستعيد restore الحالة المحفوظة. هذا يختلف عن إنشاء مسار جديد. [2] [3]

في save_restore حفظنا الحالة الحمراء بعد رسم العلوي. غيرنا اللون إلى الأزرق وأضفنا الخط السفلي، ثم استدعينا restore قبل stroke الثانية. قرأنا strokeStyle فوجدناه أحمر، وقرأنا مركزي الخطين فكانا أحمرين. لم يظهر في هذا الفرع خط أزرق نهائي.

النقطة الفاصلة أن السفلي أضيف بعد save، ومع ذلك ظهر عند الرسم بعد restore. لو كانت الاستعادة قد أعادت قائمة الخطوط إلى القائمة القديمة، لافتقدنا السفلي. نختبر هذا الاحتمال في المثال من خلال وجوده الفعلي، لا من تشابه كلمتي الحفظ والاستعادة مع حفظ ملف.

الفرع C: عزل المسار قبل إضافة السفلي

استدعينا beginPath بعد رسم العلوي وقبل تجهيز السفلي. تفرغ هذه العملية قائمة المسارات الفرعية التي سيبنى عليها المسار الجديد. [1]

في begin_path عينا الأزرق بعد تلك الخطوة، وأضفنا الخط السفلي ورسمناه. هذه المرة بقي بكسل العلوي أحمر، وكان السفلي أزرق. شاهدنا اللونين في اللوحة نفسها؛ لم نركب صورتين بعد انتهاء الاختبار.

يمكن تلخيص فرعي B وC بعمليتين مختلفتين في سجلنا. في B اخترنا لعملية الرسم الأخيرة اللون القديم، فظهر الخطان أحمرين. في C أبقينا اللون الجديد، لكن ما أضفناه إلى المسار بعد العزل هو السفلي وحده. تطابق اللون لا يكفي لتحديد الخطوات التي أدت إليه؛ احتفظ بالسجل أيضا.

الفرعالعلوي بعد الرسم الثانيالسفلي بعد الرسم الثاني
A: persistentأزرقأزرق
B: save_restoreأحمرأحمر
C: begin_pathأحمرأزرق

أعد التجربة بالشيفرة نفسها

تنشئ الدالة لوحة جديدة في كل استدعاء وتعيدها. جرب أسماء الفروع الثلاثة كما هي، وألحق كل لوحة بالصفحة. الموضعان المقروءان هما وسطا الخطين، وليسا نهايتهما. شغلنا المقطع المعروض في Edge 155.0.4283.45، ثم قارننا قراءات البكسلات بالجدول.

توضح الصورة الداخلية ترتيب التعليمات قبل الرسم الثاني. اقرأ صف إعداد اللون وصف قائمة الخطوط كلّا على حدة، ثم انظر إلى ناتج الفرع. لا تختصرهما إلى عبارة «حفظت الرسم»، لأنها لا تخبر قارئ الشيفرة بما حفظته فعلا.

بطاقات الفروع قبل الرسم الثاني تفصل اللون الحالي عن قائمة الخطوط: A أزرق وكلاهما، B أحمر وكلاهما، C أزرق والسفلي فقط.
سجلنا قبل الرسم الثاني: في B استعدنا الأحمر، وفي C أفرغنا المسار ثم أضفنا السفلي.
function draw(mode) {
  const c=
  document.createElement("canvas");
  c.width=120; c.height=100;
  const x=c.getContext("2d");
  x.lineWidth=8;
  x.strokeStyle="red";
  x.beginPath();
  x.moveTo(20,25);
  x.lineTo(100,25);
  x.stroke();
  if(mode==="save_restore")
    x.save();
  if(mode==="begin_path")
    x.beginPath();
  x.strokeStyle="blue";
  x.moveTo(20,75);
  x.lineTo(100,75);
  if(mode==="save_restore")
    x.restore();
  x.stroke();
  return c;
}
for(const mode of [
  "persistent",
  "save_restore",
  "begin_path"
]) {
  const c=draw(mode);
  document.body.append(c);
}

[1] [2] [3]

ما الذي أثبته الفحص؟

اتفق الفحص في اللوحات الثلاث مع الحالات المبينة: أزرقان، ثم أحمران، ثم علوي أحمر وسفلي أزرق. وسجلنا في كل بداية علويّا أحمر وسفليّا لم يرسم بعد. بهذا نعرف أن الفروع بدأت من الحالة التي وصفناها، لا من صورة متبقية في لوحة أعدنا استعمالها.

لم نقارن سرعة الطرائق ولم نفحص تنعيم الحواف أو نتائج متصفحات أخرى. النتيجة تخص خطوطنا المعتمة ومواضع القياس الداخلية. إذا غيرت الخطوات، فحدد موضع استدعاء beginPath وموضع save وrestore ثم أعد قراءة البكسلات؛ أسماء الدوال وحدها لا تعوض ترتيبها في السجل.

المراجع

  1. MDN — beginPath
    https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/beginPath
  2. MDN — save
    https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
  3. WHATWG — Canvas paths
    https://html.spec.whatwg.org/multipage/canvas.html
أُعد بمساعدة الذكاء الاصطناعي؛ مراجعة تحريرية آلية، دون مراجعة بشرية أو اعتماد مهني. تاريخ الإعداد13 أكتوبر2026.

أُعدّ هذا المقال بمساعدة الذكاء الاصطناعي وراجعته أدوات ذكاء اصطناعي. لا يُنسب إلى مراجع بشري أو خبير مستقل. منهجية المحتوى.