ساختاردهی در SVG

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

در این مطلب این عناصر را تعریف و تفاوت و برتری هر کدام را بیان می کنیم.

گروه بندی با عنصر <g>

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

در Adobe Illustrator هم معمولا عناصر مرتبط به هم را در یک گروه قرار می دهیم تا مثلا اگر می خواهیم همه را با هم جابجا کنیم یا تغییر اندازه بدهیم این کار برای ما ساده تر و سریع تر باشد.

عنصر <g> می تواند id یا class داشته باشد تا بتوان از آن تغییر در CSS استایل های مورد نیاز را به آن داد.

استایل هایی که به عنصر <g> داده می شود بر روی عناصر داخلی آن نیز اعمال می شود. منطقی هم هست: دقیقا شبیه به همان تغییر مکان یک گروه در Adobe Illustrator که وقتی گروه را جابجا کنیم کل عناصر جابجا می شوند. پس این مورد کمک می کند تا استایل دهی و حتی اعمال انیمیشن ها به عناصر SVG ساده تر باشد.

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

 
گروه بندی عناصر در svg
 

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

 
گروه بندی در illustrator
 

گروه بندی در SVG نیز به همین صورت است و از طریق عنصر <g> انجام می شود. در این مثال ما اشکال مربوط به بدن پرنده را در یک گروه و اشکال مربوط به سر پرنده را در گروه دیگر و در آخر هر دو گروه را درون یک گروه با id به نام bird قرار داده ایم:


<svg width="1144.12px" height="400px" viewBox="0 0 572.06 200">
  <style>
    svg{background-color:white;}
    #wing{fill:#81CCAA;}
    #body{fill:#B8E4C2;}
    #pupil{fill:#1F2600;}
    #beak{fill:#F69C0D;}
    .eye-ball{fill:#F6FDC4;}
  </style>
  <g id="bird">
    <g id="body">
        <path d="M48.42,78.11c0-17.45,14.14-31.58,31.59-31.58s31.59,14.14,31.59,31.58c0,17.44-14.14,31.59-31.59,31.59 S48.42,95.56,48.42,78.11"/>
        <path d="M109.19,69.88c0,0-8.5-27.33-42.51-18.53c-34.02,8.81-20.65,91.11,45.25,84.73 c40.39-3.65,48.59-24.6,48.59-24.6S124.68,106.02,109.19,69.88"/>
        <path id="wing" d="M105.78,75.09c4.56,0,8.84,1.13,12.62,3.11c0,0,0.01-0.01,0.01-0.01l36.23,12.38c0,0-13.78,30.81-41.96,38.09 c-1.51,0.39-2.82,0.59-3.99,0.62c-0.96,0.1-1.92,0.16-2.9,0.16c-15.01,0-27.17-12.17-27.17-27.17 C78.61,87.26,90.78,75.09,105.78,75.09"/>
    </g>
    <g id="head">
        <path id="beak" d="M50.43,68.52c0,0-8.81,2.58-10.93,4.86l9.12,9.87C48.61,83.24,48.76,74.28,50.43,68.52"/> 
        <path class="eye-ball" d="M60.53,71.68c0-6.33,5.13-11.46,11.46-11.46c6.33,0,11.46,5.13,11.46,11.46c0,6.33-5.13,11.46-11.46,11.46 C65.66,83.14,60.53,78.01,60.53,71.68"/>
        <path id="pupil" d="M64.45,71.68c0-4.16,3.38-7.53,7.54-7.53c4.16,0,7.53,3.37,7.53,7.53c0,4.16-3.37,7.53-7.53,7.53 C67.82,79.22,64.45,75.84,64.45,71.68"/>
        <path class="eye-ball" d="M72.39,74.39c0-2.73,2.22-4.95,4.95-4.95c2.73,0,4.95,2.21,4.95,4.95c0,2.74-2.22,4.95-4.95,4.95 C74.6,79.34,72.39,77.13,72.39,74.39"/>
    </g>
  </g>
</svg>

به عنوان مثال اگر بخواهیم رنگ تمام عناصر داخل بدن را تغییر دهیم کافی است رنگ body یا همان عنصر گروه بندی را تغییر دهیم و این خیلی کار را ساده می کند.

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


#bird {
  transform: scale(2);
}

همچنین گروه بندی کارهای تعاملی را راحت تر می کند. زمانی که بخواهیم با کلیک کردن روی پرنده یک اتفاق خاصی بیافتد کافی است فقط این تعامل را برای عنصر <g id="bird"> بنویسیم و دیگر لازم نیست برای تک تک اشکال داخلی آن کار را تکرار کنیم.

