vue基于Echarts的拖拽数据可视化功能实现


Posted in Vue.js onDecember 04, 2020

背景

我司产品提出了一个需求,做一个数据基于Echars的可拖拽缩放的数据可视化,上网百度了一番,结果出现了两种结局,一种花钱买成熟产品(公司不出钱),一种没有成熟代码,只能自己写了,故事即将开始,敬请期待......。  不,还是先上一张效果图吧,请看......

vue基于Echarts的拖拽数据可视化功能实现

前期知识点

1. offset(偏移量)

定义:当前元素在屏幕上占用的空间,如下图:

其中:

offsetHeight: 该元素在垂直方向上的占用的空间,单位为px,不包括margin。

offsetWidth:该元素在水平方向上的占用空间,单位为px,不包括margin。

offsetLeft: 该元素距离左侧并且是定位过(relative || absolute)的父元素内边框的距离。注意:如果父元素中没有一个是定位的,则是距离body元素的距离。

offsetTop:该元素距离顶部并且是定位过(relative || absolute)的父元素内边框的距离。注意:如果父元素中没有一个是定位的,则是距离body元素的距离。

2. 鼠标事件

2.1 当前鼠标的坐标点

clientX:返回鼠标触点相对于浏览器可视区域的X坐标,单位为px,这个属性值可以根据用户对可视区的缩放行为发生变化。

clientY:返回鼠标触点相对于浏览器可视区域的Y坐标,单位为px,这个属性值可以根据用户对可视区的缩放行为发生变化。

2.2 相关的鼠标事件

ondragstart: 规定当元素被拖动时,发生什么,该属性调用一个函数,drag(event),它规定了被拖动的数据。可通过dataTransfer.setData() 方法设置被拖数据的数据类型和值:

function drag(ev)
{
 ev.dataTransfer.setData("Text",ev.target.id);
}

ondragover: 规定在何处放置被拖动的数据,默认地,无法将数据/元素放置到其他元素中。如果需要设置允许放置,我们必须阻止对元素的默认处理方式。这要通过调用 ondragover 事件的 event.preventDefault() 方法:

event.preventDefault()

ondrop:当放置被拖数据时,会发生 drop 事件。ondrop 属性调用了一个函数,drop(event):

function drop(ev)
{ 
 // 避免浏览器对数据的默认处理(drop 事件的默认行为是以链接形式打开)
 ev.preventDefault();
 // 获得被拖的数据。该方法将返回在 setData() 方法中设置为相同类型的任何数据。
 var data=ev.dataTransfer.getData("Text");
 // 把被拖元素追加到放置元素(目标元素)中
 ev.target.appendChild(document.getElementById(data));
}

onMouseDown: 鼠标上的按钮被按下时触发的事件

onMouseMove:鼠标移动时触发的事件

onmouseup:鼠标按下后,松开时激发的事件

拖拽功能

本功能以Echarts图表中柱状图为例,进行讲解:

先定义可拖拽元素

<div>
    <el-button class="drag-button" type="success" draggable="true" 
 @dragstart.native="dragStart($event,'histogram')">
 柱状图
 </el-button>
 </div>

注意:元素默认是不能进行拖拽的,需要将draggable属性设置为"true",即draggable="true" 

dragStart(event,type){
       event.dataTransfer.setData("Text",type);
    },

定义放置区域

<div class="grid-content bg-purple-light drag-resize-area"
 @drop.prevent="drop($event)" @dragover.prevent="">
 <div style="height:300px;width:400px" id="'histogram'></div>
</div>

其中drop事件如下:

