• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

canvas 绘图

武飞扬头像
lcy668
帮助2

1. 前端中可用的绘画技术

  1. canvas: 专用于绘制 2D 图形 / 图像
  2. SVG: 专用于绘制矢量图
  3. WebGL: 目前不是 HTML5 标准技术, 功能强大, 3D 图像 / 图形

2. 定义与语法

H5 新增的 canvas 元素用于在网页中实现任意的绘图操作; canvas 默认是一个 300 * 150 的 inline-block

  • 每个 canvas 元素上有且只有一根 "画笔" 对象 -> 绘图上下文对象
<canvas id="canvasTest" width="500" height="400">
	你的浏览器不支持 canvas 标签
</canvas>

3. canvas 基本方法

  • var ctx = canvasTest.getContext('2d'): 获取画布上画笔对象
  • console.dir(ctx): 查看画笔对象的相关属性和方法成员
  • ctx.fillStyle='#f00': 填充绘画的颜色, 渐变或模式
  • ctx.strokeStyle='#000': 填充笔触( 描边 )的颜色, 渐变或模式
  • ctx.lineWidth = 1: 描边 / 线条的宽度
  • ctx.font = '10px sans-serif': 绘制文本所用字号 / 字体
  • ctx.textBaseline = 'alphabetic': 设置文本对齐的基线
  • ctx.shadowOffsetX= 0: 设置阴影水平偏移量
  • ctx.shadowOffsetY= 0: 设置阴影垂直偏移量
  • ctx.shadowColor: ' rgba(0, 0, 0, 0)': 设置阴影颜色及透明度
  • ctx.shadowBlur: 0: 设置阴影模糊半径
  • ctx.clearRect(x, y, w, h): 清除一个矩形范围内的所有内容
3.1. canvas 的尺寸如何设置
  • canvas 画布的尺寸若用 css 指定, 其实并未修改真正的尺寸, 而是进行"拉伸" -> canvas 尺寸不能用 css 指定
    • 可以使用 HTML 元素的属性 / JS 对象属性来指定
3.2. canvas 绘图填充渐变 / canvas 绘图笔触( 描边 ) 渐变
<canvas id="canvasTest" width="500" height="400">
	你的浏览器不支持 canvas 标签
</canvas>
<script type="text/javascript">
	let canvasTest = document.getElementById('canvasTest')
    let ctx = canvasTest.getContext('2d')
    let g = ctx.createLinearGradient(x1, y1, x2, y2) // 这里是线性渐变, 径向渐变使用 createRadialGradient(x1, y1, r1, x2, y2, r2)
    g.addColorStop(offset, color) // offset: 浮点值, 设置颜色的位置(0.0 表示画布的原点位置,  1.0 表示 画布的终点位置) color: 设置渐变颜色
    g.addColorStop(offset1, color1) // 径向渐变 和 线性渐变一样
    ctx.fillStyle = g // 将渐变用作填充
    ctx.strokeStyle = g // 将渐变用作笔触( 描边 )
    ctx.fillRect(x, y, w, h) // 用渐变填充矩形
    ctx.strokeRect(x, y, w, h) // 用渐变描边一个矩形
</script>

4. 使用 canvas 的画笔绘制矩形

  • 矩形定位点在左上角: 左上角的坐标为 0, 0
  • ctx.fillStyle = '#000': 填充颜色
  • ctx.strokeStyle = '#000: 描边颜色
  • ctx.fillRect(x, y, w, h): 填充一个矩形
  • ctx.strokeRect(x, y, w, h): 描边一个矩形
  • ctx.clearRect(x, y, w, h): 清除一个矩形范围内的所有内容
  • Ex:
    <style>
      body{
        text-align: center;
      }
      canvas{
        background: #ddd;
      }
    </style>
    <canvas id="canvasTest">
    	你的浏览器不支持 canvas 标签
    </canvas>
    <script type="text/javascript">
    	let canvasTest = document.getElementById('canvasTest')
    	canvasTest.width = 500
    	canvasTest.height = 400
    	let ctx = canvasTest.getContext('2d')
    	// 填充一个淡绿色背景
    	ctx.fillStyle = '#AFA'
    	ctx.fillRect(0, 0, 250, 200)
    </script>
    
