起因
基于一个复杂的图片预览的弹窗之上新增一个裁剪功用,直接用新的插件改掉本来的功用又很复杂而且操作办法与需求不符。因而需求自定义一个简略的裁剪功用。以canvas画布元素与图片标签的方位联系和大小进行裁剪。
canvas计划
流程
- 首要创建canvas对像
- 指定canvas的高度宽度(非style的宽高)
- 核算原图需求剪切的相关参数
- 经过drawImage办法将需求的部分画上去
- 经过toDataURL办法获取图片base64的值
- 完结,后续可对base64值进行其他操作。
//本地或线上图片地址
const SRC = "./aa.jpg"
const canvas = document.getElementById('canvas-cut')
const cut = canvas.getContext('2d')
const img = new Image()
img.src = SRC
//处理toDataURL遇跨域资源导致的报错
img.crossOrigin = 'Anonymous'
img.onload = function() {
cut.drawImage(img,295,40,100,100,0 ,0,100,100)
var imgbase64 = canvas.toDataURL("image/png")
//base64资源
console.log(imgbase64)
};
drawImage参数
drawImage 办法允许在 canvas 中插入其他图画(img和canvas元素)
以左上角为原点x,y轴的间隔
//参数有三种传值办法
drawImage(image, dx, dy)
drawImage(image, dx, dy, dw, dh)
//dx,dy 在画布上裁剪后图画放置的 x,y坐标方位
//sw和sh为在原图中需求截取的宽高,最终会以缩放的办法以dw,dh的大小展示在canvas中
drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)
适配原图的缩放旋转
当原图存在缩放和旋转的情况,裁剪也需求进行缩放旋转
旋转
canvas的旋转也是以左上角有为原点为旋转,旋转90度之后,则内容为空白了,因而需求translate特点移动一个间隔
cut.rotate(Math.PI / 2)
cut.translate(0, -1 * canvas.height)
//顺时针与逆时针旋转-270~270之间
// rationNum = (旋转角度/90)%4
cut.rotate(Math.PI * rationNum / 2)
switch (rationNum) {
case -1:
case 3:
cut.translate(-1 * canvas.width, 0)
break
case 1:
case -3:
cut.translate(0, -1 * canvas.height)
break
case -2:
case 2:
cut.translate(-1 * canvas.width, -1 * canvas.height)
break
}
}
依照上图旋转之后,画布与参照图片的联系,在实践裁剪的图的裁剪方位将会有变化(原点变化了) 这儿需求根据canvas与展示的图片的方位联系,推算出裁剪原图和canvas的方位联系即sx,sy的值
//drawLocal为裁剪的方位sx,sy最终还需求乘以缩放份额
//留意:我这儿的canvas是正方形的所以width和height值一样,此处都用canvas.width
//drawLocal在原图上面裁剪的起始位sx,sy的值
switch (rationNum) {
case -1:
case 3:
drawLocal = {
x: img.width - (canvasXY.y - imgXY.y) - canvas.width,
y: canvasXY.x - imgXY.x
}
break
case 1:
case -3:
drawLocal = {
x: canvasXY.y - imgXY.y,
y: img.height - (canvasXY.x - imgXY.x) - canvas.width
}
break
case -2:
case 2:
drawLocal = {
x: img.width - (canvasXY.x - imgXY.x) - canvas.width,
y: img.height - (canvasXY.y - imgXY.y) - canvas.width
}
break
}
缩放
实践中,看到的是一张图片,裁剪的是以new Image()重生的图片,因而一切的间隔有必要以画布与展示的图片核算坐标数据,然后再以缩放份额进行核算
const imgScale = img.style.transform ? img.style.transform.match(/scale\((\S*)\)/)[1] : 1
const scaleNum = originImg.width / (img.width * imgScale)
图片有两张:一张能够缩放旋转的图,一张是实践截取内容的图片
//最终大致如下
//留意:这儿canvas为一个正方形
cut.drawImage(
originImg,
drawLocal.x * ration,
drawLocal.y * ration,
canvas.width * ration,
canvas.width * ration,
0,
0,
canvas.width,
canvas.width
)
内部图片不支持跨域与canvas crossOrigin特点的抵触
所谓的跨域是因为浏览器的同源策略而引起的。(协议,域名,端口号)
可是img和link标签只能实现单向通信,即只能从客户端向服务器传递数据。img获取图片进行加载,link是获取样式表加载,而script回来的是javascript代码执行。因而,script,img,link标签不受跨域影响。 可是canvas需求对裁剪的图片进行可跨域的设置
originImg.setAttribute('crossOrigin', 'anonymous')
因而会呈现,页面分明有图片,可是设置该特点就回401(设置为允许跨域之后会图片的恳求会不带上cookie)
解决计划便是运用ajax发起恳求获取图片资源然后再设置给img(因为img标签不受跨域的影响,当用ajax恳求是很可能呈现跨域的现象,这儿需求后端设置一下)
//data 拿到资源然后转位base64格式
const reader = new FileReader()
reader.readAsDataURL(data)
reader.onload = ({ target }) => {
callback((target as FileReader).result as string)
}
重置canvas画布内容
-
运用:
context.clearRect(0, 0, canvas.width, canvas.height)
这是铲除整个canvas的最快和最具描绘性的办法。
-
不要运用:
canvas.width = canvas.width
重置
canvas.width
重置一切canvas状态(例如,转化,lineWidth,strokeStyle等),它十分缓慢,不适用于一切浏览器,并且不描绘你实践测验的内容去做(自己赋值自己???重点是typescript也无法解析)
关于git
因为屡次的测验以及本地有署理,之前跨域恳求在打包发布至测验环境才会呈现跨域的问题,产生很多git log,一把辛酸泪。所以这儿需求git兼并多个commit,否则不好看
//找到最开始的commit id
git log
//软重置
git reset --soft 1111111111
//生成一次新的commit
git commit -m'XXX功用'
git push -f
最终
总结一下,canvas裁剪会遇到图片资源跨域的问题,适配图片的旋转缩放,不同的预览图片的插件,旋转缩放的办法也不同,但最终是需求核算出份额即可。。。。。
希望遇到的每一个坑都是一次进步~