رسم گرافیک با جاوا اسکریپت (بخش اول) — راهنمای جامع
مرورگر شامل برخی ابزارهای برنامهنویسی گرافیک بسیار قدرتمند است که از زبان Scalable Vector Graphics یا به اختصار SVG تا API-هایی برای رسم روی عنصر <canvas> در HTML را در برمیگیرد. در این مقاله به بررسی مبانی بوم مرورگر و منابع دیگر برای یادگیری در این حوزه میپردازیم و بدین ترتیب با رسم گرافیک با جاوا اسکریپت آشنا میشویم.
پیشنیاز مطالعه این مقاله آشنایی با مبانی جاوا اسکریپت و مبانی API–های سمت کلاینت و هدف آن یادگیری مقدمات رسم روی عنصر <cnavas> با استفاده از جاوا اسکریپت است. برای مطالعه بخش بعدی این سری مقالات روی لینک زیر کلیک کنید:
گرافیک وب
وب در ابتدا صرفاً شامل متن و بسیار خستهکننده بود، بنابراین تصاویر وارد صفحههای وب شدند. این ورود ابتدا از طریق عنصر <img> و سپس از طریق مشخصههای CSS مانند background-image و SVG بوده است.
با این حال این مقدار کافی نبود. با این که امکان استفاده از CSS و جاوا اسکریپت برای انیمیت کردن و دیگر دستکاری های تصاویر برداری SVG وجود داشت اما از آنجا که به صورت Markup نمایش مییافتند و همچنین روشی برای اجرای این کار برای تصاویر بیتمپ وجود نداشت، ابزارهای موجود بسیار محدود بودند. وب همچنان از هیچ روشی برای ایجاد انیمیشن، بازی، صحنههای سهبعدی و دیگر الزامات که از سوی زبانهای سطح پایینی مانند ++C یا جاوا عرضه میشدند برخوردار نبود.
این وضعیت در ادامه و با شروع پشتیبانی مرورگرها از عنصر <canvas> و API-های مرتبط بهبود یافت. اپل آن را در حدود سال 2004 ابداع کرده بود و مرورگرهای دیگر نیز با پیادهسازی آن در سالهای بعد از آن پیروی کردند. همان طور که در ادامه خواهید دید بوم یا canvas ابزارهای مفید زیادی برای ایجاد انیمیشنهای دوبعدی، بازی، بصریسازی دادهها و دیگر انواع اپلیکیشن ارائه کرده است که به خصوص در ترکیب با برخی از API–های دیگر که پلتفرم وب ارائه میکند کارایی خود را بیشتر نشان میدهند.
مثال زیر یک انیمیشن دوبعدی توپهای رقصان مبتنی بر بوم را نمایش میدهد:
در حدود سالهای 2006 تا 2007 موزیلا شروع به کار روی یک پیادهسازی بوم سهبعدی آزمایشی کرد. این بوم در ادامه به WebGL تبدیل شد که مورد توجه ارائهدهندههای مرورگرها قرار گرفت و در حدود سالهای 2009 تا 2010 به یک استاندارد در این زمینه تبدیل شد و همچنین امکان ایجاد گرافیکهای 3 بعدی واقعی درون مرورگر وب را فراهم ساخت. در ادامه یک مکعب WebGL چرخان ساده را مشاهده میکنید:
در این مقاله به طور عمده روی بوم 2 بعدی تمرکز میکنیم، چون کد WebGL خام بسیار پیچیده است. با این حال شیوه استفاده از کتابخانه WebGL برای ایجاد آسان صحنههای 3 بعدی را نیز معرفی میکنیم.
نکته: کارکردهای ابتدایی بوم در همه مرورگرها به استثنای IE 8 و پایینتر برای بوم 2 بعدی و IE 11 و پایینتر برای WebGL پشتیبانی میشود.
یادگیری عملی: آغاز کار با <canvas>
اگر میخواهید یک صحنه 2 بعدی یا 3 بعدی روی صفحه وب بسازید، باید کار خود را با عنصر <canvas> در HTML آغاز کنید. از این عنصر برای تعریف ناحیهای روی صفحه استفاده میشود که تصویر در آن رسم خواهد شد.
در ادامه نمونهای از گنجاندن این عنصر در صفحه میبینید:
1<canvas width="320" height="240"></canvas>
بدین ترتیب یک بوم روی صفحه با ابعاد 320 در 240 پیکسل ایجاد میشود.
درون تگ canvas میتوان نوعی محتوای fallback نیز قرار داد که در صورتی که مرورگر کاربر از بوم پشتیبانی نکند، نمایش خواهد یافت.
1<canvas width="320" height="240">
2 <p>Your browser doesn't support canvas. Boo hoo!</p>
3</canvas>
البته پیام فوق کاملاً مفید است. در یک مثال واقعی شما میخواهید محتوای fallback را به محتوای بوم مرتبط بکنید. برای نمونه اگر مشغول رندر کردن یک گراف قیمت سهام باشید که به صورت مداوم بهروزرسانی میشود، محتوای fallback میتوانید یک تصویر استاتیک باشد که آخرین نمودار قیمت سهام را نمایش میدهد و متنی که قیمتها را به صورت متنی نمایش میدهد نیز نمایش پیدا میکند.
ایجاد و تغییر دادن اندازه بوم
ابتدا کار خود را با ایجاد یک بوم آغاز میکنیم و آزمایشهای بعدی خود را روی آن انجام خواهیم داد. بنابراین اول یک کپی از فایل زیر روی سیستم خود ایجاد و آن را در یک ویرایشگر متنی باز کنید:
فایل canvas_start.html
1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="utf-8">
5 <title>Canvas</title>
6 </head>
7 <body>
8
9 <script>
10
11 </script>
12 </body>
13</html>
کد زیر را درست زیر تگ <body> وارد کنید:
1<canvas class="myCanvas">
2 <p>Add suitable fallback here.</p>
3</canvas>
ما یک class به عنصر <canvas> اضافه کردهایم تا در صورت وجود چندین بوم روی صفحه انتخاب آن آسانتر شود، اما خصوصیتهای width و height را فعلاً حذف کردهایم. شما میتوانید در ادامه در صورت نیاز آنها را مجدداً اضافه کنید، اما آنها را در بخش بعدی با استفاده از جاوا اسکریپت تعیین خواهیم کرد. در صورتی که عرض و ارتفاعی برای بوم تعیین نشود، مقادیر پیشفرض 300 در 150 پیکسل خواهد بود.
اکنون خطوط جاوا اسکریپت زیر را درون عنصر <script> اضافه کنید:
1var canvas = document.querySelector('.myCanvas');
2var width = canvas.width = window.innerWidth;
3var height = canvas.height = window.innerHeight;
در این کد ما یک ارجاع به بوم در متغیر canvas نگهداری میکنیم. در خط دوم هر دو متغیر width و مشخصه width بوم را برابر با Window.innerWidth قرار داریم که عرض ویوپورت مرورگر را در اختیار ما قرار میدهد. در خط سوم هر دو متغیر height و مشخصه height بوم را برابر با indow.innerHeight قرار دادیم که ارتفاع ویوپورت را در اختیار ما قرار میدهد. بنابراین هماینک بومی داریم که کل عرض و ارتفاع پنجره مرورگر را میپوشاند.
همچنین میبینید که انتسابهای متغیر را به هم با چند علامت تساوی انجام میدهیم. این کار در جاوا اسکریپت مجاز است و در صورتی که میخواهید چند متغیر همگی مقدار یکسانی داشته باشند، ایده مناسبی محسوب میشود. میخواهیم عرض و ارتفاع بوم به سادگی در متغیرهای width/heigh در اختیار ما باشد، زیرا مقادیر مفیدی هستند که باید در ادامه داشته باشیم. برای نمونه اگر میخواهید چیزی را دقیقاً در نیمه عرض بوم رسم کنید به درد میخورد.
اگر مثال را هماینک ذخیره کرده و در مرورگر بارگذاری کنید، هیچ چیز نمیبینید که خوب است، اما نوارهای اسکرول دیده میشوند و این مشکلی برای ما محسوب میشود که به دلیل وجود margin در عنصر <body> رخ داده است و به بوم با اندازه پنجره کامل ما افزوده است و در نتیجه سند عریضتر از پنجره شده است. برای رهایی از شر نوارهای اسکرول باید margin را حذف کرده و ضمناً مقدار overflow را به صورت hidden تعیین کنیم. در ادامه کد زیر را در <head> سند درج میکنیم:
1<style>
2 body {
3 margin: 0;
4 overflow: hidden;
5 }
6</style>
نوارهای اسکرول اینک باید ناپدید شده باشند.
نکته: شما باید عموماً اندازه تصویر را با استفاده از خصوصیتهای HTML یا مشخصههای DOM تعیین کنید که در بخش قبل توضیح دادیم. به این منظور میتوانید از CSS استفاده کنید، اما کار دشوارتری است زیرا اندازهبندی پس از رندر شدن بوم اجرا میشود و مانند هر تصویر دیگری ممکن است تصویر پیکسلاته شده یا دچار اعوجاج شود.
دریافت context بوم و تنظیم نهایی
پیش از آن که قالب بوم خود را پایان یافته تلقی کنیم باید کار نهایی روی آن اجرا کنیم. برای رسم روی بوم باید یک ارجاع خاص به ناحیه رسم به دست آوریم که context نام دارد. این کار با استفاده از متد ()HTMLCanvasElement.getContext صورت میگیرد که برای کاربردهای مقدماتی یک رشته منفرد به عنوان آرگومان میگیرد که نماینده نوع context-ی است که میخواهیم بازیابی کنیم.
در این حالت ما یک بوم 2 بعدی نیاز داریم و از این رو خط جاوا اسکریپت زیر را درست در ادامه موارد دیگر درون عنصر <script> درج میکنیم:
1var ctx = canvas.getContext('2d');
مقادیر دیگر context که میتوان انتخاب کرد شامل webgl برای WebGL و webgl2 برای WebGL 2 و غیره است، اما در این مقاله نیازی به این موارد نداریم.
بنابراین اینک بوم ما آمادهسازی شده و میتوانیم روی آن رسم کنیم. متغیر ctx اکنون شامل یک شیء CanvasRenderingContext2D است و همه عملیات رسم روی بوم شامل دستکاری این شیء خواهد بود.
آخرین کاری که قبل از ادامه باید انجام دهیم این است که رنگ پسزمینه بوم را سیاه تعیین کنیم تا نخستین تجربه ما از API بوم را تشکیل دهد. خطوط زیر را در انتهای جاوا اسکریپت اضافه کنید:
1ctx.fillStyle = 'rgb(0, 0, 0)';
2ctx.fillRect(0, 0, width, height);
در این کد ما یک رنگ fill با استفاده از مشخصه بوم تعیین میکنیم، که مقادیر رنگی را درست مانند مشخصههای CSS میگیرد و سپس یک مستطیل رسم میکنیم که کل ناحیه بوم را با متد fillRect میپوشاند. دو پارامتر نخست مختصات گوشه چپ-بالای مستطیل و دو پارامتر بعدی عرض و ارتفاع آن هستند. چنان که گفتیم متغیرهای width و height مفید هستند.
اینک کار قالب ما پایان یافته است و میتوانیم به ادامه کار بپردازیم.
مبانی بوم 2 بعدی
چنان که پیشتر گفتیم همه عملیات رسم به وسیله دستکاری یک شیء CanvasRenderingContext2D (در این مثال ctx) صورت میگیرد.
عملیات زیادی وجود دارند که باید مختصات دقیقی به آنها داده شود تا بدانند دقیقاً چه چیزی رسم میکنند. گوشه چپ-بالای بوم نقطه (0, 0) است، محور افقی x از چپ به راست بسط یافته و محور عمودی y از بالا به پایین افزایش مییابد.
رسم شکلها با استفاده از شکل ابتدایی مستطیل یا از طریق ردگیری یک خط در روی یک مسیر و سپس پر کردن شکل انجام مییابد. در ادامه با هر دو روش رسم آشنا میشویم.
مستطیلهای ساده
کار خود را با برخی مستطیلهای ساده آغاز میکنیم.
قبل از هر چیز یک کپی از قالب بوم اخیراً کد شده آغاز میکنیم. شما میتوانید در صورتی که مراحل قبل را طی نکرده باشید یک کپی از فایل زیر روی سیستم خود ایجاد کنید:
فایل canvas_template.html
1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="utf-8">
5 <title>Canvas</title>
6 <style>
7 body {
8 margin: 0;
9 overflow: hidden;
10 }
11 </style>
12 </head>
13 <body>
14 <canvas class="myCanvas">
15 <p>Add suitable fallback here.</p>
16 </canvas>
17
18 <script>
19 var canvas = document.querySelector('.myCanvas');
20 var width = canvas.width = window.innerWidth;
21 var height = canvas.height = window.innerHeight;
22 var ctx = canvas.getContext('2d');
23 ctx.fillStyle = 'rgb(0,0,0)';
24 ctx.fillRect(0,0,width,height);
25 </script>
26 </body>
27</html>
سپس خطوط زیر را به انتهای جاوا اسکریپت اضافه کنید:
1ctx.fillStyle = 'rgb(255, 0, 0)';
2ctx.fillRect(50, 50, 100, 150);
اگر صفحه را ذخیره و رفرش کنید میبینید که مستطیل قرمز رنگی روی بوم ظاهر میشود. گوشه چپ-بالای آن 50 پیکسل از گوشه چپ و بالای بوم فاصله دارد (که توسط دو پارامتر اول تعیینشده) و عرض آن 100 و ارتفاعش 150 پیکسل است (که توسط پارامترهای سوم و چهارم تعریف شده است).
در ادامه مستطیل دیگری اضافه میکنیم که این بار سبز رنگ است. خطوط زیر را به انتهای جاوا اسکریپت اضافه کنید:
1ctx.fillStyle = 'rgb(0, 255, 0)';
2ctx.fillRect(75, 75, 100, 100);
صفحه را ذخیره و رفرش کنید تا مستطیل جدید را ببینید. بدین ترتیب نکته مهمی مشخص میشود. عملیات گرافیکی مانند رسم مستطیل، خط و غیره به ترتیبی که نوشته میشوند، اجرا خواهند شد. آن را مانند نقاشی کردن یک دیوار میتوان تصور کرد که هر پوشش رنگ روی پوشش قبلی قرار میگیرد و زیرش را پنهان میکند. هیچ کاری برای تغییر این وضعت نمیتوان انجام داد، بنابراین باید در مورد ترتیب رسم گرافیکها کاملاً اندیشمندانه عمل کنید.
توجه کنید که میتوانید گرافیکهای نیمه شفاف را با تعیین رنگ نیمه شفاف رسم کنید برای نمونه میتوان از ()rgba استفاده کرد. مقدار a چیزی را تعریف میکند که کانال آلفا یا مقدار شفافیت رنگ نام دارد. هر چه این مقدار بالاتر باشد، بیشتر میتوان اشیای پشت رنگ را مشاهده کرد. خطوط زیر را به کد اضافه کنید:
1ctx.fillStyle = 'rgba(255, 0, 255, 0.75)';
2ctx.fillRect(25, 100, 175, 50);
اکنون تلاش کنید مستطیلهای بیشتری اضافه کنید
عرض stroke و خطوط
تا به اینجا به بررسی روش رسم مستطیلهای توپر پرداختیم، اما میتوان مستطیلهایی را نیز رسم کرد که صرفاً خط بیرونی که در طراحی گرافیک، stroke نامیده میشوند، داشته باشند. برای تعیین رنگ Stroke باید از مشخصه strokeStyle استفاده کنیم. ترسیم یک مستطیل stroke نیز از طریق متد strokeRect صورت میگیرد.
خطوط زیر را نیز به مثال و در ادامه جاوا اسکریپت اضافه کنید:
1ctx.strokeStyle = 'rgb(255, 255, 255)';
2ctx.strokeRect(25, 25, 175, 200);
عرض پیشفرض Steoke-ها 1 پیکسل است، اما میتوانید مشخصه linewidth را تغییر دهید تا مقدار آن عوض شود. خط زیر را بین دو خط قبلی وارد کنید:
1ctx.lineWidth = 5;
اکنون باید ببینید که کادر بیرونی سفید رنگ ضخیمتر میشود. در این زمان مثال ما باید به صورت زیر درآمده باشد:
نکته: کد کامل مثال رسم مستطیل به صورت زیر است، در صورتی که با هر گونه مشکل در کد خود مواجه شدید، آن را با کد زیر تطبیق دهید:
1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="utf-8">
5 <title>Canvas</title>
6 <style>
7 body {
8 margin: 0;
9 overflow: hidden;
10 }
11 </style>
12 </head>
13 <body>
14 <canvas class="myCanvas">
15 <p>Add suitable fallback here.</p>
16 </canvas>
17
18 <script>
19 var canvas = document.querySelector('.myCanvas');
20 var width = canvas.width = window.innerWidth;
21 var height = canvas.height = window.innerHeight;
22 var ctx = canvas.getContext('2d');
23 ctx.fillStyle = 'rgb(0,0,0)';
24 ctx.fillRect(0,0,width,height);
25 ctx.fillStyle = 'rgb(255,0,0)';
26 ctx.fillRect(50,50,100,150);
27 ctx.fillStyle = 'rgb(0,255,0)';
28 ctx.fillRect(75,75,100,100);
29 ctx.fillStyle = 'rgba(255,0,255,0.75)';
30 ctx.fillRect(25,100,175,50);
31 ctx.strokeStyle = 'rgb(255,255,255)';
32 ctx.lineWidth = 5;
33 ctx.strokeRect(25,25,175,200);
34 </script>
35 </body>
36</html>
رسم مسیر
اگر میخواهید هر چیزی پیچیدهتر از مستطیل بکشید باید از رسم مسیر استفاده کنید. اساساً این رسم شامل نوشتن کد برای تعیین دقیق مسیری است که قلم باید روی بوم طی کند تا شکلی که میخواهید رسم شود. بوم شامل تابعهایی برای رسم خطوط مستقیم، دایره، منحنیهای بزیه (Bézier curves) و موارد دیگر است.
ابتدا یک کپی از کد قالب بوم زیر در روی سیستم خود ایجاد کنید:
فایل canvas_template.html
1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="utf-8">
5 <title>Canvas</title>
6 <style>
7 body {
8 margin: 0;
9 overflow: hidden;
10 }
11 </style>
12 </head>
13 <body>
14 <canvas class="myCanvas">
15 <p>Add suitable fallback here.</p>
16 </canvas>
17
18 <script>
19 var canvas = document.querySelector('.myCanvas');
20 var width = canvas.width = window.innerWidth;
21 var height = canvas.height = window.innerHeight;
22 var ctx = canvas.getContext('2d');
23 ctx.fillStyle = 'rgb(0,0,0)';
24 ctx.fillRect(0,0,width,height);
25 </script>
26 </body>
ما از برخی مشخصهها و متدهای رایج در همه بخشهای آتی استفاده میکنیم:
- ()beginPath – شروع به رسم از مکانی میکند که قلم هماینک قرار دارد. روی یک بوم جدید قلم در ابتدا در نقطه (0, 0) قرار دارد.
- ()moveTo – قلم را بدون ضبط یا ردگیری یک خط به نقطه متفاوتی روی بوم میبرد. در واقع قلم ناگهان به نقطه جدید میپرد.
- ()fill – یک شکل توپر با پر کردن مسیری که تاکنون ترسیم شده میسازد.
- ()stroke – یک شکل با صرفاً لبه بیرونی و ضخامتی در مسیری که تاکنون رسم شده میکشد.
- میتوان از قابلیتهایی مانند lineWidth و fillStyle/strokeStyle نیز روی مسیرها علاوه بر مستطیلها استفاده کرد.
رسم یک مسیر معمول میتواند چیزی مانند زیر باشد:
1ctx.fillStyle = 'rgb(255, 0, 0)';
2ctx.beginPath();
3ctx.moveTo(50, 50);
4// draw your path
5ctx.fill();
رسم خطوط
در ادامه یک مثلث متساویالساقین روی بوم رسم میکنیم. قبل از هر چیز تابع کمکی زیر را به انتهای کد فعلی اضافه کنید. این تابع درجه را به رادیان تبدیل میکند که مفید است، زیرا هر زاویهای که در جاوا اسکریپت تعیین کنیم بر حسب رادیان خواهد بود، اما ما معمولاً عادت داریم زوایا را بر حسب درجه محاسبه کنیم.
1function degToRad(degrees) {
2 return degrees * Math.PI / 180;
3};
سپس مسیر را با افزودن کد زیر به کدهای قبلی شروع به رسم میکنیم. در این کد ما یک رنگ برای مثلث تعیین کردهایم، شروع به رسم یک مسیر میکنیم سپس قلم را بدون رسم چیزی به (50, 50) جابجا کردهایم. این همان جایی است که شروع به رسم مثلث میکنیم:
1ctx.fillStyle = 'rgb(255, 0, 0)';
2ctx.beginPath();
3ctx.moveTo(50, 50);
اکنون خطوط زیر را به انتهای اسکریپت اضافه میکنیم:
1ctx.lineTo(150, 50);
2var triHeight = 50 * Math.tan(degToRad(60));
3ctx.lineTo(100, 50+triHeight);
4ctx.lineTo(50, 50);
5ctx.fill();
ابتدا یک خط در راستای (150, 50) رسم میکنیم، مسیر ما 100 پیکسل در راستای محور x حرکت میکند.
سپس ارتفاع مثلث متساویالساقین خود را با کمی استفاده از مثلثات حساب میکنیم. اساساً ما یک مثلث به سمت پایین رسم میکنیم. زوایا در مثلث متساویالساقین برابر با 60 درجه هستند. برای محاسبه ارتفاع میتوانیم آن را از وسط به دو مثلث قائمالزاویه تقسیم کنیم که هر کدام زوایای 60، 90 و 30 درجه دارند. بر حسب اضلاع:
طولانیترین ضلع به نام وتر خوانده میشود.
ضلع کنار زاویه 60 درجه به نام مجاور خوانده میشود که میدانیم 50 پیکسل است، چون نصف خطی است که رسم کردهایم.
ضلع مقابل زاویه 60 درجه به نام مقابل خوانده میشود که ارتفاع مثلث است و میخواهیم محاسبه کنیم:
یکی از فرمولهای مقدماتی مثلثات بیان میکند که طول ضلع مجاور ضرب در تانژانت زاویه برابر با طول ضلع مقابل است. از این رو به فرمول زیر میرسیم:
50 * Math.tan(degToRad(60))
ما از تابع degToRad() برای تبدیل 60 درجه به رادیان استفاده کردهایم، چون Math.tan() به عنوان مقدار ورودی، رادیان میگیرد.
زمانی که ارتفاع محاسبه شد، یک خط دیگر به (100, 50+triHeight) رسم میکنیم. مختصات x ساده است چون باید در نیمه بین دو مقدار X قبلی تعیین شود. از سوی دیگر مقدار Y باید 50 به علاوه ارتفاع مثلث باشد، چون میدانیم که بالای مثلث 50 پیکسل از بالای بوم فاصله دارد.
در خط بعدی کدمان یک خط به نقطه آغازین مثلث رسم میکنیم.
در نهایت ()ctx.fill را اجرا میکنیم تا مسیر خاتمه یافته و شکل با رنگ پر شود.
رسم دایره
اکنون نگاهی به رسم دایره روی بوم میاندازیم. این کار با استفاده از متد ()arc انجام مییابد که همه اجزای یک دایره را در یک نقطه خاص رسم میکند. در ادامه یک کمان به بوم خود اضافه میکنیم. کد زیر را به ادامه کدهای قبلی اضافه کنید:
1ctx.fillStyle = 'rgb(0, 0, 255)';
2ctx.beginPath();
3ctx.arc(150, 106, 50, degToRad(0), degToRad(360), false);
4ctx.fill();
()arc شش پارامتر میگیرد. دو پارامتر اول موقعیت مرکز کمان را تعیین میکنند. پارامتر سوم شعاع دایره است، پارامترهای چهارم و پنجم زوایای آغاز و انتهایی هستند که دایره رسم میشود. بنابراین تعیین مقدار 0 و 360 یک دایره کامل به ما میدهد. پارامتر ششم تعیین میکند که آیا دایره باید در جهت ساعتگرد رسم شود یا پادساعتگرد. مقدار false برای پادساعتگرد استفاده میشود.
در ادامه یک کمان دیگر اضافه میکنیم:
1ctx.fillStyle = 'yellow';
2ctx.beginPath();
3ctx.arc(200, 106, 50, degToRad(-45), degToRad(45), true);
4ctx.lineTo(200, 106);
5ctx.fill();
الگو کاملاً مشابه است اما دو تفاوت وجود دارد:
ما پارامتر آخر ()arc را به صورت true تنظیم کردهایم، یعنی کمان پادساعتگرد رسم میشود که به این معنی است که گرچه کمان در نقطه آغازی 45- درجه و نقطه انتهایی 45 درجه توصیف شده، اما ما کمان را در 270 درجه بخش بیرونی این کمان و نه بخش درونی آن رسم میکنیم. اگر بخواهید true را به false تغییر دهید و کد را مجدداً اجرا کنید، تنها قطاع 90 درجهای دایره رسم میشود.
پیش از فراخوانی ()fill یک خط به مرکز دایره رسم میکنیم. این بدان معنی است که یک استایل شبیه پکمن رندر میشود. اگر این خط را حذف کنید و سپس کد را مجدد اجرا کنید، یک لبه از دایره به دست میآید که بین نقاط آغازین و انتهایی کمان برش یافته است. اگر تلاش کنید مسیر ناکامل را پر کنید، مرورگر خط مستقیم بین نقاط ابتدایی و انتهایی و نه درون آن را پر میکند.
مثال نهایی باید مانند زیر باشد:
نکته: کد نهایی مثال فوق به صورت زیر است:
1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="utf-8">
5 <title>Canvas</title>
6 <style>
7 body {
8 margin: 0;
9 overflow: hidden;
10 }
11 </style>
12 </head>
13 <body>
14 <canvas class="myCanvas">
15 <p>Add suitable fallback here.</p>
16 </canvas>
17
18 <script>
19 var canvas = document.querySelector('.myCanvas');
20 var width = canvas.width = window.innerWidth;
21 var height = canvas.height = window.innerHeight;
22 var ctx = canvas.getContext('2d');
23 ctx.fillStyle = 'rgb(0,0,0)';
24 ctx.fillRect(0,0,width,height);
25 function degToRad(degrees) {
26 return degrees * Math.PI / 180;
27 };
28 ctx.fillStyle = 'rgb(255,0,0)';
29 ctx.beginPath();
30 ctx.moveTo(50,50);
31 ctx.lineTo(150,50);
32 var triHeight = 50 * Math.tan(degToRad(60));
33 ctx.lineTo(100,50+triHeight);
34 ctx.lineTo(50,50);
35 ctx.fill();
36 ctx.fillStyle = 'rgb(0,0,255)';
37 ctx.beginPath();
38 ctx.arc(150, 106, 50, degToRad(0), degToRad(360), false);
39 ctx.fill()
40 ctx.fillStyle = 'yellow';
41 ctx.beginPath();
42 ctx.arc(200, 106, 50, degToRad(-45), degToRad(45), true);
43 ctx.lineTo(200,106);
44 ctx.fill();
45 </script>
46 </body>
47</html>
رسم Text
بوم امکان رسم متن نیز دارد. در ادامه این قابلیت را نیز به اختصار بررسی میکنیم. کار خود را با تهیه یک کپی از فایل زیر روی سیستم خود آغاز کنید.
فایل canvas_template.html
1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="utf-8">
5 <title>Canvas</title>
6 <style>
7 body {
8 margin: 0;
9 overflow: hidden;
10 }
11 </style>
12 </head>
13 <body>
14 <canvas class="myCanvas">
15 <p>Add suitable fallback here.</p>
16 </canvas>
17
18 <script>
19 var canvas = document.querySelector('.myCanvas');
20 var width = canvas.width = window.innerWidth;
21 var height = canvas.height = window.innerHeight;
22 var ctx = canvas.getContext('2d');
23 ctx.fillStyle = 'rgb(0,0,0)';
24 ctx.fillRect(0,0,width,height);
25 </script>
26 </body>
27</html>
متن با استفاده از دو متد زیر رسم میشود:
- ()fillText –متن تو پر رسم میکند.
- ()strokeText – متن با خطوط بیرونی (stroke) رسم میکند.
هر دو متد فوق در کاربرد ابتداییشان سه مشخصه دارند: متنی که باید رسم شود و همچنین مختصات X و Y گوشه چپ-بالای کادر متن. این کادر متن در واقع همان کادری است که متن شما را احاطه میکند.
چند مشخصه دیگر نیز وجود دارند که به رندر شدن متن کمک میکنند. این مشخصهها شامل font هستند که خانواده فونت و اندازه متن را تعیین میکند. مقدار آن همانند مشخصه font در CSS تعیین میشود.
بلوک کد زیر را به انتهای جاوا اسکریپت فعلی اضافه کنید:
1ctx.strokeStyle = 'white';
2ctx.lineWidth = 1;
3ctx.font = '36px arial';
4ctx.strokeText('Canvas text', 50, 50);
5
6ctx.fillStyle = 'red';
7ctx.font = '48px georgia';
8ctx.fillText('Canvas text', 50, 150);
در این کد ما دو خط متن داریم که یکی برای outline و دیگری برای stroke است. مثال نهایی باید چیزی مانند زیر باشد:
نکته: کد نهایی مثال فوق به صورت زیر است:
1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="utf-8">
5 <title>Canvas</title>
6 <style>
7 body {
8 margin: 0;
9 overflow: hidden;
10 }
11 </style>
12 </head>
13 <body>
14 <canvas class="myCanvas">
15 <p>Add suitable fallback here.</p>
16 </canvas>
17
18 <script>
19 var canvas = document.querySelector('.myCanvas');
20 var width = canvas.width = window.innerWidth;
21 var height = canvas.height = window.innerHeight;
22 var ctx = canvas.getContext('2d');
23 ctx.fillStyle = 'rgb(0,0,0)';
24 ctx.fillRect(0,0,width,height);
25 ctx.strokeStyle = 'white';
26 ctx.lineWidth = 1;
27 ctx.font = '36px arial';
28 ctx.strokeText('Canvas text', 50, 50);
29 ctx.fillStyle = 'red';
30 ctx.font = '48px georgia';
31 ctx.fillText('Canvas text', 50, 150);
32 </script>
33 </body>
34</html>
رسم تصاویر روی بوم
میتوان تصاویر خارجی را نیز روی بوم رندر کرد. این موارد میتوانند تصاویر ساده، فریمهایی از ویدئو، یا محتوای بومهای دیگر باشند. فعلاً تنها شیوه رندر تصاویر ساده را روی بوم بررسی میکنیم.
مانند مثالهای قبل ابتدا یک کپی از فایل زیر روی سیستم خود ایجاد کنید.
فایل canvas_template.html
1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="utf-8">
5 <title>Canvas</title>
6 <style>
7 body {
8 margin: 0;
9 overflow: hidden;
10 }
11 </style>
12 </head>
13 <body>
14 <canvas class="myCanvas">
15 <p>Add suitable fallback here.</p>
16 </canvas>
17
18 <script>
19 var canvas = document.querySelector('.myCanvas');
20 var width = canvas.width = window.innerWidth;
21 var height = canvas.height = window.innerHeight;
22 var ctx = canvas.getContext('2d');
23 ctx.fillStyle = 'rgb(0,0,0)';
24 ctx.fillRect(0,0,width,height);
25 </script>
26 </body>
27</html>
در این مثال باید یک کپی از این تصویر (+) را نیز دانلود کرده و در کنار فایل مذکور قرار دهید.
تصاویر با استفاده از متد ()drawImage روی بوم رسم میشوند. سادهترین نسخه از آن سه پارامتر میگیرد که یکی ارجاع به فایلی است که قرار است رندر شود و سپس مختصات X و Y گوشه چپ-بالای تصویر میآید.
کار خود را با دریافت منبع یک تصویر برای جاسازی در بوم آغاز میکنیم. خط زیر را به انتهای جاوا اسکریپت اضافه کنید:
1var image = new Image();
2image.src = 'firefox.png';
در این کد ما یک شیء HTMLImageElement جدید با استفاده از سازنده ()Image ایجاد میکنیم. شیء بازگشتی از همان نوعی است که هنگام دریافت ارجاعی به یک عنصر <img> به دست میآید. خصوصیت src آن را برابر با تصویر لوگوی فایرفاکس قرار میدهیم. در این زمان مرورگر شروع به بارگذاری تصویر میکند.
اینک میتوانیم تصویر را با استفاده از ()drawImage جاسازی کنیم، اما باید مطمئن شویم که فایل تصویر ابتدا بارگذاری شده است، چون در غیر این صورت کد ناموفق خواهد بود. میتوانیم با استفاده از دستگیره رویداد onload این حالت را داشته باشیم که تنها زمانی فراخوانی میشود که بارگذاری تصویر به پایان رسیده باشد. بلوک کد زیر را بعد از کد قبلی اضافه کنید:
1image.onload = function() {
2 ctx.drawImage(image, 50, 50);
3}
اگر مثلتان را هماینک در مرورگر بارگذاری کنید، میتوانید تصویر جاسازیشده در بوم را ببینید.
اگر بخواهیم تنها بخشی از یک تصویر را نمایش دهیم یا اندازه آن را تغییر دهیم میتوانیم از نسخه پیچیدهتری از ()drawImage استفاده کنیم. بنابراین خط ()ctx.drawImage را به صورت زیر بهروزرسانی کنید:
1ctx.drawImage(image, 20, 20, 185, 175, 50, 50, 185, 175);
- پارامتر اول مانند مثال قبل ارجاع تصویر است.
- پارامتر 2 و 3 مختصات گوشه چپ و بالای ناحیهای است که میخواهیم تصویر بارگذاری شده از آنجا برش یابد و در نسبت با گوشه چپ-بالای خود تصویر تعریف میشود. در واقع پس از اعمال این متد هیچ چیزی در سمت چپ و بالای پارامتر اول رسم نخواهد شد.
- پارامترهای 4 و 5 عرض و ارتفاع ناحیهای که میخواهیم از تصویر اصلی بارگذاری شده برش یابد را نشان میدهد.
- پارامترهای 6 و 7 مختصاتی که میخواهیم گوشه چپ –بالای بخش برش یافته تصویر در ارتباط با گوشه چپ-بالای بوم تعیین شود را مشخص میکند.
- پارامترهای 8 و 9 عرض و ارتفاع ناحیه برش تصویر را تعیین میکند. در این مثال ما همان ابعاد قطعه اصلی را تعیین کردهایم، اما میتوان اندازه آن را با تعیین مقادیر متفاوت تغییر داد.
مثال نهایی باید مانند زیر باشد:
کد کامل این مثال به صورت زیر است:
1<!DOCTYPE html>
2<html>
3 <head>
4 <meta charset="utf-8">
5 <title>Canvas</title>
6 <style>
7 body {
8 margin: 0;
9 overflow: hidden;
10 }
11 </style>
12 </head>
13 <body>
14 <canvas class="myCanvas">
15 <p>Add suitable fallback here.</p>
16 </canvas>
17
18 <script>
19 var canvas = document.querySelector('.myCanvas');
20 var width = canvas.width = window.innerWidth;
21 var height = canvas.height = window.innerHeight;
22 var ctx = canvas.getContext('2d');
23 ctx.fillStyle = 'rgb(0,0,0)';
24 ctx.fillRect(0,0,width,height);
25 var image = new Image();
26 image.src = 'firefox.png';
27 image.onload = function() {
28 ctx.drawImage(image, 20, 20, 185, 175, 50, 50, 185, 175);
29 }
30 </script>
31 </body>
32</html>
بدین ترتیب به پایان بخش اول این مطلب میرسیم، برای مطالعه بخش دوم روی لینک زیر کلیک کنید:
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای JavaScript (جاوا اسکریپت)
- آموزش JavaScript ES6 (جاوا اسکریپت)
- مجموعه آموزشهای برنامهنویسی
- ۱۱ ترفند بسیار کاربردی جاوا اسکریپت — به زبان ساده
- آموزش جاوا اسکریپت — مجموعه مقالات جامع وبلاگ فرادرس
==