ویژگی transform در SVG

عناصر SVG نیز مثل عناصر HTML می توانند توسط توابع rotate، translate، scale و غیره دچار تغییر شکل، مکان و دگرگونی های مختلف شوند.

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

ویژگی transform

با استفاده از لیستی از توابعی که برای این ویژگی تعیین می شود می توان عناصر SVG را دچار دگرگونی کرد. ویژگی transform و توابع مربوط به آن در SVG مشابه ویژگی transform در CSS است فقط با این تفاوت که برخی توابع مربوط به SVG پارامترهای متفاوتی می پذیرند.

در ادامه توابع مختلف را بررسی می کنیم:

translate()

برای انتقال عناصر SVG از تابع translate استفاده می شود.


translate(<tx> [<ty>])

این تابع دو پارامتر می گیرد که پارامتر اول مربوط به اندازه انتقال در جهت محور X و پارامتر دوم مربوط به جهت Y می باشد.

مقدار دوم اختیاری است و اگر آن را تعیین نکنیم صفر در نظر گرفته می شود.

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

در مثال زیر دایره رسم شده به 100 واحد به سمت راست و 300 واحد به سمت پایین منتقل خواهد شد:


<circle cx="0" cy="0" r="100" transform="translate(100 300)" />

همانطور که گفته شد می توانستیم برای جداکردن دو مقدار از ویرگول نیز استفاده کنیم.

scale()

با استفاده از تابع scale می توان عناصر SVG را بزرگ یا کوچک کرد.


scale(<sx> [<sy>])

این تابع دو پارامتر می گیرد که پارامتر اول عنصر را در راستای محور X کوچک بزرگ می کند و پارامتر دوم این تغییر اندازه را در راستای محور Y انجام می دهد.

پارامتر دوم (sy) اختیاری است و اگر مقداری برای آن تنظیم نشود برابر با مقدار پارامتر اول یا همان sx خواهد بود.

این دو پارامتر نیز می توانند با یک تک فاصله یا یک ویرگول از هم جدا شوند و همچنین بدون واحد نوشته می شوند.

در مثال زیر مستطیل دو برابر اندازه اولیه اش می شود:


<rect width="150" height="100" transform="scale(2)" x="0" y="0" />

در مثال بعدی مستطیل در راستای محور X دو برابر و در راستای محور Y نصف ارتفاعش می شود:


<rect width="150" height="100" transform="scale(2 , 0.5)" x="0" y="0" />

skew()

با استفاده از این تابع نیز می توان عناصر را در SVG بصورت کج یا مورب در آورد. می توانید اینطور تصور کنید که دو راس رو به روی یک مستطیل را گرفته و در جهت مخالف هم بکشیم که در نتیجه مستطیل تبدیل به یک متوازى الاضلاع می شود:

ما می توانیم برای این کار از یک یا هر دو تابع زیر استفاده کنیم:


skewX(<skew-angle>)
skewY(<skew-angle>)

skewX عنصر را در رستای محور X و skewY در راستای محور Y کج می کنند.

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

rotate()

با استفاده از این تابع می توانیم عنصر SVG را بچرخانیم. سینتکس این تابع بصورت زیر است:


rotate(<rotate-angle> [<cx> <cy>])

در اینجا برخلاف تابع rotate در CSS این امکان وجود ندارد که با واحدهایی غیر از درجه این چرخش را انجام دهیم. و البته مقادیر این تابع باید بدون واحد نوشته شوند که در نتیجه بصورت درجه محاسبه می شوند.

پارامترهای دوم و سوم cx و cy اختیاری هستند و کارشان مشخص کردن نقطه مرکز چرخش است. (شبیه به transform-origin خودمون)

این دو پارامتر نیز بدون واحد هستند و اگر تعیین نشوند، مرکز چرخش نقطه مبدا سیستم مختصات کاربری خواهد بود که همان گوشه سمت چپ و بالای viewBox است.

در مثال زیر عنصر 45 درجه نسبت نقطه مرکزی (50,50) روی سیستم مختصات می چرخد:


