前端下载文件(exe,zip,js等)的几种方式

闲来无事,总结一下这些东西:

前端一般通过创建a标签下载文件

图片:分为本地和后端传,本地直接require引入路径后创建a标签下载:

private downFun() {
    let a=document.createElement('a')
    a.style.display = 'none'
    a.setAttribute('download', 'bg.jpg')
    a.href = require('@/assets/bg.jpg')
    document.body.appendChild(a)
    console.log('href', a.href)
    a.click()
    document.body.removeChild(a)
  }

后端传的话需要调用get接口。

其它文件类型下载基本都是一样的 调用后端get接口,使用blob类型

responseType: ‘blob’。进行下载

注意:如果要是本地下载一些静态资源(除图片外) 资源要放在public目录文件下,不然打包后路径你会发现很多报错,下载找不到路径。@这个不会被解析。

附下载代码:

async download(){
    console.log(this.urlName)
    let res = await axios.get(`jt/${this.urlName}`, { responseType: 'blob' })
    const url = window.URL.createObjectURL(res.data)
    const link = document.createElement('a')
    link.href = url;
    link.setAttribute('download', `${this.urlName}`)
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
  }

jt/${this.urlName}

jt是public下的一个文件夹, this.urlName是你要下载的文件的名字。

H5的——Web存储

分2种

localStorage 和 sessionStorage 这都是客户端的

localStorage – 用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去除。
sessionStorage – 用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据。
IE7及更早版本不支持,因为浏览器可能不支持所以我们一般要进行一下判断是否支持
if(typeof(Storage)!==”undefined”)
{
// 是的! 支持 localStorage sessionStorage 对象!
// 一些代码…..
} else {
// 抱歉! 不支持 web 存储。
}

localStorage 对象

localStorage 对象存储的数据没有时间限制。第二天、第二周或下一年之后,数据依然可用。
如:
localStorage.sitename=”菜鸟教程”; // 这里的sitename可以你任意取变量。
document.getElementById(“result”).innerHTML=”网站名:” + localStorage.sitename;
解释:
使用 key=”sitename” 和 value=”菜鸟教程” 创建一个 localStorage 键/值对。
检索键值为”sitename” 的值然后将数据插入 id=”result”的元素中。
移除 localStorage 中的 “sitename” :
localStorage.removeItem(“sitename”);

localStorage 和 sessionStorage,可使用的API都相同,常用的有如下几个(以localStorage为例):
// 下面的key值就和上面localStorage.sitename中你定义的sitename是一样的
保存数据:localStorage.setItem(key,value); 解释:这里一次性保存的是2个变量,可以通过getItem来查找key取得里面的value值,但不能通过查找value来取key值,getItem只能看key
读取数据:localStorage.getItem(key);
删除单个数据:localStorage.removeItem(key);
删除所有数据:localStorage.clear();
注意: 键/值对通常以字符串存储,你可以按自己的需要转换该格式。
得到某个索引的key:localStorage.key(index);

sessionStorage 对象

sessionStorage 方法针对一个 session 进行数据存储。当用户关闭浏览器窗口后,数据会被删除。
例子: // sessionStorage.clickcount的clickcount是自己定义的变量

 function clickCounter()
{
if(typeof(Storage)!=="undefined")
{
if (sessionStorage.clickcount)
{
sessionStorage.clickcount=Number(sessionStorage.clickcount)+1;
}
else
{
sessionStorage.clickcount=1;
}
document.getElementById("result").innerHTML="在这个会话中你已经点击了该按钮 " + sessionStorage.clickcount + " 次 ";
}
else
{
document.getElementById("result").innerHTML="抱歉,您的浏览器不支持 web 存储";
}
}
// 删除方法
function del(name) {
localStorage.removeItem(name);
alert("删除成功!");
loadAll();
}

点我!

作用域:
localStorage只要在相同的协议、相同的主机名、相同的端口下,就能读取/修改到同一份localStorage数据。

sessionStorage比localStorage更严苛一点,除了协议、主机名、端口外,还要求在同一窗口(也就是浏览器的标签页)下。

canvas详细笔记

图形的基本元素是路径
1.首先,你需要创建路径起始点。
2.然后你使用画图命令去画出路径。
3.之后你把路径封闭。
4.一旦路径生成,你就能通过描边或填充路径区域来渲染图形。
要用到的函数:
beginPath()
新建一条路径,生成之后,图形绘制命令被指向到路径上生成路径。
closePath()
闭合路径之后图形绘制命令又重新指向到上下文中。
stroke()
通过线条来绘制图形轮廓。
fill()
通过填充路径的内容区域生成实心的图形。

上面是中心函数,接下面是辅助函数:
fillRect(x, y, width, height)
绘制一个填充的矩形
strokeRect(x, y, width, height)
绘制一个矩形的边框
clearRect(x, y, width, height)
清除指定矩形区域,让清除部分完全透明。
lineJoin = “xxx”
设置或返回所创建边角的类型,当两条线交汇时
bevel 创建斜角。round 创建圆角。miter 创建尖角(默认)。

