canvas

 

canvas
只能在标签中用width。heigth修改大小
基本方法:
先得到canvas:

let canvas = document.querySelector('#canvas') // 得到canvas
let gd = canvas.getContext('2d')//得到canvas上下文环境

gd.moveTo(a,b): 从一个点开始绘图
gd.lineTo(c,d):绘图终点
gd.stroke():绘制
gd.fill():填充
gd.strokeStyle = ‘#555’ : 绘图颜色
gd.fillStyle = ‘#666’: 填充颜色
canvas.lineWidth=100:修改线宽

gd,beginPath(): 清除原来的痕迹
ge.closePath(): 自动完成闭合

绘制完毕后就不能修改颜色等属性,所以绘制是最后一步
绘制图之前一定先 beginPath()
绘制矩形
gd.strokeRect(x, y, 矩形width,矩形height)
gd.fillRect(x, y, 矩形width,矩形height)
clearRect(x, y, 矩形width,矩形height) 清除指定的矩形区域,然后这块区域会变的完全透明。
绘制圆形(弧)
gd.arc(cX, cY, R, 起始弧度, 终点弧度,是否逆时针) //弧度:Math.PI*角度
gd.stroke()
绘制文字
gd.font = '100px 宋体‘’ // 设置字体大小 型号
gd.strokeText(‘abc’, x, y) // 实心
gd.fillText(‘abc’, x, y) // 空心
gd.stroke()

canvas绘图以左上角的(0, 0)为基准原点 但是文字以基线为基点

画图

window.onload = function() {
		let canvas = document.querySelector('#canvas')
		let gd = canvas.getContext('2d')
		let obj = {}
		canvas.onmousedown = function (event) {

			obj.lastX = event.offsetX
			obj.lastY = event.offsetY
		}
		canvas.onmousemove = function (event) {
			
			gd.beginPath()
			gd.moveTo(obj.lastX, obj.lastY)
			gd.lineTo(event.offsetX, event.offsetY)
			obj.lastX = event.offsetX
			obj.lastY = event.offsetY
			gd.stroke()
		}
		canvas.onmouseup = function () {
			canvas.onmousemove = null
			canvas.onmouseup = null
		}
	}

圆弧案例:

function draw(){
    var canvas = document.getElementById('tutorial');
    if (!canvas.getContext) return;
    var ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.moveTo(50, 50); // 创建起点
    //参数1、2:控制点1坐标   参数3、4:控制点2坐标  参数5:圆弧半径
    ctx.arcTo(200, 50, 200, 200, 100); // 画弧
    ctx.lineTo(200, 200) // 创建终点
    ctx.stroke();

    ctx.beginPath();
    ctx.rect(50, 50, 10, 10);
    ctx.rect(200, 50, 10, 10)
    ctx.rect(200, 200, 10, 10)
    ctx.fill()
}
draw();
  • 在这里插入图片描述
    arcTo方法的说明:

​ 这个方法可以这样理解。绘制的弧形是由两条切线所决定。

​ 第 1 条切线:起始点和控制点1决定的直线。

​ 第 2 条切线:控制点1 和控制点2决定的直线。

​ 其实绘制的圆弧就是与这两条直线相切的圆弧。

饼图绘制

window.onload = function() {
		function draw(cX, cY, r){
		    var canvas = document.getElementById('canvas');
		    if (!canvas.getContext('2d')) return;
		    var ctx = canvas.getContext("2d");
		    //数据
		    let data = [100,50,25,25]
		    //求和
		    let sum = data.reduce((temp, item, index) => {return temp + item})
		    // 角度占比 
		    let angs = data.map(item => {return 360 * item / sum})
		    console.log(angs)
		    // 绘制
		    let last = 0
		    angs.forEach(ang => {
		    	pie(cX, cY, r, last, last+ang)
		    	last += ang
		    })
		    function pie (cX, cY, r, startAng, endAng) {
				ctx.beginPath()
				ctx.moveTo(cX, cY) // 圆心
				let x = cX + Math.sin(startAng* Math.PI / 180) * r // 求起始点
				let y = cY - Math.cos(startAng* Math.PI / 180) * r
				ctx.lineTo(x, y)
				ctx.arc(cX, cY, r, (startAng - 90) * Math.PI / 180, (endAng - 90) * Math.PI / 180, false)
				ctx.stroke()
				ctx.closePath()

			}
		}
		
		draw(200, 300, 100);
	}

