在現如今實際應用中,我覺得能夠通過操作JSON文件來操作3D上的場景變化是非常方便的一件事,尤其是在做編輯器進行拖拽圖元並且在圖元上產生的一系列變化的時候,都能將數據很直觀地反應給我們,這邊我們簡單地做了個HTML5視頻教程基礎的例子,給大家參考看看。
實踐場景再現:首先我們搭建一下這個例子的場景,熟悉的朋友可能已經看出來了,這個場景分爲三個部分:左、右上以及右下。HT通過ht.widget.SplitView可以很輕鬆地將場景分割,實現良好的頁面佈局,最後將這個分割組件添加進html的body體中,
//場景搭建
dataModel=newht.DataModel();//數據容器
g3d=newht.graph3d.Graph3dView(dataModel);//3D組件
propertyView=newht.widget.PropertyView(dataModel);//屬性組件
formPane=newht.widget.FormPane();//表單組件
rightSplit=newht.widget.SplitView(propertyView,formPane,'v',100);//分割組件
newht.widget.SplitView(g3d,rightSplit,'h',0.65).addToDOM();
接下來就是向場景中添加圖元,並把圖元添加到3D場景中,這時我們可以向圖元中添加各種屬性和樣式以及標籤作爲標記,本例中用到的圖元是3D模型,利用ht.Default.parseObj函數對obj和mtl文件進行解析:
//添加模型
varparams={center:true};//JSON格式控制參數傳入ht.Default.parseObj函數中
varmodelMap=ht.Default.parseObj(meter_obj,meter_mtl,params);//解析obj和mtl文件,解析後返回的map結構json對象中,每個材質名對應一個模型信息
當然,前提是要已經聲明瞭meter_obj以及meter_mtl兩個文件,這裏我們是將這兩個部分分別放到js文件中,並在頭部調用。
從上面的動圖中我們可以看到,這個例子中需要變化的模型部分只有“指針”以及下面的“開關”兩個部分,所以我們通過遍歷的方式獲取這兩個obj模型的部分,並註冊3D模型:
vararray=[];
for(varnameinmodelMap){
varmodel=modelMap[name];//modelMap中的模型
array.push(model);
if(name==='pointer'){//obj文件中的一個模型名稱爲pointer
model.mat={//矩陣變化參數,可對模型進行矩陣變化後導入
func:function(data){
varstart=Math.PI*0.736,
range=Math.PI*1.49,
angle=start-range*data.a('meter.value')/4;//動態獲取了meter.value的值
returnht.Default.createMatrix([//將一組JSON描述的縮放、移動和旋轉等操作轉換成對應的變化矩陣
{t3:[0,-82.5,0]},
{r3:[0,0,angle]},
{t3:[0,82.5,0]}
]);
}
};
}
if(name==='switch'){//obj文件中的一個模型名稱爲switch
model.mat={
func:function(data){
returnht.Default.createMatrix([
{t3:[0,48.5,0]},
{r3:[0,0,data.a('meter.angle')]},
{t3:[0,-48.5,0]}
]);
}
};
model.color={
func:function(data){
if(data.a('meter.angle')){
return'rgb(186,0,0)';
}else{
return'black';
}
}
};
}
}
ht.Default.setShape3dModel('meter',array);//註冊3D模型,請參考modeling建模手冊第一參數爲模型名稱,第二參數爲JSON類型對象
之後用戶可以在需要用到的地方直接設置屬性shape3d爲這邊註冊過的3D模型名稱,我們下面就創建3個節點,並將節點設置爲此3D模型:
for(vari=0;i<3;i++){//創建3個節點meter
varnode=newht.Node();
node.setTag(i);//設置tag標籤
node.setName('Meter-00'+(i+1));//設置圖元名稱一般顯示在圖元的下方
node.s({
'label.color':'white',
'label.background':'#5271B8',
'label.face':'center',
'label.position':23,
'label.scale':2,
'label.reverse.flip':true,
'note.scale':1.5,//設置字體大小,這種方式不會碰到瀏覽器最小字體的問題
'note.t3':[-30,-5,-90],
'note2.scale':1.2,
'note2.position':17,
'note2.t3':[0,-20,-30],
'note2.color':'black',
'note2.background':'yellow',
'shape3d':'meter',//設置爲前面註冊的meter3D模型
'shape3d.scaleable':false,
'wf.visible':'selected',//選中圖元時顯示線框
'select.brightness':1
});
node.a({//自定義屬性下面會利用這些自定義屬性進行數據綁定
'meter.value':i+1,
'meter.angle':i*Math.PI/3
});
node.p3(i*200-200,params.rawS3[1]/2,i===1?100:-100);
node.r3(0,-Math.PI/6*(i-1),0);
node.s3(params.rawS3);//設置圖元的大小爲rawS3模型的原始尺寸
dataModel.add(node);//向數據模型中添加節點
}
dataModel.sm().ss(dataModel.getDataByTag(1));//設置默認選中tag標籤爲1的圖元
我們在這邊爲節點添加兩個標註,作爲文字提示,可以通過重載getNote/getNote2(HT中一個節點支持雙標註,所以提供了note2第二個標註)函數重載note的命名方法,當然HT中其他類似的文字提示也可以通過這種途徑來改變文字的顯示信息,這裏我們通過數據綁定獲取meter.value以及meter.angle兩個屬性的動態數據:
g3d.getNote=function(data){//重載getNote方法
return'Value:'+data.a('meter.value').toFixed(2);
};
g3d.getNote2=function(data){
varvalue=Math.round(data.a('meter.angle')/Math.PI*180);//獲取了meter.angle屬性,數據實時變化
returnvalue?'Angle:'+value:'Switchisoff';
};
我們還在場景的顯示部分使了一點小心機~通過改變實現eye和center的值來實現視線由遠及近的效果:
varoldEye=g3d.getEye().slice(0),
oldCenter=g3d.getCenter().slice(0),
newEye=[200,300,650],
newCenter=[0,params.rawS3[1]/2,0];
ht.Default.startAnim({//動畫
duration:1000,//持續時間
easing:function(t){//動畫緩動函數,默認採用ht.Default.animEasing
return(t*=2)<1?0.5*t*t:0.5*(1-(--t)*(t-2));
},
action:function(k){//action函數必須提供,實現動畫過程中的屬性變化參數k代表通過easing(t)函數運算後的值
g3d.setEye(
oldEye[0]+(newEye[0]-oldEye[0])*k,
oldEye[1]+(newEye[1]-oldEye[1])*k,
oldEye[2]+(newEye[2]-oldEye[2])*k
);
g3d.setCenter(
oldCenter[0]+(newCenter[0]-oldCenter[0])*k,
oldCenter[1]+(newCenter[1]-oldCenter[1])*k,
oldCenter[2]+(newCenter[2]-oldCenter[2])*k
);
}
});
整個左邊實現完成~接着該實現右上部分,屬性值的顯示以及控制,我們總共添加了四個屬性:名稱、meter.value、meter.angle以及旋轉rotation,通過數據綁定操作屬性欄中的值來改變3D模型中的顯示狀態,數據綁定我們通過獲取accessType以及name中的值來配合調用到這個屬性:
propertyView.addProperties([//用json的數組參數方式批量添加屬性信息
{
name:'name',//屬性名這裏不用設置accessType,因爲accessType默認的值爲setName/getName這種格式
editable:true//設置爲可編輯狀態
},
{
name:'meter.value',//用於存取name屬性,該屬性結合accessType屬性最終實現對Data屬性的存取
accessType:'attr',//通過getAttr/setAttr獲取或設置屬性值
editable:true,
slider:{
min:0,
max:4
}
},
{
name:'meter.angle',
accessType:'attr',
editable:true,
formatValue:function(value){//一般用於將數字轉換更易讀的文本格式
returnMath.round(value/Math.PI*180);
},
slider:{
min:0,
max:Math.PI,
step:Math.PI/180*5,//每移動一下滑動的步進
getToolTip:function(){//設置鼠標放在圖元上的文字提示
returnMath.round(this.getValue()/Math.PI*180);
}
}
},
{
name:'rotation',
editable:true,
formatValue:function(value){
returnMath.round(value/Math.PI*180);
},
slider:{
min:-Math.PI,
max:Math.PI,
step:Math.PI/180*5,
getToolTip:function(){
returnMath.round(this.getValue()/Math.PI*180);
}
}
}
]);
最後進行右下部分formPane表單面板的解析,formPane通過addRow函數向表單中添加行,這個表單中總共兩行,其中第一行有兩個部分:
formPane.addRow([//向表單組件中添加行
{
id:'export',
button:{//按鈕
label:'ExportJSON',
onClicked:function(){//點擊時觸發的函數
varjson=dataModel.serialize();
formPane.v('textArea',json);
}
}
},
{
button:{
label:'ImportJSON',
onClicked:function(){
dataModel.clear();//清空數據模型
dataModel.deserialize(formPane.v('textArea'));//將獲取到的textArea中的數據反序列化,是下面一行的id值
}
}
}
],
[0.1,0.1]);//最後的參數是這行的寬度分配比例小於1的值爲比例,大於1爲實際值
formPane.addRow([
{
id:'textArea',
textArea:{
}
}
],
[0.1],0.1);
最後這樣我們就可以根據修改屬性欄中或者JSON文件,直接看到3D中我們修改的效果啦了,想要學習HTML5開發技術的小夥伴在選擇HTML5培訓機構的時候一定要看該機構的HTML5學習路線圖,通過HTML5學習路線圖可以看出該機構的課程是否合理,是否值得報名學習。HTML5學習小編建議選擇扣丁學堂,扣丁學堂不僅有專業的老師和與時俱進的課程體系,還有大量的HTML5視頻教程供學員觀看學習,想要HTML5開發工程師的小夥伴快快行動吧。扣丁學堂H5技術交流羣:673883249。