4.1. canvas 绘图实现动画
  • 原理: 使用周期性定时器执行"清除画布内容, 再重新绘制内容"

  • Ex:

    <style>
      body{
        text-align: center;
      }
      canvas{
        background: #ddd;
      }
    </style>
    <canvas id="canvasTest">
    	你的浏览器不支持 canvas 标签
    </canvas>
    <script type="text/javascript">
    	let canvasTest = document.getElementById('canvasTest')
    	canvasTest.width = 500
    	canvasTest.height = 400
    	let ctx = canvasTest.getContext('2d')
    	let x = 0
    	let xDirection = 1
    	let y = 0
    	// 定时器: 动画引擎
    	let canvasAnimation = null
    	clearInterval(canvasAnimation)
    	canvasAnimation = setInterval(function () {
    		// 清除已有内容
    		ctx.clearRect(0, 0 , 500, 400)
    		// 绘制新的内容
    		ctx.strokeRect(x, y, 100, 80)
    		x  = 10 * xDirection
        	if (x >= 400) {
    			xDirection = -1
    		} else if (x <= 0) {
    			xDirection = 1
    		}
    	}, 50)
    </script>
    

5. 使用 canvas 画笔绘制文本

  • canvas 绘制文本的定位点(0, 0) 在文本基线的起点 学新通
  • ctx.font = '10px sans-serif': 设置文本的大小及字体
  • ctx.textBaseline = 'alphabetic': 设置文本基线, 可取值: top / bottom / middle / alphabetic
  • ctx.fillText(txt, x, y): 填充文本
  • ctx.strokeText(txt, x, y): 描边文本
  • ctx.measureText(txt).width: 测量, 根据当前指定的字号和字体计算指定文本宽度
  • Ex:
    <style>
      body{
        text-align: center;
      }
      canvas{
        background: #ddd;
      }
    </style>
    <canvas id="canvasTest">
    	你的浏览器不支持 canvas 标签
    </canvas>
    <script type="text/javascript">
    	let canvasTest = document.getElementById('canvasTest')
    	canvasTest.width = 500
    	canvasTest.height = 400
    	let ctx = canvasTest.getContext('2d')
    	let txt = 'abgyj中国人' 
    	ctx.font = '16px SimHei'
    	ctx.textBaseline = 'top'
    	ctx.fillText(txt, 0, 0)
    	ctx.strokeText(txt, 200, 100)
    	console.log(ctx.measureText(txt))
    </script>
    
5.1. 为图形文字添加阴影
  • ctx.shadowColor = '#666': 设置阴影的颜色

  • ctx.shadowOffsetX = 8: 设置阴影水平偏移量

  • ctx.shadowOffsetY = 8: 设置阴影垂直偏移量

  • ctx.shadowBlur = 10: 设置阴影模糊半径

  • Ex:

    <style>
      body{
        text-align: center;
      }
      canvas{
        background: #ddd;
      }
    </style>
    <canvas id="canvasTest">
    	你的浏览器不支持 canvas 标签
    </canvas>
    <script type="text/javascript">
    	let canvasTest = document.getElementById('canvasTest')
    	canvasTest.width = 500
    	canvasTest.height = 400
    	let ctx = canvasTest.getContext('2d')
    	ctx.textBaseline = 'top'
    	ctx.font = '80px SimHei'
    	let txt = 'lcy'
    	ctx.fillText(txt, 100, 100)
    	ctx.shadowColor = '#666'
    	ctx.shadowOffsetX = 8
    	ctx.shadowOffsetY = 8
    	ctx.shadowBlur = 10
    	ctx.fillText(txt, 100, 200)
    </script>
    