یکی دیگر از ویژگی های خوب عنصر <g> این است که می تواند <title> و <desc> مربوط به خود را داشته باشد که از این طریق می توان اطلاعاتی را برای صفحه خوان ها مهیا کنیم که کار ما از لحاظ دسترس‌پذیری هم بی نقص باشد و همه نوع کاربر بتوانند بخوبی از محصول ما استفاده کنند.

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


<g id="bird">
  <title>پرنده</title>
  <desc>تصویری از یک پرنده کاکل به سر بی کاکل</desc>
  <!-- ... -->
</g>

استفاده دوباره از عناصر توسط عنصر <use>

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

عنصر <use> این عملکرد را که ما در نرم افزارهای گرافیکی داریم در SVG برای ما به ارمغان می آورد. توسط این عنصر می توان یک تک شکل یا گروهی از عناصر (<g>) را دوباره استفاده کرد.

عنصر <use> ویژگی هایی از قبیل x، y و width، height و xlink:href را دارد.

فرض کنید می خواهیم از پرنده ای که داشتیم یک کپی بسازیم. کافی است id آن را به ویژگی xlink:href بدهیم. همینطور مختصاتی که می خواهیم نقطه (0, 0) پرنده دوم داشته باشد را به ویژگی های x و y عنصر <use> می دهیم و آن را در تگ svg قرار می دهیم:


<use x="100" y="100" xlink:href="#bird" />

 
استفاده از عنصر use در svg
 

توجه داشته باشید ما می توانیم به هر عنصری توسط xlink:href در عنصر <use> اشاره کنیم حتی اگر آن عنصر در فایل دیگری باشد.

فرض کنید در مثال ما عنصر درون یک فایل svg دیگر به نام animals.svg بود در این صورت خواهیم داشت:


<use x="100" y="100" xlink:href="path/to/animals.svg#bird" />

اشاره کردن به فایل های دیگر در بیشتر مرورگر های IE کار نمی کند. در مورد روش های دور زدن این مشکل در مطالب بعد بحث می کنیم.

نکته خیلی مهم اینکه ویژگی های x و y کوتاه شده عملیات انتقال یک عنصر توسط ویژگی transform هستند و همانطور که می دانیم انتقال یک عنصر نسبت به مکانی که هست اتفاق می افتد.

پس کد نوشته شده در بالا برابر این کد می باشد:


<use xlink:href="#bird" transform="translate(100, 100)" />

 
انتقال برای عنصر use
 

مورد دیگری که باید در زمان استفاده از عنصر <use> در نظر داشته باشیم این است که کپی جدید از یک عنصر دیگر تمام استایل ها و تغییر شکل های عنصر اصلی و اولیه را خواهد داشت. پس هر زمان بر روی پرنده اصلی استایل جدید اعمال کنیم پرنده کپی هم آن استایل و تغییر شکل ها را خواهد داشت.

فرض کنید پرنده کپی را از طریق transform و تابع scale نصفش کنیم زمانی که اندازه پرنده اصلی هم نصف شود پرنده کپی یک چهارم اندازه اولیه اش می شود.

همچنین این امکان برای ما وجود ندارد تا استایل هایی از قبیل fill و stroke عنصر اصلی را override کنیم. آنها برای عنصر کپی بصورت جداگانه قابل تغییر نخواهند بود.

پس اگر می خواهید یک آیکون داشته باشید و از آن آیکون در جاهای مختلف با رنگ های مختلف استفاده کنید نیاز است به خواندن ادامه بدهید :)

استفاده دوباره از عناصر ذخیره شده توسط عنصر <defs>

عنصر <use> به ما اجازه استفاده دوباره از عنصری را می دهد که رسم شده و نمایش داده می شود. حال اگر بخواهیم یک عنصر را تعریف کنیم ولی آن را نمایش ندهیم و بعدا هر زمانی و هرجایی که خواستیم از آن استفاده کنیم چه؟

اینجا جایی است که عنصر <defs> وارد می شود.

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

از طریق <defs> می توان هر چیزی را تعریف کرد. از یک گروه مثل پرنده ای که ساختیم گرفته تا ماسک ها و گرادینت ها در SVG.

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

در مثال زیر از این عنصر برای تعریف یک گرادینت در SVG استفاده می کنیم و سپس آن گرادینت برای رنگ آمیزی یک مستطیل استفاده می کنیم:


<svg>
  <defs>
    <linearGradient id="gradient">
      <stop offset="0%" style="stop-color: deepPink"></stop>
      <stop offset="100%" style="stop-color: #009966"></stop>
    </linearGradient>
  </defs>

  <rect stroke="#eee" stroke-width="5" fill="url(#gradient)"></rect>
</svg>

