canvas 2d 绘图

canvas 2d 绘图(一)

约定原则:手绘画图原则

  1. 画布 一张无线大的能作画的布,默认以左上角顶点位置为原始坐标
  2. 画笔 一只能够变换任何颜色,任意粗细程度的画笔
  3. 填充 在绘制的范围内填充任何颜色,包含渐变和透明
  4. 图形 圆形/矩形/路径
  5. 路径记忆 将上次创建过的路径保存起来,下次继续使用
  6. 变形 添加一层自定义的透明画布进行绘画
  7. 画布快照 对画布进行编号,拿起上一次遍过号的画布来绘画

准备工作
获取dom
var canvas = document.getElementById("myCanvas")
生成作画空间
var ctx = canvas.getContext("2d")

设置画笔

  // 设定画笔颜色 (单位为前端常用的正常色值)
  ctx.strokeStyle = "orange"
  // 设定线条宽度 (单位为像素)
  ctx.lineWidth = 10
  // 设置线条末端样式
  var lineCap = ['butt','round','square']
  ctx.lineCap = lineCap[i];
  // 设定线条与线条间接合处的样式
  var lineJoin = ['round', 'bevel', 'miter'];
  ctx.lineJoin = lineJoin[i]
  // 限制当两条线相交时交接处最大长度
  ctx.miterLimit = 8.8;  
  // 设置当前虚线样式 setLineDash数组指定线段与间隙的交替, lineDashOffset属性设置起始偏移量.
  ctx.setLineDash([4, 2]);
  ctx.lineDashOffset = 0;
  // 返回一个包含当前虚线样式,长度为非负偶数的数组
  ctx.getLineDash() // [4, 2]

填充

  // 设置填充颜色 (单位为前端常用的正常色值)
  ctx.fillStyle = "rgba(255,165,0,1)";
  // 设定渐变样式 (线性渐变 => 表示渐变的起点 (x1,y1) 与终点 (x2,y2)
  var lineargradient = ctx.createLinearGradient(0,0,150,150);    
  // 上色 (第一个参数表示0.0 与 1.0 之间的数值,第二个参数表示对应位置的颜色)
  lineargradient.addColorStop(0,'white');
  lineargradient.addColorStop(1,'black');
  // 渐变样式能够添加到fillStyle,也能添加到strokeStyle
  ctx.fillStyle = lineargradient;
  ctx.strokeStyle = lineargradient;
  // 设定渐变样式 (径向渐变 => 前三个定义一个以 (x1,y1) 为原点,半径为 r1 的圆,后三个参数则定义另一个以 (x2,y2) 为原点,半径为 r2 的圆。
  var radgrad = ctx.createRadialGradient(45,45,10,52,50,30);   
  radgrad.addColorStop(0, '#A7D30C');
  radgrad.addColorStop(0.9, '#019F62');
  radgrad.addColorStop(1, 'rgba(1,159,98,0)');
  // 图案填充 (需要保证img已经加载完毕)
  var ptrn = ctx.createPattern(img, 'repeat');
  ctx.fillStyle = ptrn;
  ctx.fillRect(0, 0, 150, 150);
  // 阴影 (x方向/y方向/阴影模糊程度/阴影颜色)
  ctx.shadowOffsetX = 2;
  ctx.shadowOffsetY = 2;
  ctx.shadowBlur = 2;
  ctx.shadowColor = "rgba(0, 0, 0, 0.5)";
  // 填充规则 (该填充规则根据某处在路径的外面或者里面来决定该处是否被填充)
  ctx.fill("evenodd");  // nonzero为默认值

图形

  // 矩形 (参数为起点,距离)
  fillRect(x,y,width,height)
  strokeRect(x,y,width,height)
  clearRect(x,y,width,height)
  // 路径
  beginPath()         // 新建一条路径
  closePath()         // 闭合路径
  moveTo(x,y)         // 移动画笔到某个位置
  lineTo(x,y)         // 从上一个点开始划线到目标点
  // 圆形  (画一个以x,y为圆心的以radius为半径的圆弧/圆,从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针)来生成)
  ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise)
  // 绘制
  stroke()            // 通过线条来绘制图形轮廓
  fill()              // 通过填充路径生成实心的图形
  // 绘制二次贝塞尔曲线,cp1x,cp1y为一个控制点,x,y为结束点 (注意绘制贝塞尔曲线之前确定有一个起始点)
  quadraticCurveTo(cp1x, cp1y, x, y)
  // 绘制三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点 (注意绘制贝塞尔曲线之前确定有一个起始点)
  bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

