JavaScript制作簡(jiǎn)單的框選圖表
故事背景:這幾天遇到一個(gè)客戶,是做會(huì)議記錄的,每次會(huì)議過程中,都會(huì)有特定設(shè)備記錄下講話人的位置以角度值顯示。他給我角度值,讓我給他做一個(gè)圖表來展示每個(gè)人的一個(gè)大概位置。
客戶想到的是用 Echarts 圖表來做,我首先想到的也是用 Echarts ,但是思考了他的要求以后,發(fā)現(xiàn)就一個(gè)簡(jiǎn)單的框選圖表用 Echarts 來做是不是大材小用了,而且還要導(dǎo)入那么多的沒用的代碼。
于是我想到了用 canvas 畫布來仿著做,但又考慮了一下, canvas 操作起來不順手;究竟可不可以用普通的css結(jié)合 javascript 來把它做出來呢?此番思考驗(yàn)證了:任何事情一定要多動(dòng)腦,才能 碰到更簡(jiǎn)單的解決問題的方式。
考慮到也許某天大家用得著,所以發(fā)布出來。注:擁有可移植性,可移到頁面任何位置,效果不會(huì)改變
先看最終效果吧:
圖一:


圖二:

這個(gè)小東西會(huì)涉及的知識(shí)點(diǎn)不多,歸納一下: js的三角函數(shù) 、 CSS3的transform 、 鼠標(biāo)的坐標(biāo)軸XY的計(jì)算 ...啊哈,差不多大體就這三方面的知識(shí)吧,如果你都只是有過了解也沒關(guān)系,因?yàn)槎贾挥玫牡狡っ圆槐負(fù)?dān)心。但是如果完全沒聽過,那就請(qǐng)您再去了解一下這方面知識(shí)。
代碼區(qū)域
<!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)函數(shù): 利用三角函數(shù)定理根據(jù)傳入的角度值獲取對(duì)邊和臨邊的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對(duì)象,以及框選時(shí)的那個(gè)任意變動(dòng)大小的小方塊對(duì)象
**/
var oWrap = document.getElementById('wrapcharts');
var aLi = oWrap.getElementsByTagName('li');
var oBox =document.getElementById('boxshadow');
var allLi = '';
var posArr = [];
/*
**for循環(huán)中調(diào)用getPos(param)來獲取degArr數(shù)組中的所有角度對(duì)應(yīng)的x,y值(就是每個(gè)角度對(duì)應(yīng)的x,y坐標(biāo)),并傳入到一個(gè)數(shù)組中保存,方便取用
**/
for(var i=0;i<degArr.length; i++)
{
posArr.push(getPos(degArr[i]));
}
/*
**for循環(huán)根據(jù)度數(shù)數(shù)組degArr的長(zhǎng)度插入li小圓點(diǎn)到ul中,并將之前獲取的每個(gè)點(diǎn)對(duì)應(yīng)的x,y左邊插入到行內(nè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;
/*
**遍歷最終得到的ul中的li
**/
for(var i=0; i<aLi.length; i++)
{
aLi[i].index = i;
/*
**封裝鼠標(biāo)移入每個(gè)小圓點(diǎn)時(shí)的放大事件,這里用到了matrix矩陣,為的事想兼容ie9以下瀏覽器,但是好像出了點(diǎn)問題
*/
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);
}
}
/***框選***/
/*
**拖拽框選代碼區(qū)域,這個(gè)我就不解釋了,明白人都一眼知道什么意思,這就像是公式,
*/
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;
/*
**當(dāng)鼠標(biāo)向四個(gè)方向拖拉的時(shí)候進(jìn)行方向判斷,并相應(yīng)的改變小方塊的left,top以及width,height
**其實(shí)我這里有個(gè)問題,那就是,代碼重復(fù)了一些,本想著合并一下,但是作者有點(diǎn)懶,嘿嘿,你們也可以嘗試一下
**修改后你們拿去當(dāng)做你們的發(fā)布,作者不會(huì)介意的
*/
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> 會(huì)用到的一些知識(shí)點(diǎn)拓展
注:在js中設(shè)置Transform的時(shí)候我用到的不是scale()方法,因?yàn)槲蚁爰嫒輎e9以下的版本所以用了矩陣變化。當(dāng)然,你們也可以改為scale(),毫無影響。
1.在標(biāo)準(zhǔn)瀏覽器下的矩陣函數(shù)matix(a,b,c,d,e,f)、ie下的矩陣函數(shù)progid:DXImageTransform.Microsoft.Matrix( M11= 1, M12= 0, M21= 0 , M22=1,SizingMethod='auto expend')
他們的共同點(diǎn):M11 == a; M12 == c; M21 == b; M22 == d
不一樣的地方:ie下的矩陣函數(shù)沒有 e 和 f 兩個(gè)參數(shù),在矩陣函數(shù)中 e 和 f 是用來位移的,也就是說ie下沒法通過矩陣函數(shù)來實(shí)現(xiàn)位移[ 不過我們這里好像不需要位移,嘿嘿 ]
2.在標(biāo)準(zhǔn)瀏覽器下矩陣函數(shù)matrix中a,b,c,d,e,f 一一對(duì)應(yīng)的的初始值為:matix(1,0,0,1,0,0)
3.通過矩陣實(shí)現(xiàn)縮放:
x軸縮放:a = x a c = x c e = x*e
y軸縮放:b = y b d = y d f = y*f
4.通過矩陣實(shí)現(xiàn)位移:[ie下沒位移]
x軸位移:e = e+x
y軸位移:f = f+y
5.通過矩陣實(shí)現(xiàn)傾斜:
x軸傾斜:c = Math.tan(xDeg/180*Math.PI)
y軸傾斜:b = Math.tan(yDeg/180*Math.PI)
6.通過矩陣實(shí)現(xiàn)旋轉(zhuǎn):
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.至于三角函數(shù)我就不介紹了,百度一大把。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
JS中call(),apply(),bind()函數(shù)的區(qū)別與用法詳解
這篇文章主要介紹了JS中call(),apply(),bind()函數(shù)的高級(jí)用法詳解,需要的朋友可以參考下2022-12-12
uniapp踩坑實(shí)戰(zhàn)之文件查找失敗:'uview-ui'?at?main.js解決辦法
這篇文章主要給大家介紹了關(guān)于uniapp踩坑實(shí)戰(zhàn)之文件查找失敗:'uview-ui'?at?main.js的解決辦法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12
postman自定義函數(shù)實(shí)現(xiàn) 時(shí)間函數(shù)的思路詳解
Postman是一款功能強(qiáng)大的網(wǎng)頁調(diào)試與發(fā)送網(wǎng)頁HTTP請(qǐng)求的Chrome插件。這篇文章主要給大家介紹postman自定義函數(shù)實(shí)現(xiàn) 時(shí)間函數(shù)的思路詳解,感興趣的朋友一起看看吧2019-04-04
js獲取最近一周一個(gè)月三個(gè)月時(shí)間的簡(jiǎn)單示例
時(shí)間的獲取和格式化是我們經(jīng)常遇到的問題,下面這篇文章主要給大家介紹了關(guān)于利用js如何獲取最近一周一個(gè)月三個(gè)月時(shí)間的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-12-12
原生js實(shí)現(xiàn)旋轉(zhuǎn)木馬輪播圖效果
本文主要介紹了原生js實(shí)現(xiàn)旋轉(zhuǎn)木馬輪播圖效果的實(shí)例,具有很好的參考價(jià)值,下面跟著小編一起來看下吧2017-02-02
各瀏覽器對(duì)document.getElementById等方法的實(shí)現(xiàn)差異解析
這篇文章主要是對(duì)各瀏覽器對(duì)document.getElementById等方法的實(shí)現(xiàn)差異進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下,希望對(duì)大家有所幫助2013-12-12
前端實(shí)現(xiàn)文件下載的4種常見方式與實(shí)戰(zhàn)示例
在前端開發(fā)中,實(shí)現(xiàn)文件下載是一個(gè)非常常見的需求,本篇文章將介紹 4 種前端文件下載的方式,并提供詳細(xì)示例,希望能幫助大家掌握文件下載的各種技巧2025-04-04

