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-drawer-layout实现手势滑出菜单栏
Nov 19 Vue.js
Vue开发中常见的套路和技巧总结
Nov 24 Vue.js
Vue与React的区别和优势对比
Dec 18 Vue.js
vue中配置scss全局变量的步骤
Dec 28 Vue.js
vuex的使用步骤
Jan 06 Vue.js
vue实现验证用户名是否可用
Jan 20 Vue.js
Vue 数据响应式相关总结
Jan 28 Vue.js
Vue 事件的$event参数=事件的值案例
Jan 29 Vue.js
详解Vue3.0 + TypeScript + Vite初体验
Feb 22 Vue.js
使用Vue3+Vant组件实现App搜索历史记录功能(示例代码)
Jun 09 Vue.js
idea编译器vue缩进报错问题场景分析
Jul 04 Vue.js
Vue3中的Refs和Ref详情
Nov 11 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也可以?成Shell Script
2006/10/09 PHP
CodeIgniter框架过滤HTML危险代码
2014/06/12 PHP
php 策略模式原理与应用深入理解
2019/09/25 PHP
Thinkphp页面跳转设置跳转等待时间的操作
2019/10/16 PHP
TP5框架安全机制实例分析
2020/04/05 PHP
一个用js实现控制台控件的代码
2007/09/04 Javascript
JS学习之一个简易的日历控件
2010/03/24 Javascript
如何在一个页面显示多个百度地图
2013/04/07 Javascript
jquery实现动态操作select选中
2015/02/11 Javascript
举例讲解AngularJS中的模块
2015/06/17 Javascript
jquery 判断是否支持Placeholder属性的方法
2017/02/07 Javascript
angular实现图片懒加载实例代码
2017/06/08 Javascript
JavaScript数组的5种迭代方法
2017/09/29 Javascript
微信小程序自定义多选事件的实现代码
2018/05/17 Javascript
vue 中的keep-alive实例代码
2018/07/20 Javascript
[01:35]2014DOTA2西雅图邀请赛 专访狐狸妈青春献给刀塔
2014/07/08 DOTA
Python最基本的输入输出详解
2015/04/25 Python
使用Python的Flask框架来搭建第一个Web应用程序
2016/06/04 Python
关于Python 的简单栅格图像边界提取方法
2019/07/05 Python
python实现的批量分析xml标签中各个类别个数功能示例
2019/12/30 Python
Python requests HTTP验证登录实现流程
2020/11/05 Python
python 操作excel表格的方法
2020/12/05 Python
HTML5 声明兼容IE的写法
2011/05/16 HTML / CSS
日本著名的平价时尚女性购物网站:Fifth
2016/08/24 全球购物
Topshop法国官网:英国快速时尚品牌
2018/04/08 全球购物
微软瑞士官方网站:Microsoft瑞士
2018/04/20 全球购物
荷兰鞋类购物网站:Donelli
2019/05/24 全球购物
Helly Hansen工作服美国官方网上商店:为最恶劣的环境
2019/09/04 全球购物
迪士尼西班牙官方网上商店:ShopDisney西班牙
2020/02/02 全球购物
个人生活学习自我评价范文
2013/11/26 职场文书
大学军训感言400字
2014/03/11 职场文书
校园环保建议书
2014/05/14 职场文书
结婚仪式主持词
2015/06/29 职场文书
门卫管理制度范本
2015/08/05 职场文书
vue-cropper组件实现图片切割上传
2021/05/27 Vue.js
剖析后OpLog订阅MongoDB的数据变更就没那么难了
2022/02/24 MongoDB