路径记忆

  // 将对应的线路路径保存起来
  new Path2D();     // 空的Path对象
  new Path2D(path); // 克隆Path对象
  new Path2D(d);    // 从SVG建立Path对象

变形

  // 温馨提示:在执行变形操作之前,使用ctx.save保存格式快照
  translate(x,y)      // 移动canvas的原点位置
  rotate(angle)       // 旋转canvas的角度, 参数为顺时针以弧度为单位的值
  scale(x,y)          // 缩放画布的水平和垂直单位,默认值为 1
  // 最后一个方法允许对变形矩阵直接修改。
  // 这个方法会将当前的变形矩阵重置为单位矩阵,然后用相同的参数调用 transform 方法。如果任意一个参数是无限大,那么变形矩阵也必须被标记为无限大,否则会抛出异常。从根本上来说,该方法是取消了当前变形,然后设置为指定的变形,一步完成。
  transform(a, b, c, d, e, f)

画布快照

  // 使用场景,当需要临时大量改变绘制格式的时候,而之后还要恢复绘制格式的情况下使用
  // 保存绘制格式快照
  ctx.save()
  // 返回上一次绘制格式快照
  ctx.restore()

综合场景

// 获取画布地图
var c=document.getElementById("myCanvas");
// 获取2d生成能力
var cxt=c.getContext("2d");
// 设置填充颜色
cxt.fillStyle="#FF0000";
// 设置矩形坐标
cxt.fillRect(0,0,150,75);


// 设置画笔起点
cxt.moveTo(10,10);
// 连接线条到150,50坐标
cxt.lineTo(150,50);
// 从150,50连接线条到10,50坐标
cxt.lineTo(10,50);
// 结束
cxt.stroke();


// 设置开始路径
cxt.beginPath();
// 设置圆的大小
cxt.arc(70,18,15,0,Math.PI*2,true);
// 结束路径
cxt.closePath();
// 填充
cxt.fill();

// 设置渐变背景坐标
var grd=cxt.createLinearGradient(0,0,175,50);
// 设定起点颜色
grd.addColorStop(0,"#FF0000");
// 设定第2起点颜色
grd.addColorStop(1,"#00FF00");
// 填充颜色
cxt.fillStyle=grd;
// 填充到对应的坐标
cxt.fillRect(0,0,175,50);

// 画布设置出图片
var img=new Image()
// new出的图片设置src
img.src="flower.png"
// 绘画从0开始
cxt.drawImage(img,0,0);
canvas 2d 绘图(二)

约定原则:手绘画图原则

  1. 裁剪
  2. 合成
  3. 像素操作
  4. 动画
  5. 事件 (点击区域)
  6. 性能优化

裁剪

  // 将当前正在构建的路径转换为当前的裁剪路径 (默认情况下,canvas 有一个与它自身一样大的裁切路径(也就是没有裁切效果))
  // 设定矩形 -> 裁剪 -> 填充 => 只显示矩形这一部分的图形
  ctx.rect(50, 50, 20, 10);
  ctx.clip();
  ctx.fillRect(0, 0, 100, 100);

合成

  // 这个属性设定了在画新图形时采用的遮盖策略,其值是一个标识12种遮盖方式的字符串
  // 通常用于新图形和旧图形相交部分,做自定义处理
  ctx.globalCompositeOperation = "difference";
  // 下面两个矩形相交的地方,会随着globalCompositeOperation的设置而变更
  ctx.fillStyle = "blue";
  ctx.fillRect(10, 10, 100, 100);  
  ctx.fillStyle = "red";
  ctx.fillRect(50, 50, 100, 100);

像素操作

