سیستم مختصات SVG

عناصر SVG مثل عناصر HTML از یک سیستمی مثل Box Model در CSS تبعیت نمی کنند. که این موضوع مکان دهی و تغییر شکل این عناصر را کمی سخت تر می کند اما زمانی که با سیستم مختصات SVG به خوبی آشنا شویم کار با SVG آسان تر خواهد شد.

در این مطلب به سراغ سه تا از مهمترین ویژگی های SVG به نام های viewBox، viewport و preserveAspectRatio می رویم.

بوم نقاشی SVG

به محیطی که SVG روی آن رسم می شود بوم نقاشی SVG یا SVG Canvas گفته می شود. از لحاظ مفهومی این بوم اندازه بی نهایت دارد اما زمانی که یک مرورگر می خواهد یک طرح SVG را رسم کند این طرح محدود به یک ناحیه خاص و محدود به نام Viewport است و این باعث می شود قسمت هایی از SVG که خارج از این ناحیه قرار دارند بریده شده و نمایش داده نشوند.

Viewport

Viewport ناحیه ای است که در آن SVG قابل مشاهده خواهد بود. می توان Viewport را شبیه به پنجره ای به ذهن آورد که از طریق آن یک منظره قابل مشاهده است. حال سراسر این منظره می تواند از طریق این پنجره قابل دیدن باشد یا فقط قسمتی از آن.

Viewport در مورد SVG نیز مشابه به Viewport مرورگر است. یک صفحه وب می تواند بزرگتر از Viewport باشد و در بیشتر مواقع دراز تر از آن است. به همین دلیل است که در بیشتر مواقع صفحات وب در راستای عمودی اسکرول می شوند و در هر لحظه فقط قسمتی از یک صفحه وب از طریق پنجره ما یا همان Viewport قابل مشاهده است.

اندازه Viewport در SVG توسط ویژگی های width و height بر روی عنصر <svg> تعیین می شود. به عنوان نمونه در مثال زیر اندازه آن برابر با 800 پیکسل در 600 پیکسل خواهد بود:


<svg width="800" height="600">
  <!-- SVG content drawn onto the SVG canvas -->
</svg>

این مقادیر را می توان با واحد یا بدون واحد نوشت. زمانی که بدون واحد می نویسیم مرورگر آن ها را به px در نظر می گیرد.

واحدهای دیگر قابل استفاده می توانند em, ex, px, pt, pc, cm, mm, in و یا درصد باشند.

به محض اینکه اندازه Viewport مشخص می شود مرورگر یک سیستم مختصات اولیه viewport و یک سیستم مختصات اولیه کاربری مشخص می کند.

سیستم مختصات اولیه

سیستم مختصات اولیه viewport سیستم مختصاتی است که روی viewport قرار می گیرد با نقطه مبدا واقع در گوشه سمت چپ و بالای viewport، یعنی همان نقطه (0,0) با یک محور مثبت x به سمت راست و یک محور مثبت y به سمت پایین و هر پیکسل روی این محور برابر با یک پیکسل روی viewport می باشد.

این سیستم مختصات مشابه سیستم مختصات عناصر HTML است.

سیستم مختصات اولیه کاربری سیستم مختصاتی است که روی بوم نقاشی SVG قرار می گیرد. این سیستم مختصات هم در حالت اولیه کاملا مشابه سیستم مختصات اولیه viewport است و روی آن قرار می گیرد.

در ادامه خواهیم دید که می توان این سیستم مختصات را توسط ویژگی viewBox تغییر داد.

فعلا از ویژگی viewBox استفاده نمی کنیم تا این دو سیستم مختصات روی هم قرار گرفته و کاملا مشابه یکدیگر باشند.

در تصاویر و مثالهایی که در ادامه بررسی می کنیم سیستم مختصات اولیه viewport خاکستری و سیستم مختصات اولیه کاربری آبی خواهند بود.

 

سیستم مختصات اولیه
سیستم مختصات اولیه. در این تصویر سیستم های مختصات دقیقا روی هم قرار گرفته اند، چرا؟

 

viewBox

viewBox همان سیستم مختصات کاربری می باشد. از این سیستم مختصات برای رسم SVG برروی بوم نقاشی آن استفاده می شود، همچنین این سیستم مختصات می تواند کوچک تر یا بزرگ تر از سیستم مختصات Viewport باشد که در نتیجه می تواند قسمتی از آن یا سراسر آن از طریق Viewport قابل مشاهده باشد.

