canvas+vue实现图片的缩放、拖拽
最近做项目遇到一个需求,对图片进行拖动+缩放,本来这个功能直接采用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实现图片的缩放、拖拽相关推荐
- 【项目技术点总结之一】vue集成d3.js利用svg加载图片实现缩放拖拽功能
[项目技术点总结之一]vue集成d3.js利用svg加载图片实现缩放拖拽功能 前言 概述 技术介绍 实现过程 插件安装 引用组件 初始化组件 实现效果 简单理解 使用d3创建一个svg 在svg中提添 ...
- vue 实现图片放大缩小拖拽
https://www.h5w3.com/239173.html https://blog.51cto.com/wjw1014/5411219 // 放大缩小public setTransform ( ...
- ZRender使用中关于图片裁剪、拖拽问题
最近做项目使用到了ZRender ZRender 是二维绘图引擎,它提供 Canvas.SVG.VML 等多种渲染方式.ZRender 也是 ECharts 的渲染器,绘图的时候特别方便. 如果想在画 ...
- vue+flask实现视频合成(拖拽上传)
vue+flask实现视频合成 效果如下 欢迎访问博客代码哈士奇 技术 聊天 交流群 974178910 前端交流群 535620886 vue+flask实现视频合成 拖拽上传我们之前一个文章有写过 ...
- web使用panzoom.js 缩放拖拽 工程图cad图
web使用panzoom.js 缩放拖拽 工程图cad图 前言 第一步下载图片转换工具 将cad的dwg转换为svg 第二步 普通的cad 转换后 大概4-5M 如果直接放入html 加载会很缓慢 需 ...
- java canvas 缩放图片_详解如何用HTML5 Canvas API控制图片的缩放变换
摘要:这篇HTML5栏目下的"详解如何用HTML5 Canvas API控制图片的缩放变换",介绍的技术点是"html5_canvas.canvas.Html5.控制图片 ...
- Vue自定义指令实现弹窗拖拽,四边拉伸及对角线拉伸
Vue自定义指令实现弹窗拖拽,四边拉伸及对角线拉伸 引言 页面布局 drag.js文件 弹窗拖拽实现及边界限制 鼠标指针悬停样式 四边拉伸及对角线拉伸 拉伸干涉 引言 近期公司vue前端项目需求:实现 ...
- Vue 实现弹框自由拖拽(不出可视范围、解决快速拖动问题)
Vue 实现弹框自由拖拽(不出可视范围.解决快速拖动问题) 由于页面中弹框很多,往往会挡住想要查看的内容.从而,有了自由移动拖拽弹框的需求:但在使用的过程中发现,一开始编写的drag.js文件会移出可 ...
- javascript实现对图片的随意拖拽,放大缩小
[JS]基于javascript实现对图片的随意拖拽,放大缩小 最近写项目的过程中需要对图片进行一个操作,点击之后弹出图片,在可定div范围内对图片进行任意拖拽位置和鼠标滚动时对其放大缩小,双击图片恢 ...
最新文章
- 让人“眼前一亮、不明觉厉”的互联网技术PPT
- Swift 教學:如何使用iOS Charts API 製作漂亮的圖表
- 华为服务器修改SN,服务器渠道货SN配置
- gtj2018如何生成工程量报表_广联达BIM土建计量平台GTJ2018
- Android的TextView在显示文字的时候,如果有段中文有英文,有中文,有中文标点符号,你会发现,当要换行的时候遇到中文标点, 这一行就会空出很多空格出来...
- MySQL5.7升级到8.0 之后,配合ubantu18.04遇到的常规问题以及非常规问题的解决方案
- 普通公司员工的编程水平与阿里巴巴有多大差距?
- 一起谈.NET技术,ASP.NET MVC2.0在Tab页中实现异步无刷新分页
- MyBatis动态SQL使用
- react 中使用import()实现按需加载报错 解决方法 --‘import’ and ‘export’ may only appear at the top level
- simhash与Google的网页去重(转)
- CSS的概念及优势(简单介绍)
- Delphi POS打印的处理
- 维视智造机器视觉表面缺陷检测技术
- 【2017宁波联考】生成树
- 几何公差基础知识之圆柱度
- 1015 计算摄氏温度值
- [译转]how browsers work
- python中添加.pth_使用.pth文件扩展python环境路径
- pandas中使用fillna函数填充NaN值
热门文章
- 使用IDM下载GOOGLE CLOUD上的大文件
- 万维考试系统python_万维考试系统客户端下载|万维自动考试系统下载 v1.0 官方版_最火软件站...
- 数据仓库-多维分析展示平台Saiku
- 朴素贝叶斯、精确率与召回率、交叉验证
- datastage配置oracle,配置datastage与oracle 10g连接
- 关于百度APIStore提供的接口调用失败问题
- 手把手教你在浏览器上安装油猴
- LTE学习笔记--PHY--RSRP、RSRQ、RSSI和SINR
- java 网站计数器_Java页面计数器
- 宠物经济:一门千亿级市场的孤独生意