步骤:

  1. 生成路径的第一步叫做beginPath()。
    注意:
    当前路径为空,即调用beginPath()之后,或者canvas刚建的时候,第一条路径构造命令通常被视为是moveTo()
    无论实际上是什么。出于这个原因,你几乎总是要在设置路径之后专门指定你的起始位置。
  2. 调用函数指定绘制路径
    moveTo(x, y)
    将笔触移动到指定的坐标x以及y上。刚开始时用,接下来用lineTo(x, y)
    lineTo(x, y)
    绘制一条从当前位置到指定x以及y位置的直线。
    当你要画一条线而不是一个闭合图像时用:stroke()
    stroke()
    方法会实际地绘制出通过 moveTo() 和 lineTo() 方法定义的路径。默认颜色是黑色。
    当canvas初始化或者beginPath()调用后,你通常会使用moveTo()函数设置起点。
    strokeStyle = “red”
    定义线条颜色
    也能够使用moveTo()绘制一些不连续的路径,只是闭合时最好不要填充
  3. 就是闭合路径closePath(),不是必需的。当路径已经闭合时会自动创建开始点。
    注意:
    当你调用fill()函数时,所有没有闭合的形状都会自动闭合,不需要调用closePath()函数。
    但是调用stroke()时不会自动闭合。

辅助方法:

arc()方法
绘制圆弧或者圆
arc(x, y, radius, startAngle, endAngle, anticlockwise)
radius 圆弧的半径。startAngle 圆弧的起始点, x轴方向开始计算,单位以弧度表示。endAngle 圆弧的终点,单位以弧度表示。anticlockwise 可选 可选的Boolean值 ,如果为 true,逆时针绘制圆弧,反之,顺时针绘制。
用法示例: ctx.arc(75, 75, 50, 0, 2 * Math.PI);
画一个以(x,y)为圆心的以radius为半径的圆弧(圆),从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针)来生成。

arcTo()方法
arcTo(x1, y1, x2, y2, radius)
根据给定的控制点和半径画一段圆弧,再以直线连接两个控制点。

重点:二次贝塞尔曲线及三次贝塞尔曲线

quadraticCurveTo(cp1x, cp1y, x, y)
绘制二次贝塞尔曲线,cp1x,cp1y为一个控制点,x,y为结束点。
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
绘制三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点。

色彩colors:

fillStyle 和 strokeStyle。
fillStyle = color
设置图形的填充颜色。

strokeStyle = color
设置图形轮廓的颜色。

color 可以是表示 CSS 颜色值的字符串,渐变对象或者图案对象。默认黑色
高级用法
for (var i=0;i<6;i++){
for (var j=0;j<6;j++){
ctx.fillStyle = ‘rgb(‘ + Math.floor(255-42.5*i) + ‘,’ + Math.floor(255-42.5*j) + ‘,0)’;
ctx.fillRect(j*25,i*25,25,25);
}
}
fillStyle可以换成strokeStyle,介绍下strokeStyle来画圆
for (var i=0;i<6;i++){
for (var j=0;j<6;j++){
ctx.strokeStyle = ‘rgb(0,’ + Math.floor(255-42.5*i) + ‘,’ + Math.floor(255-42.5*j) + ‘)’;
ctx.beginPath();
ctx.arc(12.5+j25,12.5+i25,10,0,Math.PI*2,true);
ctx.stroke();
}
}

透明度

globalAlpha 属性
ctx.globalAlpha = value; value在 0.0 (完全透明)和 1.0 (完全不透明)之间默认1
但是因为strokeStyle 和 fillStyle 属性接受符合 CSS 3 规范的颜色值,所以可以用rgba方法
rgba() 方法与 rgb() 方法类似,就多了一个用于设置色彩透明度的参数。它的有效范围是从 0.0(完全透明)到 1.0(完全不透明)。

// 指定透明颜色,用于描边和填充样式
ctx.strokeStyle = “rgba(255,0,0,0.5)”;

线型

可以通过一系列属性来设置线的样式。
lineWidth = value
设置线条宽度。
lineCap = type

设置线条末端样式。

lineJoin = type
type有butt,round (半圆)和 square(直角)。默认是 butt。
用了 round、 square 的效果,端点处加上了半径为一半线宽的半圆或方块.

设定线条与线条间接合处的样式。

miterLimit = value
限制当两条线相交时交接处最大长度;所谓交接处长度(斜接长度)是指线条交接处内角顶点到外角顶点的长度。

getLineDash()

返回一个包含当前虚线样式,长度为非负偶数的数组。
setLineDash(segments)
设置当前虚线样式。
lineDashOffset = value
设置虚线样式的起始偏移量。
ctx.fillStyle = “rgba(255,0,0,0.5)”;

用 setLineDash 方法和 lineDashOffset 属性来制定虚线样式.
setLineDash 方法接受一个数组,来指定线段与间隙的交替;lineDashOffset 属性设置起始偏移量.
例如:
ctx.clearRect(0,0, canvas.width, canvas.height);
ctx.setLineDash([4, 2]); //接受数组,长度4,每个虚线间距2
ctx.lineDashOffset = -offset; //刚开始偏移单位
ctx.strokeRect(10,10, 100, 100);

上面是个动画

动画的基本步骤

  1. 清空 canvas
    除非接下来要画的内容会完全充满 canvas (例如背景图),否则你需要清空所有。最简单的做法就是用 clearRect 方法。
  2. 保存 canvas 状态
    如果你要改变一些会改变 canvas 状态的设置(样式,变形之类的),又要在每画一帧之时都是原始状态的话,你需要先保存一下。
  3. 绘制动画图形(animated shapes)
    这一步才是重绘动画帧。
  4. 恢复 canvas 状态
    如果已经保存了 canvas 的状态,可以先恢复它,然后重绘下一帧。