绘制贝塞尔曲线
2次贝塞尔曲线
quadraticCurveTo(cp1x, cp1y, x, y):

说明:

​ 参数1和2:控制点坐标

​ 参数3和4:结束点坐标

3次贝塞尔曲线
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y):

说明:

​ 参数1和2:控制点1的坐标

​ 参数3和4:控制点2的坐标

​ 参数5和6:结束点的坐标
线条样式
lineCap = type
线条末端样式。

共有3个值:

butt:线段末端以方形结束
round:线段末端以圆形结束
square:线段末端以方形结束,但是增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域。
在这里插入图片描述
lineJoin = type
同一个path内,设定线条与线条间接合处的样式。

共有3个值round, bevel 和 miter:

round:通过填充一个额外的,圆心在相连部分末端的扇形,绘制拐角的形状。 圆角的半径是线段的宽度。
bevel:在相连部分的末端填充一个额外的以三角形为底的区域, 每个部分都有各自独立的矩形拐角。
miter(默认):通过延伸相连部分的外边缘,使其相交于一点,形成一个额外的菱形区域。
在这里插入图片描述
图片处理
ctx.drawImage(img, x, y,width ,height)
width 和 height,这两个参数用来控制 当像canvas画入时应该缩放的大小。
要保证当图片完成加载后再实现绘制


let img = new Image() // 创建img
img.src = 'xxx.jpg' // img路径
img.onload = function(){ 
	ctx.drawImage(img, x, y)
}

切片(slice)
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
前4个是定义图像源的切片位置和大小,后4个则是定义切片的目标显示位置和大小。

阴影

		let canvas = document.getElementById('canvas')
		let context = canvas.getContext('2d')
		//设置阴影
		context.shadowColor="rgba(0,0,0,0.5)"//设置阴影颜色
		context.shadowOffsetX=5;//设置形状或路径x轴方向的阴影偏移量,默认值为0;
		context.shadowOffsetY=5;//设置形状或路径y轴方向的阴影偏移量,默认值为0;
		context.shadowBlur=4;//设置模糊的像素数,默认值为0,即不模糊。
		//绘制红色矩形
		context.fillStyle="red";
		context.fillRect(10,10,50,50);
		//绘制半透明的蓝色矩形
		context.fillStyle="rgba(0,0,255,1)";
		context.fillRect(30,30,50,50);

在这里插入图片描述
渐变
渐变由CanvasGradient实例表示。要创建一个新的先行渐变,可以调用createLinearGradient()方法。这个方法接收4个参数:起点的x坐标,起点的y坐标,终点的x坐标,终点的y坐标。创建渐变对象后,下一步就是使用addColorStop()方法来指定色标,这个方法接收两个参数:色标位置和css颜色值。色标位置是一个0(开始的颜色)到1(结束的颜色)之间的数据。

gradient=context.createLinearGradient(30,30,70,70); 相当于画了一条渐变直线
gradient.addColorStop(0,“red”); 渐变开始的颜色
gradient.addColorStop(1,“black”); 渐变结束的颜色
context.fillStyle=gradient; 图形填充颜色为渐变色

let canvas = document.getElementById('canvas')
let context = canvas.getContext('2d')
// 设置渐变
var gradient=context.createLinearGradient(30,30,70,70);
gradient.addColorStop(0,"red");
gradient.addColorStop(1,"black");
//绘制红色矩形
context.fillStyle="red";
context.fillRect(10,10,50,50);
//绘制渐变矩形
    context.fillStyle=gradient;
