تطوير مخططات شجرة ديناميكية باستخدام SVG و Vue.js

إن المادة ، التي نُنشر ترجمتها اليوم ، مكرسة لعملية تطوير نظام التصور للرسومات التخطيطية الشجرية الديناميكية. لرسم منحنيات بيزيير المكعبة ، يتم استخدام تقنية SVG (رسومات المتجهات القابلة للضبط ، رسومات المتجهات القابلة للتحجيم) هنا. يتم تنظيم العمل التفاعلي مع البيانات بواسطة Vue.js.

فيما يلي نسخة تجريبية من النظام يمكنك من خلالها التجربة.


مخطط الشجرة التفاعلية

أتاح لنا الجمع بين القدرات القوية لـ SVG وإطار عمل Vue.js إنشاء نظام لبناء المخططات القائمة على البيانات والتفاعلية والقابلة للتخصيص.

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

أولاً ، سنتحدث عن كيفية تشكيل منحنيات Bezier المكعبة ، ثم سنكتشف كيفية تمثيلها في نظام الإحداثيات للعنصر <svg> ، والحديث عن إنشاء أقنعة للصور.

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

SVG


are كيف يتم تشكيل منحنيات بيزييه مكعب؟


تسمى المنحنيات المستخدمة في هذا المشروع Cubic Bezier Curve. يوضح الشكل التالي العناصر الرئيسية لهذه المنحنيات.


العناصر الرئيسية لمنحنى بيزيير مكعب

يوصف المنحنى بأربعة أزواج من الإحداثيات. الزوج الأول (x0, y0) هو نقطة الانطلاق الأولى للمنحنى. آخر زوج من الإحداثيات (x3, y3) هو النقطة المرجعية النهائية.

بين هذه النقاط ، يمكنك رؤية نقاط التحكم المزعومة. هذه هي النقطة (x1, y1) والنقطة (x2, y2) .

يحدد موقع نقاط التحكم فيما يتعلق بنقاط التحكم شكل المنحنى. إذا تم تعيين المنحنى فقط بنقطتي البداية والنهاية ، الإحداثيات (x0, y0) و (x3, y3) ، (x3, y3) هذا المنحنى كقطعة مستقيمة تقع على المائل.

سنستخدم الآن إحداثيات النقاط الأربع الموضحة أعلاه لرسم المنحنى باستخدام عنصر SVG <path> . فيما يلي بناء الجملة المستخدم في العنصر <path> لإنشاء منحنيات Bezier مكعب:

 <path D="M x0,y0 C x1,y1 x2,y2 x3,y3" /> 

الحرف ، الذي يمكن رؤيته في الكود ، هو اختصار لـ Cubic Bezier Curve. يشير الحرف c ( c ) إلى استخدام القيم النسبية ، ويعني الحرف الكبير ( C ) استخدام القيم المطلقة. يمكنني استخدام القيم المطلقة لإنشاء الرسم البياني ، ويشار إلى ذلك بالحرف الكبير المستخدم في المثال.

a إنشاء مخطط متماثل


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

دعونا اسم هذا size المتغير. نظرًا لأن المخطط موجه أفقيًا - يمكن اعتبار متغير size على أنه المساحة الأفقية الكاملة المتاحة للمخطط.

عيّن هذا المتغير قيمة واقعية. سوف نستخدم هذه القيمة لحساب إحداثيات عناصر المخطط.

 size = 1000 

العثور على إحداثيات عناصر المخطط


قبل أن نتمكن من العثور على الإحداثيات اللازمة لإنشاء المخطط ، نحتاج إلى التعامل مع نظام الإحداثيات SVG.

o نظام التنسيق و viewBox


تعد سمة <svg> viewBox مهمة جدًا في مشروعنا. الحقيقة هي أنه يصف نظام إحداثيات المستخدم لصورة SVG. ببساطة ، يحدد viewBox موضع وحجم المساحة التي سيتم فيها إنشاء صورة SVG المرئية على الشاشة.

تتألف سمة viewBox من أربعة أرقام تحدد معلمات نظام الإحداثيات وما يلي بالترتيب التالي: min-x ، min-y ، width ، height . تحدد min-x و min-y أصل نظام إحداثيات المستخدم ، وتعيين معلمات العرض والارتفاع عرض الصورة المعروضة وارتفاعها. إليك ما قد تبدو viewBox سمة viewBox :

 <svg viewBox="min-x min-y width height">...</svg> 