در تصویر بالا سیستم مختصات کاربری دقیقا برابر با سیستم مختصات viewport است چرا که ما سیستم مختصات کاربری یا همان viewBox را تعیین نکردیم و مرورگر بصورت خودکار آن را برابر با سیستم مختصات viewport قرار می دهد.

ویژگی viewBox چهار مقدار را به عنوان پارامتر می پذیرد:


viewBox = <min-x> <min-y> <width> <height>

مقادیر <min-x> و <min-y> گوشه سمت چپ بالای viewBox را تعیین می کنند و width و height عرض و ارتفاع آن را مشخص می کنند.

توجه داشته باشیم که این مقادیر عرض و ارتفاع می توانند متفاوت از مقادیر عرض و ارتفاع عنصر <svg> باشند.

مقادیر صفر برای عرض و ارتفاع باعث می شوند تا عنصر SVG رسم نشود. جدا!؟ :)

توجه داشته باشیم که می توان اندازه viewport را در CSS نیز تعیین کرد. مثلا می توان عرض آن را برابر با 100 درصد قرار داد تا بتوان عنصر SVG را به سمت واکنشگرایی سوق داد.

در مثال زیر viewBox دقیقا برابر با مختصات viewport است اما می توانیم آن را به اندازه ای دیگر تغییر دهیم:


<svg width="800" height="600" viewbox="0 0 800 600">
  <!-- SVG content drawn onto the SVG canvas -->
</svg>

بهترین راه درک و تشخیص تفاوت viewBox و viewport بررسی مثال هایی در قالب تصویر است. فعلا با مثالهایی شروع می کنیم که aspect ratio یا همان نسبت ابعادی viewBox و viewport با هم برابر باشند، چون اگر نباشند نیاز است تا ویژگی دیگری را به نام preserveAspectRatio بشناسیم.

نسبت ابعادی viewBox == نسبت ابعادی viewport

در مثال اول ابعاد viewBox را برابر با نصف ابعاد viewport و همینطور مبدا آن را برابر با همان (0,0) قرار می دهیم.

چون عرض و ارتفاع viewBox برابر با نصف عرض و ارتفاع viewport است بدین معنی است که نسبت ابعادی هر دو سیستم مختصات با هم برابر است و ما آن را حفظ کرده ایم.


<svg width="800" height="600" viewbox="0 0 400 300">
  <!-- SVG content drawn onto the SVG canvas -->
</svg>

بسیار خوب، حالا viewbox="0 0 400 300" دقیقا چکار می کند؟

  • یک ناحیه خاص را برای بوم نقاشی SVG مشخص می کند که این ناحیه از نقطه (0,0) تا نقطه (400,300) کشیده می شود.
  • سپس طرح SVG محدود به همان ناحیه برش می خورد.
  • این ناحیه Scale یا همان بزرگ می شود بطوری که کل فضای viewport را بگیرد. (شبیه به حالتی که چیزی را با زوم کردن بزرگ می کنیم)
  • سیستم مختصات کاربری با همان viewBox به سیستم مختصات viewport نگاشت می شود در این مثال این یعنی هر واحد viewbox برابر با دو واحد viewport می شود.

چرا دو واحد؟

آفرین… چون ابعاد viewBox نصف ابعاد viewport بود :)

تصویر زیر عملیات نگاشت این viewBox را به مثال ما بیان می کند. یادمان باشد که محورهای خاکستری مربوط به viewport و نسبت های آبی مربوط به viewBox هستند:

 

نگاشت viewBox به viewport
نسبت ابعادی دو مختصات با هم برابر هستند

 

از الان به بعد هر چیزی که روی بوم نقاشی SVG رسم شود بر اساس سیستم مختصات جدید خواهد بود.

اکنون مقادیر <min-x> و <min-y> را به 100 تغییر می دهیم و نسبت ابعادی را هم حفظ می کنیم:


<svg width="800" height="600" viewbox="100 100 200 150">
  <!-- SVG content drawn onto the SVG canvas -->
</svg>

تاثیر viewBox="100 100 200 150" بر روی مثال ما در تصویر زیر به نمایش گذاشته شده است:

 

ابعاد یک چهارم شده و مبدا نیز جابجا شده است
ابعاد یک چهارم شده و مبدا نیز جابجا شده است که در نتیجه طرح برش خورده است

 

با این نگاشت هر واحد viewBox برابر با چهار واحد viewport خواهد بود.

عملیات تغییر اندازه مبدا یک نوع عملیات transform است و کاملا شبیه به این است که بوم نقاشی SVG را 100 واحد به بالا و 100 واحد به چپ حرکت دهیم (transform="translate(-100 -100)")