در قسمت قبل به دو مشکل عنصر <use> اشاره کردیم:

😔 مکان عنصر کپی شده نسبت به عنصر اصلی تعیین می شد و به آن وابسته بود.
😔 استایل های عنصر اصلی را نمی توانستیم در عنصر کپی شده بازنویسی و تغییر بدهیم.

و مشکل دیگر اینکه عنصر اصلی هم حتما باید در صفحه رسم میشد.

هیچکدام از این مشکلات در مورد <defs> وجود ندارد.

به عنوان نمونه فرض کنید پرنده را درون یک <defs> بنویسیم:


<defs>
  <g id="bird" >
    <g id="body">
      <path d="M48.42,78.11c0-17.45,14.14-31.58,31.59-31.58s31.59,14.14,31.59,31.58c0,17.44-14.14,31.59-31.59,31.59 S48.42,95.56,48.42,78.11"/>
      <path d="M109.19,69.88c0,0-8.5-27.33-42.51-18.53c-34.02,8.81-20.65,91.11,45.25,84.73 c40.39-3.65,48.59-24.6,48.59-24.6S124.68,106.02,109.19,69.88"/>
      <path id="wing" d="M105.78,75.09c4.56,0,8.84,1.13,12.62,3.11c0,0,0.01-0.01,0.01-0.01l36.23,12.38c0,0-13.78,30.81-41.96,38.09 c-1.51,0.39-2.82,0.59-3.99,0.62c-0.96,0.1-1.92,0.16-2.9,0.16c-15.01,0-27.17-12.17-27.17-27.17 C78.61,87.26,90.78,75.09,105.78,75.09"/>
    </g>
    <g id="head">
      <path id="beak" d="M50.43,68.52c0,0-8.81,2.58-10.93,4.86l9.12,9.87C48.61,83.24,48.76,74.28,50.43,68.52"/>
      <path class="eye-ball" d="M60.53,71.68c0-6.33,5.13-11.46,11.46-11.46c6.33,0,11.46,5.13,11.46,11.46c0,6.33-5.13,11.46-11.46,11.46 C65.66,83.14,60.53,78.01,60.53,71.68"/>
      <path id="pupil" d="M64.45,71.68c0-4.16,3.38-7.53,7.54-7.53c4.16,0,7.53,3.37,7.53,7.53c0,4.16-3.37,7.53-7.53,7.53 C67.82,79.22,64.45,75.84,64.45,71.68"/>
      <path class="eye-ball" d="M72.39,74.39c0-2.73,2.22-4.95,4.95-4.95c2.73,0,4.95,2.21,4.95,4.95c0,2.74-2.22,4.95-4.95,4.95 C74.6,79.34,72.39,77.13,72.39,74.39"/>
    </g>
  </g>
</defs>

😊 اولا که پرنده تا زمانی که توسط عنصر <use> مورد استفاده قرار نگیرد رسم نمی شود.

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


<use xlink:href="#bird" x="50" y="100" />
<use xlink:href="#bird" x="200" y="100" />
<use xlink:href="#bird" x="350" y="100" />

 
استفاده از عنصر defs
 

حال می توانیم به پرنده های مختلف رنگ های و استایل متفاوت بدهیم اما به یک شرط:

نباید آن استایل ها در <defs> برای تمپلت تعریف شده باشند و الا دوباره همان قصه قبلی بوجود خواهد آمد و استایل ها قابل بازنویسی نخواهند بود.

توجه داشته باشید حتی اگر مقدار ویژگی display عنصر <defs> برابر با none قرار دهیم باز هم فرزندان داخل آن می توانند توسط عناصر دیگر فراخوانی شده و بر روی صفحه رسم شوند.

گروه بندی با عنصر <symbol>

عنصر <symbol> هم شبیه به عنصر <g> است و از آن می توان برای گروه بندی عناصر استفاده کرد. اما دو تفاوت در اینجا وجود دارد:

1. عنصر <symbol> رسم نمی شود، در واقع شبیه به <defs> عمل می کند و زمانی نمایش داده می شود که توسط <use> مورد استفاده قرار بگیرد.

2. عنصر <symbol> می توان ویژگی های viewBox و preserveAspectRatio مخصوص به خود را داشته باشد.

که این امر باعث می شود تا درون هر فضایی که قرار بگیرد به خوبی متناسب آنجا شود.

در مورد این ویژگی ها در مطالب بعد بصورت مفصل خواهیم گفت.

با توجه به این موارد <symbol> مناسب ترین راه برای تعریف عناصری هستند که قرار است دوباره مورد استفاده قرار بگیرند.

جمع بندی

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

منبع

2 دیدگاه برای “ساختاردهی در SVG

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