Join MDN and developers like you at Mozilla's View Source conference, 12-14 September in Berlin, Germany. Learn more at https://viewsourceconf.org

رسم گرافیک با Canvas

بخش عمده‌ای از این مطلب (به جز مستندات drawWindow) به صفحه‌ی اصلی آموزش Canvas منتقل شده است، بنابراین این صفحه نیز به احتمال زیاد به آن قسمت منتقل می‌شود تا از ایجاد محتوای تکراری جلوگیری شود.

مقدمه

با انتشار فایرفاکس ۱.۵، عنصر جدیدی از HTML برای برنامه‌نویسی حالت گرافیکی در فایرفاکس به وجود آمد. <canvas> بر اساس مستندات WHATWG برای Canvas پیاده‌سازی شده است که خود این مستندات نیز بر پایه‌ی عنصر <canvas> در مرورگر سافاری از اپل ایجاد شده است. از آن می‌توان برای ترسیم نمودار، عنصرهای واسط کاربری و سایر عنصرهای گرافیکی در مرورگر استفاده کرد.

<canvas> با ایجاد یک سطح ترسیمی با اندازه‌ی ثابت سبب می‌شود که یک یا چند فضای گرافیکی به وجود بیایند. در این مقاله ما بر روی فضای گرافیکی ۲ بعدی تمرکز می‌کنیم. برای گرافیک ۳ بعدی، شما باید از فضای گرافیکی WebGL استفاده کنید.

فضای گرافیکی ۲ بعدی

یک نمونه‌ی ساده

برای شروع، با نمونه‌ای ساده که دو مستطیل با فضای مشترک شفاف مشخص شده‌اند، آغاز می‌کنیم:

Example 1.

<html>
 <head>
  <script type="application/javascript">
function draw() {
 var canvas = document.getElementById("canvas");
 var ctx = canvas.getContext("2d");

 ctx.fillStyle = "rgb(200,0,0)";
 ctx.fillRect (10, 10, 55, 50);

 ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
 ctx.fillRect (30, 30, 55, 50);
}
  </script>
 </head>
 <body onload="draw()">
   <canvas id="canvas" width="300" height="300"></canvas>
 </body>
</html>

تابع draw با دریافت عنصر canvas فضای ۲ بعدی آن را مشخص می‌کند. شی ctx می‌تواند برای رسم گرافیک روی بوم استفاده شود. در این کد، دو مستطیل با تنظیمات fillStyle و fiilRect با فضای مشترک شفاف رسم می‌شوند. fillStyle دوم از rgba برای مشخص کردن شفافیت با رنگ مورد نظر، استفاده می‌کند.

fillRect برای رسم مستطیل، strokeRect برای رسم حاشیه‌های مستطیل و clearRect برای پاک‌کردن مستطیل استفاده می‌شوند. برای ایجاد شکل‌های پیچیده‌تر، از مسیرها استفاده می‌شود.

استفاده از مسیرها

تابع beginPath یک مسیر جدید را آغاز می‌کند و متدهای moveTo, lineTo, arcTo, arc و از این قبیل، بخش‌های مختلفی را به مسیر تعریف‌شده اضافه می‌کنند. مسیر ایجاد شده توسط تابع closePath بسته می‌شود. زمانی که یک مسیر ایجاد شود، شما می‌توانید با fill یا stroke فضای داخل یا حاشیه‌ی مسیر را روی بوم رسم کنید.

Example 2.

<html>
 <head>
  <script type="application/javascript">
function draw() {
  var canvas = document.getElementById("canvas");
  var ctx = canvas.getContext("2d");

  ctx.fillStyle = "red";

  ctx.beginPath();
  ctx.moveTo(30, 30);
  ctx.lineTo(150, 150);
  // was: ctx.quadraticCurveTo(60, 70, 70, 150); which is wrong.
  ctx.bezierCurveTo(60, 70, 60, 70, 70, 150); // <- this is right formula for the image on the right ->
  ctx.lineTo(30, 30);
  ctx.fill();
}
   </script>
 </head>
 <body onload="draw()">
   <canvas id="canvas" width="300" height="300"></canvas>
 </body>
</html>

فراخوانی هر یک از توابع fill یا stroke، روی مسیر فعلی تاثیر می‌گذارد. اگر دوباره قصد رنگ‌آمیزی یا ایجاد حاشیه در مسیر را داشته باشیم باید مجدد آن را تعریف کنیم.

حالت گرافیکی

صفت‌های یک فضای گرافیکی مانند fillStyle, strokeStyle, lineWidth و lineJoin قسمتی از حالت گرافیکی فعلی هستند. فضای گرافیکی شامل دو متد save و restore است که می‌توانند برای انتقال حالت کنونی به مجموعه‌ی حالت‌ها یا از مجموعه‌ی حالت‌ها استفاده شوند.

یک نمونه‌ی پیچیده‌تر

در ادامه به نمونه‌ای پیچیده‌تر می‌پردازیم که شامل مسیرها، حالت، و همچنین ماتریس انتقال است. متدهای این فضا یعنی translate, scale و rotate برای انتقال ماتریس  به کار می‌روند که تمامی نقطه‌های ایجاد شده ابتدا توسط این ماتریس منتقل می‌شوند.

Example 3.

 <html>
  <head>
   <script type="application/javascript">
 function drawBowtie(ctx, fillStyle) {
 
   ctx.fillStyle = "rgba(200,200,200,0.3)";
   ctx.fillRect(-30, -30, 60, 60);
 
   ctx.fillStyle = fillStyle;
   ctx.globalAlpha = 1.0;
   ctx.beginPath();
   ctx.moveTo(25, 25);
   ctx.lineTo(-25, -25);
   ctx.lineTo(25, -25);
   ctx.lineTo(-25, 25);
   ctx.closePath();
   ctx.fill();
 }
 
 function dot(ctx) {
   ctx.save();
   ctx.fillStyle = "black";
   ctx.fillRect(-2, -2, 4, 4);
   ctx.restore();
 }
 
 function draw() {
   var canvas = document.getElementById("canvas");
   var ctx = canvas.getContext("2d");

   // note that all other translates are relative to this
   // one
   ctx.translate(45, 45);

   ctx.save();
   //ctx.translate(0, 0); // unnecessary
   drawBowtie(ctx, "red");
   dot(ctx);
   ctx.restore();
 
   ctx.save();
   ctx.translate(85, 0);
   ctx.rotate(45 * Math.PI / 180);
   drawBowtie(ctx, "green");
   dot(ctx);
   ctx.restore();
 
   ctx.save();
   ctx.translate(0, 85);
   ctx.rotate(135 * Math.PI / 180);
   drawBowtie(ctx, "blue");
   dot(ctx);
   ctx.restore();
 
   ctx.save();
   ctx.translate(85, 85);
   ctx.rotate(90 * Math.PI / 180);
   drawBowtie(ctx, "yellow");
   dot(ctx);
   ctx.restore();
 }
    </script>
  </head>
  <body onload="draw()">
    <canvas id="canvas" width="300" height="300"></canvas>
  </body>
 </html>

قطعه کد بالا دو متد drawBowtie و dot را که هر کدام ۴ مرتبه فراخوانی شده‌اند، دربرمی‌گیرد. قبل از هر فراخوانی، از متدهای translate و rotate برای ایجاد ماتریس انتقال استفاده می‌شود که به ترتیب نقطه و پاپیون را مکان‌دهی می‌کنند. dot یک مستطیل کوچک به مرکز (0, 0) و drawBowtie یک پاپیون کوچک را با استفاده از مسیرها و رنگ مورد نظر به وجود می‌آورد.

هر چه عملیات ماتریس انباشته‌تر می‌شوند، متدهای save و restore برای ذخیره‌سازی و بازگرداندن حالت گرافیکی استفاده می‌شوند. چیزی که باید به یاد داشت این است که چرخش همیشه در مسیر فعلی شکل می‌گیرد یعنی ترتیب translate() rotate() translate() به یک شکل و ترتیب translate() translate() rotate() به شکلی دیگر منجر می‌شوند.

