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

  1. 【项目技术点总结之一】vue集成d3.js利用svg加载图片实现缩放拖拽功能

    [项目技术点总结之一]vue集成d3.js利用svg加载图片实现缩放拖拽功能 前言 概述 技术介绍 实现过程 插件安装 引用组件 初始化组件 实现效果 简单理解 使用d3创建一个svg 在svg中提添 ...

  2. vue 实现图片放大缩小拖拽

    https://www.h5w3.com/239173.html https://blog.51cto.com/wjw1014/5411219 // 放大缩小public setTransform ( ...

  3. ZRender使用中关于图片裁剪、拖拽问题

    最近做项目使用到了ZRender ZRender 是二维绘图引擎,它提供 Canvas.SVG.VML 等多种渲染方式.ZRender 也是 ECharts 的渲染器,绘图的时候特别方便. 如果想在画 ...

  4. vue+flask实现视频合成(拖拽上传)

    vue+flask实现视频合成 效果如下 欢迎访问博客代码哈士奇 技术 聊天 交流群 974178910 前端交流群 535620886 vue+flask实现视频合成 拖拽上传我们之前一个文章有写过 ...

  5. web使用panzoom.js 缩放拖拽 工程图cad图

    web使用panzoom.js 缩放拖拽 工程图cad图 前言 第一步下载图片转换工具 将cad的dwg转换为svg 第二步 普通的cad 转换后 大概4-5M 如果直接放入html 加载会很缓慢 需 ...

  6. java canvas 缩放图片_详解如何用HTML5 Canvas API控制图片的缩放变换

    摘要:这篇HTML5栏目下的"详解如何用HTML5 Canvas API控制图片的缩放变换",介绍的技术点是"html5_canvas.canvas.Html5.控制图片 ...

  7. Vue自定义指令实现弹窗拖拽,四边拉伸及对角线拉伸

    Vue自定义指令实现弹窗拖拽,四边拉伸及对角线拉伸 引言 页面布局 drag.js文件 弹窗拖拽实现及边界限制 鼠标指针悬停样式 四边拉伸及对角线拉伸 拉伸干涉 引言 近期公司vue前端项目需求:实现 ...

  8. Vue 实现弹框自由拖拽(不出可视范围、解决快速拖动问题)

    Vue 实现弹框自由拖拽(不出可视范围.解决快速拖动问题) 由于页面中弹框很多,往往会挡住想要查看的内容.从而,有了自由移动拖拽弹框的需求:但在使用的过程中发现,一开始编写的drag.js文件会移出可 ...

  9. javascript实现对图片的随意拖拽,放大缩小

    [JS]基于javascript实现对图片的随意拖拽,放大缩小 最近写项目的过程中需要对图片进行一个操作,点击之后弹出图片,在可定div范围内对图片进行任意拖拽位置和鼠标滚动时对其放大缩小,双击图片恢 ...

最新文章

  1. 让人“眼前一亮、不明觉厉”的互联网技术PPT
  2. Swift 教學:如何使用iOS Charts API 製作漂亮的圖表
  3. 华为服务器修改SN,服务器渠道货SN配置
  4. gtj2018如何生成工程量报表_广联达BIM土建计量平台GTJ2018
  5. Android的TextView在显示文字的时候,如果有段中文有英文,有中文,有中文标点符号,你会发现,当要换行的时候遇到中文标点, 这一行就会空出很多空格出来...
  6. MySQL5.7升级到8.0 之后,配合ubantu18.04遇到的常规问题以及非常规问题的解决方案
  7. 普通公司员工的编程水平与阿里巴巴有多大差距?
  8. 一起谈.NET技术,ASP.NET MVC2.0在Tab页中实现异步无刷新分页
  9. MyBatis动态SQL使用
  10. react 中使用import()实现按需加载报错 解决方法 --‘import’ and ‘export’ may only appear at the top level
  11. simhash与Google的网页去重(转)
  12. CSS的概念及优势(简单介绍)
  13. Delphi POS打印的处理
  14. 维视智造机器视觉表面缺陷检测技术
  15. 【2017宁波联考】生成树
  16. 几何公差基础知识之圆柱度
  17. 1015 计算摄氏温度值
  18. [译转]how browsers work
  19. python中添加.pth_使用.pth文件扩展python环境路径
  20. pandas中使用fillna函数填充NaN值

热门文章

  1. 使用IDM下载GOOGLE CLOUD上的大文件
  2. 万维考试系统python_万维考试系统客户端下载|万维自动考试系统下载 v1.0 官方版_最火软件站...
  3. 数据仓库-多维分析展示平台Saiku
  4. 朴素贝叶斯、精确率与召回率、交叉验证
  5. datastage配置oracle,配置datastage与oracle 10g连接
  6. 关于百度APIStore提供的接口调用失败问题
  7. 手把手教你在浏览器上安装油猴
  8. LTE学习笔记--PHY--RSRP、RSRQ、RSSI和SINR
  9. java 网站计数器_Java页面计数器
  10. 宠物经济:一门千亿级市场的孤独生意