JavaScript制作简单的框选图表

发布时间 - 2026-01-11 01:07:31    点击率:

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

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

于是我想到了用 canvas 画布来仿着做,但又考虑了一下, canvas 操作起来不顺手;究竟可不可以用普通的css结合 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> 
 /* 
 **声明 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.至于三角函数我就不介绍了,百度一大把。

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


# js  # 框选图表  # 我想  # 鼠标  # 来做  # 小圆  # 的是  # 他们的  # 我就  # 让我  # 给我  # 大材小用  # 会有  # 小方块  # 有个  # 出了  # 那就  # 也没  # 不需要  # 给他  # 就不  # 每个人 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 历史网站制作软件,华为如何找回被删除的网站?  北京网站制作的公司有哪些,北京白云观官方网站?  Laravel如何使用Spatie Media Library_Laravel图片上传管理与缩略图生成【步骤】  长沙做网站要多少钱,长沙国安网络怎么样?  网站制作软件有哪些,制图软件有哪些?  php打包exe后无法访问网络共享_共享权限设置方法【教程】  在线制作视频网站免费,都有哪些好的动漫网站?  Laravel如何发送邮件和通知_Laravel邮件与通知系统发送步骤  怎样使用JSON进行数据交换_它有什么限制  网站制作报价单模板图片,小松挖机官方网站报价?  HTML透明颜色代码怎么让图片透明_给img元素加透明色的技巧【方法】  Laravel如何实现图片防盗链功能_Laravel中间件验证Referer来源请求【方案】  如何在Windows环境下新建FTP站点并设置权限?  微信推文制作网站有哪些,怎么做微信推文,急?  阿里云网站搭建费用解析:服务器价格与建站成本优化指南  Laravel API路由如何设计_Laravel构建RESTful API的路由最佳实践  潮流网站制作头像软件下载,适合母子的网名有哪些?  如何实现javascript表单验证_正则表达式有哪些实用技巧  如何在搬瓦工VPS快速搭建网站?  Linux系统运维自动化项目教程_Ansible批量管理实战  香港服务器选型指南:免备案配置与高效建站方案解析  BootStrap整体框架之基础布局组件  python中快速进行多个字符替换的方法小结  焦点电影公司作品,电影焦点结局是什么?  西安专业网站制作公司有哪些,陕西省建行官方网站?  使用Dockerfile构建java web环境  魔毅自助建站系统:模板定制与SEO优化一键生成指南  如何用PHP快速搭建CMS系统?  Python文本处理实践_日志清洗解析【指导】  Laravel如何使用Eloquent进行子查询  网站制作壁纸教程视频,电脑壁纸网站?  如何快速生成ASP一键建站模板并优化安全性?  Laravel如何使用withoutEvents方法临时禁用模型事件  JavaScript如何操作视频_媒体API怎么控制播放  深圳网站制作设计招聘,关于服装设计的流行趋势,哪里的资料比较全面?  如何在景安服务器上快速搭建个人网站?  香港服务器租用费用高吗?如何避免常见误区?  Laravel怎么连接多个数据库_Laravel多数据库连接配置  Laravel如何实现多语言支持_Laravel本地化与国际化(i18n)配置教程  利用vue写todolist单页应用  Laravel用户密码怎么加密_Laravel Hash门面使用教程  Laravel怎么实现软删除SoftDeletes_Laravel模型回收站功能与数据恢复【步骤】  Laravel如何设置定时任务(Cron Job)_Laravel调度器与任务计划配置  香港服务器网站推广:SEO优化与外贸独立站搭建策略  Laravel如何实现用户注册和登录?(Auth脚手架指南)  详解CentOS6.5 安装 MySQL5.1.71的方法  如何在宝塔面板中修改默认建站目录?  黑客入侵网站服务器的常见手法有哪些?  javascript中的数组方法有哪些_如何利用数组方法简化数据处理  微信公众帐号开发教程之图文消息全攻略