你的浏览器不支持canvas

Enjoy life!

canvas

Date: Author: JM

本文章采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。

  • 参考资料:《JavaScript高级程序设计(第3版)》 第 15 章 使用 Canvas 绘图

一、canvas基本用法

1.1 兼容性

canvas兼容

canvas-01

1.2 基本用法

要使用 <canvas> 元素,必须先设置其 widthheight 属性,指定可以绘图的区域大小。

出现在开始和结束标签中的内容是后备信息,如果浏览器不支持 <canvas> 元素,就会显示这些信息。

2D 上下文的坐标开始于 <canvas> 元素的左上角,原点坐标是(0,0)。

所有坐标值都基于这个原点计算,x 值越大表示越靠右,y 值越大表示越靠下。

默认情况下,widthheight 表示水平和垂直两个方向上可用的像素数目。

<canvas width="200" height="300" id="canvas">A drawing of something</canvas>
<script>
    // 获取 canvas 元素
    const canvas = document.getElementById('canvas')

    // 检测浏览器是否支持canvas元素
    if (canvas.getContext) {
      const ctx = canvas.getContext('2d')
      const canvasWidth = canvas.width
      const canvasHeight = canvas.height
      console.log(ctx)
      console.log(canvasWidth, canvasHeight) // 200 300
    }
</script>

ctx

canvas-02

canvas-03

二、2D 上下文

2.1 填充和描边

2D 上下文的两种基本绘图操作是填充和描边。

  • 填充 - 属性fillStyle :用指定的样式(颜色、渐变或图像)填充图形;
  • 描边 - 属性strokeStyle:只在图形的边缘画线。

这两个属性的值可以是字符串、渐变对象或模式对象,而且它们的默认值都是” #000000“。如果为 它们指定表示颜色的字符串值,可以使用 CSS 中指定颜色值的任何格式,包括颜色名、十六进制码、rgbrgbahslhsla

var drawing = document.getElementById("drawing");
//确定浏览器支持<canvas>元素
if (drawing.getContext){
 var context = drawing.getContext("2d");
 context.strokeStyle = "red";
 context.fillStyle = "#0000ff";
} 

所有涉及描边和填充的操作都将使用这两个样式,直至重新设置这两个值。

2.2 绘制矩形

矩形是唯一一种可以直接在 2D 上下文中绘制的形状。与矩形有关的方法包括三个方法:

  • fillRect(矩形的 x 坐标,矩形的 y 坐标,矩形宽度,矩形高度)
  • strokeRect(矩形的 x 坐标,矩形的 y 坐标,矩形宽度,矩形高度)
  • clearRect(矩形的 x 坐标,矩形的 y 坐标,矩形宽度,矩形高度)

  • demo
<canvas width="200" height="300" id="canvas">A drawing of something</canvas>
<script>
    // 获取 canvas 元素
    const canvas = document.getElementById('canvas')

    // 检测浏览器是否支持canvas元素
    if (canvas.getContext) {
      const ctx = canvas.getContext('2d')

      // 绘制红色矩形

      // 通过 fillStyle 属性填充颜色
      ctx.fillStyle = `#ff0000`
      ctx.fillRect(10, 10, 50, 50)

      // 绘制半透明的蓝色矩形

      // 修改填充色
      ctx.fillStyle = `rgba(0, 0, 255, 0.5)`
      ctx.fillRect(30, 30, 50, 50)
      
      // 在两个矩形重得的地方清除一个小矩形
      ctx.clearRect(40, 40, 10, 10)
      
      // 绘制红色描边矩形
      ctx.strokeStyle = `#ff0000`
      ctx.strokeRect(60, 60, 50, 50)
      
      //  绘制半透明的蓝色描边矩形
      ctx.strokeStyle = `rgba(0, 0, 255, 0.5)`
      ctx.strokeRect(80, 80, 50, 50)
    }
</script>

效果图如下:

canvas-04