<g id="parrot" transform="rotate(45 50 50)" x="0" y="0">
  <!-- اشکال مختلف -->
</g>

متاسفانه این امکان برای این تابع وجود ندارد تا شبیه به CSS با اعدادی مثل 50% وسط عنصر را مرکز چرخش قرار داد و مجبوریم از مقادیر ثابت استفاده کنیم.

matrix()

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


matrix(<a> <b> <c> <d> <e> <f>)

سینتکس بالا برابر با ماتریس matrix [a b c d e f] می باشد.

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


<g transform="matrix(1,2,3,4,5,6)">
  <!--
       x1 = 10 | x2 = 30
       y1 = 20 | y2 = 40
    -->
  <line x1="10" y1="20" x2="30" y2="40" />
</g>

<!-- ضرب ماتریس در چهار پارامتر خط
     x1 = 1 * 10 + 3 * 20 + 5 = 75  | x2 = 1 * 30 + 3 * 40 + 5 = 155
     y1 = 2 * 10 + 4 * 20 + 6 = 106 | y2 = 2 * 30 + 4 * 40 + 6 = 226
  -->
<line x1="75" y1="106" x2="155" y2="226"/>

از این تابع معمولا کمتر استفاده می شود اما برای اطلاعات بیشتر در مورد آن می توانید به این آدرس مراجعه کنید.

دگرگونی سیستم مختصات

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

نکته ای که باید توجه داشته باشیم این است که ویژگی transform هم مانند ویژگی viewBox باعث می شود تا سیستم مختصات جدیدی برای عنصر ایجاد شود.

این موضوع مشابه انجام transformها بر روی عناصر HTML در CSS است. آنجا هم زمانی که عنصر دچار دگرگونی می شود سیستم مختصاتی مخصوص به خودش دارد که البته این اتفاق زمانی ملموس تر است که از چند تابع بصورت زنجیره ای و پشت سر هم استفاده می کنیم.

با وجود این تشابه بین HTML و SVG تفاوت هایی نیز وجود دارد.

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

اینطور تصور کنید که یک کپی از سیستم مختصات موجود (viewBox) میگیرد و یک لایه جدید بوجود می آید.

حال با توجه به تابعی که برای transform نوشته شده است سیستم مختصات عنصر دچار دگرگونی می شود و همراه خود عنصر را نیز به همان وضعیت یا شکل در می آورد.

برای درک بهتر مثال هایی را با هم مرور می کنیم. تصویر زیر طرحی است که قرار است از آن در مثال های استفاده کنیم:

 
نمایش مثال در حالت اولیه
 

پرنده و سگ هر کدام در یک تگ <g> قرار دارند و قرار است transform را روی آنها اعمال کنیم:


<svg width="800" height="800" viewBox="0 0 800 600">
  <g id="dog">
    <!-- سگ باوفا -->
  </g>
  <g id="parrot">
    <!-- پرنده خالی -->
  </g>
</svg>

برای ساده بودن مثال ها اندازه viewBox را برابر با viewport قرار می دهیم تا فعلا درگیر مسائل حاشیه ای دیگر نشویم.

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


<svg width="800" height="800" viewBox="0 0 800 600">
  <g id="parrot" transform="translate(150 200)">
    <!-- پرنده -->
  </g>
</svg>

 

نتیجه انتقال پرنده
نتیجه انتقال پرنده به سمت راست و پایین توسط تابع translate

 

همانطور که قبلا اشاره شد دگرگونی یک عنصر باعث می شود تا سیستم مختصات جدیدی برای آن شکل بگیرد که تصویر زیر این موضوع را برای پرنده قشنگ ما نمایش می دهد:

 
تشکیل سیستم مختصات جدید برای عنصر منتقل شده
 

اکنون از تابع scale برای دو برابر کردن پرنده استفاده می کنیم:


<svg width="800" height="800" viewBox="0 0 800 600">
  <g id="parrot" transform="scale(2)">
    <!-- پرنده -->
  </g>
</svg>

 
دو برابر کردن عنصر با استفاده از تابع scale
 

