محرر مخططات الحالات بـ Mermaid
يبيّن مخطط الحالات الحالاتِ التي قد يكون عليها شيء ما وما الذي ينقله من حال إلى حال. يناسبك حين يكون للموضوع دورة حياة — طلب، فاتورة، اشتراك — ويكون السؤال المهم أي الانتقالات مسموح بها. أما إن كنت تصف خطوات تُنفَّذ لا حالات يُمكث فيها، فالذي تحتاجه مخطط تدفق.
دورة حياة طلب في متجر إلكتروني
هذه هي الحالة التي تستحق فيها آلة الحالات موضعها: فبعد الشحن ثلاث نهايات يقصي بعضها بعضًا، واثنتان منها ترجعان إلى الخلف. ولاحظ أن كل معرّف حالة مصرَّح به عبر `state "التسمية" as المعرّف`. وهذا في العربية ليس تأنقًا بل ضرورة، للسبب المشروح في قسم الأخطاء.
stateDiagram-v2
direction LR
state "مسودة" as مسودة
state "بانتظار الدفع" as بانتظارالدفع
state "جاهز للشحن" as جاهزللشحن
state "قيد التوصيل" as قيدالتوصيل
state "تم التسليم" as تمالتسليم
state "طلب إرجاع" as طلبإرجاع
[*] --> مسودة
مسودة --> بانتظارالدفع: صدر الطلب
بانتظارالدفع --> جاهزللشحن: وصل الدفع
بانتظارالدفع --> [*]: انقضت 24 ساعة
جاهزللشحن --> قيدالتوصيل: استلمه الناقل
قيدالتوصيل --> تمالتسليم: وقّع المستلم
تمالتسليم --> طلبإرجاع: ضمن مهلة الإرجاع
طلبإرجاع --> بانتظارالدفع: رُدّ المبلغ
تمالتسليم --> [*]: انقضت مهلة الإرجاعأمثلة مشروحة
١. أصغر آلة حالات
الرمز `[*]` هو نقطة الدخول ونقطة الخروج معًا: وأيّهما يكون يتوقف على أي جانبي السهم يقع. وهذا أدنى هيكل يستحق الرسم.
stateDiagram-v2
[*] --> نشط
نشط --> مغلق
مغلق --> [*]٢. انتقالات لها أسماء
النص بعد النقطتين يسمّي الحدث الذي يستدعي الانتقال. وهو الجزء الذي يجعل المخطط نافعًا: فبدونه لديك قائمة حالات ولا قاعدة واحدة.
stateDiagram-v2
[*] --> معلق
معلق --> مدفوع: نجح التحصيل
معلق --> منتهٍ: انقضى الأجل
مدفوع --> مشحون: خرج من المستودع
مشحون --> مستلم: وقّع المستلم
مستلم --> [*]
منتهٍ --> [*]٣. تسميات مقروءة بمعرّفات آمنة
في العربية لا يكاد اسم حالة يسع كلمة واحدة، والمسافة داخل المعرّف تُفسد الأمر بصمت. والصيغة `state "التسمية" as المعرّف` تحسم المسألة مرة واحدة: التسمية مقروءة والمعرّف آمن.
stateDiagram-v2
state "بانتظار الدفع" as بانتظارالدفع
state "جاهز للشحن" as جاهزللشحن
state "في الطريق إلى العميل" as فيالطريق
[*] --> بانتظارالدفع
بانتظارالدفع --> جاهزللشحن: تأكّد الدفع
جاهزللشحن --> فيالطريق: استلمه الناقل
فيالطريق --> [*]٤. الحالات المركّبة ونقاط الاختيار
تحتوي الحالة المركّبة على آلة خاصة بها: استعملها حين يكون لمرحلة ما حياة داخلية ذات شأن. و`<<choice>>` نقطة تفرّع شرطية، ويجب التصريح بها قبل الانتقالات التي تستعملها.
stateDiagram-v2
state فحص <<choice>>
[*] --> قيدالمعالجة
state قيدالمعالجة {
[*] --> التجميع
التجميع --> التغليف: جُمعت الأصناف
التغليف --> [*]
}
قيدالمعالجة --> فحص
فحص --> مقبول: اجتاز ضبط الجودة
فحص --> مرفوض: ظهر عيب
مقبول --> [*]
مرفوض --> [*]٥. المناطق المتوازية
شرطتان في سطر مستقل تقسمان الحالة المركّبة إلى مناطق نشطة في آن واحد. وهذا هو الشيء الوحيد الذي يفعله مخطط الحالات ويعجز عنه مخطط التدفق فعلًا.
stateDiagram-v2
[*] --> التسجيل
state التسجيل {
[*] --> بريدغيرموثق
بريدغيرموثق --> بريدموثق: نُقر الرابط
--
[*] --> ملففارغ
ملففارغ --> ملفمكتمل: أُرسل النموذج
}
التسجيل --> نشط: اكتمل الاثنان
نشط --> [*]ملخص صياغة مخطط الحالات
استعمل `stateDiagram-v2` لا `stateDiagram`. كلاهما يُرسم، لكن v2 هو محرك التخطيط الذي ما زال يُطوَّر، وهو يتعامل مع الحالات المركّبة والمتوازية تعاملًا أفضل بوضوح.
| الصياغة | المعنى |
|---|---|
| stateDiagram-v2 | يفتح المخطط. و`stateDiagram` ما زال يعمل لكنه يستعمل التخطيط القديم. |
| [*] --> A | الحالة الابتدائية — نقطة الدخول. |
| A --> [*] | الحالة النهائية. |
| A --> B | انتقال بلا اسم. |
| A --> B: حدث | انتقال مسمّى بالحدث الذي يستدعيه. |
| state "تسمية" as معرّف | تسمية مقروءة مع معرّف بلا مسافات. |
| state A { ... } | حالة مركّبة، بداخلها آلة خاصة بها. |
| -- | داخل حالة مركّبة، يقسمها إلى مناطق متوازية. |
| state x <<choice>> | نقطة تفرّع شرطية. |
| state f <<fork>> / <<join>> | التفريع إلى انتقالات متوازية ثم جمعها. |
| note right of A: نص | يضيف ملاحظة. ويوجد `note left of` أيضًا. |
| direction LR | يخطّط الآلة من اليسار إلى اليمين بدل الأعلى إلى الأسفل. |
الأخطاء الستة التي تُفسد مخطط الحالات
أُعيد إنتاجها على Mermaid 11.12.2. الأربعة الأولى توقف الرسم. والأخيران أسوأ: يُرسمان دون أن يرفّ لهما جفن ويعيدان مخططًا لا يعني ما كتبتَه.
ما تراه
يُرسم المخطط، لكن حالة واحدة صارت عدة مربعات
لماذا
مسافة داخل معرّف الحالة. وفي العربية هذا أسهل خطأ يقع، لأن أسماء حالاتنا لا تكاد تسع كلمة واحدة. ولا يرفض Mermaid ذلك ولا يعامل البقية وصفًا: بل ينشئ مربعًا مستقلًا لكل كلمة. قِيس بقراءة المعرّفات الناتجة — `[*] --> في انتظار الدفع` ينتج ثلاث حالات هي `في` و`انتظار` و`الدفع`، ولا يتصل بالسهم إلا أولها؛ أما البقية فتبقى معلقة بلا وصل. ويتسع المخطط جانبيًا دون أن يقول شيئًا. أما آلية الوصف فموجودة فعلًا، لكنها تطلب نقطتين: `بانتظارالدفع: بانتظار تحويل العميل`.
الحل
صرّح بالحالة عبر `state "التسمية" as المعرّف` وأشر إليها دائمًا بالمعرّف. واعدّ هذا في العربية القاعدةَ لا الاستثناء.
stateDiagram-v2
[*] --> في انتظار الدفع
في انتظار الدفع --> مغلقstateDiagram-v2
state "في انتظار الدفع" as بانتظارالدفع
[*] --> بانتظارالدفع
بانتظارالدفع --> مغلقما تراه
Parse error ينتهي بـ: got 'INVALID'
لماذا
شرطة داخل معرّف الحالة. والأسماء بالشرطة تخطر بالبال تلقائيًا عند محاولة تجنّب المسافة، لكن الشرطة تُقرأ بداية سهم انتقال.
الحل
استعمل كلمة واحدة أو شرطة سفلية للمعرّف، وضع النص المقروء في تسمية بين علامتَي اقتباس.
stateDiagram-v2
[*] --> قيد-المعالجة
قيد-المعالجة --> مغلقstateDiagram-v2
state "قيد المعالجة" as قيدالمعالجة
[*] --> قيدالمعالجة
قيدالمعالجة --> مغلقما تراه
Parse error داخل حالة مركّبة
لماذا
حالة مركّبة فُتحت بـ `{` ولم تُغلق قط. ويجب أن يكون القوس المعقوف المُغلِق في سطر مستقل.
الحل
أغلق الكتلة.
stateDiagram-v2
[*] --> خارجية
state خارجية {
[*] --> داخليةstateDiagram-v2
[*] --> خارجية
state خارجية {
[*] --> داخلية
}ما تراه
Lexical error on line N. Unrecognized text.
لماذا
فاصل المناطق المتوازية مكتوب بعدد شرطات خاطئ. فداخل الحالة المركّبة، وفي سطر مستقل، عددها اثنتان بالضبط. وثلاث شرطات رمز مختلف تمامًا.
الحل
استعمل `--` بالضبط.
stateDiagram-v2
state كلاهما {
[*] --> A
---
[*] --> B
}stateDiagram-v2
state كلاهما {
[*] --> A
--
[*] --> B
}ما تراه
Parse error on line 1 ينتهي بـ: got 'ID'
لماذا
لاحقة إصدار غير موجودة. فالموجود `stateDiagram` و`stateDiagram-v2` لا غير: و`-v3` يسقط في السطر الأول.
الحل
استعمل `stateDiagram-v2`.
stateDiagram-v3
[*] --> مسودةstateDiagram-v2
[*] --> مسودةما تراه
يُرسم المخطط، لكن نقطة الاختيار تُرسم حالةً عادية
لماذا
تصريح `<<choice>>` جاء بعد الانتقالات التي تستعمله. فـ Mermaid ينشئ الحالة أول مرة يصادفها، والنمط المضاف لاحقًا لا يغيّر ما أُنشئ.
الحل
صرّح بالحالات الزائفة قبل الانتقالات التي تشير إليها.
stateDiagram-v2
[*] --> فحص
فحص --> مقبول
فحص --> مرفوض
state فحص <<choice>>stateDiagram-v2
state فحص <<choice>>
[*] --> فحص
فحص --> مقبول
فحص --> مرفوضملاحظات على الرسم
مقيس على Mermaid 11.12.2، وهي النسخة التي يستعملها هذا الموقع.
هنا تفشل المسافة داخل المعرّف فشلًا صامتًا
المقارنة بين الأنواع تستحق المعرفة، لأن الغفلة نفسها تُعاقَب بصور شديدة الاختلاف. ففي مخطط التدفق تعطي المسافة داخل معرّف العقدة خطأ تحليل فتعلم بها فورًا. وفي مخطط الحالات لا تعطي شيئًا: يُرسم المخطط وتتحول الحالة إلى مربع لكل كلمة. قِيس: `في انتظار الدفع` يخرج بعرض 247 بكسل بأربعة مربعات بدل اثنين. وهذا هو الفرق بين خطأ ينبّهك وخطأ يسكت. ولأن أسماء الحالات العربية لا تكاد تسع كلمة واحدة، فالدفاع الوحيد الحقيقي هو كتابة `state "…" as معرّف` بحكم العادة.
الارتفاع يزيد نحو 114 بكسل لكل حالة
قِيس: ثلاث حالات تعطي إطارًا يقارب 91×348، وأربعون حالة تعطي 100×4566 — أي نحو 114 بكسل لكل حالة. وكما في مخططات التدفق يكاد العرض لا يتحرك: آلات الحالات تنمو إلى أسفل. فإن كانت دورة الحياة طويلة قليلة التفرع، فوضع `direction LR` في المخطط هو الحل المعتاد.
كلٌّ من stateDiagram وstateDiagram-v2 يُرسم — وهذا هو المزلق
كثيرًا ما يُقرأ أنه «بدون `stateDiagram-v2` لا يُرسم شيء». وهذا غير صحيح في 11.12.2: فكلتا الكلمتين المفتاحيتين تُرسمان بلا خطأ. والذي يختلف هو جودة التخطيط، خصوصًا مع الحالات المركّبة والمتوازية، ولا يظهر أي تحذير عند استعمال القديمة. فإن بدت حالة مركّبة مزدحمة أو دارت الأسهم في مسارات غريبة، فانظر بأي كلمة مفتاحية فتحت المخطط قبل أن تشرع في إعادة كتابته.
التسميات HTML، فتصدير PNG يعيد الرسم
كما في مخططات التدفق والأصناف والكيانات، تُرسم تسميات الحالات كذلك داخل `<foreignObject>` في ملف SVG. ولأن المتصفحات ترفض تحويل ذلك إلى صورة نقطية على لوحة canvas، يعيد تصدير PNG في هذا الموقع رسمَ المخطط أولًا بتسميات نصية SVG صِرفة. فيخرج الـ PNG صحيحًا وبحجمه الكامل؛ ويختلف التنضيد اختلافًا يسيرًا جدًا عما على الشاشة.
السمة تغيّر الألوان ولا تغيّر الهندسة أبدًا
تنتج السمة الفاتحة والسمة الداكنة الإطار نفسه للمصدر نفسه، فلا يُعاد تخطيط آلة الحالات عند تبديل السمة.
متى يكون مخطط آخر أنسب
إن كانت تسمياتك أفعالًا — تحقق، أرسل، أعد المحاولة — فأنت تصف عملية لا دورة حياة، والخيار الصادق هو مخطط التدفق. وأوضح إشارة إلى ذلك أن تعجز عن الإجابة عن سؤال «ما الشيء الذي يقع في هذه الحالة؟».
وإن كان لعدة مكوّنات دورةُ حياة خاصة بكل منها وكان المثير للاهتمام هو تفاعلها، فمخطط حالات لكل مكوّن مع مخطط تسلسل للتفاعل يتفوق على آلة واحدة عملاقة.
وإن كانت كل حالة متصلة بكل حالة أخرى، فسيغدو المخطط متشابكًا مهما رسمته. وهذا يعني عادةً أن ما عددته حالاتٍ هو في الحقيقة رايات تتركب بحرية؛ وعندئذ يقول جدولٌ بالتركيبات الصحيحة أكثر بكثير مما تقوله صورة.
أنواع المخططات الأخرى
بقلم Dominik Malsch · آخر تحديث: