最近做项目遇到一个需求,对图片进行拖动+缩放,本来这个功能直接采用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>

Logo

前往低代码交流专区

更多推荐