JavaScript制作简单的框选图表
故事背景:这几天遇到一个客户,是做会议记录的,每次会议过程中,都会有特定设备记录下讲话人的位置以角度值显示。他给我角度值,让我给他做一个图表来展示每个人的一个大概位置。
客户想到的是用 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> /* **模拟从后端取值过来的【角度】和相对应的【人名】数组 **/ 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.至于三角函数我就不介绍了,百度一大把。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。