// 创建一个ImageData对象
const myImageData = ctx.createImageData(width, height);
// 得到场景像素数据 (参数数据算法和矩形算法一致)
const myImageData = ctx.getImageData(left, top, width, height);
// 获取某一点的rgba像素值
const pixel = ctx.getImageData(0, 0, 1, 1);
const data = pixel.data;
const rgba = `rgba(${data[0]}, ${data[1]}, ${data[2]}, ${data[3] / 255})`;  //  rgba(67,73,35,1)
// 写入像素数据
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);  // 获取整个画布的像素数据
const data = imageData.data;
for (var i = 0; i < data.length; i += 4) {  // 改变像素数据
    data[i]     = 255 - data[i];            // red
    data[i + 1] = 255 - data[i + 1];        // green
    data[i + 2] = 255 - data[i + 2];        // blue
}
ctx.putImageData(imageData, 0, 0);          // 写入像素数据到原本的画布 (这里是将像素反相)
// 缩放 (canvas为原画布), Math.abs(x - 5), Math.abs(y - 5)为获取原画布的x,y起点,10/10表示起点之后的距离,0 0 表示新画布的起点,200 200表示画布的宽高
zoomctx.drawImage(canvas,
                  Math.abs(x - 5), Math.abs(y - 5),
                  10, 10, 0, 0, 200, 200);
// 反锯齿属性 (默认为true)
zoomctx.imageSmoothingEnabled = true;
// 保存图片
canvas.toDataURL('image/png') // 默认设定。创建一个PNG图片。
canvas.toDataURL('image/jpeg', quality) // 创建一个JPG图片。你可以有选择地提供从0到1的品质量,1表示最好品质,0基本不被辨析但有比较小的文件大小。
// 你也可以从画布中创建一个Blob对像。
canvas.toBlob(callback, type, encoderOptions) // 这个创建了一个在画布中的代表图片的Blob对像。
// callback 回调函数,可获得一个单独的Blob对象参数。
// type DOMString类型,指定图片格式,默认格式为image/png。
// encoderOptions 可选
// Number类型,值在0与1之间,当请求图片格式为image/jpeg或者image/webp时用来指定图片展示质量。如果这个参数的值不在指定类型与范围之内,则使用默认值,其余参数将被忽略。

动画

// 每隔一段时间执行
window.setInterval()  /   window.clearInterval()
// 过一段时间执行一次
window.setTimeout()   /   window.clearTimeout()
// 浏览器重绘之前调用指定的回调函数更新动画
window.requestAnimationFrame()  /   window.cancelAnimationFrame() 

事件

1. 通过设定指定区域,然后判断鼠标点击的位置是否在制定区域从而是否触发动画 (适用于矩形)
2. 先将需要执行点击事件的图形通过离屏绘制出来,然后添加到画布,并且记录距离画布的left/top
   点击事件的时候,获取到对应的x,y点,然后使用x-left,y-top , 得到离屏绘制的图形范围内相对应的位置,然后根据这个位置在离屏绘制的图形中判断data的alpha值

window.onload = function () {
  // 主画布
  const canvas = document.getElementById("canvas");
  const ctx = canvas.getContext("2d");
  canvas.width = dw
  canvas.height = dh
  // 创建一个离屏画布
  const { canvas: newCanvas, ctx: newCtx } = created()
  // 再创建一个
  const { canvas: oldCanvas, ctx: oldCtx } = created()
  // 保存对应的ctx到数组
  const list = [newCtx, oldCtx]
  // 主画布追加离屏画布
  ctx.drawImage(newCanvas, -10, -10)
  ctx.drawImage(oldCanvas, 100, 100)
  // 监听click事件
  canvas.addEventListener('click', () => {
    // 获取对应的xy
    const x = event.layerX
    const y = event.layerY
    // 循环离屏画布
    for (let i = 0; i < list.length; i++) {
      // 获取追加离屏画布时候的位置值
      const addx = i === 0 ? -10 : 100
      const addy = i === 0 ? -10 : 100
      // 得到离屏画布的像素值(位置经过计算得到相对应的坐标点)
      const pixel = list[1].getImageData(x - addx, y - addy, 1, 1);
      const data = pixel.data;
      // 判断当前像素点的alpha值是否为 0
      if (data[3] !== 0) {
        console.log('你点击的是离屏画布 ' + i);
      }
    }
  })
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值