context.fillRect(30,30,50,50);

在这里插入图片描述
径向渐变(或放射渐变)
可以使用createRadialGradient()方法,这个方法接收6个参数,对应着两个圆的圆心和半径
var gradient=context.createRadialGradient(55,55,10,55,55,30);

//设置渐变
var gradient=context.createRadialGradient(55,55,10,55,55,30);
gradient.addColorStop(0,"white");
gradient.addColorStop(1,"black");
//绘制红色矩形
context.fillStyle="red";
context.fillRect(10,10,50,50);
//绘制渐变矩形
    context.fillStyle=gradient;
context.fillRect(30,30,50,50);


在这里插入图片描述
模式
模式其实就是重复的图像,可以用来填充或描边图形

var image=document.images[0];
pattern=context.createPattern(image,"repeat");
 context.fillStyle=pattern;
context.fillRect(10,10,300,300);

游戏小人的走动

let canvas = document.getElementById('canvas')
  let ctx = canvas.getContext('2d')

  let img = new Image()
  img.src = '1.jpg'

 
    img.onload = function() {
      let frame = 0 // 列 控制行走动作
      let d = 'down' // 行 控制行走朝向
      let x = 100
      let y = 100
      let speed = 10
      document.onkeydown = function(event) {
        // switch(event.keyCode) {
        //   case 87 || 38:
        //     d = 'up'
        //     break;
        //   case 83 || 40:
        //     d = 'down'
        //     break;
        //   case 65 || 37:
        //     d = 'left'
        //     break;
        //   case 68 || 39:
        //     d = 'right'
        //     break;
        // }
        let keys = {87:'up', 83:'down', 65:'left', 68:'right'}
        let keys2 = {38:'up', 40:'down', 37:'left', 39:'right'}
        d = keys[event.keyCode] || d || keys2[event.keyCode]
      }
      setInterval(() => {
        let rows = {'down': 0, 'left': 1, 'right': 2, 'up': 3}
        ctx.clearRect(0, 0, canvas.width, canvas.height)
        ctx.drawImage(img, 10 + 94*frame, 100 * rows[d], 70, 90, x, y, 70, 90)
        if (x < 0) {
          x = 0
          frame = 2
        } 
        console.log(canvas.width)
        if (x > canvas.width-70) {
          x = canvas.width-70
          frame = 2
        }
        if (y < 0) {
          y = canvas.height
          
        } else if (y > canvas.height) {
          y = 0
          
        }
        switch (d) {
          case 'down':
            y += speed
            break;
          case 'up':
            y -= speed
            break;
          case 'left':
            x -= speed
            break;
          case 'right':
            x += speed
            break
        }
        frame++
        if (frame === 3) {
          frame = 0
        }
      }, 100)  
    }
  

像素操作
每个像素占4位:r g b a
若一张图大小为800600 则 宽=800 => 800列
高=600 => 600行
r行c列的某个像素:r
800+c
r行c列的某个像素占位:(r*800+c) *4
获得像素区
let imgData = ctx.getImageData(100, 100, img.width, img.height) // 获取像素区
处理像素(黑白:使r=g=b;
昏黄:b=0)
改变像素
ctx.putImageData(imgData, 100, 100)

window.onload = function () {
  let canvas = document.getElementById('canvas')
  let ctx = canvas.getContext('2d')
  let btn = document.querySelector('input')
  let img = new Image()
  img.src = '22.jpg'
  img.onload = function() {
    ctx.drawImage(img, 100, 100, 400, 250)
    let imgData = ctx.getImageData(100, 100, img.width, img.height) // 获取像素区
    btn.onclick = function() {
      for(let r = 0; r < img.height; r++) { // 行
        for(let c = 0; c< img.width; c++) { // 列
          let avg = (imgData.data[(r*img.width + c) * 4] + imgData.data[(r*img.width + c) * 4 + 1] + imgData.data[(r*img.width + c) * 4 + 2]) / 3
          imgData.data[(r*img.width + c) * 4] = imgData.data[(r*img.width + c) * 4 + 1] =imgData.data[(r*img.width + c) * 4 + 2] = avg

        }
      }
      ctx.putImageData(imgData, 100, 100)
    }
    
  }
  
}
  •  
  •  