为了实现动画,我们需要一些可以定时执行重绘的方法。有两种方法可以实现这样的动画操控。首先可以通过 setInterval 和 setTimeout 方法来控制在设定的时间点上执行重绘。可以用window.setInterval(), window.setTimeout(),和window.requestAnimationFrame()来设定定期执行一个指定函数。

setInterval(function, delay)
当设定好间隔时间后,function会定期执行。
setTimeout(function, delay)
在设定好的时间之后执行函数
requestAnimationFrame(callback)
告诉浏览器你希望执行一个动画,并在重绘之前,请求浏览器执行一个特定的函数来更新动画。

如果你并不需要与用户互动,你可以使用setInterval()方法,它就可以定期执行指定代码。
如果我们需要做一个游戏,我们可以使用键盘或者鼠标事件配合上setTimeout()方法来实现。通过设置事件监听,我们可以捕捉用户的交互,并执行相应的动作。

渐变

用线性或者径向的渐变来填充或描边。实质是:建一个 canvasGradient 对象,并且赋给图形的 fillStyle 或 strokeStyle 属性

ctx.createLinearGradient(x1, y1, x2, y2)
createLinearGradient 方法接受 4 个参数,表示渐变的起点 (x1,y1) 与终点 (x2,y2)。
它最后显示出来的页面是由填充函数ctx.fillRect(x,y,width,height);来控制的

ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);
createRadialGradient 方法接受 6 个参数,前三个定义一个以 (x1,y1) 为原点,半径为 r1 的圆
x0 开始圆形的 x 轴坐标。
y0 开始圆形的 y 轴坐标。
r0 开始圆形的半径。
x1 结束圆形的 x 轴坐标。
y1 结束圆形的 y 轴坐标。
r1 结束圆形的半径

一般情况下先建立这些画布渐变对象再用addColorStop 方法给它上色

