故事背景:这几天遇到一个客户,是做会议记录的,每次会议过程中,都会有特定设备记录下讲话人的位置以角度值显示。他给我角度值,让我给他做一个图表来展示每个人的一个大概位置。
客户想到的是用 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']; 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}; } var oWrap=document.getElementById('wrapcharts'); var aLi=oWrap.getElementsByTagName('li'); var oBox=document.getElementById('boxshadow'); var allLi=''; var posArr=[]; for(var i=0;i<degArr.length; i++) { posArr.push(getPos(degArr[i])); } 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; for(var i=0; i<aLi.length; i++) { aLi[i].index=i; 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; 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('你选中的人是: '+lastSelect+' '); 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