6. 使用 canvas 绘制路径

  • path: 路径, 类似于 Photoshop 中的钢笔工具, 路径本身不可见, 可用于: 描边, 填充, 选区裁剪
  • ctx.beginPath(): 开始绘制一条新路径
  • ctx.clostPath(): 闭合路径
  • ctx.moveTo(x, y): 移动到某一点
  • ctx.lineTo(x, y): 从当前点到指定点绘制直线
  • ctx.arc(cx, cy, r, start, end): 绘制圆形 / 圆弧路径
  • ctx.ellipse(cx, cy, rx, ry, start, end): 绘制椭圆路径
  • ctx.bezierCurveTo(): 绘制贝塞尔曲线路径
  • ctx.stroke(): 使用当前路径描边
  • ctx.fill(): 使用当前路径进行填充
  • ctx.clip(): 使用当前路径进行裁剪
  • Ex:
    <style>
      body{
        text-align: center;
      }
      canvas{
        background: #ddd;
      }
    </style>
    <canvas id="canvasTest">
    	你的浏览器不支持 canvas 标签
    </canvas>
    <script type="text/javascript">
    	let canvasTest = document.getElementById('canvasTest')
    	canvasTest.width = 500
        canvasTest.height = 400
    	let ctx = canvasTest.getContext('2d')
    	// 绘制灰色的背景圆环
    	ctx.beginPath()
    	ctx.arc(250, 200, 100, 0, 2*Math.PI)
    	ctx.lineWidth = 20
    	ctx.strokeStyle = '#AAA'
    	ctx.stroke()
    	// 绘制圆形的进度条
    	let start = -90
    	let end = -90
    	let timer = setInterval(function () {
    		ctx.beginPath()
    		ctx.arc(250, 200, 100, start * Math.PI / 180, end * Math.PI / 180)
    		ctx.strokeStyle = '#0A0'
    		ctx.stroke()
        
        	end  = 3
    		if (end > 270) {
    			clearInterval(timer)
    		}
    	}, 50)
    </script>
    

7. 使用 canvas 绘制图像

  • 绘制图像时, 客户端必须等待图片异步加载完成
<canvas id="canvasTest" width="500" height="400">
	您的浏览器不支持 canvas
</canvas>
<script type="text/javascript">
	let canvasTest = document.getElementById('canvasTest')
    let ctx = canvasTest.getContext('2d')
    let img = new Image()
    img.src = 'xxx.png' // 客户端会自动异步下载此图片
    console.log(img.width) // 0
    // 图片加载完成事件
    img.onload = function () {
      console.log(img.width) // 有值
      ctx.drawImage(img, x, y) // 原尺寸绘图
      ctx.drawImage(img, x, y, w, h) // 缩放绘图
    }
</script>

8. 使用 canvas 绘制变形后的图形 / 图像

  • CSS 中有变形的属性: transform: rotate / translate / scale / skew, 这些变形属性只能用于特定的 HTML DOM 元素
  • canvas 绘图只有一个元素: <canvas></canvas>, 若想仅仅让其中的某个图形 / 图像变形, 不能使用 css 变形属性