addColorStop 方法接受 2 个参数,
position 参数必须是一个 0.0 与 1.0 之间的数值,表示渐变中颜色所在的相对位置,从此位置开始渐变。例如,0.5 表示颜色会出现在正中间。
color 参数必须是一个有效的 CSS 颜色值(如 #FFF, rgba(0,0,0,1),等等)。


var lineargradient = ctx.createLinearGradient(0,0,150,150); //建立了画布渐变对象
lineargradient.addColorStop(0,’white’);
lineargradient.addColorStop(1,’black’);
strokeStyle 和 fillStyle 属性都可以接受
ctx.fillStyle = gradient;
ctx.strokeStyle = gradient;
ctx.fillRect(10,10,130,130);
ctx.strokeRect(50,50,50,50);

fillStyle 属性还可以填充图案
唯一要注意的是,使用 Image 对象的 onload handler 来确保设置图案之前图像已经装载完毕。
如:

 function draw() {
   var ctx = document.getElementById('canvas').getContext('2d');
// 创建新 image 对象,用作图案
   var img = new Image();
   img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png';
   img.onload = function() {
// 创建图案
   var ptrn = ctx.createPattern(img, 'repeat');
   ctx.fillStyle = ptrn;
   ctx.fillRect(0, 0, 150, 150);
}
 }

阴影 Shadows

shadowOffsetX = float
shadowOffsetX 和 shadowOffsetY 用来设定阴影在 X 和 Y 轴的延伸距离,它们是不受变换矩阵所影响的。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,它们默认都为 0。

shadowOffsetY = float
shadowOffsetX 和 shadowOffsetY 用来设定阴影在 X 和 Y 轴的延伸距离,它们是不受变换矩阵所影响的。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,它们默认都为 0。
shadowBlur = float
shadowBlur 用于设定阴影的模糊程度,其数值并不跟像素数量挂钩,也不受变换矩阵的影响,默认为 0。
shadowColor = color
shadowColor 是标准的 CSS 颜色值,用于设定阴影颜色效果,默认是全透明的黑色。

canvas 填充规则
当我们用到 fill(或者 clip和isPointinPath )你可以选择一个填充规则,该填充规则根据某处在路径的外面或者里面来决定该处是否被填充
nonzero (默认,普通的填充) evenodd (填充2个闭合图案之间的空白)

绘制文本

fillText(text, x, y [, maxWidth])
在指定的(x,y)位置填充指定的文本,绘制的最大宽度是可选的.
如:ctx.font = “48px serif”; //这是一段使用 font 属性的简单的代码片段,设置了不同的字体大小和字体种类
ctx.fillText(“Hello world”, 50, 100);

strokeText(text, x, y [, maxWidth])
在指定的(x,y)位置绘制文本边框,绘制的最大宽度是可选的.
只是个框

ctx.font = “48px serif”;
这是一段使用 font 属性的简单的代码片段,设置了不同的字体大小和字体种类
ctx.textAlign = “left” || “right” || “center” || “start” || “end”;
left 文本左对齐。
right 文本右对齐。
center 文本居中对齐。
start 文本对齐界线开始的地方 (左对齐指本地从左向右,右对齐指本地从右向左)。
end 文本对齐界线结束的地方 (左对齐指本地从左向右,右对齐指本地从右向左)。
默认值是 start。

top
文本基线在文本块的顶部。
hanging 文本基线是悬挂基线。
middle 文本基线在文本块的中间。
alphabetic 文本基线是标准的字母基线。(默认)
ideographic 文字基线是表意字基线;如果字符本身超出了alphabetic 基线,那么ideograhpic基线位置在字符本身的底部。
bottom 文本基线在文本块的底部。 与 ideographic 基线的区别在于 ideographic 基线不需要考虑下行字母

direction 描述当前文本方向(目前只有谷歌浏览器支持)
ctx.direction = “ltr” || “rtl” || “inherit”;
ltr 文本方向从左向右。
rtl 文本方向从右向左。
inherit 根据情况继承 元素或者 Document(默认) 。

引入图像到canvas里需要以下两步基本操作:

  1. 获得一个指向HTMLImageElement的对象或者另一个canvas元素的引用作为源,也可以通过提供一个URL的方式来使用图片(参见例子)
  2. 使用drawImage()函数将图片绘制到画布上

首先第一步获得需要绘制的图片
canvas的API可以使用下面这些类型中的一种作为图片的源:

HTMLImageElement
这些图片是由Image()函数构造出来的,或者任何的元素
HTMLVideoElement
用一个HTML的 元素作为你的图片源,可以从视频中抓取当前帧作为一个图像
你还可以使用 中的视频帧(即便视频是不可见的)。例如,如果你有一个ID为“myvideo”的 元素,你可以这样做:

function getMyVideo() {
  var canvas = document.getElementById('canvas');
  if (canvas.getContext) {
    var ctx = canvas.getContext('2d');

    return document.getElementById('myvideo');
  }
}

它将为这个视频返回HTMLVideoElement对象

HTMLCanvasElement
可以使用另一个 元素作为你的图片源。
ImageBitmap
这是一个高性能的位图,可以低延迟地绘制,它可以从上述的所有源以及其它几种源中生成。
这些源统一由 CanvasImageSource类型来引用。

补充解释:
toDataURL(in optional DOMString type, in any …args)
返回一个data: URL,根据type参数指定的类型将包含在canvas中的图片文件编码成字符串形式, type参数的默认值为image/png.
toBlob(in Function callback, in optional DOMString type, in any …args)
返回一个Blob对象,表示了包含在该canvas中的图片文件,这个文件可能缓存在硬盘上,也可能存储在内存中,这由浏览器决定.如果没有指定type参数,则默认使用image/png.

例子从canvas对象中导出data: URL:

function test() {
 var canvas = document.getElementById("canvas");
 var url = canvas.toDataURL();
 
 var newImg = document.createElement("img");
 newImg.src = url;
 document.body.appendChild(newImg);
}
例子:从canvas对象中获得文件:
function test() {
 var canvas = document.getElementById("canvas");
 canvas.toBlob(function(blob) {
    var newImg = document.createElement("img"),
        url = URL.createObjectURL(blob);
    newImg.onload = function() {
        // no longer need to read the blob so it's revoked
        URL.revokeObjectURL(url);
    };
    newImg.src = url;
    document.body.appendChild(newImg);
 });
}

使用相同页面内的图片
我们可以通过下列方法的一种来获得与canvas相同页面内的图片的引用:

document.images集合 如:var imageCollection = document.images;
提供了包含在该文档中的所有images元素实时的列表。 是一个集合(‘[]’),集合中的每条代表了一个单image元素的HTMLImageElement
document.getElementsByTagName()方法
如果你知道你想使用的指定图片的ID,你可以用document.getElementById()获得这个图片
使用其它域名下的图片节
在 HTMLImageElement上使用crossOrigin属性,你可以请求加载其它域名上的图片。如果图片的服务器允许跨域访问这个图片,那么你可以使用这个图片而不污染canvas,否则,使用这个图片将会污染canvas。

使用其它 canvas 元素节
和引用页面内的图片类似地,用 document.getElementsByTagName 或 document.getElementById 方法来获取其它 canvas 元素。但你引入的应该是已经准备好的 canvas。

一个常用的应用就是将第二个canvas作为另一个大的 canvas 的缩略图。

由零开始创建图像节

或者我们可以用脚本创建一个新的 HTMLImageElement 对象。要实现这个方法,我们可以使用很方便的Image()构造函数。

代码详解:
var img = new Image(); // 创建一个元素
img.src = ‘myImage.png’; // 设置图片源地址
当脚本执行后,图片开始装载。

若调用 drawImage 时,图片没装载完,那什么都不会发生(在一些旧的浏览器中可能会抛出异常)。因此你应该用load事件来保证不会在加载完毕之前使用这个图片
var img = new Image(); // 创建img元素
img.onload = function(){
// 执行drawImage语句
}
img.src = ‘myImage.png’; // 设置图片源地址

以上第一步就完成。第二步绘制开始:
使用 drawImage 方法将它渲染到 canvas 里。drawImage 方法有三种形态,下面是最基础的一种。

drawImage(image, x, y)
其中 image 是 image 或者 canvas 对象,x 和 y 是其在目标 canvas 里的起始坐标。
例子:

function draw() {
    var ctx = document.getElementById('canvas').getContext('2d');
    var img = new Image();
    img.onload = function(){
      ctx.drawImage(img,0,0);
      ctx.beginPath();
      ctx.moveTo(30,96);
      ctx.lineTo(70,66);
      ctx.lineTo(103,76);
      ctx.lineTo(170,15);
      ctx.stroke();
    }
    img.src = 'images/backdrop.png';
  }

代码解释:这里只用到一个 image 对象,于是就在它的 onload 事件响应函数中触发绘制动作。drawImage 方法将背景图放置在 canvas 的左上角 (0,0) 处。

drawImage 方法的又一变种是增加了两个用于控制图像在 canvas 中缩放的参数。
drawImage(image, x, y, width, height)
这个方法多了2个参数:width 和 height,这两个参数用来控制 当向canvas画入时应该缩放的大小
如:

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');
  var img = new Image();
  img.onload = function(){
    for (var i=0;i<4;i++){
      for (var j=0;j<3;j++){
        ctx.drawImage(img,j*50,i*38,50,38);
      }
    }
  };
  img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
}

