كيفية الترجمة من DOM إلى إحداثيات SVG والعودة مرة أخرى

يعد استخدام SVGs أمرًا مباشرًا نسبيًا – حتى تريد مزج تفاعلات DOM والمتجه.

تحتوي SVGs على نظام إحداثيات خاص بها محدد في ملف viewBox ينسب. فمثلا:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 600">

هذا يحدد عرض 800 وحدة وارتفاع 600 وحدة بدءًا من 0,0. هؤلاء الوحدات هي قياسات عشوائية لأغراض الرسم ، ومن الممكن استخدام كسور الوحدة. إذا قمت بوضع هذا SVG في ملف 800 بواسطة 600 منطقة البكسل ، كل وحدة SVG ينبغي تعيين مباشرة إلى بكسل الشاشة.

ومع ذلك ، يمكن تغيير حجم الصور المتجهة إلى أي حجم – خاصة في التصميم سريع الاستجابة. يمكن تصغير SVG إلى 400 بواسطة 300 أو حتى امتدت إلى ما بعد الاعتراف في 10 بواسطة 1000 الفراغ. تصبح إضافة المزيد من العناصر إلى SVG أكثر صعوبة إذا كنت تريد وضعها وفقًا لموقع المؤشر.

ملحوظة: راجعوا سارة سويدان viewport ، viewBox ، و keepAspectRatio مقالة لمزيد من المعلومات حول إحداثيات SVG.

تجنب تنسيق الترجمة

قد تكون قادرًا على تجنب الترجمة بين أنظمة الإحداثيات تمامًا.

تصبح SVGs المضمنة في صفحة HTML (بدلاً من صورة أو خلفية CSS) جزءًا من DOM ويمكن معالجتها بطريقة مشابهة للعناصر الأخرى. على سبيل المثال ، خذ SVG أساسيًا بدائرة واحدة:

<svg id="mysvg" xmlns="https://www.w3.org/2000/svg" viewBox="0 0 800 600" preserveAspectRatio="xMidYMid meet">
  <circle id="mycircle" cx="400" cy="300" r="50" />
<svg>

يمكنك تطبيق تأثيرات CSS على هذا:

circle {
  stroke-width: 5;
  stroke: #f00;
  fill: #ff0;
}

circle:hover {
  stroke: #090;
  fill: #fff;
}

يمكنك أيضًا إرفاق معالجات الأحداث لتعديل السمات:

const mycircle = document.getElementById('mycircle');

mycircle.addEventListener('click', (e) => {
  console.log('circle clicked - enlarging');
  mycircle.setAttribute('r', 60);
});

يضيف المثال التالي ثلاثين دائرة عشوائية إلى صورة SVG ، ويطبق تأثير التمرير في CSS ، ويستخدم JavaScript لزيادة نصف القطر بمقدار عشر وحدات عند النقر فوق دائرة.

انظر القلم
تفاعل SVG
بواسطة SitePoint (تضمين التغريدة)
على كود.

SVG إلى DOM تنسيق الترجمة

قد يصبح من الضروري تراكب عنصر DOM أعلى عنصر SVG – على سبيل المثال ، قائمة أو مربع معلومات في البلد النشط المعروض على خريطة العالم. بافتراض أن SVG مضمن في HTML ، تصبح العناصر جزءًا من DOM ، لذا فإن ملف getBoundingClientRect () يمكن استخدام طريقة لاستخراج الموقف والأبعاد. (افتح وحدة التحكم في المثال أعلاه للكشف عن السمات الجديدة للدائرة التي تم النقر عليها بعد زيادة نصف القطر.)

Element.getBoundingClientRect() مدعوم في جميع المتصفحات ويعيد ملف DOMrect كائن مع الخصائص التالية بأبعاد البكسل:

  • .x و .left: إحداثيات س ، بالنسبة إلى أصل منفذ العرض ، للجانب الأيسر من العنصر
  • .right: إحداثيات س ، بالنسبة إلى أصل منفذ العرض ، للجانب الأيمن من العنصر
  • .y و .top: تنسيق y ، بالنسبة إلى أصل منفذ العرض ، للجانب العلوي من العنصر
  • .bottom: تنسيق y ، بالنسبة إلى أصل منفذ العرض ، للجانب السفلي من العنصر
  • .width: عرض العنصر (غير مدعوم في IE8 وأدناه ولكنه مطابق لـ .right ناقص .left)
  • .height: ارتفاع العنصر (غير مدعوم في IE8 وأدناه ولكنه مطابق لـ .bottom ناقص .top)

جميع الإحداثيات مرتبطة بإطار عرض المتصفح ، وبالتالي ستتغير مع تمرير الصفحة. يمكن حساب الموقع المطلق على الصفحة عن طريق الإضافة window.scrollX إلى .left و window.scrollY إلى .top.

