مجاني · بدون تسجيل · يدعم ملفات ‎.mmd

محرر مخططات الحالات بـ 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 · آخر تحديث:

افتح المحرر ←