在实际应用中,我觉得能够通过操作JSON文件来操作3D上的场景变化是非常方便的,尤其是在制作编辑器拖拽图片数据的时候可以很直观当图元发生一系列变化时,反映给我们。这里我们简单的做了一个基础的例子,供大家参考。本例地址:http://www.hightopo.com/guide...场景重现练习:首先我们来搭建本例的场景。熟悉的朋友可能已经看到了。这个场景分为左、右上、右下三个部分。HT可以很方便的通过ht.widget.SplitView进行场景拆分,实现良好的页面布局,最后将这个拆分组件添加到html的body中://场景构建dataModel=newht.DataModel();//dataContainerg3d=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文件中,在头部调用。从上面的动图可以看出,本例中model需要改变的部分只有下面的“指针”和“switch”,所以我们遍历得到两个obj模型的部分并注册3D模型:vararray=[];for(varnameinmodelMap){varmodel=modelMap[name];//模型数组inmodelMap.push(model);if(name==='pointer'){//obj文件中的一个模型命名为pointermodel.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文件中的模型名称为switchmodel.mat={func:function(data){returnht.Default.createMatrix([{t3:[0,48.5,0]},{r3:[0,0,数据。a('meter.angle')]},{t3:[0,-48.5,0]}]);}};model.color={func:function(data){if(data.a('meter.angle')){return'rgb(186,0,0)';}else{返回'黑色';}}};}}ht.Default.setShape3dModel('meter',array);//注册3D模型,请参考建模手册。第一个参数是模型名称,第二个参数是JSON类型对象。直接设置属性shape3d为这里注册的3D模型的名字,下面我们创建3个节点,将节点设置为这个3D模型:for(vari=0;i<3;i++){//创建3个A节点表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});节点。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){//ReSetgetNotemethodreturn'Value:'+data.a('meter.value').toFixed(2);};g3d.getNote2=function(data){varvalue=Math.round(data.a('meter.angle')/Math.PI*180);//获取仪表.angle属性,数据变化实时返回值?'角度:'+值:'开关关闭';};我们还用到了场景的显示部分注意~通过改变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({//animationduration:1000,//durationeasing:function(t){//动画缓动函数,默认ht.Default.animEasingreturn(t*=2)<1?0.5*t*t:0.5*(1-(--t)*(t-2));},action:function(k){//必须提供action函数,实现动画过程中属性变化参数k。参数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]-旧中心[2])*k);}});左边的整个实现就完成了~接下来是右上部分的实现,属性值的显示和控制,我们一共添加了name、meter.value、meter.angle和rotation旋转四个属性,通过数据绑定操作在属性bar值中改变3D模型中的显示状态,数据绑定我们通过获取accessType中的值和名称来调用这个属性:propertyView.addProperties([//使用json数组参数方法添加属性信息在batches{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.角度',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函数向表单添加行。这个表单有两行,第一行有两部分: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中看到我们修改的效果了~怎么样?快点不是很酷吗?
