保存图片
前言
canvas是画布的概念,那么canvas在浏览器表现出来的是一张图片
那么我们可以把这张图片右键保存(把canvas以图片的形式保存)(保存的图片格式是png(底部的透明的) )
那么怎么用js代码下载canvas图片
先在canvas上面画出一个实心圆来吧
CSS样式代码
<style>
*{
margin:0;
padding:0;
}
canvas{
display: block;
margin: 50px auto;
border: 2px blue solid;
}
</style>
HTML和JS代码
<body>
<canvas id="canvas1" width="500" height="500"></canvas>
<script>
var canvas = document.getElementById('canvas1');
var cxt = canvas.getContext('2d');
//绘画一个圆
cxt.beginPath();
cxt.arc(250,250,250,0,Math.PI*2);
cxt.fill();
</script>
</body>
方法一 通过todataURL转换成base64位的字符串赋值给了href(缺点base65位的字符串太大了)
基础知识
- canvas节点.toDataURL(),方法返回结果是base64位的字符串(这些字符串的结果就是一张图片)
- a节点.download,通过a标签的download修改了下载图片的名字
- a节点.click(),表示在JS脚本内部手动点击a标签(a标签独有)
把需要下载的图片放到一个函数里,让这个函数先执行,然后创建一个a标签,在用toDataURL方法获取到base64位的字符赋值给a标签的href属性,在通过a标签的download属性修改下载图片的名字,在通过click函数自动点击图下载
var canvas = document.getElementById('canvas1');
var cxt = canvas.getContext('2d');
//绘画一个圆
cxt.beginPath();
cxt.arc(250,250,250,0,Math.PI*2);
cxt.fill();
download();
function download(){
//创建一个a标签
var link = document.createElement('a');
// canvas.toDataURL()函数执行时 返回结果是base64位的字符串 这些字符串的结果就是一张图片
//把a标签的href属性赋值到canvas图片的地址
link.href = canvas.toDataURL();
// 通过a标签的download属性修改下载图片的名字
link.download = 'canvas.png';
//让a标签的click函数,直接下载图片
link.click();//这句代码的作用就是相当于手动点击a标签
};
方法二 通过Bole构造函数生成一个图片对象在进行操作
基础知识
- canvas节点.toBlob函数执行,能够把canvas节点变成Bolb数据
- canvas节点.toBlob()函数执行时内部支持回调函数 ,第一参数就存储着当画布被转换成Bolb数据时就把Bolb数据给这个参数
- URL.createObjectURL(Blob数据); 把Blob数据传递到URL.createObjectURL生成一个URL
把需要下载的图片放到一个函数里,让这个函数先执行,在调用canvas节点上面的toBlob函数,当函数执行时传递一个参数这个参数就是Blob数据,然后把blob数据传递到URL.createObjectURL生成一个URL,然后在创建一个a标签在把a标签的href属性赋值到url里用download属性修改一下下载图片的名字,然后在JS内部click自动点击一次就好了
var canvas = document.getElementById('canvas1');
var cxt = canvas.getContext('2d');
//绘画一个圆
cxt.beginPath();
cxt.arc(250,250,250,0,Math.PI*2);
cxt.fill();
downBolb()
function downBolb() {
//canvas.toBlob函数能够把这个画布变成Bolb数据
//当画布转换成Blob数据时触发回调函数
canvas.toBlob((blob) => {
//把blob传递到URL.createObjectURL生成一个URL
var url = URL.createObjectURL(blob);
//创建一个a标签
var link = document.createElement('a');
//把a标签的href属性赋值到生成好了的url
link.href = url;
//通过a标签的download属性修改下载图片的名字
link.download = 'blob.png';
//让a标签的click函数,直接下载图片
link.click();
})
}
globalCompositeOperation
基础知识
设置画布的透明度
- 画笔.globalAlpha//查询当前画布的透明度(默认是1)
- 画笔.globalAlpha = 数值(0-1); 设置当前画布的透明度
var canvas = document.getElementById('canvas');
var cxt = canvas.getContext('2d');
//设置画布的透明度
//cxt.globalAlpha(0-1)透明度
console.log(cxt.globalAlpha);//查询当前画布的透明度(默认是1)
cxt.globalAlpha = 0.2;//设置当前画布的透明度
//绘制矩形
cxt.fillRect(0,0,100,100);
//绘制圆
cxt.beginPath();
cxt.fillStyle = 'pink';
cxt.arc(100,100,100,0,Math.PI*2);
cxt.fill();
globalCompositeOperation
globalCompositeOperation表示融合的部分 Composite(融合) Operation(操作活动)
可以通过通过属性来设置两个图片融合的部分
globalCompositeOperation 设置两个图片的重合部分的显示情况
目标图像和源图像
以cxt.globalCompositeOperation这句代码为分割点
- 上面的一个图形(路径)叫做目标图像
- 下面的一个图形(路径)叫做源图像
globalCompositeOperation一般是写在beginPath之前的
基础知识
cxt.globalCompositeOperation 设置两个图片的重合部分的显示情况
source-over 默认 源图像在上面
- source-atop 超过目标图像的源图像全都不可见 目标图像是可见的
- source-in 只有在目标图像之内的源图像是可见的 目标图像是不见的
- source-out 只有在目标图像之外的源图像是可见的 目标图像是不见的
destination-over 目标图像在上面
- destination-atop 超过源图像的目标图像全都不可见 源图像是可见的
- destination-in 只有在源图像之内的目标图像是可见的 源图像是不见的
- destination-out 只有在源图像之外的目标图像是可见的 源图像是不见的
xor 设置两个图像重合的部分透明
var canvas = document.getElementById('canvas1');
var cxt = canvas.getContext('2d');
//目标图像
cxt.fillRect(0,0,100,100);
// cxt.globalCompositeOperation('source-over');
//source-over原图像在上面(默认值) source(表示源) over(上面)
// cxt.globalCompositeOperation('source-atop');
//source-atop目标图像超过原图像的部分都不可见 atop(上顶)
// cxt.globalCompositeOperation('source-in');
//source-in 只要在目标之内的源图像是可见的 in(在..内)
// cxt.globalCompositeOperation('source-out');
//source-out 超过目标图像之外的源图像是可见的 out(出来)
// cxt.globalCompositeOperation('destination-over');
//destination-over目标图像在上面 destination(目的地)
// cxt.globalCompositeOperation('destination-atop');
//destination-atop 超过源图像的目标图像全都不可见
// cxt.globalCompositeOperation('destination-in');
// destination-in 只有在源图像之内的目标图像是可见的 源图像是不见的
// cxt.globalCompositeOperation('destination-out');
//destination-out 只有在源图像之外的目标图像是可见的 源图像是不见的
cxt.globalCompositeOperation('xor');
// xor设置两个图像重合的部分透明
cxt.beginPath();
// 源图像
cxt.fillStyle = 'pink';
cxt.arc(100,100,100,0,Math.PI*2);
cxt.fill();
补充(清除画布)
- 清除画布 clearRect(x,y,w,h)
- cxt.clearRect(清除图片的水平距离,清除图片的竖直距离,清除宽度,清除高度)
var canvas = document.getElementById('canvas1');
var cxt = canvas.getContext('2d');
cxt.fillRect(0,0,500,500);
//在水平方向为0和竖直方向为0,清除范围为宽200高200
//清除画布
cxt.clearRect(0,0,200,200);
练习canvas时钟
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
*{
margin:0;
padding: 0;
}
canvas{
display: block;
border:2px solid blue;
margin:50px auto;
border-radius: 50%;
}
</style>
</head>
<body>
<canvas id="canvas" width="500" height="500"></canvas>
<script>
var canvas = document.getElementById('canvas');
var cxt = canvas.getContext('2d');
function getTime(){
//修改时针的背景颜色
canvas.style.backgroundColor = "#" + Math.random().toString(16).slice(2,8)
//清除长方形(清除图形)
//cxt.clearRect(清除图片的水平距离,清除图片的竖直距离,清除宽度,清除高度)
// 清除画布 clearRect(x,y,w,h)
cxt.clearRect(0,0,500,500);
//绘制外部的大圆形
cxt.strokeStyle = 'red';//设置画笔的颜色
cxt.lineWidth = 2;//设置画笔的线宽
cxt.beginPath();//闭合上一次路径
cxt.arc(250, 250, 250, 0, Math.PI * 2);//绘制圆形轨迹
cxt.closePath();//闭合下一次路径
cxt.stroke();//绘制空心圆形
//绘制内部的圆饼
cxt.beginPath();
cxt.fillStyle = 'blue';
cxt.arc(250, 250, 10, 0, Math.PI * 2);
cxt.closePath();
cxt.fill();//绘制实心的圆形
//通过fill画出空心的圆,其实空心的圆外部还有条圆线可以通过stroke给他画出来
//绘制圆饼的线条
cxt.stroke();
//绘制指针
var nowTime = new Date;//获取现在时间
var h = nowTime.getHours();//获取小时
var m = nowTime.getMinutes();//获取分钟
var s = nowTime.getSeconds();//获取秒钟
//绘制时间文字
cxt.font = '25px 微软雅黑';
cxt.fillStyle = 'red';
cxt.textAlign = 'center';
cxt.fillText(toTwo(h)+':'+toTwo(m)+':'+ toTwo(s),252,400);
//处理获取的小时 变成12进制的时间
h = h>12 ? h-12 : h;
//12个小时 对应的是 360° 则应该1小时旋转30°
var rotateH = h*Math.PI/6;
//60分钟对应的是 360° 则应该1分钟旋转6°
var rotateM = m*Math.PI/30;
//60秒对应的是 360° 则应该1秒旋转6°
var rotateS = s*Math.PI/30;
for(var i=1;i<=12;i++){//for循环中的变量i是index的缩写
cxt.save();//保存上一次画布的状态
cxt.translate(250,250);//设置画布(字)的起始位置
cxt.fillStyle = 'black';//设置字体的颜色
//设置字体
cxt.font = '20px 微软雅黑';
cxt.textAlign = 'center';
cxt.textBaseline = 'middle'
var x = 230*Math.sin(Math.PI*i/6)
var y = 230*Math.cos(Math.PI*i/6)
//画出实心的字体
cxt.fillText(i,x,-y);
cxt.restore();//释放上一次画布的状态
};
//绘制时针
drawPointer({
rotate:rotateH,//旋转角度
color:'green',//颜色
width:5,//针的宽度
length:100,//针的长度
})
//绘制分针
drawPointer({
rotate:rotateM,//旋转角度
color:'blue',//颜色
width:4,//针的宽度
length:150,//针的长度
})
//绘制秒针
drawPointer({
rotate:rotateS,//旋转角度
color:'purple',//颜色
width:3,//针的宽度
length:200,//针的长度
})
}
//把 1这样的数字变成 01 给个位数补充一个字符串0
function toTwo(num){
return num<10 ? '0' + num : num;
}
//绘制分针 时针 秒针
function drawPointer(options){
cxt.save();
cxt.translate(250,250);//设置画布(针)的起始位置
cxt.beginPath();
//设置针的旋转角度
cxt.rotate(options.rotate);
cxt.strokeStyle = options.color;//设置秒针的颜色
cxt.lineWidth = options.width;//设置秒针的线宽
cxt.moveTo(0,0);
cxt.lineTo(0,-options.length);
cxt.closePath();
cxt.stroke();
cxt.restore();//释放上一次画布的状态
//cxt.translate和cxt.rotate方法都是有叠加效果的
}
//开启定时器每个一段时间 获取 时 分秒
getTime();
setInterval(getTime,1000);
</script>
</body>
</html>