最近做项目遇到一个需求,对图片进行拖动+缩放,本来这个功能直接采用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>
如果觉得《canvas+vue实现图片的缩放 拖拽》对你有帮助,请点赞、收藏,并留下你的观点哦!