تنها تفاوت این دو روش در این است که روش transform روی ویژگی های x، y، width و height تاثیر می گذارد اما روش تغییر مبدا از طریق viewBox روی این ویژگی های عنصر <svg> تاثیری نمی گذارد.

برگردیم به همان مثالی که viewBox ابعادی برابر با 300 و 400 واحد داشت. اکنون به جای اعداد مثبت از اعداد منفی برای تعیین مبدا viewBox استفاده می کنیم:


<svg width="800" height="600" viewbox="-100 -100 400 300">
  <!-- SVG content drawn onto the SVG canvas -->
</svg>

در مثال قبل دیدیم که اعداد مثبت طرح را به سمت بالا و چپ حرکت می دادند پس در اینجا بالعکس این اتفاق می افتد و طرح به سمت پایین و راست انتقال پیدا می کند:

 
تاثیر اعداد منفی بر مبدا viewbox
 

برای درک بهتر این موضوع همیشه viewBox را شبیه به یک قاب ببینیم و زمانی که که مقادیر آن تغییر می کند آن قاب را درون viewport جابجا کنیم و تصویر نهایی که در ذهن ما بوجود می آید جواب قصه ما خواهد بود.

در مثال بالا زمانی که مبدا viewBox ما 100 واحد منفی در هر دو جهت تغییر مکان داشت قاب 400 واحد در 300 واحد را بر روی viewport در نظر می گیریم که قرار است 100 واحد منفی به هر دو سمت جابجا شود:

 

 

آنچه که بعد از تغییرات از دریچه قاب ما قابل دیدن است نتیجه نهایی خواهد بود.

در مثال آخر این قسمت به جای اینکه ابعاد viewBox را کوچک تر از viewport در نظر بگیریم آنها را بزرگ تر می کنیم اما توجه داشته باشیم که فعلا نسبت ابعادی را حفظ کنیم:


<svg width="800" height="600" viewbox="0 0 1200 900">
  <!-- SVG content drawn onto the SVG canvas -->
</svg>

در این مثال viewBox را 1.5 برابر viewport در نظر می گیریم و نتیجه بصورت زیر خواهد بود:

 
viewbox-1200-900
 

حال هر واحد viewBox از نظر افقی (viewport-width / viewBox-width) برابر هر واحد viewport است. و هر واحد viewBox بر روی محور عمودی (viewport-height / viewBox-height) برابر هر واحد viewport است.

این یعنی در این نگاشت هر واحد viewBox ما 0.66 برابر هر واحد viewport می باشد.

 

تا الان تمام مثال های ما نسبت ابعادی را حفظ می کردند و تغییر نمی دادند اما چه اتفاقی خواهد افتاد اگر مثلا در مثال آخر عرض و ارتفاع viewBox را برابر با 1000 و 500 قرار دهیم؟

 
viewbox-1000-500
 

در اینجا:

  • کل viewBox درون viewport جا شده است.
  • نسبت ابعادی viewBox حفظ شده است و کشیده نشده تا فضای viewport را پر کند.
  • viewBox از نظر افقی و عمودی در وسط viewport قرار گرفته است.

این رفتار پیشفرض است. چه چیزی این رفتارها را کنترل می کند؟ و چگونه می توانیم این رفتارها را تغییر دهیم؟

ویژگی preserveAspectRatio

از ویژگی preserveAspectRatio برای این استفاده می شود که نسبت ابعادی طرح گرافیکی را مجبور کند تا حفظ شود و طرح از نسبت صحیحش خارج نشود.

اگر سیستم مختصات کاربری را با نسبت ابعادی متفاوت نسبت به سیستم مختصات viewport تعیین کنیم و اگر مرورگر بخواهد تا viewBox را بکشد تا اندازه اش متناسب با viewport شود این امر باعث می شود تا طرح گرافیکی ما تناسب صحیح خود را از دست بدهد. کشیدن viewBox در مثال قبل نتیجه زیر را خواهد داشت:

 

نتیجه نگاشت سیستم ها بدون حفظ نسبت ابعادی
نتیجه نگاشت سیستم ها بدون حفظ نسبت ابعادی

 

سینتکس رسمی این ویژگی بصورت زیر است:


preserveAspectRatio = defer? <align> <meetOrSlice>?

این ویژگی برای تمام ویژگی هایی که viewport جدید می سازند کاربرد دارد.

