JavaScript制作简单的框选图表


Posted in Javascript onMay 15, 2017

故事背景:这几天遇到一个客户,是做会议记录的,每次会议过程中,都会有特定设备记录下讲话人的位置以角度值显示。他给我角度值,让我给他做一个图表来展示每个人的一个大概位置。

客户想到的是用 Echarts 图表来做,我首先想到的也是用 Echarts ,但是思考了他的要求以后,发现就一个简单的框选图表用 Echarts 来做是不是大材小用了,而且还要导入那么多的没用的代码。

于是我想到了用 canvas 画布来仿着做,但又考虑了一下, canvas 操作起来不顺手;究竟可不可以用普通的css结合 javascript 来把它做出来呢?此番思考验证了:任何事情一定要多动脑,才能 碰到更简单的解决问题的方式。

考虑到也许某天大家用得着,所以发布出来。注:拥有可移植性,可移到页面任何位置,效果不会改变

先看最终效果吧:

图一:

JavaScript制作简单的框选图表JavaScript制作简单的框选图表

图二:

JavaScript制作简单的框选图表

这个小东西会涉及的知识点不多,归纳一下: js的三角函数 、 CSS3的transform 、 鼠标的坐标轴XY的计算 ...啊哈,差不多大体就这三方面的知识吧,如果你都只是有过了解也没关系,因为都只用的到皮毛所以不必担心。但是如果完全没听过,那就请您再去了解一下这方面知识。

代码区域

<!doctype html> 
<html> 
<head> 
 <meta charset="utf-8" /> 
 <title>仿Echarts图表</title> 
 <style> 
 * { 
  padding:0; 
  margin:0; 
 } 
 #getcharts { 
  position:relative; 
  width:510px; 
  height:510px; 
 
 } 
 #wrapcharts { 
  list-style:none; 
  height:500px; 
  width:500px; 
  border:2px solid #aaa; 
  border-radius:50%; 
  position:relative; 
  margin:20px auto; 
 } 
 #wrapcharts li { 
  height:10px; 
  width:10px; 
  diaplay:block; 
  position:absolute; 
  cursor:pointer; 
  left:247px; 
  top:2px; 
  height:10px; 
  width:10px; 
  transition:0.2s; 
  background:red; 
  border-radius:50%; 
 } 
 #boxshadow { 
  position:absolute; 
  background:blue; 
  opacity:0.2; 
  height:0; 
  width:0; 
  left:0; 
  top:0; 
 } 
 </style> 
</head> 
<body> 
 
 <ul id="wrapcharts"></ul> 
 <div id="boxshadow"></div> 
 
