首先讓我們來看下這個案例:
我們來看看如何操作這個3d交互模型,可以直接滑動“Rotation”的滑動條,你會看到3d和左下角的2d上的圖元都會旋轉(zhuǎn),接著點(diǎn)擊“Axis”中的任意一個值,然后點(diǎn)擊“Animate”,你會看到中間這個圖元會旋轉(zhuǎn),同時滑動“Range”的滑動條,這是控制你旋轉(zhuǎn)的幅度的,如果你調(diào)到“0”,那么就不會旋轉(zhuǎn),調(diào)到“30”就會旋轉(zhuǎn)30度,以此類推。接著調(diào)整“Reset”你會發(fā)現(xiàn),不是完全刷新這個界面,而是局部刷新兩邊的圓柱,根據(jù)這兩個圓柱與中間節(jié)點(diǎn)之間的關(guān)聯(lián)而重置的。
左下角的是整個3d場景內(nèi)的俯視圖,這樣我們可以非常直觀地看清圖元的移動方向和位置。
可能你會好奇這個是怎么俯視圖是怎么放上去的?如果3d中的圖元變化,這個俯視圖中的圖元也會跟著變化么?如何把右上角的form表單和左下角的視圖又是怎么放的?如何只移動3d二把這兩個固定在這邊?或者你可能還有別的問題,在這里我會盡量清楚地解答,實(shí)在找不到答案可以去我們的官網(wǎng)HT for Web查找你的問題。
好了,基礎(chǔ)就是先布局,布3d場景,HT在提供方法方面算是非常細(xì)致的了,平時我們生成網(wǎng)格可能就要花費(fèi)一段時間,又是基礎(chǔ)代碼,新手開發(fā)人員都能很快上手呢~短短幾行代碼就能創(chuàng)建一個3d場景,簡直太快。。
dm = new ht.DataModel(); g3d = new ht.graph3d.Graph3dView(dm); g3d.setGridVisible(true);//設(shè)置網(wǎng)格可視g3d.setGridSize(m);//設(shè)置網(wǎng)格大小g3d.setGridGap(w);//設(shè)置網(wǎng)格間距g3d.setEye([-200, 150, 200]);//設(shè)置camera位置g3d.getView().className = 'main'; document.body.appendChild(g3d.getView());
由于HT默認(rèn)將所有組件都設(shè)置了style“position:absolute”,所以當(dāng)我們初始化這個組件之后,一定要在style中寫上位置,并且將這個組件添加進(jìn)你想要添加進(jìn)的標(biāo)簽中,這個例子中,form表單、2d組件和3d組件都互不依附,所以我們直接將這三個都添加進(jìn)body中即可,還有一點(diǎn)值得注意的,所有HT組件的最根層都是一個p,是通過組件的getView()函數(shù)獲得的。所以我們?nèi)绻砑舆M(jìn)HTML標(biāo)簽中,肯定也要是HTML標(biāo)簽才行。
然后再界面的右上角放上form表單,放到右上角就直接設(shè)置style中的“top”“bottom”“l(fā)eft”“right”即可,2d圖同理:
formPane = new ht.widget.FormPane(); formPane.setLabelAlign('right'); formPane.getView().className = 'formpane'; document.body.appendChild(formPane.getView()); formPane.addRow(['Rotation:', { id: 'rotation', slider: { min: -180, max: 180, value: 0, step: 1, onValueChanged: function(e){ node.setRotation(this.getValue() * Math.PI / 180); } } }], [60, 0.1]);
因?yàn)檫@個例子的form表單中的行數(shù)和內(nèi)容比較多,所以我這邊就只取了一個form表單自定義行的例子。這邊的“id”只是為了能快速查找到這個元素,slider是HT form表單自定義的一個方法,滑動條功能,設(shè)置了該屬性后HT將根據(jù)屬性值自動構(gòu)建ht.widger.Slider對象,具體參數(shù)可以參考HT for Web表單手冊。
至于左下角的2d俯視圖,這是通過跟3d共享同一個datamodel數(shù)據(jù)模型,只要我們繪制好了圖形,然后添加進(jìn)datamodel中去,不管是什么組件,只要調(diào)用了這個datamodel的都可以擁有datamodel中的所有數(shù)據(jù):
g2d = new ht.graph.GraphView(dm); g2d.getView().className = 'g2d'; g2d.setEditable(true); document.body.appendChild(g2d.getView()); ht.Default.callLater(g2d.fitContent, g2d, [true, 50, true]);
ht.Default.callLater(func, scope, args, delay)獲取全局下一個編號,其中 func指的是回調(diào)函數(shù),scope指的是函數(shù)域,args指的是函數(shù)參數(shù)列表,delay則是延遲時間(毫秒)。這個函數(shù)可以在頁面打開時回調(diào)g2d.fitContent函數(shù),然后作用域僅在g2d中,這個函數(shù)參數(shù)列表是fitContent(anim, padding, notZoomIn)函數(shù)的參數(shù),這三個參數(shù)分別代表“是否使用動畫”,“縮放后圖元區(qū)域與拓?fù)溥吘壍木嚯x”,以及“是否將最小縮放值限定為1”。
接著將3d中的圖元添加進(jìn)去,這里我不截取全部代碼,只取一個比較特別的有趣的圖元,中間外層的透明圖元:
shape = new ht.Shape(); shape.s({ 'all.reverse.cull': true, 'all.color': 'rgba(0, 255, 0, 0.5)', 'all.transparent': true }); shape.setThickness(2); dm.add(shape); var resetShape = function() { var cs = node.getCorners(10, 10); cs.push(cs[0]); shape.setPoints(cs); g3d.setBoundaries(ht.Default.toBoundaries(cs)); }; resetShape();
這邊比較有趣的有幾點(diǎn):
1. 這邊用了node.getCorners()這個方法,這個是獲取四個點(diǎn),對于2d來說就是左上、右上、右下、左下四個點(diǎn);對于3d來說就是直接獲取底面的四個“左上、右上、右下、左下”點(diǎn),這個我反應(yīng)了好一會兒才反應(yīng)過來。。并以這四個點(diǎn)為基礎(chǔ)作為shape的points。
2. 這邊還用了setBoundaries(boundaries)函數(shù),借用ht.Default.toBoundaries函數(shù)來將不符合setBoundaries函數(shù)參數(shù)的格式轉(zhuǎn)換成它需要的參數(shù)格式。雖然我認(rèn)為這一行在這個例子中沒有什么作用,但是還是讓我好好學(xué)習(xí)了一把碰撞測試。
我們在碰撞測試的時候經(jīng)常要設(shè)置g3d.setNear函數(shù),我實(shí)在沒搞懂這個函數(shù)是拿來干嘛的,結(jié)果這個例子讓我注意到,如果“我”的視線的近端截面位置也就是setNear(1),那么我能看到的就是比表面跟進(jìn)1的距離,這個函數(shù)默認(rèn)設(shè)置為10,就算我們不設(shè)置這個值我們也能在3d中看到圖元的內(nèi)部去,剛剛我們介紹的getCorners()函數(shù),其實(shí)它還有兩個參數(shù)xpadding和ypadding,分別代表“水平方向padding”“垂直方向padding”,也就是說,在我們獲取四個角的同時,我們還能設(shè)置這四個角和邊之間的padding。只要將這個值設(shè)置得比setNear設(shè)置的大,我們就不會看到3d圖元的內(nèi)部中去了。
我們還注意到似乎是“廢代碼”的一行: cs.push(cs[0])。這個完全不是廢代碼啊,幫了很大忙呢!在HT中,用ht.Shape創(chuàng)建的圖元,只要你不手動設(shè)置繪制關(guān)閉,那么就會停留在你最終繪制的位置,所以我把最后的一個點(diǎn)又和第一個點(diǎn)連起來,那么就是一個封閉的圖形了,否則你會看到后面缺了一部分,像這樣:
我在其他文章中也提到過HT封裝了一些很方便的方法和事件,比如datamodel#md,監(jiān)聽數(shù)據(jù)的屬性的變化,這邊我們用了md方法來判斷只有中間這個node能夠繞著一個點(diǎn)旋轉(zhuǎn),具體參考HT for Web數(shù)據(jù)模型手冊:
dm.md(function(e){ if(e.data === node){ if(e.property === 'rotation'){ formPane.v('rotation', 180 / Math.PI * e.newValue); } resetShape(); } });
這邊我想要說一下“繞著一個點(diǎn)旋轉(zhuǎn)”的功能,這邊沒有用我們自定義的anchor錨點(diǎn),但是功能類似,通過獲取我form表單上選擇的“l(fā)eft、right、front、back”來設(shè)置旋轉(zhuǎn)中心點(diǎn),HT中form表單通過getValue(id)簡寫成v(id)根據(jù)id獲取對應(yīng)item元素值:
formPane.addRow([ { button: { label: 'Animate', onClicked: function(){ var dx = 0, dy = 0, range = formPane.v('range') * Math.PI / 180; if(formPane.v('left')){ dx = -node.getWidth()/2; } if(formPane.v('right')){ dx = node.getWidth()/2; } if(formPane.v('back')){ dy = -node.getHeight()/2; } if(formPane.v('front')){ dy = node.getHeight()/2; } animate(node, range, dx, dy); } } }, { button: { label: 'Reset', onClicked: function(){ node.setRotation(0); } } } ], [0.1, 0.1]);
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com