برنامه سازی وب، دانشگاه صنعتی شریف
ارائه دهنده درس: جناب آقای محمد نظری
نویسندگان: سیدعلی طیب، احمدرضا خناری، سیدعلی حسینی
کتابخانه Processing پروژه ایست که در سال ۲۰۰۱ توسط دو دانشجو در MIT شروع شد. هدف این پروژه ساخت ابزاری برای طراحان و برنامهنویسان بود که به کمک آن بتوانند ایدهها و تصاویر ذهنی خود را از طریق برنامهنویسی مصور کنند. Processing در ابتدا در زبان برنامهنویسی Java نوشته شد. یکی از دلایل انتخاب این زبان، امکان قرار دادن این مصورسازیها در وب (بوسیله applet ها) بود.
اما در این دوره و زمانه، زبان برنامهنویسی وب JavaScript است. به همین خاطر در سال ۲۰۱۳، Lavren McCarthy به کمک تیم Processing،پروژهی p5js را شروع کردند.
کتابخانه P5js در واقع یک کتابخانه از توابع نسبتا ساده است که هدف ساخت برنامههای خلاقانه در بستر مرورگر را ممکن میکند. همچنین با توجه به بهینگی و کمبودن پیچیدگی توابع آن، در برخی دورهها برای تدریس مبانی برنامهنویسی نیز از آن بهره برده میشود. همچنین در سایت رسمی P5js رفرنس دقیقی از تمام توابع این کتابخانه به همراه مثالهای مختلف وجود دارد. در این آموزش سعی کردهایم توابع پرکاربرد تر این کتابخانه را بررسی کنیم.
بد نیست پیش از بررسی توابع این کتابخانه، یک بار ساختار کلی یک کد p5js را مشاهده کنیم. برای اجرای کد P5js تنها کافیست دو فایل p5.min.js و p5.sound.min.js را در فایل index.html خود (به همراه فایل sketch.js که شامل کد p5 شماست)اضافه کنید. همچنین برای شروع میتوانید از وایرایشگر تحت وب p5 نیز استفاده کنید.
function setup {
createCanvas(400, 400);
}
function draw {
background(220);
circle(width / 2, height / 2, 400);
}
در مثال بالا، ابتدا یک canvas (پنجرهي برنامهی شما) به ابعاد 400x400 ساخته میشود. سپس در هر frame بکگراند آن خاکستری میشود و یک دایره در نقطه وسط صفحه و به قطر ۴۰۰ رسم میشود. در ادامه با تمام توابع استفاده شده در این کد و بسیاری توابع کاربرد دیگر در این کتابخانه آشنا خواهیم شد.
این سه تابع، مراحل کلی شروع و ادامه اجرای برنامه را شکل میدهند. این توابع توسط خود p5js فراخوانی میشوند.
تابع preload مستقیماً قبل از اجرای setup فراخوانی میشود و برای مدیریت بارگذاری همزمان فایلهای خارجی به صورت blocking مورد استفاده قرار میگیرند. اگر یک تابع preload تعریف شود، setup منتظر میماند تا اجرای آن به طور کامل تمام شود. هیچ چیز جز تماسهای load (loadImage، loadJSON، loadFont، loadStrings و غیره) نباید در داخل تابع preload قرار گیرد. اگر بارگذاری asynchronous ترجیح داده شود، میتوان از تماسهای load در داخل setup یا هر جای دیگر با استفاده از پارامتر callback استفاده کرد.
تابع setup یک بار در زمان شروع برنامه فراخوانی میشود. از این تابع برای تعیین ویژگیهای محیط اولیه نظیر اندازه صفحه و رنگ پسزمینه و بارگذاری رسانهها مانند تصاویر و فونتها استفاده میشود. تنها یک تابع setup برای هر برنامه وجود دارد و بعد از اجرای اولیه خود دیگر نباید فراخوانی شود.
توجه: متغیرهای declare شده در داخل setup در توابع دیگر قابل دسترسی نیستند.
تابع draw مستقیماً پس از setup فراخوانی میشود و خطوط کد موجود در داخل خود را به طور مداوم اجرا میکند تا برنامه متوقف شود یا تا زمانی که noLoop فراخوانی شود.
تعداد اجراهای draw در هر ثانیه با استفاده از تابع frameRate قابل کنترل است. در هر اسکچ، تنها یک تابع draw وجود دارد.
تابع draw همواره باید با استفاده از noLoop، redraw و loop کنترل شود.
توابع loop و noLoop برای فعال و غیرفعال کردن حلقه اجرای draw مورد استفاده قرار میگیرند. توابع isLooping نیز وضعیت فعلی حلقه را بررسی میکند.
در شرایط noLoop میتوان از تابع redraw برای اجرای تابع draw در یک زمان خاص (مثل کلیک mouse) استفاده کرد.
توابع push و pop برای ذخیره و بازیابی وضعیت ماتریس تبدیلات، رنگ، و دیگر تنظیمات گرافیکی مورد استفاده قرار میگیرند. در بخش تبدیلات کاربرد این تابع را بهتر خواهیم دید.
کتابخانه p5js شامل اشکال رایج مثل circle, triangle, elipse, rect, ... هست، اما در این بخش، موارد سوال برانگیز در رابطه با اشکال در p5 را بررسی میکنیم.
توابع beginShape و endShape امکان ایجاد اشکال پیچیده را فراهم میکنند. beginShape شروع به ضبط نقاط یک شکل هندسی میکند و endShape این ضبط را متوقف میکند. تابع vertex برای مشخص کردن مختصات نقاط برای نقاط، خطوط، مثلثها، چهارضلعیها و چندضلعیها استفاده میشود. این تابع به صورت انحصاری در داخل توابع beginShape و endShape استفاده میشود.
مثال:
function setup {
createCanvas(100, 100);
translate(50);
beginShape;
vertex(-10, 10);
vertex(0, 35);
vertex(10, 10);
vertex(35, 0);
vertex(10, -8);
vertex(0, -35);
vertex(-10, -8);
vertex(-35, 0);
vertex(-10, 10);
endShape;
}
تابع rectMode مکانی که مستطیلها و مربعها رسم میشوند را تغییر میدهد. تابع ellipseMode نیز مکانی که بیضیها، دایرهها و قوسها رسم میشوند را تغییر میدهد. به طور پیشفرض، دو پارامتر اول مختصات x و y نقطه بالا-چپ شکل هستند. پارامترهای بعدی عرض و ارتفاع باکس شکل هستند. این معادل فراخوانی دو تابع مذکور با آرگومان CORNERS است. در زیر بقیهی آرگومانهای ممکن را بررسی میکنیم.
CENTER از دو پارامتر اول به عنوان مختصات x و y مرکز شکل استفاده میکند. پارامترهای بعدی عرض و ارتفاع هستند.
RADIUS همچنین از دو پارامتر اول به عنوان مختصات x و y مرکز شکل استفاده میکند. پارامترهای بعدی نصف عرض و ارتفاع شکل هستند.
آرگومان ارسالی به این توابع باید با حروف بزرگ (ALL CAPS) نوشته شود زیرا ثابتهای CENTER، RADIUS، CORNER و CORNERS به این صورت تعریف شدهاند.
در این بخش از p5js تعداد زیادی توابع برای ساخت المانهای مختلف وجود دارد که به موارد پرکاربردتر اشاره میکنیم:
تابع createSlider یک المان ورودی از نوع اسلایدر <input></input>
ایجاد میکند. اسلایدرهای محدودهای برای سریع انتخاب اعداد از یک محدوده داده شده مفید هستند.
پارامترهای اول و دوم، min و max، اعدادی هستند که حداقل و حداکثر اسلایدر را تعیین میکنند.
پارامتر سوم، value، اختیاری است. عددی که مقدار پیشفرض اسلایدر را تنظیم میکند.
پارامتر چهارم، step، نیز اختیاری است. عددی که فاصله بین هر مقدار در محدوده اسلایدر را تعیین میکند. تنظیم step به 0 این امکان را فراهم میکند که اسلایدر به صورت صاف از min به max حرکت کند.
تابع createButton یک المان دکمه <button></button>
ایجاد میکند.
پارامتر اول، label، یک رشته است که برچسب نمایش داده شده بر روی دکمه را تنظیم میکند.
تابع createInput یک المان متنی <input></input>
ایجاد میکند. با فراخوانی myInput.size
میتوانید طول جعبه متن را تنظیم کنید.
پارامتر اول، value، اختیاری است. یک رشته که مقدار پیشفرض ورودی را تنظیم میکند. ورودی به طور پیشفرض خالی است.
تابع createFileInput یک المان <input></input>
از نوع 'file' ایجاد میکند. این امکان را به کاربر میدهد تا فایلهای محلی را برای استفاده در یک اسکچ انتخاب کند.
پارامتر اول، callback، یک تابع است که هنگام بارگذاری فایل فراخوانی میشود. تابع با یک پارامتر، file (یک شیء p5.File)، باید فراخوانی شود.
پارامتر دوم، multiple، اختیاری است. یک مقدار بولی که اگر به true تنظیم شود، امکان بارگذاری چندین فایل را فراهم میکند. در صورت true بودن، callback برای هر فایل یکبار فراخوانی میشود.
در p5.js، p5.Color یک کلاس است که امکان ایجاد و مدیریت رنگها را فراهم میکند. با استفاده از این کلاس، میتوانید رنگها را به صورت RGB یا HSB ایجاد کرده و ویژگیهای مختلف آنها را تغییر دهید.
برای استخراج ویژگیهای رنگ از یک شیء p5.Color، میتوانید از متدهای red، green، blue برای حالت RGB یا hue، saturation، brightness برای حالت HSB استفاده کنید. این متدها به ترتیب مقدار رنگ قرمز، سبز، آبی یا هیو، اشباع و روشنایی را باز میگردانند.
let c = color(255, 0, 0); // یک رنگ قرمز ایجاد میکند
let r = red(c); // بازگرداندن مقدار قرمز
let g = green(c); // بازگرداندن مقدار سبز
let b = blue(c); // بازگرداندن مقدار آبی
تابع lerpColor از دو رنگ و یک عدد میانگین، یک رنگ ترکیبی ایجاد میکند. این تابع برای ایجاد انتقال رنگ یا انیمیشنهای تغییر رنگ مفید است.
let c1 = color(255, 0, 0); // رنگ قرمز
let c2 = color(0, 0, 255); // رنگ آبی
let cBlend = lerpColor(c1, c2, 0.5); // ترکیب رنگ قرمز و آبی با میانگین 0.5
تابع colorMode امکان تعیین حالت رنگ (RGB یا HSB) و محدوده مقادیر رنگ را فراهم میکند.
colorMode(RGB, 255); // حالت RGB با محدوده 0 تا 255
colorMode(HSB, 100); // حالت HSB با محدوده 0 تا 100
توابع background و clear برای تنظیم رنگ پسزمینه صفحه به یک رنگ خاص یا پاکسازی محتوای فعلی استفاده میشوند.
background(255, 0, 0); // تنظیم رنگ پسزمینه به قرمز
clear; // پاکسازی محتوای صفحه
توابع fill و stroke برای تعیین رنگ پرکردن و حاشیه اشیاء به ترتیب مورد استفاده قرار میگیرند. توابع noFill و noStroke برای خاموش کردن پرکردن و حاشیه به ترتیب مورد استفاده میشوند.
fill(0, 255, 0); // تعیین رنگ پرکردن به سبز
stroke(0, 0, 255); // تعیین رنگ حاشیه به آبی
noFill; // خاموش کردن پرکردن
noStroke; // خاموش کردن حاشیه
توجه مهم: سیستم مختصات نقاشی در ابتدای هر فراخوانی draw بازنشانی خواهد شد. اگر هر گونه تغییرات (مانند scale، rotate، translate) در داخل draw انجام شود، تأثیرات آنها در ابتدای draw لغو خواهد شد، بنابراین تغییرات در طول زمان ادغام نخواهند شد. از سوی دیگر، استایلهای اعمال شده (مانند fill، stroke و غیره) در اثر باقی خواهند ماند.
تابع rotate مختصات را به میزان تعیین شده توسط پارامتر angle میچرخاند. این تابع با استفاده از push و pop قابل کنترل بیشتر است.
تابع scale اندازه مختصات را با گسترش یا تقلیل تغییر میدهد. اشیاء همیشه از مبدا نسبت به سیستم مختصات مقیاس میشوند. مقادیر مقیاس به عنوان درصدهای اعشاری مشخص میشوند. به عنوان مثال، فراخوانی تابع scale(2.0) ابعاد یک شکل را به نسبت 200٪ افزایش میدهد.
تبدیلها به هر چیزی که بعد از آن اتفاق میافتد اعمال میشود و فراخوانیهای متعاقب به تابع اثر را تجمع میدهند. به عنوان مثال، فراخوانی scale(2.0) و سپس scale(1.5) همان scale(3.0) است. این تابع با استفاده از push و pop قابل کنترل بیشتر است.
تابع translate مبدا مختصات را به اندازه x, y جابجا میکند. تبدیلها تجمعی هستند و بر روی هر چیزی که بعد از آن اتفاق میافتد اعمال میشوند و فراخوانیهای متعاقب به تابع اثر را تجمع میدهند. به عنوان مثال، فراخوانی translate(50, 0) و سپس translate(20, 0) همان translate(70, 0) است. اگر translate درون draw فراخوانی شود، تبدیل هنگام شروع مجدد حلقه بازنشانی میشود. این تابع با استفاده از push و pop قابل کنترل بیشتر است.
متغیر سیستمی keyIsPressed درست است اگر هر کلیدی فشرده شده باشد و غلط است اگر هیچ کلیدی فشرده نشده باشد.
تابع keyPressed یکبار در هر بار فشرده شدن یک کلید فراخوانی میشود. keyCode مربوط به کلیدی که فشرده شده است در متغیر keyCode ذخیره میشود. این تابع را خود برنامهنویس میتواند پیاده کند.
به دلیل چگونگی که سیستمهای عامل با تکرار کلیدها برخورد میکنند، نگه داشتن یک کلید ممکن است باعث چندین فراخوانی keyTyped (و همچنین keyReleased) شود. نرخ تکرار توسط سیستم عامل و تنظیمات هر کامپیوتر تعیین میشود.
ممکن است مرورگرها به رویدادهای مختلف کلیدی رفتارهای پیشفرض متفاوتی اضافه کرده باشند. برای جلوگیری از هر گونه رفتار پیشفرض برای این رویداد، "return false" را به انتهای متد اضافه کنید.
تابع keyReleased یکبار در هر بار رها شدن یک کلید فراخوانی میشود.
ممکن است مرورگرها به رویدادهای مختلف کلیدی رفتارهای پیشفرض متفاوتی اضافه کرده باشند. برای جلوگیری از هر گونه رفتار پیشفرض برای این رویداد، "return false" را به انتهای تابع اضافه کنید.
تابع keyTyped یکبار در هر بار فشرده شدن یک کلید، به جز کلیدهای عمل مانند Backspace، Delete، Ctrl، Shift و Alt، فراخوانی میشود.
ممکن است مرورگرها به رویدادهای مختلف کلیدی رفتارهای پیشفرض متفاوتی اضافه کرده باشند. برای جلوگیری از هر گونه رفتار پیشفرض برای این رویداد، "return false" را به انتهای تابع اضافه کنید.
تابع keyIsDown بررسی میکند که آیا کلید در حال حاضر پایین (فشرده) است یا نه.
تابع mousePressed یک بار پس از هر فشار دکمه موس فراخوانی میشود.
تابع mouseReleased هر بار که یک دکمه موس رها شده است، فراخوانی میشود. اگر هیچ تابع mouseReleased تعریف نشده باشد، تابع touchEnded به جای آن فراخوانی میشود.
تابع mouseClicked یک بار پس از فشردن و سپس رها کردن یک دکمه موس فراخوانی میشود.
تابع text متنی را در مکان مشخص شده در آرگومانها مینویسد.
تابع loadFont یک فونت را بارگذاری کرده و یک شیء p5.Font ایجاد میکند. loadFont میتواند فونتها را در فرمتهای .otf یا .ttf بارگذاری کند. فونتهای بارگذاری شده میتوانند برای استایل متن در canvas و در المانهای HTML استفاده شوند.
تابع textFont فونتی را که توسط تابع text استفاده میشود را تعیین میکند.
تابع loadImage یک تصویر را بارگذاری کرده و یک شیء p5.Image ایجاد میکند. تابع image یک تصویر منبع را روی canvas نمایش میدهد.
تابع tint تصاویر را با یک رنگ مشخص رنگ میکند. noTint هم این تاثیر را حدف میکند.
تابع loadPixels پیکسلهای تصویر را لود میکند و در متغیری داخل p5.Image قرار میدهد.