از تصویر بالا و مکان پرنده در میابیم که نه تنها پرنده دو برابر شد بلکه سیستم مختصات آن نیز دو برابر شد که تصویر زیر این موضوع را نمایش می دهد:

 
دو برابر شدن سیستم مختصات عنصر
 

توجه کنید که مکان پرنده در سیستم مختصاتش تغییر نکرده و همچنان به عنوان مثال در 100 واحدی محور X قرار دارد. که این نکته بار دیگر این موضوع را نشان می دهد که این سیستم مختصات عنصر است که دچار دگرگونی می شود و سپس عنصر مورد نظر در سیستم مختصات جدید با همان مکان قبلیش رسم می شود.

در ادامه تابع skewX با زاویه 25 درجه را به سسسگ اضافه می کنیم :)


<svg width="800" height="800" viewBox="0 0 800 600">
  <!-- ... -->
  <g id="dog" transform="skewX(25)">
    <!-- سسگ -->
  </g>
</svg>

نتیجه بصورت زیر خواهد بود:

 
skewX svg
 

اگر بجای این تابع از تابع skewY استفاده کنیم خواهیم داشت:

 
SVG skewY
 

در آخر به سراغ تابع rotate می رویم و پرنده را با زوایه 45 درجه می چرخانیم:


<svg width="800" height="800" viewBox="0 0 800 600">
  <g id="parrot" transform="rotate(45)">
    <!-- پرنده -->
  </g>
</svg>

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

 
چرخش عنصر در svg
 

اگر بخواهیم پرنده را نسبت به مرکز خودش بچرخانیم با توجه به مکان اولیه پرنده روی سیستم مختصات و ابعاد آن می توان بصورت حدودی مرکز آن را (150, 170) دانست.


<svg width="800" height="800" viewBox="0 0 800 600">
  <g id="parrot" transform="rotate(45 150 170)">
    <!-- پرنده -->
  </g>
</svg>

 
svg rotate
 

قبل از اینکه به بحث بعد بپردازیم توجه داشته باشید که تمام دگرگونی ها برای عناصر سیستم مختصات خود را بوجود می آورند پس مثلا اگر هر دو عنصر را تغییر دهیم خواهیم داشت:

 
سیستم های مختصات مستقل از هم
 

نکته دیگر اینکه یادمان نرود تمام این سیستم های مختصات و دگرگونی ها درون سیستم مختصات اصلی یا همان viewBox انجام می شود پس هر تغییری بر روی viewBox تاثیرش را بر روی تمام عناصر داخل آن خواهد گذاشت.

دگرگونی زنجیره ای

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

در این مواقع نکته مهم این است که مانند دگرگونی عناصر HTML هر دگرگونی روی سیستم مختصاتی انجام می شود که توسط تابع قبلی تغییر یافته است. پس هر کدام بصورت جدا سیستم مختصات مخصوص به خود را ندارند.

مثلا اگر می خواهیم عنصری هم بچرخد و هم جابجا شود باید بدانیم که انتقال با توجه به سیستم مختصات چرخیده شده توسط تابع rotate انجام خواهد شد و نه یک سیستم مختصات اولیه.

در مثال زیر دقیقا همین اتفاق می افتد اول عنصر 45 درجه نسبت به مرکز خودش می چرخد و سپس 200 واحد در جهت مثبت محور X انتقال پیدا می کند: transform="rotate(45 150 170) translate(200)"

 
دگرگونی های زنجیره ای در svg
 

پس وقتی بصورت زنجیره ای نیاز به تغییرات دارید خیلی مراقب سیستم مختصات باشید.

با این تفاسیر اگر تابع اولی که استفاده می شود skew باشد دگرگونی های بعدی دیگر با سیستم مختصای با زاویه قائمه سروکار ندارند بلکه تغییرات با زاویه جدیدی که همان زاویه skew خواهد بود انجام می شوند.

دگرگونی تو در تو

زمانی که عنصری را دچار دگرگونی می کنیم که پدرش نیز دگرگون شده است واقعه فجیع دگرگونی تو در تو رخ می دهد :)