<script> 
 /* 
 **模拟从后端取值过来的【角度】和相对应的【人名】数组 
 **/ 
 var degArr = [25,88,252,323,33,28,30,90,290,100,300,50,180,205,220,331,195,97,102,77,62,38,32,79]; 
 var nameArr = ['内衣天使','小恶魔','金正恩','奥巴马','duolaA梦','午夜激情','梁静茹','刘亦菲','琪琪','大熊','小静','小屁孩','张三','李四','王五','麻六','小明','小张','丽丽','多多','瑾瑾','biubiu','Mr.boluo','Hanson']; 
 /* 
 **声明 getPos(param)函数: 利用三角函数定理根据传入的角度值获取对边和临边的x,y值 
 **/ 
 function getPos(deg) 
 { 
 var X = Math.sin(deg*Math.PI/180)*250 + 245; 
 var Y = -Math.cos(deg*Math.PI/180)*250 + 245; 
 return {x:X,y:Y}; 
 } 
 /* 
 **这里不用说吧,获取页面中的ul,和ul中的li对象,以及框选时的那个任意变动大小的小方块对象 
 **/ 
 var oWrap = document.getElementById('wrapcharts'); 
 var aLi = oWrap.getElementsByTagName('li'); 
 var oBox =document.getElementById('boxshadow'); 
 var allLi = ''; 
 var posArr = []; 
 /* 
 **for循环中调用getPos(param)来获取degArr数组中的所有角度对应的x,y值(就是每个角度对应的x,y坐标),并传入到一个数组中保存,方便取用 
 **/ 
 for(var i=0;i<degArr.length; i++) 
 { 
 posArr.push(getPos(degArr[i])); 
 } 
 /* 
 **for循环根据度数数组degArr的长度插入li小圆点到ul中,并将之前获取的每个点对应的x,y左边插入到行内样式 
 **/ 
 for(var i=0; i<degArr.length; i++) 
 { 
 allLi += '<li style="left:'+posArr[i].x+'px;top:'+posArr[i].y+'px;" title="'+degArr[i]+'°;姓名:'+nameArr[i]+'"></li>'; 
 } 
 oWrap.innerHTML = allLi; 
 /* 
 **遍历最终得到的ul中的li 
 **/ 
 for(var i=0; i<aLi.length; i++) 
 { 
 aLi[i].index = i; 
 /* 
  **封装鼠标移入每个小圆点时的放大事件,这里用到了matrix矩阵,为的事想兼容ie9以下浏览器,但是好像出了点问题 
  */ 
 function focusOn(_this,color, size) 
 { 
  _this.style.background = color; 
  _this.style.WebkitTransform = 'matrix('+size+', 0, 0, '+size+', 0, 0)'; 
  _this.style.MozTransform = 'matrix('+size+', 0, 0, '+size+', 0, 0)'; 
  _this.style.transform = 'matrix('+size+', 0, 0, '+size+', 0, 0)'; 
  _this.style.filter="progid:DXImageTransform.Microsoft.Matrix( M11= "+size+", M12= 0, M21= 0 , M22="+size+",SizingMethod='auto expend')"; 
 } 
 aLi[i].onmouseover = function() 
 { 
  //alert(this.offsetLeft); 
  _this = this; 
  focusOn(_this,'blue', 2); 
 } 
 aLi[i].onmouseout = function() 
 { 
  //alert(this.offsetLeft); 
  _this = this; 
  focusOn(_this,'red', 1); 
 
 } 
 } 
 /***框选***/ 
 /* 
 **拖拽框选代码区域,这个我就不解释了,明白人都一眼知道什么意思,这就像是公式, 
 */ 
 var allSelect = {}; 
 document.onmousedown = function(ev) 
 { 
 var ev = ev || window.event; 
 var disX = ev.clientX; 
 var disY = ev.clientY; 
 var H = W = clientleft = clienttop = clientright = clientbottom = 0; 
 oBox.style.cssText = 'left:'+disX+'px;top:'+disY+'px;'; 
 //console.log(disX+';'+disY); 
 function again(f) 
 { 
  for(var i=0; i<posArr.length; i++) 
  { 
  if(posArr[i].x > clientleft && posArr[i].y > clienttop && (posArr[i].x + 10) < clientright && (posArr[i].y +10) < clientbottom) 
  { 
   //console.log(clientleft+';'+ clienttop +';'+ clientright +';' + clientbottom); 
   if(f){allSelect[i] = i;}else{ 
   aLi[i].style.background = 'blue'; 
   } 
  } else 
  { 
   aLi[i].style.background = 'red'; 
  } 
  } 
 
 } 
 
 document.onmousemove = function(ev) 
 { 
  var ev = ev || window.event; 
  /* 
  **当鼠标向四个方向拖拉的时候进行方向判断,并相应的改变小方块的left,top以及width,height 
  **其实我这里有个问题,那就是,代码重复了一些,本想着合并一下,但是作者有点懒,嘿嘿,你们也可以尝试一下 
  **修改后你们拿去当做你们的发布,作者不会介意的 
  */ 
  if(ev.clientX > disX && ev.clientY > disY) 
  { 
  W = ev.clientX - disX; 
  H = ev.clientY - disY; 
 
  oBox.style.width = W + 'px'; 
  oBox.style.height = H + 'px'; 
 
  clienttop = disY-oWrap.offsetTop; 
  clientleft = disX-oWrap.offsetLeft; 
 
  }else if(ev.clientX < disX && ev.clientY < disY) 
  { 
  W = disX - ev.clientX; 
  H = disY - ev.clientY; 
 
  oBox.style.top = ev.clientY + 'px'; 
  oBox.style.left = ev.clientX + 'px'; 
 
  oBox.style.width = W + 'px'; 
  oBox.style.height = H + 'px'; 
 
  clienttop = ev.clientY - oWrap.offsetTop; 
  clientleft = ev.clientX - oWrap.offsetLeft; 
 
  }else if(ev.clientX > disX && ev.clientY < disY) 
  { 
  W = ev.clientX - disX; 
  H = disY - ev.clientY; 
 
  oBox.style.top = ev.clientY + 'px'; 
 
  oBox.style.width = W + 'px'; 
  oBox.style.height = H + 'px'; 
 
  clienttop = ev.clientY - oWrap.offsetTop; 
  clientleft = disX - oWrap.offsetLeft; 
 
  }else if(ev.clientX < disX && ev.clientY > disY) 
  { 
  W = disX - ev.clientX; 
  H = ev.clientY - disY; 
 
  oBox.style.left = ev.clientX + 'px'; 
 
  oBox.style.width = W + 'px'; 
  oBox.style.height = H + 'px'; 
 
  clienttop = disY-oWrap.offsetTop; 
  clientleft = ev.clientX - oWrap.offsetLeft; 
  } 
 
 
  clientright = clientleft+ W; 
  clientbottom = clienttop + H; 
 
  W = ''; 
  H = ''; 
 
  again(); 
 
 } 
 document.onmouseup = function() 
 { 
  again(1); 
 
  document.onmouseup = document.onmousemove = null; 
  oBox.style.cssText = 'height:0;width:0;'; 
  if(JSON.stringify(allSelect) == '{}'){return;} 
  console.log(allSelect); 
 
  var lastSelect = []; 
  for(var attr in allSelect){ 
  lastSelect.push(nameArr[attr]); 
  } 
  allSelect = {}; 
 
  console.log(lastSelect); 
  alert('你选中的人是:\n\n'+lastSelect+'\n\n'); 
 
  for(var i=0; i<aLi.length; i++) 
  { 
  aLi[i].style.background = 'red'; 
  } 
 } 
 return false; 
 } 
