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代码
Nov 10 Javascript
用js重建星际争霸
Dec 22 Javascript
javascript下利用arguments实现string.format函数
Aug 24 Javascript
jBox 2.3基于jquery的最新多功能对话框插件 常见使用问题解答
Nov 10 Javascript
浏览器加载、渲染和解析过程黑箱简析
Nov 29 Javascript
js带前后翻页的图片切换效果代码分享
Sep 08 Javascript
js中的事件委托或是事件代理使用详解
Jun 23 Javascript
js+html5实现页面可刷新的倒计时效果
Jul 15 Javascript
Three.js利用orbit controls插件(轨道控制)控制模型交互动作详解
Sep 25 Javascript
Bootstrap Table实现定时刷新数据的方法
Aug 13 Javascript
详解微信小程序开发聊天室—实时聊天,支持图片预览
May 20 Javascript
vue2.0实现列表数据增加和删除
Jun 17 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
全国FM电台频率大全 - 26 西藏自治区
2020/03/11 无线电
解决phpmyadmin 乱码,支持gb2312和utf-8
2006/11/20 PHP
PHP分页显示制作详细讲解
2006/12/05 PHP
Apache下禁止php文件被直接访问的解决方案
2013/04/25 PHP
yii操作cookie实例简介
2014/07/09 PHP
php以post形式发送xml的方法
2014/11/04 PHP
Jquery操作Select 简单方便 一个js插件搞定
2009/11/12 Javascript
javascript 循环读取JSON数据的代码
2010/07/17 Javascript
jquer之ajaxQueue简单实现代码
2011/09/15 Javascript
JavaScript模块随意拖动示例代码
2014/05/27 Javascript
js下拉选择框与输入框联动实现添加选中值到输入框的方法
2015/08/17 Javascript
vue.js通过自定义指令实现数据拉取更新的实现方法
2016/10/18 Javascript
jQuery遮罩层实例讲解
2017/05/11 jQuery
vue-awesome-swiper 基于vue实现h5滑动翻页效果【推荐】
2018/11/08 Javascript
Vuejs监听vuex中值的变化的方法示例
2018/12/02 Javascript
javascript json对象小技巧之键名作为变量用法分析
2019/11/11 Javascript
vant 中van-list的用法说明
2020/11/11 Javascript
python爬虫常用的模块分析
2014/08/29 Python
python进阶_浅谈面向对象进阶
2017/08/17 Python
Python回文字符串及回文数字判定功能示例
2018/03/20 Python
Django框架视图介绍与使用详解
2019/07/18 Python
Python如何调用外部系统命令
2019/08/07 Python
在python中利用pycharm自定义代码块教程(三步搞定)
2020/04/15 Python
python3定位并识别图片验证码实现自动登录功能
2021/01/29 Python
localstorage和sessionstorage使用记录(推荐)
2017/05/23 HTML / CSS
Html5 webRTC简单实现视频调用的示例代码
2020/09/23 HTML / CSS
英国领先的狗和宠物美容专家:Christies Direct
2017/04/03 全球购物
芬兰灯具网上商店:Nettilamppu.fi
2018/06/30 全球购物
EJB2和EJB3在架构上的不同点
2014/09/29 面试题
银行出纳岗位职责
2013/11/25 职场文书
总会计师岗位职责
2014/02/19 职场文书
学校班班通实施方案
2014/06/11 职场文书
企业战略合作意向书
2015/05/08 职场文书
理想国读书笔记
2015/06/25 职场文书
初中思品教学反思
2016/02/20 职场文书
Nginx限流和黑名单配置
2022/05/20 Servers