drop(event){
      const data=event.dataTransfer.getData("Text");
      if(data === 'histogram'){ 
 var myChart = echarts.init(document.getElementById('histogram')); // 指定图表的配置项和数据
 var option = { 
 title: { text: 'ECharts 入门示例' }, 
 tooltip: {}, legend: { data:['销量'] },
 xAxis: { data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"] },
 yAxis: {}, series: [{ name: '销量', type: 'bar', data: [5, 20, 36, 10, 10, 20] }] 
 }; 
 // 使用刚指定的配置项和数据显示图表。 
 myChart.setOption(option);
 }
}

基于自己封装的组件的源码请看github:github地址

效果图如下:

vue基于Echarts的拖拽数据可视化功能实现

拖动功能

此功能用到了上面提到的offsetLeft、offsetTop、clientX,clientY。实现思路如下:

(1)当鼠标刚按下去时,记录当前元素距离带定位的父元素的offsetLeft、offsetTop距离;以及当前鼠标在浏览器可视区的坐标clientX、clientY的距离。

(2)分别计算两者的差值作为偏移常量,如下:

let disX = e.clientX - el.offsetLeft;
        let disY = e.clientY - el.offsetTop;

(3)监听鼠标的移动事件,获取当前鼠标距离浏览器可是区域的坐标clientX,clientY;然后减去偏移常量,即为当前元素的坐标

let tX = e.clientX - disX;
 let tY = e.clientY - disY; 
 el.style.left = tX + 'px'; 
 el.style.top = tY + 'px';

说明:el为当前图表对象

由于本人封装了通用vue组件,详细拖拽方法代码如下:

      // 初始化可拖拽方法
      initDrag(){
       let el = this.$el;
       el.onmousedown = (e)=>{
            e.preventDefault();
            e.target.style.cursor = 'move'; 
            //鼠标按下,计算鼠标触点距离元素左侧和顶部的距离
            let disX = e.clientX - el.offsetLeft;
            let disY = e.clientY - el.offsetTop;
            // console.log('22222',document);
            document.onmousemove = function (e) {
              //计算需要移动的距离
              let tX = e.clientX - disX;
              let tY = e.clientY - disY;
              //移动当前元素
              if (tX >= 0 && tX <= window.innerWidth - el.offsetWidth) {
                el.style.left = tX + 'px';
              } 
              if (tY >= 0 && tY <= window.innerHeight - el.offsetHeight) {
                el.style.top = tY + 'px';
              } 
            };
            //鼠标松开时,注销鼠标事件,停止元素拖拽。
            document.onmouseup = function (e) {
                document.onmousemove = null;
                document.onmouseup = null;
                e.target.style.cursor = 'default';
            };
       }
     },

如果想看封装的组件,请查看github地址:github地址

拖动效果如下图:

vue基于Echarts的拖拽数据可视化功能实现

缩放功能

此功能用到了上面提到的 offsetWidth、offsetHeight、offsetLeft、offsetTop、clientX,clientY。实现思路如下:

(1)先设置可缩放的四个拖拽方框

<div v-show="isResize && resizeFlag" ref="resizeDivTag" id="resizeDivTag">
        <span class="br"></span>
        <span class="bl"></span>
        <span class="tr"></span>
        <span class="tl"></span> 
    </div>

其中isResize 与 resizeFlag表示是否可缩放以及是否可拖拽

(2)为每个可可缩放方框设置缩放函数,请看注释

// 初始化可缩放
      initResize(){
        let el = this.$el; //获取当前元素
        let spanNodes = this.$refs.resizeDivTag.childNodes;
        for(let i=0;i<spanNodes.length;i++){
          this.resizeElementFun(spanNodes[i],el); // 分别为四个缩放方框设置监听事件
        }
      },
      resizeElementFun(element,el){
        element.onmousedown = function(ev){
          console.log('我是按下的元素')
          let oEv = ev || event;
          oEv.stopPropagation();
          let oldWidth = el.offsetWidth; // 当前元素的宽度
          let oldHeight  = el.offsetHeight; // 当前元素的高度
          console.log('-----'+ oldWidth+'----'+oldHeight);
          let oldX = oEv.clientX; // 当前鼠标对于浏览器可视区域的X坐标
          let oldY = oEv.clientY; // 当前鼠标对于浏览器可视区域的Y坐标
          let oldLeft = el.offsetLeft; // 当前元素对于父级定位元素的宽度
          let oldTop = el.offsetTop; // 当前元素对于父级定位元素的高度
          console.log('--zuo---'+ oldLeft+'--gao--'+oldTop);
          document.onmousemove = function(ev){
            // oEv.stopPropagation();
            let oEv = ev || event;
            let disY = (oldTop + (oEv.clientY - oldY)); // 当前缩放的元素距离定位父元素的高度
            // let disX = (oldLeft + (oEv.clientX - oldLeft));
            let disX = (oldLeft + (oEv.clientX - oldX)); // 当前缩放的元素距离定位父元素的宽度
            if(disX>oldLeft+oldWidth){
                disX=oldLeft+oldWidth
            }
            if(disY>oldTop+oldHeight){
                disY=oldTop+oldHeight
            }
            if(element.className == 'tl'){ // 左上缩放时
              el.style.width = oldWidth - (oEv.clientX - oldX) + 'px'; 
 // 元素宽度= 缩放前宽度-鼠标当前坐标与原始坐标差值
              el.style.height = oldHeight - (oEv.clientY - oldY) + 'px';
 // 元素宽度= 缩放前高度-鼠标当前坐标与原始坐标差值
              el.style.left = disX + 'px';
 // 元素距离父元素的距离 = 
              el.style.top = disY + 'px';
            } else if (element.className == 'bl'){ // 左下
              el.style.width = oldWidth - (oEv.clientX - oldX) + 'px';
              el.style.height = oldHeight + (oEv.clientY - oldY) + 'px';
              el.style.left = disX + 'px';
              // el.style.bottom = oldTop + (oEv.clientY + oldY) + 'px';
            } else if (element.className == 'tr'){ //右上
              el.style.width = oldWidth + (oEv.clientX - oldX) + 'px';
              el.style.height = oldHeight - (oEv.clientY - oldY) + 'px';
              el.style.right = oldLeft - (oEv.clientX - oldX) + 'px';
              el.style.top = disY + 'px';
            } else if (element.className == 'br'){ //右下
              el.style.width = oldWidth + (oEv.clientX - oldX) + 'px';
              el.style.height = oldHeight + (oEv.clientY - oldY) + 'px';
              el.style.right = oldLeft - (oEv.clientX - oldX) + 'px';
              // el.style.bottom = oldTop + (oEv.clientY + oldY) + 'px';
            }
          }
          document.onmouseup = function(){
            document.onmousemove = null;
          };
          return false;
        }
      },

如果想看封装的组件,请查看github地址:github地址

缩放效果如下图:

vue基于Echarts的拖拽数据可视化功能实现

Echarts缩放中存在的问题

vue中使用echarts图表自适应的几种基本解决方案,此处不再进行赘述,详情请参考如下链接:echarts图表自适应

结束语

本文只是粗略的记录了数据可视化简单demo的实现思路,如果您觉得对您有帮助,请下载源码  github地址

喜欢的小伙伴给个star,谢谢

参考文献

到此这篇vue基于Echarts的拖拽数据可视化功能实现的文章就介绍到这了,更多相关vue基于Echarts拖拽数据可视化内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Vue.js 相关文章推荐
vue实现图片裁剪后上传
Dec 16 Vue.js
vue实现一个获取按键展示快捷键效果的Input组件
Jan 13 Vue.js
Vue项目打包部署到apache服务器的方法步骤
Feb 01 Vue.js
vue使用echarts画组织结构图
Feb 06 Vue.js
vue3.0封装轮播图组件的步骤
Mar 04 Vue.js
使用Vue.js和MJML创建响应式电子邮件
Mar 23 Vue.js
Vue+Element UI实现概要小弹窗的全过程
May 30 Vue.js
vue中利用mqtt服务端实现即时通讯的步骤记录
Jul 01 Vue.js
Element-ui Layout布局(Row和Col组件)的实现
Dec 06 Vue.js
深入讲解Vue中父子组件通信与事件触发
Mar 22 Vue.js
一起来看看Vue的核心原理剖析
Mar 24 Vue.js
vue-cli3.x配置全局的scss的时候报错问题及解决
Apr 30 Vue.js
vue使用echarts图表自适应的几种解决方案
Dec 04 #Vue.js
vue-calendar-component 封装多日期选择组件的实例代码
Dec 04 #Vue.js
如何正确解决VuePress本地访问出现资源报错404的问题
Dec 03 #Vue.js
vue表单验证之禁止input输入框输入空格
Dec 03 #Vue.js
对vue生命周期的深入理解
Dec 03 #Vue.js
用vue设计一个日历表
Dec 03 #Vue.js
实用的 vue tags 创建缓存导航的过程实现
Dec 03 #Vue.js
You might like
PHP中func_get_args(),func_get_arg(),func_num_args()的区别
2013/09/30 PHP
php的api数据接口书写实例(推荐)
2016/09/22 PHP
IE与Firefox下javascript getyear年份的兼容性写法
2007/12/20 Javascript
Microsoft Ajax Minifier 压缩javascript的方法
2010/03/05 Javascript
javascript 日期时间 转换的方法
2013/02/21 Javascript
基于jquery实现的定时显示与隐藏div广告的实现代码
2013/08/22 Javascript
js监听鼠标事件控制textarea输入字符串的个数
2014/09/29 Javascript
使用script的src实现跨域和类似ajax效果
2014/11/10 Javascript
jquery渐隐渐显的图片幻灯闪烁切换实现方法
2015/02/26 Javascript
jQuery EasyUI之DataGrid使用实例详解
2016/01/04 Javascript
jQuery+PHP+MySQL实现无限级联下拉框效果
2016/02/19 Javascript
jQuery实现返回顶部功能
2016/02/23 Javascript
JS实现线性表的顺序表示方法示例【经典数据结构】
2017/04/11 Javascript
使用selenium抓取淘宝的商品信息实例
2018/02/06 Javascript
vue 虚拟dom的patch源码分析
2018/03/01 Javascript
解决layui上传文件提示上传异常,实际文件已经上传成功的问题
2018/08/19 Javascript
js使用Promise实现简单的Ajax缓存
2018/11/14 Javascript
用element的upload组件实现多图片上传和压缩的示例代码
2019/02/12 Javascript
利用js-cookie实现前端设置缓存数据定时失效
2019/06/18 Javascript
linux服务器快速卸载安装node环境(简单上手)
2021/02/22 Javascript
[51:07]VGJ.S vs Pain 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/20 DOTA
[01:14]2019完美世界城市挑战赛(秋季赛)全国总决赛精彩花絮
2020/01/08 DOTA
python获取局域网占带宽最大3个ip的方法
2015/07/09 Python
Django的session中对于用户验证的支持
2015/07/23 Python
python利用插值法对折线进行平滑曲线处理
2018/12/25 Python
基于python爬取梨视频实现过程解析
2020/11/09 Python
python中random模块详解
2021/03/01 Python
CSS3地图动态实例代码(圆圈向外扩散)
2018/06/15 HTML / CSS
物业电工岗位职责
2013/11/20 职场文书
青年教师培训方案
2014/02/06 职场文书
大学生优秀自荐信范文
2014/02/25 职场文书
小学教师师德承诺书
2014/05/23 职场文书
师范学院毕业生求职信
2014/06/24 职场文书
公司员工宿舍管理制度
2015/08/07 职场文书
关于感恩的作文
2019/08/26 职场文书
Java并发编程之Executor接口的使用
2021/06/21 Java/Android