变形
在变形之前,先保存ctx.save(),变形之后再恢复,ctx.restore()

  • 1.translate
  • translate(x, y) 用来移动 canvas 的原点到指定的位置
function draw(){
        var canvas = document.querySelector('canvas');
        if (!canvas.getContext) return;
        var ctx = canvas.getContext("2d");
        ctx.save(); //保存坐原点平移之前的状态
        ctx.translate(100, 100);
        ctx.strokeRect(0, 0, 100, 100)
        ctx.restore(); //恢复到最初状态
        ctx.translate(220, 220);
        ctx.fillRect(0, 0, 100, 100)
    }
    draw();

在这里插入图片描述
2.rotate
这个方法只接受一个参数:旋转的角度(angle),它是顺时针方向的,以弧度为单位的值。
​ 旋转的中心是坐标原点。
在这里插入图片描述
3.scale
scale(x, y) 用它来增减图形在 canvas 中的像素数目,对形状,位图进行缩小或者放大。
x,y分别是横轴和纵轴的缩放因子,它们都必须是正值。值比 1.0 小表示缩 小,比 1.0 大则表示放大,值为 1.0 时什么效果都没有。

function draw(){
      var canvas = document.querySelector('canvas');
        
      var ctx = canvas.getContext("2d");
      let rotate = 0
      ctx.strokeRect(100, 100, 200, 200) //先基于原原点画一个矩形
      setInterval(() => {
        ctx.clearRect(0,0,canvas.width,canvas.height)
        rotate++
        ctx.save(); //保存坐原点平移之前的状态
        ctx.translate(200, 200); // 移动原点
        ctx.rotate(Math.PI/180 * rotate) // 基于后来的原点再进行旋转
        ctx.fillRect(-100,-100, 200, 200) // 基于后来的原点画一个矩形  实现新矩形围绕矩形中心旋转
        ctx.restore()
      }, 24)
        
    }
    draw();

合成
globalCompositeOperation = type

  1. source-over(default)
    这是默认设置,新图像会覆盖在原有图像。
  2. source-in
    仅仅会出现新图像与原来图像重叠的部分,其他区域都变成透明的。(包括其他的老图像区域也会透明)
  3. source-out
    仅仅显示新图像与老图像没有重叠的 新图像的那一部分,其余部分全部透明。(老图像也不显示)
  4. source-atop
    显示新图像与老图像重叠区域 + 老图像其余部分。新图像其他部分不显示。
  5. destination-over
    新图像会在老图像的下面
  6. destination-in
    仅仅新老图像重叠部分的老图像部分被显示,其他区域全部透明。
  7. destination-out
    仅仅老图像与新图像没有重叠的部分。 注意显示的是老图像的部分区域。
  8. destination-atop
    老图像仅仅仅仅显示重叠部分,新图像会显示在老图像的下面。
    9. lighter
    新老图像都显示,但是重叠区域的颜色做加处理
  9. darken
    保留重叠部分最黑的像素。(每个颜色位进行比较,得到最小的)

blue: #0000ff
red: #ff0000
所以重叠部分的颜色:#000000
11. lighten 与lighter 相似
保证重叠部分最量的像素。(每个颜色位进行比较,得到最大的)