补充:

  • lineWidth:描边线条的宽度由 lineWidth 属性控制,该属性的值可以是任意整数
  • lineCap:通过 lineCap 属性可以控制线条末端的形状是平头、圆头还是方头(”butt“、”round“或”square“)
  • lineJoin:通过 lineJoin 属性可以控制线条相交的方式是圆交、斜交还是斜接(”round“、”bevel“或”miter“)。

2.3 绘制路径

通过路径可以创造出复杂的形状和线条。 要绘制路径,首先必须调用 beginPath()方法,表示要开始绘制新路径。 然后,再通过调用下列方法来实际地绘制路径。

  • arc(x, y, radius, startAngle, endAngle, counterclockwise):以(x,y)为圆心绘 制一条弧线,弧线半径为 radius,起始和结束角度(用弧度表示)分别为 startAngleendAngle。最后一个参数表示 startAngleendAngle 是否按逆时针方向计算,值为 false 表示按顺时针方向计算。
  • arcTo(x1, y1, x2, y2, radius):从上一点开始绘制一条弧线,到(x2,y2)为止,并且以 给定的半径 radius 穿过(x1,y1)。
  • bezierCurveTo(c1x, c1y, c2x, c2y, x, y):从上一点开始绘制一条曲线,到(x,y)为 止,并且以(c1x,c1y)(c2x,c2y)为控制点。
  • lineTo(x, y):从上一点开始绘制一条直线,到(x,y)为止。
  • moveTo(x, y):将绘图游标移动到(x,y),不画线。
  • quadraticCurveTo(cx, cy, x, y):从上一点开始绘制一条二次曲线,到(x,y)为止,并且以(cx,cy)作为控制点。
  • rect(x, y, width, height):从点(x,y)开始绘制一个矩形,宽度和高度分别由widthheight 指定。这个方法绘制的是矩形路径,而不是 strokeRect()fillRect()所绘制的独立的形状。

创建了路径后,接下来有几种可能的选择。

  • 如果想绘制一条连接到路径起点的线条,可以调用 closePath()
  • 如果路径已经完成,你想用 fillStyle 填充它,可以调用 fill()方法。
  • 另外,还可以调用 stroke()方法对路径描边,描边使用的是 strokeStyle
  • 最后还可以调用clip(),这个方法可以在路径上创建一个剪切区域。

在 2D 绘图上下文中,路径是一种主要的绘图方式,因为路径能为要绘制的图形提供更多控制。由 于路径的使用很频繁,所以就有了一个名为 isPointInPath() 的方法。这个方法接收 x 和 y 坐标作为 参数,用于在路径被关闭之前确定画布上的某一点是否位于路径上

if (context.isPointInPath(100, 100)){
 alert("Point (100, 100) is in the path.");
} 

一直弄不懂,画时钟时,画内外圆的moveTo究竟是怎么样移动的,现在终于弄懂了,请看下图:

canvas-05


画时针和分针的时候,不同角度对 xy 都是有要求的:(x,y)的限制就是内圆;同时分针必须比时针要长

只有满足了下图的公式,才能保证所画的时针和分针在内圆内!

canvas-06


<canvas width="200" height="300" id="canvas">A drawing of something</canvas>
<script>
    // 获取 canvas 元素
    const canvas = document.getElementById('canvas')

    // 检测浏览器是否支持canvas元素
    if (canvas.getContext) {
      const ctx = canvas.getContext('2d')

      // 第一步:开始路径
      ctx.beginPath()

      // 绘制外圆
      ctx.arc(100, 150, 80, 0, 2 * Math.PI, false)

      // 移动绘图游标
      ctx.moveTo(170, 150)

      // 绘制内圆
      ctx.arc(100, 150, 70, 0, 2 * Math.PI, false)

      // 移动绘图游标
      ctx.moveTo(100, 150)
      // 分针
      ctx.lineTo(100, 90)

      // 移动绘图游标
      ctx.moveTo(100, 150)
      // 时针
      ctx.lineTo(80, 120)

      // 调用 stroke()方法才能把图形绘制到画布上
      ctx.stroke()
    }
</script>

2.4 绘制文本

