التراجع والتاريخ
graph.history هو سجل ما تحمله اللوحة القماشية وتظهره — ما تم إحضاره، ما تم إخراجه وما تم إخفاؤه – وطريقة لاستعادة أي جزء منه.
إنه ليس سجلاً لكل طفرة يمكن للمكتبة إجراؤها. تنتمي بيانات العقدة إلى حسابك الواجهة الخلفية، لذلك لن تعرض المكتبة إرجاع حقل لم تقم بتأليفه. ما يمكن أن يتكلم لأن التركيب، وهو أيضًا ما يفكر فيه المحلل: وصلت اثنتا عشرة عقدة، وثلاث ذهب، خمسة مخفية.
المفردات المستخدمة باستمرار أدناه
- إدخال: حدث شيء واحد قابل للعكس، كصف واحد في القائمة
- النوع: أي أنواع الدخول الستة هو
- span: الكتلة المتجاورة من الإدخال الأحدث وصولاً إلى الإدخال الذي نقرت عليه
- استمر: إدخال كتبه المستهلك إلى الواجهة الخلفية
- مختوم: حذف مستمر - مُدرج، ولم يتم التراجع عنه مطلقًا
الأنواع الستة
مجموعة مغلقة. وكل ما تسجله المكتبة هو واحد من هذه الأشياء، ولا يسجل أي شيء آخر.
| نوع | ما هو عليه | كيف يتم عكس ذلك |
|---|---|---|
pivot | استيعاب واحد - راجع محاور وإثراء | يتم إسقاط ضمان الهروب، ويذهب أي شيء آخر يكفله |
delete | حذف العقد أو الحواف بمبادرة من المستخدم | العناصر تعود، المصدر وكل شيء |
visibility | إخفاء أو إظهار متين (queryEngine.excludeNode / includeNode) | الآخر |
create | عقدة أو حافة مرسومة باليد | يذهب العنصر، إلا إذا كان هناك شيء آخر يضمن ذلك |
removal | مكالمة graph.removeBySource(source) | ما بقي يعود، وما بقي يسترد ضمان المصدر |
group | مجموعة تم إنشاؤها أو إعادة تسميتها أو إزالتها يدويًا (راجع تبسيط) | تعود المجموعات المصنوعة يدوياً إلى ما كانت عليه؛ لا تتم إضافة أو إزالة أي عقدة |
لم يتم تسجيله عمدا:
- تعديلات الخاصية. حالة الواجهة الخلفية، كما هو مذكور أعلاه.
onBeforeNodeEditCommitهو المكان الذي أنت فيه تنفيذ بنفسك. - حالة التصفية والأسطورة. الإعدادات الخاصة بها واضحة بدلاً من الأفعال. الفلتر يتم تطبيق النموذج مباشرة عند كل ضغطة على المفتاح، لذا فإن كتابة
domainستدفع ستة إدخالات. - ملاحظات. نص مؤلف، أقرب إلى التحرير منه إلى تكوين الرسم البياني.
graph.hideNode(). يتم مسحه في المرة القادمة التي يتم فيها إعادة اشتقاق المرشحات، لذلك إدخال له من شأنه أن يعكس شيئًا قد عاد بالفعل إلى نفسه.excludeNodeهو إخفاء ذلك ينجو، والذي يتم تسجيله.- فتح مجموعة، وسحب العقدة، وتبديل قاعدة التبسيط. طريقة البحث، مثل المرشحات.
الطفرات البرمجية — graph.addNode()، graph.removeNode() — ليست إدخالات أيضًا. مجرد إيماءة، بالإضافة إلى graph.removeBySource()، وهي الطريقة التي يقدم بها التطبيق المحلل هو إجراء "إزالة ما جلبه هذا المصدر"، وgraph.simplify.groupNodes()، renameGroup() وungroup()، المكالمات خلف إيماءات المجموعة.
التراجع متجاور
إن استهداف الصف الثالث للأسفل يلغي تلك الثلاثة، مثل واحد dataBatchChanged وواحد إعادة العرض. لا توجد طريقة لعكس إدخال قديم بمفرده: مكدس يمكن أن يكون وسطه لم يعد المسحوب يصف كيف وصل الرسم البياني بهذه الطريقة.
بالنسبة إلى "لقد قام هذا المزود بإرجاع البريد غير الهام، قم بإسقاطه واحتفظ بالباقي"، استخدم graph.removeBySource(source). فهو يسقط شهادة مصدر واحد ويحذف فقط ما لا شيء آخر يضمن ذلك، لذلك تبقى العقدة التي تم العثور عليها في الجولة الثانية أيضًا على قيد الحياة، وتدعي إحداها أنها أخف. إنه أ عملية forward، يتم تسجيلها كإدخال جديد بدلاً من الترجيع.
يتم تسجيل هذا الإدخال عندما يضمن المصدر أي شيء، حتى عندما يبقى كل عنصر لأن مصدرا آخر يشهد له أيضا: الدعوى ساقطة على الوجهين، ويقول الصف لم يبق شيء من القماش. يؤدي التراجع عن ذلك إلى استعادة ضمان كل عنصر تمامًا كما كان، لذا لا يزال إدخال التشغيل الموجود أسفله كاملاً ويؤدي التراجع التالي إلى إعادة تشغيله.
الإعادة هي عملية خطية تمامًا وأي إجراء جديد يفرغها. المدى الذي تم التراجع عنه وبعد ذلك الذين تقطعت بهم السبل بسبب العمل اللاحق ذهب؛ استعادته يعني تشغيل المحور مرة أخرى.
من الشريط العلوي
كل زر من الزرين الموجودين في الرأس عبارة عن زر منقسم: يتحرك الرمز مرة واحدة، وهي علامة الإقحام يفتح التاريخ. Ctrl+Z و Ctrl+Shift+Z (⌘Z و ⌘⇧Z على macOS) يصلان إلى نفس الاثنين الخطوات بدون الرأس، وتصل إلى التراجع عن النص الخاص بالمتصفح أثناء وجود حقل نصي لديه التركيز. كلا الزرين موجودان في الوضع full وlight، حيث يوجد الرأس، و UI.history: { enabled: false } يأخذهم، القائمة المنسدلة والاختصارين بعيدًا عن a التراجع عن قيادة المستهلك من الكروم الخاص به - يستمر graph.history في التسجيل في كلتا الحالتين.
القائمة المنسدلة عبارة عن قائمة واحدة من أي زر، الأحدث في الأعلى، مع خط now من خلال it: تم التراجع عن الصفوف الموجودة فوقه، والصفوف الموجودة أدناه هي ما لا يزال من الممكن التراجع عنه. انقر فوق أ الصف والخط يمر عبره، وهي نفس الإيماءة في كلا الاتجاهين.
يحمل كل صف رمز نوعه وعلامته وعدد الخطوات التي تقطعها النقرة. هذا الرقم هو الذي يذكره التذييل، لذلك لا يمكن أن تختلف القائمة والتذييل. ال يوضح التذييل التأثير الصافي الدقيق قبل تنفيذ أي شيء. مفاتيح الأسهم تهدف، أدخل يسافر، ويغلق الهروب.
يجيب القماش أيضًا
تحريك الصف يتنبأ بالتغيير على اللوحة القماشية، ولا يغير أي شيء آخر: العناصر ستخرج النقرة من مكانها، والعقد التي ستخفيها معهم، و كل ما سيعيده هو محدد أين سيهبط — عقدة لا يظهرها الرسم البياني استمر في ذلك، مرسومًا كحلقة في الموضع الذي تركته. هذا الجزء الأخير هو معظم ما تحتوي عليه الإعادة ليقول، والسبب في أن التوقعات ليست تسليط الضوء: لا شيء يتراجع لجعل ملحوظ تبرز العناصر، لأن السؤال هو ما الذي سيتغير، وليس العناصر التي يذكرها الصف.
الخطوط العريضة ليست تخمينات. ملاحظات التراجع حيث كان كل عنصر يقف عند إزالته من اللوحة القماشية، والإعادة تعيدها إلى هناك - لذا فإن ما ترسمه التوقعات هو المكان الذي تصل إليه النقرة الأشياء. يقوم المحور بإعادة العرض من البيانات الأولية لمزوده، والتي لا تحمل أي إحداثيات وبدون ذلك ستعود الوجبة متناثرة في مكان جديد.
preview() تُرجع نفس الشيء مثل البيانات، ضمن forecast وgraph.showForecast(…) / graph.clearForecast() قم برسمها - واجهة المستخدم الخاصة بسجل المستهلك، أو أي شيء آخر يريد أن يسأل "ماذا لو"، ويحصل على لغة القماش مجانًا.
العمليات المكتوبة حتى النهاية الخلفية
يمكن للمستهلك فقط معرفة أن العملية قد تمت كتابتها إلى الواجهة الخلفية، لذلك فقط يمكن للمستهلك أن يقول ذلك. onBeforeNodeCreate و onBeforeEdgeCreate و onBeforeDelete لكل منهما قبول persisted على قرارهم:
callbacks: {
onBeforeNodeCreate: async (ctx) => {
const values = await ctx.promptData({ fields: [{ key: 'value', label: 'Value', type: 'text' }] })
if (!values) return false
const saved = await myBackend.create(values)
return { accept: true, id: saved.uuid, data: values, persisted: true }
},
}لا يُصدر التراجع أي كتابة تعويضية، لذا فإن ما يفعله بمثل هذا الإدخال يعتمد على الطريقة التي يتم بها ذلك ذهبت الكتابة.
الخلق المستمر لا يزال ينعكس. تفقد اللوحة القماشية شيئًا تحتفظ به الواجهة الخلفية، وهو يتم التراجع عن إعادة الجلب، لذلك يتم وضع علامة على الإدخال تم الحفظ بدلاً من إيقافه ويتم احتساب التذييل ذلك قبل النقر: Undoes 2 steps · 1 item saved upstream.
الحذف المستمر هو مختوم: تم إدراجه، لأنه جزء من كيفية ظهور اللوحة القماشية بهذه الطريقة، ولكن لم يتم عكسها أبدًا. ستؤدي استعادتها إلى إعادة العقدة التي لم تعد الواجهة الخلفية موجودة فيها، ولا شيء على القماش بعد ذلك سيقول ذلك. يمتد مدى يحتوي على واحد فوقه بدلاً من ذلك من أن يتوقف عنده، ويقول ذلك أولاً: Undoes 2 of 3 · 1 saved item kept.
const [newest] = graph.history.entries()
newest.persisted // the consumer wrote it through
newest.sealed // …and it was a deletion, so undo will not take it backينجح التخطي لأن كل إدخال يذكر العناصر المحددة التي لمسها، لذا لا يوجد أي منها تختلف الحالة للخروج عن النظام. وهذا أيضًا هو سبب إغلاق الأنواع الستة ومستهلكها لا يمكن تسجيل إدخال خاص به: قد يؤدي رد الاتصال التعسفي في المكدس إلى منتصف الطريق خلال فترة، ولن يكون للتاريخ وسيلة لمعرفة ذلك.
أخذ استيعاب مرة أخرى
يؤدي التراجع عن الاستيعاب ** إلى إعادة مراحل المرشحين**، بحيث تعود الصفوف إلى جزء المراجعة حيث أتوا منها، ويعاد فتح الجزء إذا كان الاستيعاب قد أغلقه، ولا تزال عمليات الرفض السابقة قائمة، ويتم استدعاء أي مزود. هذا الجزء الأخير هو بيت القصيد: البديل هو إعادة جلب اثنين ألف ارتباط من خلال واجهة برمجة تطبيقات ذات معدل محدود لإصلاح خطأ حدث قبل ثانيتين.
لقد عادوا دون ترتيب بدلاً من أن يظلوا محددين. التراجع هو من أجل المرور بشكل صحيح، وليس لإعادة الهبوط نفس الاثني عشر بنقرة واحدة.
التشغيل الذي تم بدون مراجعة، مثل النقر المحوري بنقرة واحدة من قائمة السياق أو الموفر الذي يحدد autoIngest، جاء من عدم وجود جزء، لذا فإن التراجع عنه يؤدي فقط إلى إزالة العقد الخاصة به.
يحدث هذا فقط عندما يكون الاستيعاب هو الإدخال الأحدث. إذا كان هناك أي شيء على الإطلاق حدث منذ ذلك الحين، يؤدي التراجع إلى إزالة العقد ولا يظهر أي جزء: جزء يعيد إحياء نفسه سيكون العمل اللاحق أسوأ من الإعادة.
ما يحمله
ثلاثون مدخلاً، أقدمهم طردوا. الإخلاء يستحق الفهم، لأنه ليس كذلك متماثل: يفقد القدرة على استعادة مسار قديم، وليس إزالة واحد. المصدر يعيش على العناصر نفسها، لذلك لا يزال graph.removeBySource(pivotId) يصل جولة نسيها التاريخ.
السجل هو جلسة فقط. لا ينجو من إعادة التحميل. استعادة حالة سابقة من الرسم البياني بأكمله هو ميزة مختلفة، وليس هذه الميزة.
قيادتها
graph.history.entries() // what can be undone, newest first — the order the menu renders
graph.history.redoable() // what has been undone and can be redone, newest first
graph.history.canUndo()
graph.history.canRedo()
graph.history.undo() // the newest entry
graph.history.undo(entryId) // the span from the newest through that entry
graph.history.redo(entryId) // and back again
graph.history.preview(entryId) // what that span would do, before doing it
graph.history.on(history => …) // every change to either direction; returns a disposer
graph.history.clear() // forget everything; the canvas is left as it isالإدخال المحوري id is هو runId، لذا فإن PivotRunOutcome يحمل المقبض بالفعل إلى صف خاص به:
const outcome = await graph.pivots.run('correlations', graph.getSelectedNodes())
// …later
graph.history.undo(outcome.runId)preview(entryId, direction?) يستحق الملاحظة. ولا يلخص الإدخالات - ذلك يعيد عرض الامتداد مقابل نسخة من حالة الرسم البياني، من خلال نفس الرمز عند النقر يرتكب ويختلف النتيجة:
const { entries, skipped, canvasOnly, nodes, edges, effect, forecast } = graph.history.preview(entryId)
// entries the span, newest first
// skipped the sealed ones inside it, which will be left alone
// canvasOnly the ones it reverses that the backend keeps a copy of
// nodes the elements it would touch that are on the canvas now
// effect { nodesRemoved, nodesRestored, edgesRemoved, edgesRestored, nodesHidden, nodesShown }
// forecast the same change as something to paint: { removing, hiding, touching, arriving }
graph.showForecast(forecast) // …and take it back down with graph.clearForecast()نظرًا لأنه تم تشغيله بدلاً من وصفه، فإن الحالات المحرجة تظهر بدون سبب: أ تم إلغاء إخفاء إخفاء الشباك لاحقًا إلى الصفر ويقول ذلك، وعقدة محورية ثانية أيضًا لا يعتبر الضمانات بمثابة مغادرة.
المصدر، ولماذا الحذف يتذكره
تحمل كل عقدة وحافة مجموعة المصادر التي تؤكدها: 'seed' للبيانات التي كانت محملة، معرف محوري لكل ما جاء به، و'manual' لأي شيء مرسوم باليد. أ بدلاً من العددية، لأن تداخل محورين على عقدة واحدة هو الحالة العادية.
وبالتالي، يجب أن يتذكر الحذف سند كل عنصر، وليس بياناته فقط. بدون أن: تشغيلًا يضيف اثني عشر، ويحذف المحلل ثلاثة، ويبطل الحذف، ويأتي الثلاثة العودة كأيتام مجهولي المصير؛ التراجع عن التشغيل بعد ذلك ثم يتركهم على القماش مع عدم وجود ما يفسر لهم. ومعه يتم التراجع عن الحذف ومن ثم يترك التشغيل تمامًا ماذا كان هناك من قبل.
إحدى النتائج التي تستحق معرفتها عند الترقية: تقارير العقدة التي تم إنشاؤها يدويًا ['manual'] من getSources() وليس ['seed']. وهذا ما يجعل graph.removeBySource('manual') الوصول إلى العمل المرسوم باليد، وما يسمح للتراجع عن الإنشاء بإزالة العنصر فقط عندما لا يكون هناك شيء آخر لا يزال يضمن ذلك.