احتمالا آخر این پست همگی با هم دگرگون میشیم :)

تاثیر این مورد کاملا شبیه به دگرگونی زنجیره ای است با این تفاوت که به جای اینکه همه دگرگونی ها روی یک عنصر اعمال شود برخی روی پدران عنصر و برخی روی خود عنصر اعمال می شود.

در مثال ما فرض کنید می خواستیم همزمان با انتقال سگ دم آن را نیز بچرخانیم:


<svg width="800" height="800" viewBox="0 0 800 600">
  <!-- ... -->
  <g id="dog" transform="translate(..)">
    <g id="head">
      <!-- .. -->
    </g>
    <g id="body" transform="rotate(.. .. ..)">
      <path id="tail" d="..." transform="rotate(..)">
            
      </path>
      <g id="legs">
        <!-- ... -->
      </g>
    </g>
  </g>
</svg>

دگرگونی عناصر SVG در CSS

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

به عنوان مثال برای چرخاندن پرنده نسبت به مرکز خودش باید بنویسیم:


.parrot {
  transform-origin: 50% 50%;
  transform: rotate(45deg);
}

همینطور CSS این امکان را به ما می دهد که عناصر SVG را بصورت سه بعدی نیز تغییر شکل و مکان بدهیم.

4 دیدگاه برای “ویژگی transform در SVG

  1. سلام
    من چند روزی هست که با این سایت اشنا(دوباره) شدم و بدترین چیز اینه که این سایت حداقل 1 ساله تو بوکمارکم هست ولی استفاده نکردم ازش
    از موقعی که با این سایت اشنا(دوباره) شدم کلا نامید شدم و فهمیدم هیچی از طراحی وب نمیدونم
    واقعا سایت عالی دارین اگه بتونید یه ویدیو آموزشی پروژه محور رو درست کنید خیلی خوب میشه و همچنین یه انجمن هم بزارید که بشه توش فعالیت کرد
    کلا به نظر من سایت اصلا معروف نیست و این خیلی بد چون همین سایت به راحتی 10 برابر میکنه علم طراحان وب رو و اموزش های خیلی خوبی داره ولی حیف که دوستان زیاد نمیشناسند
    البته من از زمانی که با این سایت اشنا شدمه و دارم اموزش هارو میخونم یه بقیه هم معرفی میکنم
    یه سوالی داشتم من اموزش رو میخونم ولی تو استفاده کردن هنوز ناتوانم وقتی میخوام بیام و نمونه های که تو کدپن هست رو اجرا کنم میبینم از یه تگ ها و چیزایی استفاده میکنند که من نمیدونم
    به نظر شما بهترین راه برای درک مطلب و استفاده عملی اموزشها چیه
    با تشکر از اموزش های خوبتون

    1. سلام خیلی ممنون از پیامتون

      اگر منظورتون مطالب مربوط به SVG هستش خب اول کار هست و این مطالب نیاز دارند که تکمیل بشن و هنوز به جایی نرسیدیم که بشه وارد مثال های کامل تر بشیم.

      راهش اینه که مطالب سایت های دیگه رو بخونید و تمرین کنید و همون کدهای توی کدپن رو ببینید و تحقیق و بررسی کنید و بعد هم خودتون کد بزنید.

      مطالب اینجا زمان نیاز داره تا تکمیل بشه.

      امیدوارم موفق باشید.

  2. آقای سیدی ببخشید اینجا مطرح کردم
    این آزمونی که تو کانالتون حرفشو زدید، بخش ثبت نام،
    اسم و ایمیل زدم ولی واسم ایمیل نیومده…
    مشکل از اکانت خودمه یا خدای نکرده از بخش ثبت نام؟

    1. ببخشید ایمیل شما اسپم شناخته شده بود اشتباهی و من هم ندیدم و این کامنت هم اسپم شده بود الان متوجهش شدم. فکر می کنم مشکل ثبت نامتون حل شده ولی باز هم اگر نشده بود خبرم کنید تا درست شه.

      ممنونم ازتون

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