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 相关文章推荐
js trim函数 去空格函数与正则集锦
Nov 20 Javascript
File, FileReader 和 Ajax 文件上传实例分析(php)
Apr 27 Javascript
一张表格告诉你windows.onload()与$(document).ready()的区别
May 16 Javascript
Underscore.js常用方法总结
Feb 28 Javascript
js上传图片及预览功能实例分析
Apr 24 Javascript
在JavaScript中处理数组之reverse()方法的使用
Jun 09 Javascript
Bootstrap每天必学之媒体对象
Nov 30 Javascript
基于jQuery实现仿微博发布框字数提示
Jul 27 Javascript
用js实现简单算法的实例代码
Sep 24 Javascript
详解PHP中pathinfo()函数导致的安全问题
Jan 05 Javascript
利用JavaScript如何查询某个值是否数组内
Jul 30 Javascript
详解vue-cli中模拟数据的两种方法
Jul 03 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
预告映像公开!第1章续篇剧场版动画《Princess Principal Crown Handler》4月10日上映!
2020/03/06 日漫
PHP使用者状态管理功能的应用
2006/10/09 PHP
PHP解析html类库simple_html_dom的转码bug
2014/05/22 PHP
Thinkphp将二维数组变为标签适用的一维数组方法总结
2014/10/30 PHP
php程序内部post数据的方法
2015/03/31 PHP
php实现简易计算器
2020/08/28 PHP
extjs ColumnChart设置不同的颜色实现代码
2013/05/17 Javascript
jquery得到font-size属性值实现代码
2013/09/30 Javascript
js获取当前页面路径示例讲解
2014/01/08 Javascript
jquery解析JSON数据示例代码
2014/03/17 Javascript
用js设置下拉框为只读的小技巧
2014/04/10 Javascript
js实现类似于add(1)(2)(3)调用方式的方法
2015/03/04 Javascript
JavaScript通过字符串调用函数的实现方法
2015/03/18 Javascript
jquery实现带缩略图的可定制高度画廊效果(5种)
2015/08/28 Javascript
浅谈window.onbeforeunload() 事件调用ajax
2016/06/29 Javascript
js事件驱动机制 浏览器兼容处理方法
2016/07/23 Javascript
jQuery事件与动画基础详解
2017/02/23 Javascript
jQuery实现图片滑动效果
2017/03/08 Javascript
史上最全JavaScript常用的简写技巧(推荐)
2017/08/17 Javascript
JavaScript多种页面刷新方法小结
2019/04/04 Javascript
详解vue-cli项目开发/生产环境代理实现跨域请求
2019/07/23 Javascript
js实现转动骰子模型
2019/10/24 Javascript
vue props 一次传多个值实例
2020/07/22 Javascript
[02:11]2014DOTA2 TI专访VG战队Fenrir:队伍气氛良好
2014/07/11 DOTA
python对数组进行反转的方法
2015/05/20 Python
python利用urllib实现爬取京东网站商品图片的爬虫实例
2017/08/24 Python
Python开发最牛逼的IDE——pycharm
2018/08/01 Python
PyQt5下拉式复选框QComboCheckBox的实例
2019/06/25 Python
Python scrapy爬取小说代码案例详解
2020/07/09 Python
HTML5几个设计和修改的页面范例分享
2015/09/29 HTML / CSS
英国在线房屋中介网站:Yopa
2018/01/09 全球购物
Vrbo西班牙:预订您的度假公寓(公寓、乡村房屋…)
2020/04/27 全球购物
计算机专业推荐信范文
2013/11/27 职场文书
个人工作表现自我评价
2015/03/06 职场文书
放假通知
2015/04/14 职场文书
教师节老师寄语
2015/05/28 职场文书