سيتم استخدام متغير size الموضح أعلاه للتحكم في معلمات width height لنظام الإحداثيات هذا.

في وقت لاحق ، في القسم الخاص بـ Vue.js ، viewBox محسوبة لتحديد قيم width height . علاوة على ذلك ، في مشروعنا ، سيتم دائمًا تعيين الخصائص min-x و min-y على 0.

لاحظ أننا لا نستخدم سمات height width الخاصة بعنصر <svg> نفسه. سنقوم بتعيينهم على width: 100% height: 100% باستخدام CSS. سيتيح لنا ذلك إنشاء صورة SVG تتكيف بمرونة مع حجم الصفحة.

الآن بعد أن أصبح نظام إحداثيات المستخدم جاهزًا لرسم مخطط ، دعنا نتحدث عن استخدام متغير size لحساب إحداثيات عناصر المخطط.

▍ إحداثيات ثابتة وديناميكية



مفهوم الرسم البياني

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

يتم تقسيم ارتفاع المخطط إلى جزأين. هذه هي topHeight (20٪ من size ) و bottomHeight (80٪ المتبقية من size ). ينقسم العرض الإجمالي للمخطط إلى جزأين - يبلغ طول كل منهما 50٪ من size .

هذا يجعل استنتاج المعلمات الدائرة لا تتطلب توضيحات خاصة (هنا يتم استخدام مؤشرات topHeight و topHeight ). يتم ضبط المعلمة radius على نصف قيمة topHeight . بفضل هذا ، تتناسب الدائرة تمامًا مع المساحة المتاحة.

الآن دعونا نلقي نظرة على إحداثيات المنحنيات.

  • تحدد الإحداثيات (x0, y0) نقطة البداية المرجعية للمنحنى. تظل هذه الإحداثيات ثابتة طوال الوقت. الإحداثي x0 هو مركز المخطط (نصف size ) ، و y0 هو الإحداثي الذي ينتهي به أسفل الدائرة. لذلك ، في صيغة حساب هذا الإحداثي ، يتم استخدام نصف قطر الدائرة. نتيجة لذلك ، يمكن العثور على إحداثيات هذه النقطة من خلال الصيغة التالية : (50% size, 20% size + radius) .
  • الإحداثيات (x1, y1) هي أول نقطة تحكم للمنحنى. كما أنه لم يتغير بالنسبة لجميع المنحنيات. إذا لم ننسى أن المنحنيات يجب أن تكون متناظرة ، اتضح أن قيمتي x1 و y1 تساوي دائمًا نصف قيمة size . ومن هنا الصيغة لحسابهم: (50% size, 50% size) .
  • تمثل الإحداثيات (x2, y2) نقطة التحكم الثانية لمنحنى بيزير. هنا يشير x2 إلى الشكل الذي يجب أن يكون عليه المنحنى. يتم حساب هذا المؤشر بشكل حيوي لكل منحنى. والمؤشر y2 ، كما كان من قبل ، سيكون نصف size . ومن هنا الصيغة التالية لحساب هذه الإحداثيات: (x2, 50% size) .
  • الإحداثيات (x3, y3) هي نقطة النهاية المرجعية للمنحنى. يشير هذا الإحداثي إلى المكان الذي تريد الانتهاء من رسم الخط. هنا ، يتم حساب قيمة x3 ، مثل x2 ، ديناميكيًا. ويصل y3 إلى قيمة تساوي 80٪ من size . نتيجة لذلك ، نحصل على الصيغة التالية: (x3, 80% size) .

نعيد ، بشكل عام ، كتابة رمز العنصر <path> ، مع مراعاة الصيغ التي استخلصناها للتو. يتم عرض النسب المئوية المستخدمة أعلاه هنا بتقسيمها على 100.

 <path d="M size*0.5, (size*0.2) + radius          C size*0.5, size*0.5           x2,    size*0.5           x3,    size*0.8" > 