绘制文本主要有两个方法:

  • fillText(要绘制的文本字符串, x 坐标, y 坐标, 可选的最大像素宽度):使用 fillStyle 属性绘制文本
  • strokeText(要绘制的文本字符串, x 坐标, y 坐标, 可选的最大像素宽度):使用 strokeStyle 属性为文本描边

而且,这两个方法都以下列 3 个属性为基础。

  • font:表示文本样式、大小及字体,用 CSS 中指定字体的格式来指定,例如”10px Arial”。
  • textAlign:表示文本对齐方式。可能的值有”start”、”end”、”left”、”right”和”center”。 建议使用”start”和”end”,不要使用”left”和”right”,因为前两者的意思更稳妥,能同时 适合从左到右和从右到左显示(阅读)的语言。
  • textBaseline:表示文本的基线。可能的值有”top“、”hanging“、”middle“、”alphabetic“、”ideographic“和”bottom“。

  • demo4
<canvas width="200" height="300" id="canvas">A drawing of something</canvas>
<script>
    // 获取 canvas 元素
    const canvas = document.getElementById('canvas')

    // 检测浏览器是否支持canvas元素
    if (canvas.getContext) {
      const ctx = canvas.getContext('2d')

      // 第一步:开始路径
      ctx.beginPath()

      // 绘制外圆
      ctx.arc(100, 150, 80, 0, 2 * Math.PI, false)

      // 移动绘图游标
      ctx.moveTo(170, 150)

      // 绘制内圆
      ctx.arc(100, 150, 70, 0, 2 * Math.PI, false)

      // 移动绘图游标
      ctx.moveTo(100, 150)
      // 分针
      ctx.lineTo(100, 100)

      // 移动绘图游标
      ctx.moveTo(100, 150)
      // 时针
      ctx.lineTo(80, 120)

      // 绘制文本
      ctx.strokeStyle = 'red'
      ctx.textAlign = 'center'
      ctx.strokeText('12', 100, 98)

      ctx.textAlign = 'start'
      ctx.strokeText('12', 100, 115)

      ctx.textAlign = 'end'
      ctx.strokeText('12', 100, 125)

      // 调用 stroke()方法才能把图形绘制到画布上
      ctx.strokeStyle = 'black'
      ctx.stroke()
    }
</script>

效果图如下:

canvas-07


measureText(要绘制的文本)

可把文本控制在某一区域中。返回一个 TextMetrics 对象。返回的对象目前只有一个 width 属性,但将来还会增加更多度量属性。

measureText() 方法利用 fonttextAligntextBaseline 的当前值计算指定文本的大小。 比如,假设你想在一个 140 像素宽的矩形区域中绘制文本 Hello world!,下面的代码从 100 像素的字体大小开始递减,最终会找到合适的字体大小。

<canvas width="200" height="300" id="canvas">A drawing of something</canvas>
<script>
    // 获取 canvas 元素
    const canvas = document.getElementById('canvas')

    // 检测浏览器是否支持canvas元素
    if (canvas.getContext) {
      const ctx = canvas.getContext('2d')

      // 第一步:开始路径
      ctx.beginPath()

      let fontSize = 100;
      ctx.font = fontSize + "px Arial";
      
      while(ctx.measureText("Hello world!").width > 140){
        fontSize--;
        ctx.font = fontSize + "px Arial";
      }

      console.log(fontSize) // 26

      ctx.fillText("Hello world!", 30, 30);
      ctx.fillText("Font size is " + fontSize + "px", 5, 80);
    }
</script>

前面提到过,fillText 和 strokeText()方法都可以接收第四个参数, 也就是文本的最大像素宽度。不过,这个可选的参数尚未得到所有浏览器支持 (最早支持它的是 Firefox 4)。提供这个参数后,调用 fillText()或 strokeText()时如果传入的字符串大于最大宽度,则绘制的文本字符的高度 正确,但宽度会收缩以适应最大宽度。


对于本文内容有问题或建议的小伙伴,欢迎在文章底部留言交流讨论。