canvas这样使用

199 阅读4分钟

canvas是什么

<canvas> 元素可被用来通过 JavaScript(Canvas API 或 WebGL API)绘制图形及图形动画。

canvas绘制的是位图。

canvas绘制线段

使用HTMLCanvasElement.getContext()获得一个绘图上下文并开始绘制。

  • 效果图

image.png

  • 代码
    <canvas id="canvas" width="600" height="500"> 抱歉,您的浏览器不支持 canvas 元素
            (这些内容将会在不支持<canvas>元素的浏览器或是禁用了 JavaScript 的浏览器内渲染并展现)</canvas>
	const canvas = document.getElementById("canvas");
        // 使用HTMLCanvasElement.getContext()获得一个绘图上下文并开始绘制
        // HTMLCanvasElement.getContext() 方法返回canvas 的上下文,如果上下文没有定义则返回 null .
        // 在同一个 canvas 上以相同的 contextType 多次调用此方法只会返回同一个上下文。
        const ctx =canvas.getContext('2d');

        // 创建一个新的路径时
        ctx.beginPath();
        // 将一个新的子路径的起始点移动到 (x,y) 坐标的方法。
        ctx.moveTo(100, 100);
        // 使用直线连接子路径的终点到 x,y 坐标的方法(并不会真正地绘制)。
        ctx.lineTo(300, 300);
        ctx.lineTo(300, 100);
        ctx.lineWidth = 4;
        ctx.strokeStyle = 'blue';
        //  将笔点返回到当前子路径起始点的方法。它尝试从当前点到起始点绘制一条直线。如果图形已经是封闭的或者只有一个点,那么此方法不会做任何操作。
        ctx.closePath()
        // 根据当前的画线样式,绘制当前或已经存在的路径的方法。
        ctx.stroke();

canvas高清绘制操作

当物理设备的像素分辨率大于css像素的分辨率时,显示的会模糊,反之则会清晰。

代码实现:

		<canvas id="canvas" width="600" height="500"
			>您的浏览器当前不支持 canvas</canvas
		>
		const canvas = document.getElementById("canvas");
		// 使用HTMLCanvasElement.getContext()获得一个绘图上下文并开始绘制
		const ctx = canvas.getContext("2d");
		/**像素大小的比率*/
		const getPixelRatio = (context) => {
			// 当前显示设备的物理像素分辨率与CSS 像素分辨率之比
			return window.devicePixelRatio || 1;
		};

		/* 
                    01 放大 canvas 
                    02 再在 css 里将宽高设置为原来的大小 
                    03 考虑到内容的缩放,因此也需将 ctx 缩放
                */
		// 像素大小的比率
		const ratio = getPixelRatio();
		// 绘制区域的宽
		const oldWidth = canvas.width;
		// 绘制区域的高
		const oldHeight = canvas.height;
                // 设置当前像素比下,绘制区域的大小
		canvas.width = canvas.width * ratio;
		canvas.height = canvas.height * ratio;
                // 设置canvas大小
		canvas.style.width = oldWidth + "px";
		canvas.style.height = oldHeight + "px";

                // 为 canvas 单位添加缩放变换
                ctx.scale(ratio, ratio)
		// 创建一个新的路径时
		ctx.beginPath();
		// 线段宽度
		ctx.lineWidth = 10;
		// 线段颜色
		ctx.strokeStyle = "red";
		// 将一个新的子路径的起始点移动到 (x,y) 坐标
		ctx.moveTo(100, 100);
		ctx.lineTo(300, 300);
		ctx.lineTo(500, 100);
		ctx.stroke(); // 绘制一条路径
		ctx.closePath();

图示

  • 未考虑设备像素比: image.png

  • 考虑设备像素比,更为清晰 image.png

canvas画坐标系

效果 image.png 代码

