canvas+vue实现图片的缩放、拖拽
最近做项目遇到一个需求,对图片进行拖动+缩放,本来这个功能直接采用viewerjs这个插件就可以实现的。但是我们还有其他需求啊,在底层图片上添加一些图片或者文字注释,并且随着底层图片的拖动和缩放后,其相对位置不能发生改变,因此选择了用canvas解决,毕竟x,y坐标在那里,敌动我也动。定义canvas,解决绘制图片模糊的问题<template><canvas ref="bargr
·
最近做项目遇到一个需求,对图片进行拖动+缩放,本来这个功能直接采用viewerjs这个插件就可以实现的。
但是我们还有其他需求啊,在底层图片上添加一些图片或者文字注释,并且随着底层图片的拖动和缩放后,其相对位置不能发生改变,因此选择了用canvas解决,毕竟x,y坐标在那里,敌动我也动。
定义canvas,解决绘制图片模糊的问题
<template>
<canvas ref="bargraphCanvas" :width="canvasWidth" :height="canvasHeight" :style="'width:'+canvasWidth/2+'px;height:'+canvasHeight/2+'px;'"></canvas>
</template>
这里注意一下,canvas有自身的width、height和style里面的width、height,这两者是不同的 。
敲黑板: canvas的width、height是canvas实际的宽高,而style里面设置的width、height是被浏览器渲染的宽高。如果我们不设置style宽高,那么canvas会默认将一个逻辑单位映射到一个像素。
但是一般浏览器都是两个像素点映射称一个像素的,所以为了保证图片不模糊,简单的将画布的大小设置成了浏览器渲染大小的一半(这个有更精确的方法,可以自己去百度)。
实现图片渲染
在data中定义一些参数,按需定义
//定义需要渲染的图片数组
canvasWidth: 2400, // 画布大小
canvasHeight: 1400,
myCanvas: null,
ctx: null,
imgX: 200, // 图片在画布中渲染的起点x坐标,这个坐标为后期的添加注释图片、文字位置提供了相对坐标点
imgY: 100,
imgScale: 0.9, // 图片启示的缩放大小
extraImgList: [ {url:require("@public/images/dashboard/labor3.png"), x: 0, y: 0, width: 2400, height: 1400},
{url:require("@public/images/icon-menu-2.png"), x: 700, y: 100, width: 40, height: 40}
],
imgObject: [], // 存放预加载好了的图片对象
在mounted中获取到canvas对象,并调用方法
mounted() {
this.myCanvas = this.$refs.bargraphCanvas;
this.ctx = this.myCanvas.getContext('2d');
this.loadImg();
this.canvasEventsInit();
},
实现函数:
图片预加载
loadImg() {
var _this = this;
let extraImgList = _this.extraImgList;
let length = extraImgList.length;
var imageList = [];
let count = 0;
//加载底层图片,这个先后顺序一定要有,不然用来注释的图片可能会被底层图片覆盖
var isBgLoaded = false;
var img = new Image();
var bgImg = extraImgList[0];
img.src = bgImg.url;
img.onload = () => {
imageList.push({img: img, x: bgImg.x, y: bgImg.y, width: bgImg.width, height: bgImg.height});
++count;
if(length > 1) { // 加载多张图片
//加载剩余图片
for(let key = 1; key < length; key++) {
let item = extraImgList[key];
let extarImg = new Image();
extarImg.src = item.url;
extarImg.onload = () => {
imageList.push({img: extarImg, x: item.x, y: item.y, width: item.width, height: item.height})
if(++count >= length) { // 判断是否所有的图片都被预加载完成
_this.imgObject = imageList;
_this.drawImage(imageList);
}
}
}
} else { //只加载一张图片
_this.imgObject = imageList;
_this.drawImage(imageList);
}
}
绘制图片
drawImage(imgList) {
var _this = this;
_this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight); // 先清空画布
for(let i = 0; i < imgList.length; i++) {
_this.ctx.drawImage(
imgList[i].img, //规定要使用的图片
_this.imgX + imgList[i].x * _this.imgScale, _this.imgY+ imgList[i].y * _this.imgScale,//在画布上放置图像的 x 、y坐标位置
imgList[i].width*_this.imgScale, imgList[i].height*_this.imgScale //要使用的图像的宽度、高度
);
}
// this.ctx.font="15px Arial"; // 添加文字注释
// this.ctx.fillStyle = "black"
// this.ctx.fillText("name",this.imgX + 120 * this.imgScale, this.imgY+ 25 * this.imgScale);
},
为canvas添加点击拖动、缩放事件
canvasEventsInit() {
var _this = this;
var canvas = _this.myCanvas;
canvas.onmousedown = function (event) {
var imgx = _this.imgX;
var imgy = _this.imgY;
var pos = {x:event.clientX, y:event.clientY}; //获取相对浏览器窗口的坐标,为后期将窗口坐标转换成canvas的坐标做准备
canvas.onmousemove = function (evt) { //移动
canvas.style.cursor = 'move';
var x = (evt.clientX - pos.x) * 2 + imgx; //坐标转换
var y = (evt.clientY - pos.y) * 2 + imgy;
_this.imgX = x;
_this.imgY = y;
_this.drawImage(_this.imgObject); //重新绘制图片
};
canvas.onmouseup = function () {
canvas.onmousemove = null;
canvas.onmouseup = null;
canvas.style.cursor = 'default';
};
};
canvas.onmousewheel = canvas.onwheel = function (event) { //滚轮放大缩小
var wheelDelta = event.wheelDelta ? event.wheelDelta : (event.deltalY * (-40)); //获取当前鼠标的滚动情况
if (wheelDelta > 0) { // 放大时,每次放大到原来的1.1倍
_this.imgScale *= 1.1; //注意,我的缩放是以左上角位置为中心进行缩放的,如果要以图片中心为缩放点,需要修改 imgX,imgY的值
} else {
if(_this.imgScale > 0.9) { // 缩小到原来的0.9倍
_this.imgScale *= 0.9;
}
}
_this.drawImage(_this.imgObject); //重新绘制图片
event.preventDefault && event.preventDefault(); // 阻止默认事件,可能在滚动的时候,浏览器窗口也会滚动
return false;
};
},
附上完整代码
要运行的话,把图片位置改成自己的就可以
<template>
<canvas ref="bargraphCanvas" :width="canvasWidth" :height="canvasHeight" :style="'width:'+canvasWidth/2+'px;height:'+canvasHeight/2+'px;'"></canvas>
</template>
<script>
export default {
name: 'laborImage',
components: {
},
data() {
return {
canvasWidth: 2400, // 画布大小
canvasHeight: 1400,
extraImgList: [
{url:require("../images/labor1.png"), x: 0, y: 0, width: 2400, height: 1400},
{url:require("../images/labor2.png"), x: 700, y: 100, width: 40, height: 40}
],
myCanvas: null,
ctx: null,
imgObject: [],
imgX: 200, // 图片在画布中渲染的起点x坐标
imgY: 100,
imgScale: 0.9, // 图片的缩放大小
}
},
mounted() {
this.myCanvas = this.$refs.bargraphCanvas;
this.ctx = this.myCanvas.getContext('2d');
this.loadImg();
this.canvasEventsInit();
},
methods: {
loadImg() {
var _this = this;
let extraImgList = _this.extraImgList;
let length = extraImgList.length;
var imageList = [];
let count = 0;
//加载背景图片
var isBgLoaded = false;
var img = new Image();
var bgImg = extraImgList[0];
img.src = bgImg.url;
img.onload = () => {
imageList.push({img: img, x: bgImg.x, y: bgImg.y, width: bgImg.width, height: bgImg.height});
++count;
if(length > 1) {
//加载剩余图片
for(let key = 1; key < length; key++) {
let item = extraImgList[key];
let extarImg = new Image();
extarImg.src = item.url;
extarImg.onload = () => {
imageList.push({img: extarImg, x: item.x, y: item.y, width: item.width, height: item.height})
if(++count >= length) {
_this.imgObject = imageList;
_this.drawImage(imageList);
}
}
}
} else {
_this.imgObject = imageList;
_this.drawImage(imageList);
}
}
},
drawImage(imgList) {
var _this = this;
_this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
for(let i = 0; i < imgList.length; i++) {
_this.ctx.drawImage(
imgList[i].img, //规定要使用的图片
_this.imgX + imgList[i].x * _this.imgScale, _this.imgY+ imgList[i].y * _this.imgScale,//在画布上放置图像的 x 、y坐标位置。
imgList[i].width*_this.imgScale, imgList[i].height*_this.imgScale //要使用的图像的宽度、高度
);
}
// this.ctx.font="15px Arial";
// this.ctx.fillStyle = "black"
// this.ctx.fillText("name",this.imgX + 120 * this.imgScale, this.imgY+ 25 * this.imgScale);
},
/**
* 为画布上鼠标的拖动和缩放注册事件
*/
canvasEventsInit() {
var _this = this;
var canvas = _this.myCanvas;
canvas.onmousedown = function (event) {
var imgx = _this.imgX;
var imgy = _this.imgY;
var pos = {x:event.clientX, y:event.clientY}; //坐标转换,将窗口坐标转换成canvas的坐标
canvas.onmousemove = function (evt) { //移动
canvas.style.cursor = 'move';
var x = (evt.clientX - pos.x) * 2 + imgx;
var y = (evt.clientY - pos.y) * 2 + imgy;
_this.imgX = x;
_this.imgY = y;
_this.drawImage(_this.imgObject); //重新绘制图片
};
canvas.onmouseup = function () {
canvas.onmousemove = null;
canvas.onmouseup = null;
canvas.style.cursor = 'default';
};
};
canvas.onmousewheel = canvas.onwheel = function (event) { //滚轮放大缩小
var wheelDelta = event.wheelDelta ? event.wheelDelta : (event.deltalY * (-40)); //获取当前鼠标的滚动情况
if (wheelDelta > 0) {
_this.imgScale *= 1.1;
} else {
if(_this.imgScale > 0.9) {
_this.imgScale *= 0.9;
}
}
_this.drawImage(_this.imgObject); //重新绘制图片
event.preventDefault && event.preventDefault();
return false;
};
},
},
}
</script>
更多推荐
已为社区贡献4条内容
所有评论(0)