يرجى ملاحظة أنه من النظرة الأولى ، قد يبدو استخدام النسب المئوية في صيغنا اختياريًا ، بناءً على رأيي فقط. ومع ذلك ، لا يتم تطبيق هذه القيم على نزوة ، ولكن لأن استخدامها يساعد على تحقيق التناسق والنسب الصحيحة للمخطط. بعد أن تشعر بدورها في التخطيط ، يمكنك تجربة قيم النسبة المئوية الخاصة بك وفحص النتائج التي تم الحصول عليها من خلال تطبيقها.

الآن دعنا نتحدث عن كيف سنبحث عن الإحداثيين x2 و x3 . إنها تتيح لك إنشاء العديد من المنحنيات بشكل ديناميكي استنادًا إلى index العناصر في الصفيف المقابل.

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

يجب أن تعمل الصيغة التي نشتقها لاحقًا مع أي عدد من العناصر. ولكن هنا سنقوم بتجربة صفيف يحتوي على 5 عناصر: [0,1,2,3,4] . تصور مثل هذه المجموعة يعني أنه من الضروري رسم 5 منحنيات.

الإحداثيات الديناميكية (x2 و x3)


أولاً ، أقسم size على عدد العناصر ، أي حسب طول المصفوفة. دعوت هذه distance المتغيرة. ويمثل المسافة بين عنصرين.

 distance = size/arrayLength // distance = 1000/5 = 200 

ثم تجولت حول المصفوفة وضربت مؤشر كل عنصر من عناصرها ( index ) حسب distance . للبساطة ، أنا ببساطة أسمي x كل من المعلمة x2 والمعلمة x3 .

 //  x2  x3 x = index * distance 

إذا قمت بتطبيق القيم التي تم الحصول عليها عند إنشاء المخطط ، أي استخدام قيمة x المحسوبة أعلاه لكل من x2 و x3 ، x3 غريبة بعض الشيء.


المخطط غير متماثل

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

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

من أجل إحضار المخطط إلى النموذج الذي أحتاج إليه ، أضفت ببساطة إلى x نصف قيمة distance .

 x = index * distance + (distance * 0.5) 

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


مخطط متماثل

إضافة نصف قيمة distance إلى إحداثيات x2 و x3 جعلت صيغة الحساب لهذه الإحداثيات مناسبة لتصور الصفائف التي تحتوي على عدد زوجي وفرد من العناصر.

▍ اخفاء الصورة


نحتاج إلى عرض صورة معينة في الجزء العلوي من المخطط ، داخل الدائرة. لحل هذه المشكلة ، قمت بإنشاء قناع لقطة يحتوي على دائرة.

 <defs>  <mask id="svg-mask">     <circle :r="radius"             :cx="halfSize"             :cy="topHeight"             fill="white"/>  </mask> </defs> 

بعد ذلك ، باستخدام العلامة <image> للعنصر <image> <svg> <image> لعرض الصورة ، قمت بربط الصورة بعنصر <mask> تم إنشاؤه أعلاه باستخدام سمة mask للعنصر <image> .

 <image mask="url(#svg-mask)"      :x="(halfSize-radius)"      :y="(topHeight-radius)" ... > </image> 

نظرًا لأننا نحاول وضع صورة مربعة في "نافذة" مستديرة ، فقد قمت بضبط موضع العنصر بطرح المعلمة radius من المعلمات المقابلة. نتيجة لذلك ، تكون الصورة مرئية من خلال قناع تم إنشاؤه في شكل دائرة.

دعونا نجمع كل ما تحدثنا عنه في رسم واحد. هذا سوف يساعدنا على رؤية الصورة الشاملة للتقدم في العمل.


البيانات المستخدمة في حساب المعلمات المخطط

إنشاء صورة SVG ديناميكية باستخدام Vue.js


في هذه المرحلة ، اكتشفنا منحنيات بيزييه المكعبة وأجرينا الحسابات اللازمة لتشكيل الرسم البياني. نتيجة لذلك ، يمكننا الآن إنشاء مخططات SVG ثابتة. إذا قمنا بدمج إمكانات SVG و Vue.js ، فيمكننا إنشاء مخططات تعتمد على البيانات. سوف تصبح المخططات الثابتة ديناميكية.

في هذا القسم ، نراجع مخطط SVG ، ونعرضه كمجموعة من مكونات Vue. سنرفق أيضًا سمات SVG بالخصائص المحسوبة ونجعل المخطط يستجيب لتغييرات البيانات.