<canvas id="canvas" width="600" height="400"
			>抱歉,您的浏览器不支持 canvas 元素
            (这些内容将会在不支持<canvas>元素的浏览器或是禁用了 JavaScript 的浏览器内渲染并展现)</canvas
		>
        const canvas=document.querySelector('#canvas')
        // 使用HTMLCanvasElement.getContext()获得一个绘图上下文并开始绘制
        const ctx=canvas.getContext('2d')
        console.log(ctx);
        // 设置canvas大小
        canvas.style.width = canvas.width + 'px'
        canvas.style.height = canvas.height + 'px'
        // 设置canvas绘制区域大小
        canvas.width = canvas.width * 1.5
        canvas.height = canvas.height * 1.5
        // 获取canvas元素宽高
        const ht = canvas.clientHeight
        const wd = canvas.clientWidth
        const pad = 20
        const bottomPad = 20
        const step = 100

        const drawAxis=(options)=>{
            const { ht, wd, pad, bottomPad, step, ctx } = options
            // 绘制X、Y轴
            ctx.beginPath();
            ctx.lineWidth = 2
            ctx.strokeStyle = 'lightblue'
            ctx.moveTo(pad, pad);
            ctx.lineTo(pad, ht * 1.5 - bottomPad );
            ctx.lineTo(wd * 1.5 - pad, ht * 1.5 - bottomPad );
            ctx.stroke()
            ctx.closePath();

            // 绘制X轴刻度
            ctx.beginPath()
            ctx.lineWidth = 1
            ctx.strokeStyle = '#666'
            for (let i = 1; i <  Math.floor(wd * 1.5 / step); i++) {
                ctx.moveTo(pad + i * step, ht * 1.5 - bottomPad)
                ctx.lineTo(pad + i * step, ht * 1.5 - bottomPad - 10)
            }
            ctx.stroke()
            ctx.closePath()

            // 绘制Y轴刻度
            ctx.beginPath()
            ctx.lineWidth = 1
            ctx.strokeStyle = '#666'
            for (let i = 1; i <  Math.floor(ht * 1.5 / step); i++) {
                ctx.moveTo(pad, (ht * 1.5 - bottomPad) - (i * step))
                ctx.lineTo(pad + 10, (ht * 1.5 - bottomPad) - (i * step))
            }
            ctx.stroke()
            ctx.closePath()
        }
        drawAxis({
            ht: ht,
            wd: wd,
            pad: pad,
            bottomPad: bottomPad,
            step: step,
            ctx: ctx
        })

canvas绘制直方图

矩形

  • 矩形 image.png
        ctx.beginPath()
        ctx.lineWidth = 5
        ctx.strokeStyle = 'orange'
        // 创建矩形路径
        ctx.rect(100, 100, 300, 200)
        ctx.stroke()
        ctx.closePath()
  • 填充矩形

image.png

  ctx.beginPath()
  ctx.fillStyle = 'skyblue'
  ctx.fillRect(410, 310, 300, 200)
  ctx.closePath()

直方图

image.png

        // 绘制直方图
        ctx.beginPath();
        for (var i = 1; i < Math.floor(wd * 1.5 / step); i++) {
            // 矩形高度
            const height = Math.random() * 300 + 50;
            // 矩形填充颜色
            ctx.fillStyle = '#' + parseInt(Math.random() * 0xFFFFFF).toString(16);
            // 绘制矩形
            ctx.fillRect((i * step), ht * 1.5 - bottomPad - height, 40, height)
        }
        ctx.closePath()

canvas绘制圆形

  • image.png
        ctx.beginPath()
        ctx.lineWidth = 2
        ctx.strokeStyle = 'orange'
        // 绘制圆弧路径
        ctx.arc(400, 300, 200, 0, 2*Math.PI, true)
        ctx.stroke()
        ctx.closePath()
  • 填充圆

image.png

        ctx.beginPath()
        ctx.fillStyle = 'skyblue'
        ctx.arc(400, 300, 100, 0,  2*Math.PI, true)
        ctx.fill()
        ctx.closePath()

canvas绘制饼状图

image.png

  ctx.beginPath();
//   阴影偏移距离
  ctx.shadowOffsetX = 0
  ctx.shadowOffsetY = 0
//   模糊效果程度
    ctx.shadowBlur = 4
  ctx.shadowColor = '#333'  
    // 填充样式
  ctx.fillStyle = '#5C1918'
  ctx.moveTo(400, 300);
  ctx.arc(400, 300, 100, -Math.PI / 2, -Math.PI / 4);
  ctx.fill()
  ctx.closePath()

  ctx.beginPath();
  ctx.shadowOffsetX = 0
  ctx.shadowOffsetY = 0
  ctx.shadowBlur = 4
  ctx.shadowColor = '#5C1918'  
  ctx.fillStyle = '#A32D29'
  ctx.moveTo(400, 300);
  ctx.arc(400, 300, 110, -Math.PI / 4, Math.PI / 4);
  ctx.fill()
  ctx.closePath()

  ctx.beginPath()
  ctx.shadowOffsetX = 0
  ctx.shadowOffsetY = 0
  ctx.shadowBlur = 4
  ctx.shadowColor = '#A32D29'
  ctx.fillStyle = '#B9332E'
  ctx.moveTo(400, 300)
  ctx.arc(400, 300, 120, Math.PI / 4, Math.PI * 5 / 8)
  ctx.fill()
  ctx.closePath()

  ctx.beginPath()
  ctx.shadowOffsetX = 0
  ctx.shadowOffsetY = 0
  ctx.shadowBlur = 4
  ctx.shadowColor = '#B9332E'
  ctx.fillStyle = '#842320'
  ctx.moveTo(400, 300)
  ctx.arc(400, 300, 130, Math.PI * 5 / 8, Math.PI)
  ctx.fill()
  ctx.closePath()

  ctx.beginPath()
  ctx.shadowOffsetX = 0
  ctx.shadowOffsetY = 0
  ctx.shadowBlur = 4
  ctx.shadowColor = '#842320'
  ctx.fillStyle = '#D76662'
  ctx.moveTo(400, 300)
  ctx.arc(400, 300, 140, Math.PI, Math.PI * 3 / 2)
  ctx.fill()
  ctx.closePath()