DOM إلى SVG تنسيق الترجمة

هذا أكثر صعوبة. افترض أنك تريد وضع عنصر SVG جديد عليه viewBox في الموضع الذي يحدث فيه حدث النقر. يوفر كائن معالج الحدث DOM .clientX و .clientY إحداثيات البكسل ، ولكن يجب ترجمتها إلى وحدات SVG.

من المغري التفكير في أنه يمكنك حساب إحداثيات نقطة SVG من خلال تطبيق عوامل الضرب. على سبيل المثال ، إذا تم وضع SVG بعرض 1000 وحدة في حاوية عرض 500 بكسل ، فيمكنك مضاعفة أي عنصر من عناصر DOM x قم بالتنسيق بمقدار اثنين للحصول على موقع SVG. لن يعمل! …

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

لحسن الحظ ، توفر SVGs آليات تحليل المصفوفة الخاصة بها لترجمة الإحداثيات. تتمثل الخطوة الأولى في إنشاء نقطة على SVG باستخدام امتداد createSVGPoint() طريقة وتمرير في الشاشة / الحدث x و y إحداثيات:

const
  svg = document.getElementById('mysvg'),
  pt = svg.createSVGPoint();

pt.x = 100;
pt.y = 200;

يمكنك بعد ذلك تطبيق تحويل مصفوفة تم إنشاؤه من معكوس SVG .getScreenCTM() الطريقة التي تحدد وحدات SVG لإحداثيات الشاشة:

const svgP = pt.matrixTransform( svg.getScreenCTM().inverse() );

svgP لديها الآن .x و .y الخصائص ، التي توفر الإحداثيات على SVG viewBox.

يضع الكود التالي دائرة عند نقطة تم النقر فوقها على قماش SVG:


const
  svg = document.getElementById('mysvg'),
  NS = svg.getAttribute('xmlns');


svg.addEventListener('click', (e) => {

  const pt = svg.createSVGPoint();

  
  pt.x = e.clientX;
  pt.y = e.clientY;

  
  const svgP = pt.matrixTransform( svg.getScreenCTM().inverse() );

  
  const circle = document.createElementNS(NS, 'circle');
  circle.setAttribute('cx', svgP.x);
  circle.setAttribute('cy', svgP.y);
  circle.setAttribute('r', 10);

  svg.appendChild(circle);

});

لاحظ ال createElementNS() الطرق مماثلة لـ DOM القياسي createElement() ، إلا أنه يحدد ملف مساحة اسم XML URI. بمعنى آخر ، إنه يعمل على مستند SVG بدلاً من HTML.

الترجمة إلى إحداثيات SVG المحولة

هناك تعقيد آخر. يمكن تحويل SVG أو العناصر الفردية عن طريق الترجمة و / أو القياس و / أو التدوير و / أو الانحراف ، مما يؤثر على إحداثيات SVG الناتجة. على سبيل المثال ، ما يلي <g> الطبقة أكبر بمقدار 4x من وحدات SVG القياسية ، لذا ستكون الإحداثيات ربع تلك الخاصة بـ SVG المحتوية:

<g id="transformed" transform="scale(4)">
  <rect x="50" y="50" width="100" height="100" />
</g>

المستطيل الناتج يبدو للحصول على 400 عرض الوحدة وارتفاعها في الموضع 200, 200.

لحسن الحظ ، فإن .getScreenCTM() يمكن تطبيق الطريقة على أي عنصر بالإضافة إلى SVG نفسه. تأخذ المصفوفة الناتجة في الاعتبار جميع التحويلات حتى تتمكن من إنشاء ملف svgPoint() وظيفة الترجمة:

const
  svg = document.getElementById('mysvg'),
  transformed = svg.getElementById('transformed');

console.log( svgPoint(svg, 10, 10) ); 
console.log( svgPoint(transformed, 10, 10) ); 


function svgPoint(element, x, y) {

  const pt = svg.createSVGPoint();
  pt.x = x;
  pt.y = y;

  return pt.matrixTransform( element.getScreenCTM().inverse() );

}

الشرح التالي يعمل في جميع المتصفحات الحديثة ، (وسيعمل في IE11 إذا قمت بتحويل JavaScript إلى ES5!). تتم إضافة دائرة عند نقطة المؤشر عند الضغط / النقر فوق SVG.

يحدث هذا أيضًا عند تحويل ملف <g> تم النقر فوق المنطقة ، ولكن يتم تمرير هذا العنصر بدلاً من SVG نفسه إلى ملف svgPoint() وظيفة لضمان حساب الإحداثيات الصحيحة:

انظر القلم
DOM لتنسيق الترجمة SVG
بقلم كريج باكلر (تضمين التغريدة)
على كود.

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

المصدر

أضف تعليق