drawImage 方法的第三个也是最后一个变种有8个新参数,用于控制做切片显示的
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
第一个参数和其它的是相同的,都是一个图像或者另一个 canvas 的引用。其它8个参数最好是参照右边的图解,前4个是定义图像源的切片位置和大小,后4个则是定义切片的目标显示位置和大小。
sx可选
需要绘制到目标上下文中的,image的矩形(裁剪)选择框的左上角 X 轴坐标。
sy可选
需要绘制到目标上下文中的,image的矩形(裁剪)选择框的左上角 Y 轴坐标。
sWidth可选
需要绘制到目标上下文中的,image的矩形(裁剪)选择框的宽度。如果不说明,整个矩形(裁剪)从坐标的sx和sy开始,到image的右下角结束。
sHeight可选
需要绘制到目标上下文中的,image的矩形(裁剪)选择框的高度。

dx
image的左上角在目标canvas上 X 轴坐标。
dy
image的左上角在目标canvas上 Y 轴坐标。
dWidth可选
image在目标canvas上绘制的宽度。 允许对绘制的image进行缩放。 如果不说明, 在绘制时image宽度不会缩放。
dHeight可选
image在目标canvas上绘制的高度。 允许对绘制的image进行缩放。 如果不说明, 在绘制时image高度不会缩放。

简单来说,前4 个是被切的图,在一张完整的图上,取一个宽,高为 sWidth, sHeight的框,取的位置是sx, sy。
取完后在位置dx, dy的地方开始将它显示出来,显示出来的宽,高为dWidth, dHeight

附加:Gecko 1.9.2 引入了 mozImageSmoothingEnabled 属性,值为 false 时,图像不会平滑地缩放。默认是 true 。

cx.mozImageSmoothingEnabled = false;

保存状态
ctx.save();
保存到栈中的绘制状态有下面部分组成:

当前的变换矩阵。
当前的剪切区域。
当前的虚线列表.
以下属性当前的值: strokeStyle, fillStyle, globalAlpha, lineWidth, lineCap, lineJoin, miterLimit, lineDashOffset, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, globalCompositeOperation, font, textAlign, textBaseline, direction, imageSmoothingEnabled.

例子:

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

ctx.save(); // 保存默认的状态

ctx.fillStyle = "green";
ctx.fillRect(10, 10, 100, 100);

ctx.restore(); // 还原到上次保存的默认状态
ctx.fillRect(150, 75, 100, 100);

解释:这样出来的是11个绿色的这封信和一个黑色的正方形,因为一开始的save保存了原来的状态
在后面的ctx.restore()后所有在这之间设置的颜色等属性都回归当时储存时的状态,所以才有回到了黑色,形成黑色方格。

ctx.restore() 恢复 保存时的canvas 状态
注意这个save是可以嵌套的,比如我save了一次黑色后,没用restore回归属性,继续save一个绿色。那么restore第一次回退到绿色,再restore一次才回到黑色

移动translate
它用来移动 canvas 和它的原点到一个不同的位置。

translate(x, y)
translate 方法接受两个参数。x 是左右偏移量,y 是上下偏移量。
做变形之前先保存状态是一个良好的习惯。
例子:

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');
  for (var i = 0; i < 3; i++) {
    for (var j = 0; j < 3; j++) {
      ctx.save();
      ctx.fillStyle = 'rgb(' + (51 * i) + ', ' + (255 - 51 * i) + ', 255)';
      ctx.translate(10 + j * 50, 10 + i * 50);
      ctx.fillRect(0, 0, 25, 25);
      ctx.restore();
    }
  }
}

代码介绍:在 draw 方法中调用 fillRect() 方法 9 次,用了 2 层循环。每一次循环,先移动 canvas ,画螺旋图案,然后恢复到原始状态。

旋转rotate
rotate 方法,它用于以原点(0,0)为中心旋转 canvas。
rotate(angle)
这个方法只接受一个参数:旋转的角度(angle),它是顺时针方向的,以弧度为单位的值。
旋转的中心点始终是 canvas 的原点,如果要改变它,我们需要用到 translate 方法
// 记住,要先移动原点位置,再进行旋转,最后再是画图和放图片

缩放
用它来增减图形在 canvas 中的像素数目,对形状,位图进行缩小或者放大。
scale(x, y)
scale 方法接受两个参数。x,y 分别是横轴和纵轴的缩放因子,它们都必须是正值。值比 1.0 小表示缩小,比 1.0 大则表示放大,值为 1.0 时什么效果都没有
用法:ctx.scale(0.75,0.75);

变形 transform

该方法允许对变形矩阵直接修改。
transform(m11, m12, m21, m22, dx, dy)
这么来看6个参数

m11 m21 dx
m12 m22 dy
0 0 1

m11:水平方向的缩放

m12:水平方向的倾斜偏移

m21:竖直方向的倾斜偏移

m22:竖直方向的缩放

dx:水平方向的移动

dy:竖直方向的移动