بالإضافة إلى ذلك ، في نهاية المشروع ، سنقوم بإنشاء مكون يمثل لوحة التكوين. سيتم استخدام هذا المكون لإدخال البيانات التي سيتم إرسالها إلى المخطط.

inding تجليد البيانات إلى معلمات viewBox


لنبدأ بتعديل نظام الإحداثيات. بدون القيام بذلك ، لن نتمكن من رسم صور SVG. viewbox خاصية viewbox المحسوبة بإرجاع ما نحتاج إليه باستخدام متغير size . سيكون هناك أربع قيم مفصولة بمسافات. كل هذا سيصبح قيمة السمة viewBox للعنصر <svg> .

 viewbox() {   return "0 0 " + this.size + " " + this.size; } 

في SVG ، تمت كتابة اسم السمة viewBox بالفعل باستخدام نمط الجمل.

 <svg viewBox="0 0 1000 1000"> </svg> 

لذلك ، من أجل ربط هذه السمة .camel بشكل صحيح ، كتبت اسم السمة في نمط الكباب .camel معدّل .camel بعدها. باستخدام هذا الأسلوب ، من الممكن "خداع" HTML وتنفيذ ربط السمة بشكل صحيح.

 <svg :view-box.camel="viewbox">   ... </svg> 

الآن عند تغيير size يتم إعادة تكوين المخطط بشكل مستقل. لا نحتاج إلى تغيير التنسيق يدويًا.

of حساب المعلمات منحنى


نظرًا لأن معظم القيم اللازمة لإنشاء المنحنيات يتم حسابها على أساس متغير واحد ( size ) ، اعتدت أن أجد كل الإحداثيات الثابتة حسب الخصائص المحسوبة. ما نسميه هنا "الإحداثيات الثابتة" يتم حسابه على أساس size ، وبعد ذلك لا يتغير ولا يعتمد على عدد المنحنيات التي سيشملها المخطط.

إذا قمت بتغيير size - سيتم إعادة حساب "الإحداثيات الثابتة". بعد ذلك ، لن يتغيروا حتى يتغير size التالي. بالنظر إلى ما سبق ، إليك خمس قيم نحتاج إلى رسم منحنيات بيزيير:

  • topHeight — size * 0.2
  • bottomHeight — size * 0.8
  • width — size
  • halfSize — size * 0.5
  • distance — size/arrayLength

الآن لدينا فقط اثنين من القيم المجهولة اليسار - x2 و x3 . معادلة حسابهم التي استخلصناها بالفعل:

 x = index * distance + (distance * 0.5) 

لإيجاد قيم محددة ، نحتاج إلى استبدال مؤشرات عناصر الصفيف في هذه الصيغة.

الآن دعنا نسأل أنفسنا إذا كانت الخاصية المحسوبة مناسبة لنا للعثور على x . أجب باختصار على هذا السؤال ، ثم - لا ، لن يفعل.

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

يرجى ملاحظة أن هناك استثناء فيما يتعلق بالمبدأ أعلاه. انها عن Vuex. إذا كنت تستخدم مجموعات Vuex التي ترجع الوظائف ، فيمكنك تمرير المعلمات إليها.

في هذه الحالة ، لا نستخدم Vuex. ولكن حتى في هذه الحالة ، لدينا عدة طرق لحل هذه المشكلة.

▍ الخيار رقم 1


يمكنك إعلان دالة index تمرير index إليها كوسيطة ، والتي تُرجع النتيجة التي نحتاجها. يبدو هذا النهج أكثر نظافة إذا كنا سنستخدم القيمة التي يتم إرجاعها بواسطة دالة مشابهة في عدة أماكن في القالب.

 <g v-for="(item, i) in itemArray">  <path :d="'M' + halfSize + ','     + (topHeight+r) +' '+            'C' + halfSize + ','     + halfSize +' '+                     calculateXPos(i) + ',' + halfSize +' '+                  calculateXPos(i) + ',' + bottomHeight"  /> </g> 

سيتم تنفيذ طريقة calculateXPos() العمليات الحسابية في كل مرة يتم استدعاء. تأخذ هذه الطريقة حجة فهرس العنصر - i .

 <script>  methods: {    calculateXPos (i)    {      return distance * i + (distance * 0.5)    }  } </script> 