مقدار defer اختیاری است و فقط وقتی موثر خواهد بود که از ویژگی preserveAspectRatio بر روی عناصر تصویر استفاده شود. و روی عناصر دیگر تاثیری نخواهد داشت. پس در اینجا در مورد این مقدار بحثی نمی کنیم.

پارامتر align باعث می شود که تغییر اندازه viewBox با حفظ نسبت ابعادی باشد یا نه و اگر این نسبت حفظ شود این پارامتر تراز بندی و یا همان مکان viewBox در viewport را نیز مشخص می کند.

پس در مثال بالا وقتی که نسبت ابعادی viewBox برابر با نسبت ابعادی viewport نیست و می خواهیم با وجود این موضوع طرح گرافیکی نسبت صحیح خود را حفظ کند باید از این پارامتر با مقداری غیر از none استفاده کنیم.

مقدار none باعث می شود تا نسبت ابعادی حفظ نشود.

preserveAspectRatio = "none"

تمام مقادیر دیگر ویژگی preserveAspectRatio باعث می شوند تا نسبت ابعادی زمانی که viewBox درون viewport متناسب می شود، حفظ شود.

پارامتر آخر این ویژگی meetOrSlice است که البته اختیاری می باشد و مقدار پیشفرض آن برابر با meet است.

این پارامتر مشخص می کند که کل viewBox درون viewport قابل مشاهده باشد یا نه.

مقادیر meet و slice برای این ویژگی خیلی شبیه به مقادیر contain و cover برای ویژگی background-size هستند.

slice شبیه به cover و meet شبیه به contain می باشد.

meet

این مقدار پیشفرض است و طرح گرافیکی را تا زمانی که دو شرط زیر برقرار باشد بزرگ می کند:

  • نسبت ابعادی در طرح گرافیکی حفظ شود.
  • کل viewBox از طریق viewport قابل مشاهده باشد.

کلمه meet از اینجا می آید که باعث می شود کل طرح دیده شود.

slice

دقیقا مثل مقدار cover در ویژگی background-size عمل می کند و باعث می شود طوری طرح گرافیکی کشیده شود تا viewBox تمام سطح viewport را بپوشاند نه بیشتر.

که در این روش اگر نسبت ابعادی viewBox و viewport یکی نباشند قسمتی از viewBox از مرزهای viewport خارج شده و قابل مشاهده نخواهد بود.

کلمه slice از همان برشی که احتمالا طرح گرافیکی می خورد می آید.

پس پارامتر meetOrSlice برای ویژگی preserveAspectRatio مشخص می کند که viewBox بطور کامل داخل viewport باشد و حتما قابل مشاهده باشد یا اینکه کشیده شود تا سراسر viewport را بپوشاند هر چند که احتمال دارد قسمتی از آن بریده شده و قابل مشاهده نباشد.

در مثال ما اگر اندازه viewBox را برابر با 200×300 قرار داده و هر دو مقدار meet و slice را برای ویژگی preserveAspectRatio امتحان کنیم خواهیم داشت:

 
meet و slice در svg
 

align

پارامتر align در ویژگی preserveAspectRatio به غیر از none نه (9) مقدار دیگر می پذیرد که همه آنها نسبت ابعادی طرح گرافیکی را حفظ می کنند و همچنین مکان viewBox را نسبت به viewport مشخص می کنند.

align شبیه به ویژگی background-position با مقدار درصد عمل می کند. تنها فرقی که این دو دارند در این است که align در SVG ترازبندی را بر اساس یک محور خاص viewBox و محور متناظر آن در viewport انجام می دهد.

برای درک بهتر مقادیر این پارامتر بهتر است اول با محورها آشنا شویم.

مقادیر <min-x> و <min-y> را یادتان هست؟ قرار است از آنها برای تعریف محور min-x و محور min-y روی viewBox استفاده کنیم.

بعلاوه دو محور max-x و max-y را تعریف می کنیم که که به ترتیب مکان های <width> + <min-x> و <height> + <min-y> را دارند.

و در آخر دو محور mid-x و mid-y را داریم که در وسط این دو محور دیگر در هر راستا قرار دارند. البته می توان مکان دقیق آنها را بترتیب به این صورت حساب کرد:

<min-x> + (<width>/2)

<min-y> + (<height>/2)

در تصویر زیر محورها مشخص شده اند که محورهای min-x و min-y در مکان پیشفرض خود یعنی همان صفر قرار دارند و داریم: viewBox = "0 0 300 300"

 
محورهای مختلف Svg
 

در تصویر بالا خط چین های خاکستری محورهای viewport هستند.