globalCompositeOperation (是一个组合图形方法具体请看https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial/Compositing)
我们不仅可以在已有图形后面再画新图形,还可以用来遮盖指定区域,清除画布中的某些部分(清除区域不仅限于矩形,像clearRect()方法做的那样)以及更多其他操作。

globalCompositeOperation = type
这个属性设定了在画新图形时采用的遮盖策略,其值是一个标识12种遮盖方式的字符串。

裁切路径
裁切路径和普通的 canvas 图形差不多,不同的是它的作用是遮罩,用来隐藏不需要的部分。
裁切路径不会在 canvas 上绘制东西,而且它永远不受新图形的影响。
clip()
将当前正在构建的路径转换为当前的裁剪路径。
例子:

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

// Create clipping region
ctx.arc(100, 100, 75, 0, Math.PI*2, false);
ctx.clip();			// 将接下来画的图按上面的标准裁。

ctx.fillRect(0, 0, 100,100);

像素操作

ImageData 对象节
ImageData对象中存储着canvas对象真实的像素数据,它包含以下几个只读属性:

width

图片宽度,单位是像素
height
图片高度,单位是像素
data
Uint8ClampedArray类型的一维数组,包含着RGBA格式的整型数据,范围在0至255之间(包括255)。
data属性返回一个 Uint8ClampedArray,它可以被使用作为查看初始像素数据。每个像素用4个1bytes值(按照红,绿,蓝和透明值的顺序; 这就是”RGBA”格式) 来代表。每个颜色值部份用0至255来代表。每个部份被分配到一个在数组内连续的索引,左上角像素的红色部份在数组的索引0位置。像素从左到右被处理,然后往下,遍历整个数组。
Uint8ClampedArray 包含高度 × 宽度 × 4 bytes数据,索引值从0到(高度×宽度×4)-1

如,要读取图片中位于第50行,第200列的像素的蓝色部份
blueComponent = imageData.data[((50-1)imageData.width + (200-1))4 – 1 + 3];

创建一个ImageData对象节
去创建一个新的,空白的ImageData对象,你应该会使用createImageData() 方法。有2个版本的createImageData()方法。

var myImageData = ctx.createImageData(width, height);
上面代码创建了一个新的具体特定尺寸的ImageData对象。所有像素被预设为透明黑。

你也可以创建一个被anotherImageData对象指定的相同像素的ImageData对象。这个新的对象像素全部被预设为透明黑。这个并非复制了图片数据。

var myImageData = ctx.createImageData(anotherImageData);
解释: createImageData()函数
createImageData() 是 Canvas 2D API 创建一个新的、空白的、指定大小的 ImageData 对象。 所有的像素在新对象中都是透明的。
语法
ImageData ctx.createImageData(width, height);
ImageData ctx.createImageData(imagedata);
参数
width ImageData 新对象的宽度。
height ImageData 新对象的高度。
imagedata 从现有的 ImageData 对象中,复制一个和其宽度和高度相同的对象。图像自身不允许被复制。

返回值
指定了宽度和高度的,新的 ImageData 对象。 新对象使用透明的像素进行填充。

抛出错误
IndexSizeError
如果宽度或者高度变量值为零,会抛出此异常。

得到场景像素数据

为了获得一个包含画布场景像素数据的ImageData对像,你可以用getImageData()方法:

var myImageData = ctx.getImageData(left, top, width, height);
这个方法会返回一个ImageData对象,它代表了画布区域的对象数据,此画布的四个角落分别表示为(left, top), (left + width, top), (left, top + height), 以及(left + width, top + height)四个点。这些坐标点被设定为画布坐标空间元素。

注:任何在画布以外的元素都会被返回成一个透明黑的ImageData对像。
就是在画布的 left,top 位置开始,选择一个width,height的方型区域的对象数据

在场景中写入像素数据

你可以用putImageData()方法去对场景进行像素数据的写入。

ctx.putImageData(myImageData, dx, dy);
dx和dy参数表示你希望在场景内左上角绘制的像素数据所得到的设备坐标。
dx, dy分别是从画布的左边和上边多少开始渲染图片
例如,为了在场景内左上角绘制myImageData代表的图片,你可以写如下的代码:

ctx.putImageData(myImageData, 0, 0);

图片灰度和反相颜色节

在这个例子里,我们遍历所有像素以改变他们的数值。然后我们将被修改的像素数组通过putImageData()放回到画布中去。invert函数仅仅是去减掉颜色的最大色值255.grayscale函数仅仅是用红绿和蓝的平均值。你也可以用加权平均,例如x = 0.299r + 0.587g + 0.114b这个公式。
其实就是改变颜色后从新放到该位置

缩放和反锯齿

在drawImage() 方法, 第二个画布和imageSmoothingEnabled 属性的帮助下,我们可以放大显示我们的图片及看到详情内容。

我们得到鼠标的位置并裁剪出距左和上5像素,距右和下5像素的图片。然后我们将这幅图复制到另一个画布然后将图片调整到我们想要的大小。在缩放画布里,我们将10×10像素的对原画布的裁剪调整为 200×200 。(200×200是你想要放大后的像素,这里就是将10×10放大为200×200)

zoomctx.drawImage(canvas,
Math.abs(x – 5), Math.abs(y – 5),
10, 10, 0, 0, 200, 200);