canvas绘制文字

image.png

  // 实心、描边文字
  ctx.fillStyle = 'orange'
  ctx.strokeStyle = "hotpink"
  ctx.font = 'bold 60px 微软雅黑'
  ctx.fillText('canvas', 100, 100, 100)
  ctx.strokeText('前端', 100, 200)

  // 对齐属性设置
  ctx.textAlign = 'center'  
  ctx.textBaseline = "middle"  
  ctx.fillText('我的天哪', 200, 300)

image.png

canvas碰撞检测

image.png

		const canvas = document.getElementById("canvas");
		const ctx = canvas.getContext("2d");

		canvas.style.width = canvas.width + "px";
		canvas.style.height = canvas.height + "px";
		canvas.width = canvas.width * 1.5;
		canvas.height = canvas.height * 1.5;
		/**
		 *绘制圆形
		 */
		const drawCircle = (x, y, r) => {
			ctx.beginPath();
			ctx.fillStyle = "orange";
			ctx.arc(x, y, r, 0, Math.PI * 2);
			ctx.fill();
			ctx.closePath();
		};
		// 绘制区域大小
		const wd = canvas.clientWidth * 1.5;
		const ht = canvas.clientHeight * 1.5;
		// 圆心位置
		let x = (y = 100);
		// 圆的半径
		const r = 20;
		// x轴方向移动大小
		let xSpeed = 6;
		// y轴方向移动大小
		let ySpeed = 4;

		setInterval(() => {
			// 清空画布
			ctx.clearRect(0, 0, wd, ht);
			// 当圆要碰到边界时,改变移动方向
			if (x - r <= 0 || x + r >= wd) {
				xSpeed = -xSpeed;
			}
			if (y - r <= 0 || y + r >= ht) {
				ySpeed = -ySpeed;
			}
      // 再次绘制圆时,圆心位置
			x += xSpeed;
			y += ySpeed;
			drawCircle(x, y, r);
		}, 20);

canvas动画

下图中的小球会不停运动 image.png

		const canvas = document.getElementById("canvas");
		const ctx = canvas.getContext("2d");

		canvas.style.width = canvas.width + "px";
		canvas.style.height = canvas.height + "px";
		canvas.width = canvas.width * 1.5;
		canvas.height = canvas.height * 1.5;

		// 定义圆形小球类
		class Ball {
			constructor(canvas) {
				// 当前小球所处的canvas
				this.canvas = canvas;
				// 绘制的上下文
				this.ctx = this.canvas.getContext("2d");
				// 绘制区域的宽度
				this.wd = this.canvas.clientWidth * 1.5;
				// 绘制区域的高度
				this.ht = this.canvas.clientHeight * 1.5;
				// 半径,随机大小
				this.r = Math.random() * 40 + 10;
				// 圆心的位置--X
				this.x = Math.random() * (this.wd - this.r * 2) + this.r;
				// 圆心的位置--Y
				this.y = Math.random() * (this.ht - this.r * 2) + this.r;
				// 圆的填充颜色
				this.color =
					"#" + parseInt(Math.random() * 0xffffff).toString(16);
				// 圆的移动大小
				this.xSpeed = Math.random() * 4 + 6;
				this.ySpeed = Math.random() * 6 + 4;
				// 初始化
				this.init();
			}

			init() {
				this.run();
				this.draw();
			}
			// 画圆
			draw() {
				this.ctx.beginPath();
				this.ctx.fillStyle = this.color;
				this.ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
				this.ctx.fill();
				this.ctx.closePath();
			}
			// 圆的远动
			run() {
				if (this.x - this.r <= 0 || this.x + this.r >= this.wd) {
					this.xSpeed = -this.xSpeed;
				}
				if (this.y - this.r <= 0 || this.y + this.r >= this.ht) {
					this.ySpeed = -this.ySpeed;
				}
				this.x += this.xSpeed;
				this.y += this.ySpeed;
			}
		}
		// 记录小球
		let ballArr = [];
		// 创建小球
		for (let i = 0; i < 50; i++) {
			let ball = new Ball(canvas);
			ballArr.push(ball);
		}
		// 动画操作
		setInterval(() => {
			// 清空画布
			ctx.clearRect(
				0,
				0,
				canvas.clientWidth * 1.5,
				canvas.clientHeight * 1.5
			);
			// 绘制记录的小球
			for (let i = 0; i < ballArr.length; i++) {
				let ball = ballArr[i];
				ball.init();
			}
		}, 15);