blue: #0000ff
red: #ff0000
所以重叠部分的颜色:#ff00ff
12. xor
重叠部分会变成透明
裁剪路径
clip()
​ 把已经创建的路径转换成裁剪路径。
​ 裁剪路径的作用是遮罩。只显示裁剪路径内的区域,裁剪路径外的区域会被隐藏。
​ 注意:clip()只能遮罩在这个方法调用之后绘制的图像,如果是clip()方法调用之前绘制的图像,则无法实现遮罩。
clip()遮住方法之前绘制的图像,显示之后的绘制的区域
动画
动画的基本步骤
1 清空canvas
再绘制每一帧动画之前,需要清空所有。清空所有最简单的做法就是clearRect()方法
2 保存canvas状态
如果在绘制的过程中会更改canvas的状态(颜色、移动了坐标原点等),又在绘制每一帧时都是原始状态的话,则最好保存下canvas的状态
3 绘制动画图形
这一步才是真正的绘制动画帧
4恢复canvas状态
如果你前面保存了canvas状态,则应该在绘制完成一帧之后恢复canvas状态
时钟绘制

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
  <style>
    body {
            padding: 0;
            margin: 0;
            background-color: rgba(0, 0, 0, 0.1)
        }

        canvas {
            display: block;
            margin: 200px auto;
        }
  </style>
  <script>
  window.onload = function() {
    let canvas = document.getElementsByTagName('canvas')[0]
    let ctx = canvas.getContext('2d')
    draw(ctx)
    function draw(ctx) {
      requestAnimationFrame(function step() {
        drawDeil(ctx) // 表盘
        drawAllHand(ctx) // 指针
        requestAnimationFrame(step) // 回调
      })
    }
    function drawAllHand(ctx) {
      //得到时分秒
      let time = new Date()
      let s = time.getSeconds()
      let m = time.getMinutes()
      let h = time.getHours()
      // 得到指针的弧度
      let pi = Math.PI 
      let secondAngle = pi / 180 * s * 360 / 60
      let minuteAngle = pi / 180 * m * 360 / 60 + secondAngle / 60
      let hourAngle = pi / 180 *h *360 / 12 + minuteAngle / 12

      //drawHand(指针弧度, 指针长度, 指针宽度, 颜色, ctx);  //绘制指针
      drawHand(hourAngle, 60, 6, "red", ctx);  //绘制时针
      drawHand(minuteAngle, 106, 4, "green", ctx);  //绘制分针
      drawHand(secondAngle, 129, 2, "blue", ctx);  //绘制秒针
    }
    function drawHand(angle, len, width, color, ctx) {
      ctx.save()
      ctx.translate(150, 150) // 原点转移到canvas中心
      // 弧度与角度的0相差九十度,角度顺时针转90(-90)与弧度重合
      ctx.rotate(-90 * Math.PI / 180 + angle);  //旋转坐标轴。 x轴就是针
      ctx.beginPath() // 绘制之前先清除路径
      ctx.moveTo(-4, 0) // 以新原点为基点
      ctx.lineTo(len, 0) // x周就是指针,所以与x重合即可
      ctx.strokeStyle = color
      ctx.lineWidth = width
      ctx.stroke()
      ctx.closePath()
      ctx.restore()
    }
    // 绘制表盘
    function drawDeil(ctx) {
      let pi = Math.PI
      ctx.clearRect(0, 0, canvas.width, canvas.height)
      ctx.save()

      ctx.translate(150, 150) // 原点转移到canvas中心
      ctx.beginPath()
      ctx.arc(0, 0, 148, 0, 2 * pi) // 绘制圆周
      ctx.stroke()
      ctx.closePath()

      // 绘制刻度
      for(let i = 0; i < 60; i++) {
        ctx.save()
        ctx.rotate(-90 * pi / 180 + i * 360 / 60 * pi / 180)
        ctx.beginPath()
        ctx.moveTo(110, 0)
        ctx.lineTo(140, 0)
        ctx.lineWidth = i % 5 === 0 ? 4 : 2
        ctx.strokeStyle = i % 5 === 0 ? 'red' : 'blue'
        ctx.stroke()
        ctx.closePath()
        ctx.restore()
      }
      ctx.restore()
    }
  }

  </script>
</head>
<body>
<canvas width="300" height="300">请更新浏览器</canvas>
</body>
</html>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值