none

همانطور که قبلا گفته شد این مقدار باعث می شود تا طرح گرافیکی در زمان تغییر اندازه مجبور به حفظ نسبت ابعادی نباشد. وقتی از none استفاده می کنیم پارامتر meetOrSlice نادیده گرفته می شود.

xMinYMin

طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.

محور min-x در viewBox با کمترین مقدار محور X در viewport تراز می شود.

محور min-y در viewBox با کمترین مقدار محور Y در viewport تراز می شود.

شبیه به background-position: 0% 0%; عمل می کند.

xMinYMid

طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.

محور min-x در viewBox با کمترین مقدار محور X در viewport تراز می شود.

نقطه وسط راستای Y در viewBox با نقطه وسط راستای Y در viewport تراز می شود.

شبیه به background-position: 0% 50%; عمل می کند.

xMinYMax

طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.

محور min-x در viewBox با کمترین مقدار محور X در viewport تراز می شود.

محور max-y در viewBox با بزرگترین مقدار راستای Y در viewport تراز می شود.

شبیه به background-position: 0% 100%; عمل می کند.

xMidYMin

طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.

نقطه وسط راستای X در viewBox با نقطه وسط راستای X در viewport تراز می شود.

محور min-y در viewBox با کمترین مقدار محور Y در viewport تراز می شود.

شبیه به background-position: 50% 0%; عمل می کند.

xMidYMid (مقدار پیشفرض)

طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.

نقطه وسط راستای X در viewBox با نقطه وسط راستای X در viewport تراز می شود.

نقطه وسط راستای Y در viewBox با نقطه وسط راستای Y در viewport تراز می شود.

شبیه به background-position: 50% 50%; عمل می کند.

xMidYMax

طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.

نقطه وسط راستای X در viewBox با نقطه وسط راستای X در viewport تراز می شود.

محور max-y در viewBox با بزرگترین مقدار راستای Y در viewport تراز می شود.

شبیه به background-position: 50% 100%; عمل می کند.

xMaxYMin

طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.

محور max-x در viewBox با بزرگترین مقدار راستای X در viewport تراز می شود.

محور min-y در viewBox با کمترین مقدار محور Y در viewport تراز می شود.

شبیه به background-position: 100% 0%; عمل می کند.

xMaxYMid

طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.

محور max-x در viewBox با بزرگترین مقدار راستای X در viewport تراز می شود.

نقطه وسط راستای Y در viewBox با نقطه وسط راستای Y در viewport تراز می شود.

شبیه به background-position: 100% 50%; عمل می کند.

xMaxYMax

طرح گرافیکی مجبور به حفظ نسبت ابعادی می شود.

محور max-x در viewBox با بزرگترین مقدار راستای X در viewport تراز می شود.

محور max-y در viewBox با بزرگترین مقدار راستای Y در viewport تراز می شود.

شبیه به background-position: 100% 100%; عمل می کند.

در مثال پرنده قشنگ ما وقتی داریم viewBox="0 0 200 300" بعضی مقادیر نتیجه یکسان خواهند داشت. در تصاویر زیر برای پارامتر meetOrSlice مقدار پیشفرض یا همان meet را در نظر می گیریم پس در نتیجه همیشه طرح ما قابل مشاهده خواهد بود:

 
align در Svg
 

حال اگر بجای meet از slice نتایج متفاوت خواهد بود. در تصاویر زیر مشاهده می کنید که چطور طرح کشیده می شود تا کل فضای viewport را بپوشاند. یعنی عرض 200 واحدی viewBox عرض 800 واحدی viewport را می پوشاند و چون قرار است نسبت ابعادی طرح حفظ شود قسمت هایی از آن قابل مشاهده نیست:

 
viewbox slice align svg
 

توجه داشته باشید که اگر مقادیر <min-x> و <min-y> تغییر کنند محورهای وسط و بیشینه نیز تغییر خواهند کرد.

به عنوان نمونه اگر در مثال قبلی viewBox را بصورت زیر تغییر دهیم:

viewBox = "100 0 200 300"

و مقادیر preserveAspectRatio را همان مقادیر پیشفرض یعنی xMidYMid meet قرار می دهیم:

 

 

تمرین کنیم

در لینک زیر دمویی وجود دارد که می توانید با تغییر تمام ویژگی ها و پارامترهایی که گفته شد به درک بهتر موضوع کمک کنیم.

 
 

منبع

یک دیدگاه برای “سیستم مختصات SVG

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *