這篇文章主要介紹怎么用HTML5 Canvas實(shí)現(xiàn)交互式地鐵線路圖,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
專注于為中小企業(yè)提供網(wǎng)站建設(shè)、成都做網(wǎng)站服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)商南免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上1000+企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
界面生成
底層的p是通過(guò)ht.graph.GraphView組件生成的,然后就可以利用HTforWeb提供好的方法,調(diào)用canvas畫(huà)筆隨便繪制就好,先來(lái)看看怎么生成底層p:
vardm=newht.DataModel();//數(shù)據(jù)容器
vargv=newht.graph.GraphView(dm);//拓?fù)浣M件
gv.addToDOM();//將拓?fù)鋱D組件添加進(jìn)body中
addToDOM函數(shù)聲明如下:
addToDOM=function(){
varself=this,
view=self.getView(),
style=view.style;
document.body.appendChild(view);//將組件底層p添加到body中
style.left='0';//默認(rèn)組件是絕對(duì)定位,所以要設(shè)置位置
style.right='0';
style.top='0';
style.bottom='0';
window.addEventListener('resize',function(){self.iv();},false);//窗口變化事件
}
現(xiàn)在我就可以在這個(gè)p上亂涂亂畫(huà)了~首先我獲取下載好的地鐵線路圖上的點(diǎn),我將它們放在subway.js中,這個(gè)js文件全部都是下載的內(nèi)容,我沒(méi)有做其他的改動(dòng),主要是將這些點(diǎn)根據(jù)線路來(lái)分分配添加到數(shù)組中,比如:
mark_Point13=[];//線路數(shù)組內(nèi)包含線路的起點(diǎn)和終點(diǎn)坐標(biāo)以及這條線路的名稱
t_Point13=[];//換成站點(diǎn)數(shù)組內(nèi)包含線路中的換乘站點(diǎn)坐標(biāo)以及換成站點(diǎn)名稱
n_Point13=[];//小站點(diǎn)數(shù)組內(nèi)包含線路中的小站點(diǎn)坐標(biāo)以及小站點(diǎn)名稱
mark_Point13.push({name:'十三號(hào)線',value:[113.4973,23.1095]});
mark_Point13.push({name:'十三號(hào)線',value:[113.4155,23.1080]});
t_Point13.push({name:'魚(yú)珠',value:[113.41548,23.10547]});
n_Point13.push({name:'裕豐圍',value:[113.41548,23.10004]});
接下來(lái)來(lái)描繪地鐵線路,我聲明了一個(gè)數(shù)組lineNum,用來(lái)裝js中所有的地鐵線路的編號(hào),以及一個(gè)color數(shù)組,用來(lái)裝所有的地鐵線的顏色,這些顏色的index與lineNum中地鐵線編號(hào)的index是一一對(duì)應(yīng)的:
varlineNum=['1','2','3','30','4','5','6','7','8','9','13','14','32','18','21','22','60','68'];
varcolor=['#f1cd44','#0060a1','#ed9b4f','#ed9b4f','#007e3a','#cb0447','#7a1a57',
'#18472c','#008193','#83c39e','#8a8c29','#82352b','#82352b','#09a1e0','#8a8c29',
'#82352b','#b6d300','#09a1e0'];
接著遍歷lineNum,將lineNum中的元素和顏色傳到createLine函數(shù)中,根據(jù)這兩個(gè)參數(shù)來(lái)繪制地鐵線路以及配色,畢竟js文件中的命名方式也是有規(guī)律的,哪一條線路,則命名后面一定會(huì)加上對(duì)應(yīng)的數(shù)字,所以我們只需要將字符串與這個(gè)編號(hào)結(jié)合即可獲得js中對(duì)應(yīng)的數(shù)組了:
letlineName='Line'+num;
letline=window[lineName];
createLine的定義也非常簡(jiǎn)單,我的代碼設(shè)置了不少的樣式,所以看起來(lái)有點(diǎn)多。創(chuàng)建一個(gè)ht.Polyline管線,我們可以通過(guò)polyline.addPoint()函數(shù)向這個(gè)變量中添加具體的點(diǎn),通過(guò)setSegments可以設(shè)置點(diǎn)的連接方式。
functioncreateLine(num,color){//繪制地圖線
varpolyline=newht.Polyline();//多邊形管線
polyline.setTag(num);//設(shè)置節(jié)點(diǎn)tag標(biāo)簽,作為唯一標(biāo)示
if(num==='68')polyline.setToolTip('APM');//設(shè)置提示信息
elseif(num==='60')polyline.setToolTip('GF');
elsepolyline.setToolTip('Line'+num);
if(color){
polyline.s({//s為setStyle的簡(jiǎn)寫(xiě),設(shè)置樣式
'shape.border.width':0.4,//設(shè)置多邊形的邊框?qū)挾?/p>
'shape.border.color':color,//設(shè)置多邊形的邊框顏色
'select.width':0.2,//設(shè)置選中節(jié)點(diǎn)的邊框?qū)挾?/p>
'select.color':color//設(shè)置選中節(jié)點(diǎn)的邊框顏色
});
}
letlineName='Line'+num;
letline=window[lineName];
for(leti=0;i<line.length;i++){
for(letj=0;j<line[i].coords.length;j++){
polyline.addPoint({x:line[i].coords[j][0]*300,y:-line[i].coords[j][1]*300});
if(num==='68'){//APM線(有兩條,但是點(diǎn)是在同一個(gè)數(shù)組中的)
if(i===0&&j===0){
polyline.setSegments([1]);
}
elseif(i===1&&j===0){
polyline.getSegments().push(1);
}
else{
polyline.getSegments().push(2);
}
}
}
}
polyline.setLayer('0');//將線設(shè)置在下層,點(diǎn)設(shè)置在上層“top”
dm.add(polyline);//將管線添加進(jìn)數(shù)據(jù)容器中儲(chǔ)存,不然這個(gè)管線屬于“游離”狀態(tài),是不會(huì)顯示在拓?fù)鋱D上的
returnpolyline;
}
上面代碼中添加地鐵線上的點(diǎn)有分為幾種情況,是因?yàn)閖s中設(shè)置線的時(shí)候Line68有一個(gè)“跳躍”點(diǎn)的現(xiàn)象,所以我們必須“跳躍”過(guò)去,篇幅有限Line68數(shù)組具體的聲明自行看subway.js。
這里說(shuō)明一點(diǎn),如果用的是addPoint函數(shù),不設(shè)置segments時(shí),默認(rèn)將添加進(jìn)的點(diǎn)用直線連接,segments的定義如下:
1:moveTo,占用1個(gè)點(diǎn)信息,代表一個(gè)新路徑的起點(diǎn)
2:lineTo,占用1個(gè)點(diǎn)信息,代表從上次最后點(diǎn)連接到該點(diǎn)
3:quadraticCurveTo,占用2個(gè)點(diǎn)信息,第一個(gè)點(diǎn)作為曲線控制點(diǎn),第二個(gè)點(diǎn)作為曲線結(jié)束點(diǎn)
4:bezierCurveTo,占用3個(gè)點(diǎn)信息,第一和第二個(gè)點(diǎn)作為曲線控制點(diǎn),第三個(gè)點(diǎn)作為曲線結(jié)束點(diǎn)
5:closePath,不占用點(diǎn)信息,代表本次路徑繪制結(jié)束,并閉合到路徑的起始點(diǎn)
所以我們要做“跳躍”的行為設(shè)置segments為1即可。
最后繪制這些地鐵線上的點(diǎn),這個(gè)部分subway.js中也分離出來(lái)了,命名以“mark_Point”、“t_Point”以及“n_Point”開(kāi)頭,我在前面js的展示部分有對(duì)這些數(shù)組進(jìn)行解釋,大家動(dòng)動(dòng)中指劃上去看看。
我們?cè)谶@些點(diǎn)的位置添加ht.Node節(jié)點(diǎn),當(dāng)節(jié)點(diǎn)一添加進(jìn)dm數(shù)據(jù)容器中時(shí),就會(huì)在拓?fù)鋱D上顯示,當(dāng)然,前提是這個(gè)拓?fù)鋱D組件gv設(shè)置的數(shù)據(jù)容器是這個(gè)dm。篇幅有限,添加地鐵線上的點(diǎn)的代碼部分我只展示添加“換乘站點(diǎn)”的點(diǎn):
vartName='t_Point'+num;
vartP=window[tName];//大站點(diǎn)
if(tP){//有些線路沒(méi)有“換乘站點(diǎn)”
for(leti=0;i<tP.length;i++){
letnode=createNode(tP[i].name,tP[i].value,color[index]);//在獲取的線路上的點(diǎn)的坐標(biāo)位置添加節(jié)點(diǎn)
node.s({//設(shè)置節(jié)點(diǎn)的樣式style
'label.scale':0.05,//文本縮放,可以避免瀏覽器限制的最小字號(hào)問(wèn)題
'label.font':'bold12pxarial,sans-serif'//設(shè)置文本的font
});
node.setSize(0.6,0.6);//設(shè)置節(jié)點(diǎn)大小。由于js中每個(gè)點(diǎn)之間的偏移量太小,所以我不得不把節(jié)點(diǎn)設(shè)置小一些
node.setImage('images/旋轉(zhuǎn)箭頭.json');//設(shè)置節(jié)點(diǎn)的圖片
node.a('alarmColor1','rgb(150,150,150)');//attr屬性,可以在這里面設(shè)置任何的東西,alarmColor1是在上面設(shè)置的image的json中綁定的屬性,具體參看HTforWeb矢量手冊(cè)(http://www.hightopo.com/guide/guide/core/vector/ht-vector-guide.html#ref_binding)
node.a('alarmColor2','rgb(150,150,150)');//同上
node.a('tpNode',true);//這個(gè)屬性設(shè)置只是為了用來(lái)區(qū)分“換乘站點(diǎn)”和“小站點(diǎn)”的,后面會(huì)用上
}
}
所有的地鐵線路以及站點(diǎn)都添加完畢。但是!你可能會(huì)看不見(jiàn)自己繪制的圖,因?yàn)樗麄兲×耍@個(gè)時(shí)候可以設(shè)置graphView拓?fù)浣M件上的fitContent函數(shù),我們順便將拓?fù)鋱D上的所有東西不可移動(dòng)也設(shè)置一下:
gv.fitContent(false,0.00001);//自適應(yīng)大小,參數(shù)1為是否動(dòng)畫(huà),參數(shù)2為gv與邊框的padding值
gv.setMovableFunc(function(){
returnfalse;//設(shè)置gv上的節(jié)點(diǎn)不可移動(dòng)
});
這下你的地鐵線路圖就可以顯示啦~接下來(lái)看看交互。
交互
首先是鼠標(biāo)移動(dòng)事件,鼠標(biāo)滑過(guò)具體線路時(shí),線路會(huì)變粗,懸停一會(huì)兒還能看到這條線路的編號(hào);當(dāng)鼠標(biāo)移動(dòng)到“換乘站點(diǎn)”或“小站點(diǎn)”,站點(diǎn)對(duì)應(yīng)的圖標(biāo)都會(huì)變大并且變色,字體也會(huì)變大,鼠標(biāo)移開(kāi)圖標(biāo)變回原來(lái)的顏色并且字體變小。不同點(diǎn)在于鼠標(biāo)移動(dòng)到“換乘站點(diǎn)”時(shí),“換乘站點(diǎn)”會(huì)旋轉(zhuǎn)。
鼠標(biāo)滑動(dòng)事件,我直接基于gv的底層p進(jìn)行的mousemove事件,通過(guò)ht封裝的getDataAt函數(shù)傳入事件event參數(shù),獲取事件下對(duì)應(yīng)的節(jié)點(diǎn),然后就可以隨意操作節(jié)點(diǎn)了:
gv.getView().addEventListener('mousemove',function(e){
vardata=gv.getDataAt(e);//傳入邏輯坐標(biāo)點(diǎn)或者交互event事件參數(shù),返回當(dāng)前點(diǎn)下的圖元
if(name){
originNode(name);//不管什么時(shí)候都要讓節(jié)點(diǎn)保持原來(lái)的大小
}
if(datainstanceofht.Polyline){//判斷事件節(jié)點(diǎn)的類型
dm.sm().ss(data);//選中“管道”
name='';
clearInterval(interval);
}
elseif(datainstanceofht.Node){
if(data.getTag()!==name&&data.a('tpNode')){//若不是同一個(gè)節(jié)點(diǎn),并且mousemove的事件對(duì)象為ht.Node類型,那么設(shè)置節(jié)點(diǎn)的旋轉(zhuǎn)
interval=setInterval(function(){
data.setRotation(data.getRotation()-Math.PI/16);//在自身旋轉(zhuǎn)的基礎(chǔ)上再旋轉(zhuǎn)
},100);
}
if(data.a('npNode')){//如果鼠標(biāo)移到“小站點(diǎn)”也要停止動(dòng)畫(huà)
clearInterval(interval);
}
expandNode(data,name);////自定義的放大節(jié)點(diǎn)函數(shù),比較容易,我不粘代碼了,可以去http://hightopo.com/查看
dm.sm().ss(data);//設(shè)置選中節(jié)點(diǎn)
name=data.getTag();//作為“上一個(gè)節(jié)點(diǎn)”的存儲(chǔ)變量,可以通過(guò)這個(gè)值來(lái)獲取節(jié)點(diǎn)
}
else{//其他任何情況則不選中任何內(nèi)容并且清除“換乘站點(diǎn)”上的動(dòng)畫(huà)
dm.sm().ss(null);
name='';
clearInterval(interval);
}
});
鼠標(biāo)懸停在地鐵線路上時(shí)顯示“具體線路信息”,我是通過(guò)設(shè)置tooltip來(lái)完成的(注意:要打開(kāi)gv的tooltip開(kāi)關(guān)):
gv.enableToolTip();//打開(kāi)tooltip的開(kāi)關(guān)
if(num==='68')polyline.setToolTip('APM');//設(shè)置提示信息
elseif(num==='60')polyline.setToolTip('GF');
elsepolyline.setToolTip('Line'+num);
然后我利用右下角的form表單,單擊表單上的具體線路,或者雙擊拓?fù)鋱D上任意一個(gè)“站點(diǎn)”或者線路,則拓?fù)鋱D會(huì)自適應(yīng)到對(duì)應(yīng)的部分,將被雙擊的部分展現(xiàn)到拓?fù)鋱D的中央。
form表單的聲明部分我好像還沒(méi)有解釋。。。就是通過(guò)new一個(gè)ht.widget.FomePane類創(chuàng)建一個(gè)form表單組件,通過(guò)form.getView()獲取表單組件的底層p,將這個(gè)p擺放在body右下角,然后通過(guò)addRow函數(shù)向form表單中添加一行的表單項(xiàng),可以在這行中添加任意多個(gè)項(xiàng),通過(guò)addRow函數(shù)的第二個(gè)參數(shù)(一個(gè)數(shù)組),對(duì)添加進(jìn)的表單項(xiàng)進(jìn)行寬度的設(shè)置,通過(guò)第三個(gè)參數(shù)設(shè)置這行的高度:
functioncreateForm(){//創(chuàng)建右下角的form表單
varform=newht.widget.FormPane();
form.setWidth(200);//設(shè)置表單寬度
form.setHeight(416);//設(shè)置表單高度
letview=form.getView();
document.body.appendChild(view);//將表單添加進(jìn)body中
view.style.zIndex=1000;
view.style.bottom='10px';//ht組件幾乎都設(shè)置絕對(duì)路徑
view.style.right='10px';
view.style.background='rgba(211,211,211,0.8)';
names.forEach(function(nameString){
form.addRow([//向表單中添加行
{//這一行中的第一個(gè)表單項(xiàng)
button:{//向表單中添加button按鈕
icon:'images/Line'+nameString.value+'.json',//設(shè)置按鈕的圖標(biāo)
background:'',//設(shè)置按鈕的背景
borderColor:'',//設(shè)置按鈕的邊框顏色
clickable:false//設(shè)置按鈕不可點(diǎn)擊
}
},
{//第二個(gè)表單項(xiàng)
button:{
label:nameString.name,
labelFont:'bold14pxarial,sans-serif',
labelColor:'#fff',
background:'',
borderColor:'',
onClicked:function(){//按鈕點(diǎn)擊回調(diào)事件
gv.sm().ss(dm.getDataByTag(nameString.value));//設(shè)置選中按下的按鈕對(duì)應(yīng)的線路
gv.fitData(gv.sm().ld(),true,5);//將選中的地鐵線路顯示在拓?fù)鋱D的中央
}
}
}
],[0.1,0.2],23);//第二個(gè)參數(shù)是設(shè)置第一參數(shù)中的數(shù)組的寬度,小于1是比例,大于1是實(shí)際寬度。第三個(gè)參數(shù)是該行的高度
});
}
單擊“站點(diǎn)”顯示紅色標(biāo)注,雙擊節(jié)點(diǎn)自適應(yīng)放置到拓?fù)鋱D中央以及雙擊空白處將紅色標(biāo)注隱藏的內(nèi)容都是通過(guò)對(duì)拓?fù)浣M件gv的事件監(jiān)聽(tīng)來(lái)控制的,非常清晰易懂,代碼如下:
varnode=createRedLight();//創(chuàng)建一個(gè)新的節(jié)點(diǎn),顯示為“紅燈”的樣式
gv.mi(function(e){//ht中拓?fù)浣M件中的事件監(jiān)聽(tīng)
if(e.kind==='clickData'&&(e.data.a('tpNode')||e.data.a('npNode'))){//e.kind獲取當(dāng)前事件類型,e.data獲取當(dāng)前事件下的節(jié)點(diǎn)
node.s('2d.visible',true);//設(shè)置node節(jié)點(diǎn)可見(jiàn)
node.setPosition(e.data.getPosition().x,e.data.getPosition().y);//設(shè)置node的坐標(biāo)為當(dāng)前事件下節(jié)點(diǎn)的位置
}
elseif(e.kind==='doubleClickData'){//雙擊節(jié)點(diǎn)
gv.fitData(e.data,false,10);//將事件下的節(jié)點(diǎn)自適應(yīng)到拓?fù)鋱D的中央,參數(shù)1為自適應(yīng)的節(jié)點(diǎn),參數(shù)2為是否動(dòng)畫(huà),參數(shù)3為gv與邊框的padding
}
elseif(e.kind==='doubleClickBackground'){//雙擊空白處
node.s('2d.visible',false);//設(shè)置node節(jié)點(diǎn)不可見(jiàn)查看HTforWeb樣式手冊(cè)(http://www.hightopo.com/guide/guide/core/theme/ht-theme-guide.html#ref_style)
}
});
注意s(style)和a(attr)定義是這樣的,s是ht預(yù)定義的一些樣式屬性,而a是我們用戶來(lái)自定義的屬性,一般是通過(guò)調(diào)用字符串來(lái)調(diào)用結(jié)果的,這個(gè)字符串對(duì)應(yīng)的可以是常量也可以是函數(shù),還是很靈活的。
最后還做了一個(gè)小小的部分,選中“站點(diǎn)”,則該“站點(diǎn)”的上方會(huì)顯示一個(gè)紅色的會(huì)“呼吸”的用來(lái)注明當(dāng)前選中的“站點(diǎn)”。
“呼吸”的部分是利用ht的setAnimation函數(shù)來(lái)完成的,在用這個(gè)函數(shù)之前要先打開(kāi)數(shù)據(jù)容器的動(dòng)畫(huà)開(kāi)關(guān),然后設(shè)置動(dòng)畫(huà):
dm.enableAnimation();//打開(kāi)數(shù)據(jù)容器的動(dòng)畫(huà)開(kāi)關(guān)
functioncreateRedLight(){
varnode=newht.Node();
node.setImage('images/紅燈.json');//設(shè)置節(jié)點(diǎn)的圖片
node.setSize(1,1);//設(shè)置節(jié)點(diǎn)的大小
node.setLayer('firstTop');//設(shè)置節(jié)點(diǎn)顯示在gv的最上層
node.s('2d.visible',false);//節(jié)點(diǎn)不可見(jiàn)
node.s('select.width',0);//節(jié)點(diǎn)選中時(shí)的邊框?yàn)?,不可見(jiàn)
node.s('2d.selectable',false);//設(shè)置這個(gè)屬性,則節(jié)點(diǎn)不可選中
node.setAnimation({//設(shè)置動(dòng)畫(huà)具體參見(jiàn)HTforWeb動(dòng)畫(huà)手冊(cè)(http://www.hightopo.com/guide/guide/plugin/animation/ht-animation-guide.html)
expandWidth:{
property:"width",//設(shè)置這個(gè)屬性,并且未設(shè)置accessType,則默認(rèn)通過(guò)setWidth/getWidth來(lái)設(shè)置和獲取屬性。這里的width和下面的height都是通過(guò)前面設(shè)置的size得到的
from:0.5,//動(dòng)畫(huà)開(kāi)始時(shí)的屬性值
to:1,//動(dòng)畫(huà)結(jié)束時(shí)的屬性值
next:"collapseWidth"//字符串類型,指定當(dāng)前動(dòng)畫(huà)完成之后,要執(zhí)行的下個(gè)動(dòng)畫(huà),可將多個(gè)動(dòng)畫(huà)融合
},
collapseWidth:{
property:"width",
from:1,
to:0.5,
next:"expandWidth"
},
expandHeight:{
property:"height",
from:0.5,
to:1,
next:"collapseHeight"
},
collapseHeight:{
property:"height",
from:1,
to:0.5,
next:"expandHeight"
},
start:["expandWidth","expandHeight"]//數(shù)組,用于指定要啟動(dòng)的一個(gè)或多個(gè)動(dòng)畫(huà)
});
dm.add(node);
returnnode;
}
以上是“怎么用HTML5 Canvas實(shí)現(xiàn)交互式地鐵線路圖”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
當(dāng)前名稱:怎么用HTML5Canvas實(shí)現(xiàn)交互式地鐵線路圖
文章起源:http://muchs.cn/article34/ieghse.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供域名注冊(cè)、網(wǎng)站改版、品牌網(wǎng)站制作、ChatGPT、網(wǎng)站制作、App設(shè)計(jì)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)