Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

Revision 640345 of Drawing graphics with canvas

  • 版本網址代稱: Web/HTML/Canvas/Drawing_graphics_with_canvas
  • 版本標題: Drawing graphics with canvas
  • 版本 ID: 640345
  • 建立日期:
  • 建立者: sailplaneTW
  • 是目前線上的版本?
  • 回應

版本內容

Most of this content (but not the documentation on drawWindow) has been rolled into the more expansive Canvas tutorial, this page should probably be redirected there as it's now redundant but some information may still be relevant.

介紹

  在 Firefox 1.5, Firefox 引入了新的 HTML 元素 <canvas> 來繪製圖形。<canvas> 是基於 WHATWG canvas specification 的技術 (其發軔於蘋果公司在 Safari 上的實做)。 我們可以用它來在使用者端進行圖形和 UI 元件的渲染。

  <canvas> 創建了一個具有一致多個 rendering contexts 的區域。在本文中,我們著重於 2D rendering context 的部份。對於 3D 圖形,您可以參考 WebGL rendering context

2D Rendering Context

先來個簡單的範例

  以下的程式碼做了一個簡單的展示:繪製兩個部份交疊的矩形 (其中一個矩形有透明屬性) :

function draw() {
  var ctx = document.getElementById('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);
}

{{EmbedLiveSample('A_Simple_Example','150','150','/@api/deki/files/602/=Canvas_ex1.png')}}

  這個名為 draw 的函式從 canvas element 取得 2d context。物件 ctx 可以被用來在 canvas 上頭繪製圖形。從程式碼可以看出,我們簡單的藉由設定 fillStyle 繪製了兩個顏色不同的矩形,並透過 fillRect 設定其位置。此外,第二個矩形透過 rgba() 配置了透明屬性。

The fillRect, strokeRect, and clearRect calls render a filled, outlined, or clear rectangle. To render more complex shapes, paths are used.

使用路徑

The beginPath function starts a new path, and moveTo, lineTo, arcTo, arc, and similar methods are used to add segments to the path. The path can be closed using closePath. Once a path is created, you can use fill or stroke to render the path to the canvas.

function draw() {
  var ctx = document.getElementById('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();
}

{{EmbedLiveSample('Using_Paths','190','190','/@api/deki/files/603/=Canvas_ex2.png')}}

Calling fill() or stroke() causes the current path to be used. To be filled or stroked again, the path must be recreated.

圖像狀態

Attributes of the context such as fillStyle, strokeStyle, lineWidth, and lineJoin are part of the current graphics state. The context provides two methods, save() and restore(), that can be used to move the current state to and from the state stack.

一個更為複雜的範例

Here's a little more complicated example, that uses paths, state, and also introduces the current transformation matrix. The context methods translate(), scale(), and rotate() all transform the current matrix. All rendered points are first transformed by this matrix.

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 ctx = document.getElementById('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();
}

{{EmbedLiveSample('A_More_Complicated_Example','215','215','/@api/deki/files/604/=Canvas_ex3.png')}}

This defines two methods, drawBowtie and dot, that are called 4 times. Before each call, translate() and rotate() are used to set up the current transformation matrix, which in turn positions the dot and the bowtie. dot renders a small black square centered at (0, 0). That dot is moved around by the transformation matrix. drawBowtie renders a simple bowtie path using the passed-in fill style.

As matrix operations are cumulative, save() and restore() are used around each set of calls to restore the original canvas state. One thing to watch out for is that rotation always occurs around the current origin; thus a translate() rotate() translate() sequence will yield different results than a translate() translate() rotate() series of calls.

和 Apple <canvas> 的相容性

For the most part, <canvas> is compatible with Apple's and other implementations. There are, however, a few issues to be aware of, described here.

</canvas> tag 是必要的

In the Apple Safari implementation, <canvas> is an element implemented in much the same way <img> is; it does not have an end tag. However, for <canvas> to have widespread use on the web, some facility for fallback content must be provided. Therefore, Mozilla's implementation has a required end tag.

If fallback content is not needed, a simple <canvas id="foo" ...></canvas> will be fully compatible with both Safari and Mozilla -- Safari will simply ignore the end tag.

If fallback content is desired, some CSS tricks must be employed to mask the fallback content from Safari (which should render just the canvas), and also to mask the CSS tricks themselves from IE (which should render the fallback content).

canvas {
  font-size: 0.00001px !ie;
}

其他特性

藉由 Canvas 渲染網頁內容

This feature is only available for code running with Chrome privileges. It is not allowed in normal HTML pages. Read why.

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)");

would draw the contents of the current window, in the rectangle (0,0,100,200) in pixels relative to the top-left of the viewport, on a white background, into the canvas. By specifying "rgba(255,255,255,0)" as the color, the contents would be drawn with a transparent background (which would be slower).

It is usually a bad idea to use any background other than pure white "rgb(255,255,255)" or transparent, as this is what all browsers do, and many websites expect that transparent parts of their interface will be drawn on white background.

With this method, it is possible to fill a hidden IFRAME with arbitrary content (e.g., CSS-styled HTML text, or SVG) and draw it into a canvas. It will be scaled, rotated and so on according to the current transformation.

Ted Mielczarek's tab preview extension uses this technique in chrome to provide thumbnails of web pages, and the source is available for reference.

Note: Using canvas.drawWindow() while handling a document's onload event doesn't work. In Firefox 3.5 or later, you can do this in a handler for the MozAfterPaint event to successfully draw HTML content into a canvas on page load.

更多資訊

版本來源

<div class="note">
 <p>Most of this content (but not the documentation on drawWindow) has been rolled into the more expansive <a href="/en-US/docs/HTML/Canvas/Tutorial" title="HTML/Canvas/tutorial">Canvas tutorial</a>, this page should probably be redirected there as it's now redundant but some information may still be relevant.</p>
</div>
<h2 id="Introduction" name="Introduction">介紹</h2>
<p>&nbsp; 在&nbsp;<a href="/en-US/docs/Mozilla/Firefox/Releases/1.5" title="Firefox_1.5_for_developers">Firefox 1.5</a>, Firefox 引入了新的 HTML 元素 &lt;canvas&gt; 來繪製圖形。<code>&lt;canvas&gt;</code>&nbsp;是基於&nbsp;<a href="https://www.whatwg.org/specs/web-apps/current-work/#the-canvas">WHATWG canvas specification</a>&nbsp;的技術 (其發軔於蘋果公司在&nbsp;Safari 上的實做)。 我們可以用它來在使用者端進行圖形和 UI 元件的渲染。</p>
<p><code>&nbsp; &lt;canvas&gt;</code>&nbsp;創建了一個具有一致多個&nbsp;<em>rendering contexts 的</em>區域。在本文中,我們著重於&nbsp;2D rendering context 的部份。對於 3D 圖形,您可以參考&nbsp;<a href="/en-US/docs/WebGL" title="https://developer.mozilla.org/en/WebGL">WebGL rendering context</a>。</p>
<h2 id="The_2D_Rendering_Context" name="The_2D_Rendering_Context">2D Rendering Context</h2>
<h3 id="A_Simple_Example" name="A_Simple_Example">先來個簡單的範例</h3>
<p>&nbsp; 以下的程式碼做了一個簡單的展示:繪製兩個部份交疊的矩形 (其中一個矩形有透明屬性) :</p>
<pre class="brush: js">
function draw() {
  var ctx = document.getElementById('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);
}
</pre>
<div class="hidden">
 <pre class="brush: html">
&lt;canvas id="canvas" width="120" height="120"&gt;&lt;/canvas&gt;</pre>
 <pre class="brush: js">
draw();</pre>
</div>
<p>{{EmbedLiveSample('A_Simple_Example','150','150','/@api/deki/files/602/=Canvas_ex1.png')}}</p>
<p>&nbsp; 這個名為&nbsp;<code>draw</code>&nbsp;的函式從&nbsp;<code>canvas</code> element 取得&nbsp;<code>2d</code> context。物件&nbsp;<code>ctx</code>&nbsp;可以被用來在 canvas 上頭繪製圖形。從程式碼可以看出,我們簡單的藉由設定 fillStyle 繪製了兩個顏色不同的矩形,並透過 <code>fillRect 設定其位置。此外,第二個矩形透過</code>&nbsp;<code>rgba()</code>&nbsp;配置了透明屬性。</p>
<p>The <code>fillRect</code>, <code>strokeRect</code>, and <code>clearRect</code> calls render a filled, outlined, or clear rectangle. To render more complex shapes, paths are used.</p>
<h3 id="Using_Paths" name="Using_Paths">使用路徑</h3>
<p>The <code>beginPath</code> function starts a new path, and <code>moveTo</code>, <code>lineTo</code>, <code>arcTo</code>, <code>arc</code>, and similar methods are used to add segments to the path. The path can be closed using <code>closePath</code>. Once a path is created, you can use <code>fill</code> or <code>stroke</code> to render the path to the canvas.</p>
<pre class="brush: js">
function draw() {
  var ctx = document.getElementById('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); // &lt;- this is right formula for the image on the right -&gt;
  ctx.lineTo(30, 30);
  ctx.fill();
}
</pre>
<div class="hidden">
 <pre class="brush: html">
&lt;canvas id="canvas" width="160" height="160"&gt;&lt;/canvas&gt;</pre>
 <pre class="brush: js">
draw();</pre>
</div>
<p>{{EmbedLiveSample('Using_Paths','190','190','/@api/deki/files/603/=Canvas_ex2.png')}}</p>
<p>Calling <code>fill()</code> or <code>stroke()</code> causes the current path to be used. To be filled or stroked again, the path must be recreated.</p>
<h3 id="Graphics_State" name="Graphics_State">圖像狀態</h3>
<p>Attributes of the context such as <code>fillStyle</code>, <code>strokeStyle</code>, <code>lineWidth</code>, and <code>lineJoin</code> are part of the current <em>graphics state</em>. The context provides two methods, <code>save()</code> and <code>restore()</code>, that can be used to move the current state to and from the state stack.</p>
<h3 id="A_More_Complicated_Example" name="A_More_Complicated_Example">一個更為複雜的範例</h3>
<p>Here's a little more complicated example, that uses paths, state, and also introduces the current transformation matrix. The context methods <code>translate()</code>, <code>scale()</code>, and <code>rotate()</code> all transform the current matrix. All rendered points are first transformed by this matrix.</p>
<pre class="brush: js">
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 ctx = document.getElementById('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();
}
</pre>
<div class="hidden">
 <pre class="brush: html">
&lt;canvas id="canvas" width="185" height="185"&gt;&lt;/canvas&gt;</pre>
 <pre class="brush: js">
draw();</pre>
</div>
<p>{{EmbedLiveSample('A_More_Complicated_Example','215','215','/@api/deki/files/604/=Canvas_ex3.png')}}</p>
<p>This defines two methods, <code>drawBowtie</code> and <code>dot</code>, that are called 4 times. Before each call, <code>translate()</code> and <code>rotate()</code> are used to set up the current transformation matrix, which in turn positions the dot and the bowtie. <code>dot</code> renders a small black square centered at <code>(0, 0)</code>. That dot is moved around by the transformation matrix. <code>drawBowtie</code> renders a simple bowtie path using the passed-in fill style.</p>
<p>As matrix operations are cumulative, <code>save()</code> and <code>restore()</code> are used around each set of calls to restore the original canvas state. One thing to watch out for is that rotation always occurs around the current origin; thus a <code>translate() rotate() translate()</code> sequence will yield different results than a <code>translate() translate() rotate()</code> series of calls.</p>
<h2 id="Compatibility_With_Apple_.3Ccanvas.3E" name="Compatibility_With_Apple_.3Ccanvas.3E">和 Apple &lt;canvas&gt; 的相容性</h2>
<p>For the most part, <code>&lt;canvas&gt;</code> is compatible with Apple's and other implementations. There are, however, a few issues to be aware of, described here.</p>
<h3 id="Required_.3C.2Fcanvas.3E_tag" name="Required_.3C.2Fcanvas.3E_tag"><code>&lt;/canvas&gt;</code> tag 是必要的</h3>
<p>In the Apple Safari implementation, <code>&lt;canvas&gt;</code> is an element implemented in much the same way <code>&lt;img&gt;</code> is; it does not have an end tag. However, for <code>&lt;canvas&gt;</code> to have widespread use on the web, some facility for fallback content must be provided. Therefore, Mozilla's implementation has a <em>required</em> end tag.</p>
<p>If fallback content is not needed, a simple <code>&lt;canvas id="foo" ...&gt;&lt;/canvas&gt;</code> will be fully compatible with both Safari and Mozilla -- Safari will simply ignore the end tag.</p>
<p>If fallback content is desired, some CSS tricks must be employed to mask the fallback content from Safari (which should render just the canvas), and also to mask the CSS tricks themselves from IE (which should render the fallback content).</p>
<pre>
canvas {
  font-size: 0.00001px !ie;
}</pre>
<h2 id="Additional_Features" name="Additional_Features">其他特性</h2>
<h3 id="Rendering_Web_Content_Into_A_Canvas" name="Rendering_Web_Content_Into_A_Canvas">藉由 Canvas 渲染網頁內容</h3>
<div class="note">
 This feature is only available for code running with Chrome privileges. It is not allowed in normal HTML pages. <a href="https://mxr.mozilla.org/mozilla/source/content/canvas/src/nsCanvasRenderingContext2D.cpp#2352" title="https://mxr.mozilla.org/mozilla/source/content/canvas/src/nsCanvasRenderingContext2D.cpp#2352">Read why</a>.</div>
<p>Mozilla's <code>canvas</code> is extended with the <a href="/en-US/docs/DOM/CanvasRenderingContext2D#drawWindow()" title="DOM/CanvasRenderingContext2D#drawWindow()"><code>drawWindow()</code></a> method. This method draws a snapshot of the contents of a DOM <code>window</code> into the canvas. For example,</p>
<pre class="brush: js">
ctx.drawWindow(window, 0, 0, 100, 200, "rgb(255,255,255)");
</pre>
<p>would draw the contents of the current window, in the rectangle (0,0,100,200) in pixels relative to the top-left of the viewport, on a white background, into the canvas. By specifying "rgba(255,255,255,0)" as the color, the contents would be drawn with a transparent background (which would be slower).</p>
<p>It is usually a bad idea to use any background other than pure white "rgb(255,255,255)" or transparent, as this is what all browsers do, and many websites expect that transparent parts of their interface will be drawn on white background.</p>
<p>With this method, it is possible to fill a hidden IFRAME with arbitrary content (e.g., CSS-styled HTML text, or SVG) and draw it into a canvas. It will be scaled, rotated and so on according to the current transformation.</p>
<p>Ted Mielczarek's <a href="https://ted.mielczarek.org/code/mozilla/tabpreview/">tab preview</a> extension uses this technique in chrome to provide thumbnails of web pages, and the source is available for reference.</p>
<div class="note">
 <strong>Note:</strong> Using <code>canvas.drawWindow()</code> while handling a document's <code>onload</code> event doesn't work. In Firefox 3.5 or later, you can do this in a handler for the <a href="/en-US/docs/Gecko-Specific_DOM_Events#MozAfterPaint" title="Gecko-Specific DOM Events#MozAfterPaint"><code>MozAfterPaint</code></a> event to successfully draw HTML content into a canvas on page load.</div>
<h2 id="See_also" name="See_also">更多資訊</h2>
<ul>
 <li><a href="/en-US/docs/HTML/Canvas" title="HTML/Canvas">Canvas topic page</a></li>
 <li><a href="/en-US/docs/Canvas_tutorial" title="Canvas_tutorial">Canvas tutorial</a></li>
 <li><a href="https://www.whatwg.org/specs/web-apps/current-work/#the-canvas">WHATWG specification</a></li>
 <li><a href="https://developer.apple.com/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Tasks/Canvas.html" title="https://developer.apple.com/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Tasks/Canvas.html">Apple Canvas Documentation</a></li>
 <li><a href="https://weblogs.mozillazine.org/roc/archives/2005/05/rendering_web_p.html">Rendering Web Page Thumbnails</a></li>
 <li>Some <a href="/en-US/docs/tag/canvas_examples">examples</a>:
  <ul>
   <li><a href="https://azarask.in/projects/algorithm-ink">Algorithm Ink</a></li>
   <li><a href="https://www.tapper-ware.net/canvas3d/">OBJ format 3D Renderer</a></li>
   <li><a href="/en-US/docs/A_Basic_RayCaster" title="A_Basic_RayCaster">A Basic RayCaster</a></li>
   <li><a href="https://awordlike.textdriven.com/">The Lightweight Visual Thesaurus</a></li>
   <li><a href="https://caimansys.com/painter/">Canvas Painter</a></li>
  </ul>
 </li>
 <li><a href="/en-US/docs/tag/canvas">And more...</a></li>
</ul>
還原至此版本