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 相关文章推荐
发布一个高效的JavaScript分析、压缩工具 JavaScript Analyser
Nov 30 Javascript
Jquery公告滚动+AJAX后台得到数据
Apr 14 Javascript
javascript:文字不间断向左移动的实例代码
Aug 08 Javascript
JS.elementGetStyle(element, style)应用示例
Sep 24 Javascript
Jquery下EasyUI组件中的DataGrid结果集清空方法
Jan 06 Javascript
JS模拟简易滚动条效果代码(附demo源码)
Apr 05 Javascript
JavaScript ES5标准中新增的Array方法
Jun 28 Javascript
Node.js的文件权限及读写flag详解
Oct 11 Javascript
Javascript实现倒计时(防页面刷新)实例
Dec 13 Javascript
在node中如何使用 ES6
Apr 22 Javascript
Bootstrap Table从零开始
Jun 30 Javascript
Vuex的actions属性的具体使用
Apr 14 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实现在线生成条形码示例分享(条形码生成器)
2013/12/30 PHP
实现获取http内容的php函数分享
2014/02/16 PHP
PHP实现抓取Google IP并自动修改hosts文件
2015/02/12 PHP
列举PHP的Yii 2框架的开发优势
2015/07/03 PHP
PHP中Cookie的使用详解(简单易懂)
2017/04/28 PHP
jquery图片延迟加载 前端开发技能必备系列
2012/06/18 Javascript
JavaScript 上万关键字瞬间匹配实现代码
2013/07/07 Javascript
jquery自动填充勾选框即把勾选框打上true
2014/03/24 Javascript
JS的encodeURI和java的URLDecoder.decode使用介绍
2014/05/08 Javascript
javascript使用正则表达式实现去掉空格之后的字符
2015/02/15 Javascript
JS动态修改图片的URL(src)的方法
2015/04/01 Javascript
js获取iframe中的window对象的实现方法
2016/05/20 Javascript
JQuery 设置checkbox值二次无效的解决方法
2016/07/22 Javascript
脚本div实现拖放功能(两种)
2017/02/13 Javascript
Angular2自定义分页组件
2017/04/19 Javascript
原生JavaScript实现remove()和recover()功能示例
2018/07/24 Javascript
解决LayUI数据表格复选框不居中显示的问题
2019/09/25 Javascript
微信小程序实现同时上传多张图片
2020/02/03 Javascript
Jquery如何使用animation动画效果改变背景色的代码
2020/07/20 jQuery
[03:04]2018年国际邀请赛典藏宝瓶&莱恩声望物品展示 片尾有彩蛋
2018/06/04 DOTA
centos下更新Python版本的步骤
2013/02/12 Python
Python使用设计模式中的责任链模式与迭代器模式的示例
2016/03/02 Python
视觉直观感受若干常用排序算法
2017/04/13 Python
Anaconda多环境多版本python配置操作方法
2017/09/12 Python
python的unittest测试类代码实例
2017/12/07 Python
Python Socket编程之多线程聊天室
2018/07/28 Python
Python测试网络连通性示例【基于ping】
2018/08/03 Python
Keras: model实现固定部分layer,训练部分layer操作
2020/06/28 Python
浅析Python 抽象工厂模式的优缺点
2020/07/13 Python
会计主管岗位职责范文
2013/11/08 职场文书
事业单位请假制度
2014/01/13 职场文书
参观考察邀请函范文
2014/01/29 职场文书
安全大检查反思材料
2014/01/31 职场文书
计算机学生的自我评价分享
2014/02/18 职场文书
淘宝活动总结范文
2014/06/26 职场文书
Python爬虫进阶之Beautiful Soup库详解
2021/04/29 Python