8.1. 绘图上下文提供了专用的变形方法
  • ctx.rotate(旋转的弧度): 让画笔旋转指定的弧度

    1. 画笔的旋转轴为画笔的坐标原点
    2. 画笔的旋转具有累加效果
    3. 若想让绘图内容绕着其他点旋转, 必须平移画布的坐标原点
  • ctx.translate(x, y): 平移画笔的坐标原点

    • 注意: 画笔原点平移, 其上所有点的坐标值都发生了变化

  • ctx.scale(): 画笔缩放

  • ctx.save(): 保存当前画笔的变形状态

  • ctx.restore(): 恢复画笔变形状态到最近一次保存的值

  • Ex: 绘制绕自己为中心旋转的小飞机

    <style>
      body{
        text-align: center;
      }
      canvas{
        background: #ddd;
      }
    </style>
    <canvas id="canvasTest">
    	你的浏览器不支持 canvas 标签
    </canvas>
    <script type="text/javascript">
    	let canvasTest = document.getElementById('canvasTest')
    	canvasTest.width = 500
    	canvasTest.height = 400
    	let ctx = canvasTest.getContext('2d')
    	let img = new Image()
    	img.src = 'img/fly.png'
    	img.onload = function () {
    		let degOne = 0 // 飞机1 旋转的角度
    		let degThree = 0 // 飞机3 旋转的角度
    		setInterval(function () {
    			// 绘制飞机1
    			ctx.sava() // 保存画笔当前的变形状态
    			// 平移 -> 选装 -> 绘图 -> 逆向选装 -> 逆向平移
          	  ctx.translate(img.width / 2, img.height / 2)
    			ctx.rotate(degOne * Math.PI / 180)
    			ctx.drawImage(img, -img.width / 2, -img.height / 2)
    			ctx.restore() // 恢复画笔最近的变形状态
    			degOne  = 5
    			// 绘制飞机2
    			ctx.drawImage(img, 500 - img.width, 0)
    			// 绘制飞机3
    			// 平移 -> 选装 -> 绘图 -> 逆向选装 -> 逆向平移
    			ctx.translate(img.width / 2, img.height / 2)
    			ctx.rotate(degThree * Math.PI / 180)
    			ctx.drawImage(img, -img.width / 2, -img.height / 2)
    			ctx.rotate(-degThree * Math.PI / 180)
    			ctx.translate(-img.width / 2, -(400 - img.height / 2))
    			degThree  = 10
    		}, 20)
    	}
    </script>
    
  • Ex: 绘制验证码

    <style>
      body{
        text-align: center;
      }
      canvas{
        background: #ddd;
      }
    </style>
    <canvas id="canvasTest">
    	你的浏览器不支持 canvas 标签
    </canvas>
    <script type="text/javascript">
    	let canvasTest = document.getElementById('canvasTest')
    	let cw = 120
    	let ch = 30
    	canvasTest.width = cw
    	canvasTest.height = ch
    	let ctx = canvasTest.getContext('2d')
    	/* 1. 绘制背景颜色 -- 填充矩形 */ 
    	ctx.fillStyle = randomColor(150, 230)
    	ctx.fillRect(0, 0, cw, ch)
        /* 2. 循环绘制 4 个随机字符 */
    	ctx.textBaseline = 'top'
    	let pool = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789'
    	for (let i = 0; i < 4; i  ) {
    		let randomString = pool[randomNum(0, pool.length)] // 随机一个字符
    		let fontSize = randomNum(10, 40) // 字体大小
        	ctx.font = `${fontSize}px SimHei`
    		let fontColor = randomNum(50, 150)
    		ctx.strokeStyle = fontColor
    		let deg = randomNum(-40, 45)
    		let x = -fontSize / 2 // 每个字符左上角的坐标
    		let y = -fontSize / 2
    		// 绘制一个字符: 保存状态 -> 平移 -> 旋转 -> 绘制 -> 恢复状态
    		ctx.save()
    		ctx.translate(30 * i   15, 15)
    		ctx.rotate(deg * Math.PI / 180)
    		ctx.strokeText(randomString, x, y)
    		ctx.restore()		
    	}
    	/* 3.绘制 5 条干扰线 -- 直线路径 */
     	 for(let i = 0; i < 5; i  ) {
    		ctx.beginPath()
        	ctx.moveTo(randomNum(0, cw), randomNum(0, ch))
        	ctx.lineTo(randomNum(0, cw), randomNum(0, ch))
        	ctx.strokeStyle = randomColor(0, 255)
       	 	ctx.stroke()
    	}
    	/* 4.绘制50个杂色点 -- 半径为 0.5 圆形路径 */
    	for(let i = 0; i < 50; i  ) {
    		ctx.beginPath()
    		ctx.arc(randomNum(0, cw), randomNum(0, ch), 0.5, 0, 2 * Math.PI)
    		ctx.strokeStyle = randomColor(0, 255)
    		ctx.fill()
    	}
        // random number, 返回指定范围内的随机整数
    	function randomNum(min, max) {
    		return Math.floor(Math.random() * (max - min)   min)
    	}
    	// random color, 返回指定范围的随机颜色
    	function randomColor(min, max) {
    		let r = randomNum(min, max)
    		let g = randomNum(min, max)
    		let b = randomNum(min, max)
    		return `rgb(${r}, ${g}, ${b})`
    	}
    </script>
    

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhckeikh
系列文章
更多 icon
同类精品
更多 icon
继续加载