سازگاری با عنصر <canvas> اپل

در اکثر موارد، <canvas> با نمونه‌ی پیاده‌سازی شده‌ی اپل سازگاری دارد. اگرچه چند مورد هستند که باید به آن‌ها توجه کرد.

برچسب پایانی مورد نیاز است

در پیاده‌سازی سافاری از اپل، <canvas> عنصری است که مشابه <img> پیاده‌سازی شده است، یعنی به برچسب پایانی نیازی ندارد. اگرچه، برای این‌که <canvas> به صورت گسترده در وب استفاده شود، برخی امکانات برای محتوای بازگشتی بایستی فراهم شوند. از این رو، پیاده‌سازی موزیلا از این عنصر، نیازمند استفاده از برچسب پایانی است.

اگر به محتوای بازگشتی نیازی نباشد، یک نمونه‌ی ساده مانند <canvas id="foo" ...></canvas> با هر دو پیاده‌سازی سافاری و موزیلا سازگاری دارد، با این تفاوت که سافاری برچسب پایانی را در نظر نمی‌گیرد.

اگر محتوای بازگشتی مورد استفاده قرار گیرد، بایستی از برخی تکنیک‌های CSS برای ایجاد آن در سافاری استفاده کرد و همچنین از برخی تکنیک‌ها برای فهماندن این مطلب به IE!

ویژگی‌های دیگر

فراهم‌کردن محتوای وب در داخل Canvas

این ویژگی تنها با مجوزهای مرورگر Chrome قابل اعمال است و در صفحه‌های HTML معمولی استفاده نمی‌شود. علت آن را بدانید.

پیاده‌سازی موزیلا از canvas با استفاده از متد drawWindow گسترش یافته است. این متد تصویری از یک صفحه‌ی DOM را در داخل canvas رسم می‌کند. برای نمونه:

Mozilla's canvas is extended with the drawWindow() method. This method draws a snapshot of the contents of a DOM window into the canvas. For example,

ctx.drawWindow(window, 0, 0, 100, 200, "rgb(255,255,255)");

قطعه‌کد بالا محتوای پنجره‌ی فعلی را در مستطیلی با ابعاد ذکر شده به پیکسل نسبت به گوشه‌ی بالا و چپ پنچره در یک پیش‌زمینه‌ی سفید از بوم، رسم می‌کند. با مشخص کردن "rgba(255,255,255,0)" به عنوان رنگ، محتوا با پیش‌زمینه‌ی شفاف رسم می‌شود.

معمولا استفاده از رنگ پیش‌زمینه‌ای به جز سفید "rgb(255,255,255)" یا شفاف کار درستی نیست چرا که تمامی مرورگرها از این استاندارد برای نمایش صفحات وب استفاده می‌کنند.

با این روش، ممکن است بتوان یک IFRAME پنهان با محتوای دلخواه (برای نمونه متنی که با CSS سبک‌دهی شده باشد یا SVG) را در یک بوم رسم کرد، که به این صورت می‌توان آن را مقیاس‌دهی کرد یا چرخاند یا هر عمل دیگری که با انتقال‌های فعلی می‌توان انجام داد.

Ted Mielczarek با افزونه‌ی tab preview خود در chrome این امکان را فراهم می‌کند تا بتوان تصویرهای کوچک از وب‌سایت‌ها را مشاهده کرد، و کد آن نیز در دسترس است.

یادداشت: استفاده از canvas.drawWindow() در داخل رخداد onload سند عمل نمی‌کند. در فایرفاکس ۳.۵ به بعد، می‌توان با استفاده از رخداد MozAfterPaint این حالت را در زمان بارگذاری صفحه پیاده‌سازی کرد.

See also

Document Tags and Contributors

 Contributors to this page: navid-emami
 Last updated by: navid-emami,