هنا مثال على CodePen يستخدم هذا الحل.


شاشة لأول تطبيق البديل

▍ الخيار رقم 2


هذا الخيار أفضل من الأول. يمكننا استخراج علامة SVG الصغيرة اللازمة لبناء المنحنى في مكون فرعي صغير منفصل وتمرير index إليه باعتباره أحد الخصائص.

باستخدام هذا الأسلوب ، يمكنك حتى استخدام الخاصية المحسوبة للعثور على x2 و x3 .

 <g v-for="(item, i) in items">    <cubic-bezier :index="i"                   :half-size="halfSize"                   :top-height="topHeight"                   :bottom-height="bottomHeight"                   :r="radius"                   :d="distance"     >     </cubic-bezier> </g> 

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

 <clip-mask :title="title"           :half-size="halfSize"           :top-height="topHeight"                               :r="radius"> </clip-mask> 

لوحة التكوين



لوحة التكوين

ربما تكون قد شاهدت بالفعل لوحة التهيئة ، التي تم استدعاؤها بواسطة الزر الموجود في الركن الأيسر العلوي من شاشة المثال أعلاه. تسهل هذه اللوحة إضافة عناصر إلى المصفوفة وإزالتها منها. باتباع الأفكار التي تمت مناقشتها في قسم "الخيار رقم 2" ، قمتُ بإنشاء مكون فرعي للوحة التكوين. بفضل هذا ، فإن مكون المستوى الأعلى نظيف ويمكن قراءته جيدًا. نتيجة لذلك ، تبدو لدينا شجرة صغيرة لطيفة من مكونات Vue يشبه ما يلي.


شجرة مكون المشروع

هل تريد إلقاء نظرة على الكود الذي ينفذ هذا الإصدار من المشروع؟ إذا كان الأمر كذلك ، ألقِ نظرة هنا .


شاشة لمتغير التطبيق الثاني

مستودع المشروع


فيما يلي مستودع جيثب للمشروع (يتم تنفيذ "الخيار رقم 2" هنا). أعتقد أنه سيكون من المفيد لك أن تنظر إليه قبل الانتقال إلى القسم التالي.

الواجب المنزلي


حاول إنشاء نفس المخطط الذي وصفناه هنا ، لكن اجعله موجهًا رأسيًا. استفد من الأفكار الموضحة في هذه المقالة.

إذا كنت تعتقد أن هذه مهمة سهلة ، فبناء هذا الرسم التخطيطي يكفي تبديل إحداثي x و y ، فأنت على حق. بالنظر إلى أن المشروع الذي تم النظر فيه هنا لم يتم إنشاؤه على أنه عالمي ، بعد تغيير الإحداثيات التي تحتاج إليها ، ستحتاج أيضًا إلى تعديل الكود عن طريق إعادة تسمية بعض المتغيرات والأساليب.

بفضل Vue.js ، يمكن تجهيز مخططنا البسيط بميزات إضافية. على سبيل المثال ، ما يلي:

  • يمكنك إنشاء آلية تسمح لك بالتبديل بين أوضاع المخطط الأفقي والرأسي.
  • يمكن أن تحاول منحنيات تحريك. على سبيل المثال ، باستخدام GSAP.
  • يمكنك ضبط خصائص المنحنيات (قل - اللون وعرض الخط) من لوحة التكوين.
  • يمكنك استخدام مكتبة خارجية لتنظيم حفظ المخططات في أي تنسيق رسومي أو كملف PDF. يمكن السماح لهذه المواد بتنزيلها لأولئك الذين يعملون مع المخطط.

جرب هذا الواجب المنزلي. وإذا كان لديك أي مشاكل - أدناه سوف تحصل على رابط لحلها.

النتائج


يعد عنصر <path> أحد الميزات القوية لـ SVG. يتيح لك هذا العنصر إنشاء صور متنوعة بدقة عالية. اكتشفنا هنا كيفية هيكلة منحنيات بيزييه ، وكيفية وضعها موضع التنفيذ لإنشاء المخططات الخاصة بك.

, , JavaScript-. Vue.js . , , , , DOM. , — .

, , , , , Vue.js SVG. — , Vue.js. — .

, - , , , — .

أعزائي القراء! ?

Source: https://habr.com/ru/post/ar463329/


All Articles