</script> 
</body> 
</html>

会用到的一些知识点拓展

注:在js中设置Transform的时候我用到的不是scale()方法,因为我想兼容ie9以下的版本所以用了矩阵变化。当然,你们也可以改为scale(),毫无影响。

1.在标准浏览器下的矩阵函数matix(a,b,c,d,e,f)、ie下的矩阵函数progid:DXImageTransform.Microsoft.Matrix( M11= 1, M12= 0, M21= 0 , M22=1,SizingMethod='auto expend')

他们的共同点:M11 == a; M12 == c; M21 == b; M22 == d

不一样的地方:ie下的矩阵函数没有 e 和 f 两个参数,在矩阵函数中 e 和 f 是用来位移的,也就是说ie下没法通过矩阵函数来实现位移[ 不过我们这里好像不需要位移,嘿嘿 ]

2.在标准浏览器下矩阵函数matrix中a,b,c,d,e,f 一一对应的的初始值为:matix(1,0,0,1,0,0)

3.通过矩阵实现缩放:

x轴缩放:a = x a c = x c e = x*e

y轴缩放:b = y b d = y d f = y*f

4.通过矩阵实现位移:[ie下没位移]

x轴位移:e = e+x

y轴位移:f = f+y

5.通过矩阵实现倾斜:

x轴倾斜:c = Math.tan(xDeg/180*Math.PI)

y轴倾斜:b = Math.tan(yDeg/180*Math.PI)

6.通过矩阵实现旋转:

a = Math.cos(deg/180*Math.PI);

b = Math.sin(deg/180*Math.PI);

c = -Math.sin(deg/180*Math.PI);