解释下imageSmoothingEnabled 属性
ctx.imageSmoothingEnabled
是 Canvas 2D API 用来设置图片是否平滑的属性,true表示图片平滑(默认值),false表示图片不平滑。当我们获取 imageSmoothingEnabled 属性值时, 它会返回最新设置的值。
以缩放画布为例,这个属性对像素为主的游戏很有用。默认的改变大小的算法会造成图片模糊并且破坏图片原有的像素。 如果那样的话,设置属性值为false
用法:(各个兼容都可以写)
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.msImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;

保存图片

HTMLCanvasElement 提供一个toDataURL()方法,此方法在保存图片的时候非常有用。它返回一个包含被类型参数规定的图像表现格式的数据链接。返回的图片分辨率是96dpi。

canvas.toDataURL(‘image/png’)
默认设定。创建一个PNG图片。
如果画布的高度或宽度是0,那么会返回字符串“data:,”

canvas.toDataURL(type, encoderOptions);
参数
type 可选 图片格式,默认为 image/png
encoderOptions 可选
在指定图片格式为 image/jpeg 或 image/webp的情况下,可以从 0 到 1 的区间内选择图片的质量。如果超出取值范围,将会使用默认值 0.92。其他参数会被忽略。

返回值
包含 data URI 的DOMString。

当你从画布中生成了一个数据链接,例如,你可以将它用于任何元素,或者将它放在一个有download属性的超链接里用于保存到本地。

你也可以从画布中创建一个Blob对像。

canvas.toBlob(callback, type, encoderOptions)
这个创建了一个在画布中的代表图片的Blob对像。

canvas.toBlob(callback, type, encoderOptions);
参数
callback
回调函数,可获得一个单独的Blob对象参数。
type 可选
DOMString类型,指定图片格式,默认格式为image/png。
encoderOptions 可选
Number类型,值在0与1之间,当请求图片格式为image/jpeg或者image/webp时用来指定图片展示质量。如果这个参数的值不在指定类型与范围之内,则使用默认值,其余参数将被忽略。
返回值 无。
详细请看
https://developer.mozilla.org/zh-CN/docs/Web/API/HTMLCanvasElement/toBlob

点击区域和无障碍访问

标签只是一个位图,它并不提供任何已经绘制在上面的对象的信息。
应该避免在交互型的网站或者App上使用canvas。

点击区域
hit region API让你可以在canvas上定义一个区域,这让无障碍工具获取canvas上的交互内容成为可能。它能让你更容易地进行点击检测并把事件转发到DOM元素去。它有3个方法:
CanvasRenderingContext2D.addHitRegion()
在canvas上添加一个点击区域。
CanvasRenderingContext2D.removeHitRegion()
从canvas上移除指定id的点击区域。
CanvasRenderingContext2D.clearHitRegions()
移除canvas上的所有点击区域。

解释:
ctx.addHitRegion(options); 允许你很容易地实现一个点击区域, 让你触发 DOM 元素的事件
options 参数是可选的。 当赋值时, Object 包含以下属性:

path

Path2D 对象

描述点击区的区域范围。 如果不给此属性赋值, 则会使用当前的路径。
fillRule
遵循的填充规则(默认是“nonzero”)。
id 点击区的ID,在事件中可以引用此ID,就像示例中那样。
parentID 父区域的ID,为了光标回退或者辅助工具导航 。
cursor
鼠标移动到点击区时的 cursor (默认是 “inherit”)。 继承父点击区域的光标,或者canvas元素的光标。
control 触发事件的元素(canvas的子孙元素)。 默认为 null。
label 如果没有control属性,文本标签作为辅助工具,用作点击区域的描述。 默认为 null。
role 如果没有control属性,ARIA role 作为辅助工具,决定如何表示点击区域。 默认为 null.
例子:
ctx.addHitRegion({id: “circle”});

addHitRegion()方法也可以带一个control选项来指定把事件转发到哪个元素上(canvas里的元素)。

ctx.addHitRegion({control: element});
把这个特性用在元素上会很有用

鼠标事件

区域只读属性返回受事件影响的画布命中区域的id。如果没有命中区域受到影响,则返回null。
var hitRegion = instanceOfMouseEvent.region
返回值
表示命中区域id的DOMString。

焦点圈

当用键盘控制时,焦点圈是一个能帮我们在页面上快速导航的标记。要在canvas上绘制焦点圈,可以使用drawFocusIfNeeded 属性。

CanvasRenderingContext2D.drawFocusIfNeeded()
如果给定的元素获得了焦点,这个方法会沿着在当前的路径画个焦点圈。

scrollPathIntoView()方法可以让一个元素获得焦点的时候在屏幕上可见(滚动到元素所在的区域)。
CanvasRenderingContext2D.scrollPathIntoView()
把当前的路径或者一个给定的路径滚动到显示区域内。

解释:
1.
drawFocusIfNeeded() 是 Canvas 2D API 用来给当前路径或特定路径绘制焦点的方法,如果给定的元素获取了焦点。
语法
ctx.drawFocusIfNeeded(element);
ctx.drawFocusIfNeeded(path, element);
参数
element 是否需要设置焦点的元素。
path Path2D 路径。
示例

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

button.focus();

ctx.beginPath();
ctx.rect(10, 10, 30, 30);
ctx.drawFocusIfNeeded(button);

其实就是给获取焦点的东西加个框

2.
scrollPathIntoView() 是 Canvas 2D API 将当前或给定的路径滚动到窗口的方法。类似于 Element.scrollIntoView()
ctx.scrollPathIntoView();
ctx.scrollPathIntoView(path);

使用例子:

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

ctx.beginPath();
ctx.fillRect(10, 10, 30, 30);
ctx.scrollPathIntoView();
//这个兼容差

解释下canvas的API接口Path2D构造函数

Path2D()

Path2D 构造函数。 创建一个新的 Path2D 对象。
方法
1.Path2D.addPath()
添加一条新路径到对当前路径。
2.Path2D.closePath()
使笔点返回到当前子路径的起始点。它尝试从当前点到起始点绘制一条直线。 如果图形已经是封闭的或者只有一个点,那么此函数不会做任何操作。
3.Path2D.moveTo()
将一个新的子路径的起始点移动到(x,y)坐标。
4.Path2D.lineTo()
使用直线连接子路径的终点到 x, y 坐标。
5.Path2D.bezierCurveTo()
添加一条三次贝赛尔曲线到当前路径。 该方法需要三个点。 第一、第二个点是控制点,第三个点是结束点。起始点是当前路径的最后一个点,绘制贝赛尔曲线前,可以通过调用 moveTo() 进行修改。
6.Path2D.quadraticCurveTo()
添加一条二次贝赛尔曲线到当前路径。
7.Path2D.arc()
添加一条圆弧路径。 圆弧路径的圆心在 (x, y) 位置,半径为 r ,根据anticlockwise (默认为顺时针)指定的方向从 startAngle 开始绘制,到 endAngle 结束。
8.Path2D.arcTo()
根据控制点和半径添加一条圆弧路径,使用直线连接前一个点。
9.Path2D.ellipse()
添加一条椭圆路径。椭圆的圆心在(x,y)位置,半径分别是radiusX 和 radiusY ,按照anticlockwise (默认顺时针)指定的方向,从 startAngle 开始绘制,到 endAngle 结束。
10.Path2D.rect()
创建一条矩形路径,矩形的起点位置是 (x, y) ,尺寸为 width 和 height。

解释:
Path2D() 构造函数返回一个新的 Path2D 对象的实例,可以选择另一条路径作为参数(创建一个拷贝),或者选择 SVG path 数据构成的字符串
语法
new Path2D();
new Path2D(path);
new Path2D(d);
参数
path 可选
当调用另一个 Path2D 对象时,会创建一个 path 变量的拷贝。
d 可选
当调用 SVG path 数据构成的字符串时,会根据描述创建一个新的路径。
如:

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

var path1 = new Path2D();
path1.rect(10, 10, 100,100);

var path2 = new Path2D(path1);
path2.moveTo(220, 60);
path2.arc(170, 60, 50, 0, 2 * Math.PI);

ctx.stroke(path2);

使用 SVG 路径

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

var p = new Path2D("M10 10 h 80 v 80 h -80 Z");
ctx.fill(p);

解释:路径将会移动到点 (M10 10) ,然后向右侧水平移动80个点 (h 80),然后向下80个点 (v 80),然后向左80个点(h -80),最后回到起始点(z)。

1.Path2D.addPath()
是 Canvas 2D API 根据指定路径变量添加路径的方法。
path.addPath(path [, transform]);
参数
path
需要添加的 Path2D 路径。
transform 可选
SVGMatrix 作为新增路径的变换矩阵。

示例

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

// 用矩形创建一个新路径
var p1 = new Path2D();
p1.rect(0,0,100,100);

// 使用rect创建另一个路径
var p2 = new Path2D();
p2.rect(0,0,100,100);

// 创建一个向右垂直移动300个点的变换矩阵	这是第一条路径
var m = document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGMatrix();
m.a = 1; m.b = 0;
m.c = 0; m.d = 1;
m.e = 300; m.f = 0;

// 将第二条路径添加到第一条路径
p1.addPath(p2, m);

//最后,将第一个路径填充到画布上
ctx.fill(p1);

2.Path2D.closePath()
使笔点返回到当前子路径的起始点。它尝试从当前点到起始点绘制一条直线。 如果图形已经是封闭的或者只有一个点,那么此函数不会做任何操作。
ctx.closePath();
ctx.beginPath();
ctx.moveTo(20,20);
ctx.lineTo(200,20);
ctx.lineTo(120,120);
ctx.closePath();

3.Path2D.moveTo()
将一个新的子路径的起始点移动到(x,y)坐标。
4.Path2D.lineTo()
使用直线连接子路径的终点到 x, y 坐标。
5.Path2D.bezierCurveTo()
添加一条三次贝赛尔曲线到当前路径。 该方法需要三个点。 第一、第二个点是控制点,第三个点是结束点。起始点是当前路径的最后一个点,绘制贝赛尔曲线前,可以通过调用 moveTo() 进行修改。
6.Path2D.quadraticCurveTo()
添加一条二次贝赛尔曲线到当前路径。
7.Path2D.arc()
添加一条圆弧路径。 圆弧路径的圆心在 (x, y) 位置,半径为 r ,根据anticlockwise (默认为顺时针)指定的方向从 startAngle 开始绘制,到 endAngle 结束。n
8.Path2D.arcTo()
根据控制点和半径添加一条圆弧路径,使用直线连接前一个点。
9.Path2D.ellipse()
添加一条椭圆路径。椭圆的圆心在(x,y)位置,半径分别是radiusX 和 radiusY ,按照anticlockwise (默认顺时针)指定的方向,从 startAngle 开始绘制,到 endAngle 结束。
10.Path2D.rect()
创建一条矩形路径,矩形的起点位置是 (x, y) ,尺寸为 width 和 height。
其它和上面方法一样