d = Math.cos(deg/180*Math.PI);

7.至于三角函数我就不介绍了,百度一大把。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jquery 图片截取工具jquery.imagecropper.js
Apr 09 Javascript
JavaScript基础语法、dom操作树及document对象
Dec 02 Javascript
jQuery中DOM树操作之使用反向插入方法实例分析
Jan 23 Javascript
2则自己编写的jQuery特效分享
Feb 26 Javascript
jQuery实现的简单提示信息插件
Dec 08 Javascript
Js类的静态方法与实例方法区分及jQuery拓展的两种方法
Jun 03 Javascript
bootstrap中使用google prettify让代码高亮的方法
Oct 21 Javascript
javascript 跨域问题以及解决办法
Jul 17 Javascript
vue实现在一个方法执行完后执行另一个方法的示例
Aug 25 Javascript
原生JS实现轮播图效果
Oct 12 Javascript
详解VUE前端按钮权限控制
Apr 26 Javascript
详解Vue 如何监听Array的变化
Jun 06 Javascript
vue.js 使用v-if v-else发现没有执行解决办法
May 15 #Javascript
AngularJs 常用的过滤器
May 15 #Javascript
Vue关于数据绑定出错解决办法
May 15 #Javascript
Jquery把获取到的input值转换成json
May 15 #jQuery
jQuery实现radio第一次点击选中第二次点击取消功能
May 15 #jQuery
jQuery返回定位插件详解
May 15 #jQuery
一个可复用的vue分页组件
May 15 #Javascript
You might like
PHP修改session_id示例代码
2014/01/08 PHP
php 解决substr()截取中文字符乱码问题
2016/07/18 PHP
PHP静态成员变量
2017/02/14 PHP
javascript 获取图片颜色
2009/04/05 Javascript
浅析Cookie中的Path与domain
2013/12/18 Javascript
Egret引擎开发指南之编译项目
2014/09/03 Javascript
jQuery中remove()方法用法实例
2014/12/25 Javascript
详解AngularJS中自定义指令的使用
2015/06/17 Javascript
nodejs初始化init的示例代码
2018/10/10 NodeJs
解决vue路由name同名,路由重复的问题
2020/08/05 Javascript
前端使用crypto.js进行加密的函数代码
2020/08/16 Javascript
python使用cookie库操保存cookie详解
2014/03/03 Python
用Python编写简单的定时器的方法
2015/05/02 Python
Python实现爬取逐浪小说的方法
2015/07/07 Python
用Pygal绘制直方图代码示例
2017/12/07 Python
python实现list由于numpy array的转换
2018/04/04 Python
python 请求服务器的实现代码(http请求和https请求)
2018/05/25 Python
python 获取微信好友列表的方法(微信web)
2019/02/21 Python
谈一谈基于python的面向对象编程基础
2019/05/21 Python
python统计字符的个数代码实例
2020/02/07 Python
Python unittest 自动识别并执行测试用例方式
2020/03/09 Python
自定义Django_rest_framework_jwt登陆错误返回的解决
2020/10/18 Python
Python 带星号(* 或 **)的函数参数详解
2021/02/23 Python
生产车间实习自我鉴定
2013/09/23 职场文书
总裁助理岗位职责
2014/02/17 职场文书
《木笛》教学反思
2014/03/01 职场文书
如何撰写一封出色的求职信
2014/04/27 职场文书
城管综合整治方案
2014/05/01 职场文书
暑期社会实践心得体会
2014/09/02 职场文书
穆斯林的葬礼读书笔记
2015/06/26 职场文书
民间借贷纠纷答辩状
2015/08/03 职场文书
中学团支部工作总结
2015/08/13 职场文书
2016年第二十五次全国助残日活动总结
2016/04/01 职场文书
ThinkPHP5和ThinkPHP6的区别
2021/03/31 PHP
使用@Value值注入及配置文件组件扫描
2021/07/09 Java/Android
SQL语句中JOIN的用法场景分析
2021/07/25 SQL Server