JavaScript-X3DOM學習筆記(二)-物件的選取
阿新 • • 發佈:2018-11-19
Date: 2018-03-16
Author: kagula
演示如何選取物件,並移動選取的物件。
只有shape型別的物件才能被選取,這個例子有三個檔案組成,其中一個是html,另外兩個是js。
這裡是render效果
x3dom_translate.html
<html> <head> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta charset="utf-8"> <title>測試X3DOM 指定物件的平移</title> <!-- Demo內容 [1]指定物件的平移。 [2]對場景中非當前物件的操作。 2018-3-14 by kagula --> <!-- x3dom用的是1.7.2dev --> <script type="text/javascript" src="/x3dom/x3dom.1.7.3dev-full.debug.js"></script> <!-- d3用的是4.13.0 --> <script type="text/javascript" src='/d3/d3.min.js'></script> <script type="text/javascript" src='/kagula/coordinator.js'></script> <script type="text/javascript" src='/kagula/gizmo.js'></script> <link rel="stylesheet" type="text/css" href="/x3dom/x3dom.css"> </head> <body> <x3d style="width:100%;height:800px" showLog="false" id="x3d" needLineWidth="true"> <scene> <transform translation='0 0 0' id="myBox" onclick="pickObject(event)"> <shape id="myBox"> <appearance> <material diffuseColor='1 0 0'></material> </appearance> <box size="1 2 3"></box> </shape> </transform> <transform translation='-3 0 0' id="myCone" onclick="pickObject(event)"> <shape> <appearance> <material diffuseColor='0 1 0'></material> </appearance> <cone></cone> </shape> </transform> <transform translation='3 0 0' id="mySphere" onclick="pickObject(event)"> <shape> <appearance> <material diffuseColor='0 0 1'></material> </appearance> <sphere></sphere> </shape> </transform> </scene> </x3d> </body> </html> <script type="text/javascript"> x3dom.runtime.ready = function () { console.log("About to render something the first time"); //切換到wireframe模式, 其它類似呼叫參考https://www.x3dom.org/download/1.5/docs/singlehtml/ //var e = document.getElementById('x3d'); //e.runtime.togglePoints(true); //e.runtime.togglePoints(true); } drawAxis(); function pickObject(event) { //d3.selectAll("shape").attr("render", "false");//hide所有shape型別的物件。 var pickObj = event.hitObject.parentNode; //pickObj.render = "false";//隱藏當前shape物件,注意,只有shape物件才會被pick. console.log("pickObject => " + pickObj.id); setGizmo(pickObj); } </script>
coordinator.js
//Horizontal axis function drawAxisX(selectorRoot, countOfTick, lengthOfTick, heightOfTick) { var axisLength = countOfTick * lengthOfTick; //draw axis var linesetX = d3.select(selectorRoot).append("group").attr("id", "groupAxisX") .append("shape") .append("lineset").attr("vertexcount", "2"); linesetX.append("coordinate").attr("point", d => "0 0 0, " + axisLength + " 0 0"); linesetX.append("color").attr("color", "1 0 0, 1 0 0"); //draw tick //第一個shape是axis,後面countOfTick個才是真正的刻度。 let ticks = d3.range(countOfTick + 1).map(function (i) { return i; //i=[0,1,...,countOfTick] }) d3.select("#groupAxisX").selectAll("lineset").data(ticks) .enter().append("shape").append("lineset").attr("vertexcount", "2") .append("coordinate").attr("point", d => d * lengthOfTick + " 0 0, " + d * lengthOfTick + " " + heightOfTick + " 0"); //因為第一個是axis,d的第一個元素被跳過,所以d=[1,2,..] //draw text d3.select("#groupAxisX").selectAll(".label").data(ticks) .enter().append("transform").classed("label", "true").attr("translation", d => (d * lengthOfTick + 0.6) + " " + (heightOfTick - 0.5) + " 0") .append("billboard") .append("shape").classed("shapeAxisX", "true") .append("text").attr("string", d => d).attr("solid", "false")//正反兩面可見 .append("fontstyle").attr("family", "yahei").attr("size", "1.2"); //返回#groupAxisX子節點下面的子節點下面class為shapeAxisX的所有節點 d3.select("#groupAxisX").selectAll(".shapeAxisX") .append("appearance")//新增appearance子節點 .append("material").attr("diffuseColor", "0 0 0"); //draw arrow d3.select("#groupAxisX").append("transform").attr("translation", (axisLength + 0.25) + " 0 0").attr("rotation", "0 0 1 " + (-3.14159) / 2) .append("shape").attr("id", "xAxisArrow").append("cone").attr("height", "0.5").attr("bottomRadius", "0.1").attr("lit", "true"); d3.select("#xAxisArrow").append("appearance").append("material").attr("diffuseColor", '1 0 0'); } //Vertical axis function drawAxisY(selectorRoot, countOfTick, lengthOfTick, heightOfTick) { var axisLength = countOfTick * lengthOfTick; //draw axis var linesetY = d3.select(selectorRoot).append("group").attr("id", "groupAxisY") .append("shape") .append("lineset").attr("vertexcount", "2"); linesetY.append("coordinate").attr("point", d => "0 0 0, 0 " + axisLength + " 0"); linesetY.append("color").attr("color", "0 1 0, 0 1 0"); //draw tick //第一個shape是axis,後面countOfTick個才是真正的刻度。 let ticks = d3.range(countOfTick + 1).map(function (i) { return i + 1; //i=[0,1,...,countOfTick] }) d3.select("#groupAxisY").selectAll("lineset").data(ticks) .enter().append("shape").append("lineset").attr("vertexcount", "2") .append("coordinate").attr("point", d => "0 " + ((d - 1) * lengthOfTick) + " 0, " + heightOfTick + " " + (d - 1) * lengthOfTick + " 0"); //因為第一個是axis,d的第一個元素被跳過,所以d=[1,2,..] //draw text ticks.splice(ticks.length - 1, 1); d3.select("#groupAxisY").selectAll(".label").data(ticks) .enter().append("transform").classed("label", "true").attr("translation", d => (0.8) + " " + (d * lengthOfTick + 1) + " 0") .append("billboard") .append("shape").classed("shapeAxisY", "true") .append("text").attr("string", d => d).attr("solid", "false")//正反兩面可見 .append("fontstyle").attr("family", "yahei").attr("size", "1.2"); //返回#groupAxisY子節點下面的子節點下面class為shapeAxisY的所有節點 d3.select("#groupAxisY").selectAll(".shapeAxisY") .append("appearance")//新增appearance子節點 .append("material").attr("diffuseColor", "0 0 0"); //draw arrow d3.select("#groupAxisY").append("transform").attr("translation", "0 " + (axisLength + 0.25) + " 0") .append("shape").attr("id", "yAxisArrow").append("cone").attr("height", "0.5").attr("bottomRadius", "0.1").attr("lit", "true"); d3.select("#yAxisArrow").append("appearance").append("material").attr("diffuseColor", '0 1 0'); } //Depth axis function drawAxisZ(selectorRoot, countOfTick, lengthOfTick, heightOfTick) { var axisLength = countOfTick * lengthOfTick; //draw axis var linesetY = d3.select(selectorRoot).append("group").attr("id", "groupAxisZ") .append("shape") .append("lineset").attr("vertexcount", "2"); linesetY.append("coordinate").attr("point", d => "0 0 0, 0 0 " + axisLength); linesetY.append("color").attr("color", "0 0 1, 0 0 1"); //draw tick //第一個shape是axis,後面countOfTick個才是真正的刻度。 let ticks = d3.range(countOfTick + 1).map(function (i) { return i + 1; //i=[0,1,...,countOfTick] }) d3.select("#groupAxisZ").selectAll("lineset").data(ticks) .enter().append("shape").append("lineset").attr("vertexcount", "2") .append("coordinate").attr("point", d => "0 0 " + ((d - 1) * lengthOfTick) + ", " + heightOfTick + " 0 " + (d - 1) * lengthOfTick); //因為第一個是axis,d的第一個元素被跳過,所以d=[1,2,..] //draw text ticks.splice(ticks.length - 1, 1); d3.select("#groupAxisZ").selectAll(".label").data(ticks) .enter().append("transform").classed("label", "true").attr("translation", d => (0.8) + " 1.0 " + (d * lengthOfTick + 1)) .append("billboard") .append("shape").classed("shapeAxisZ", "true") .append("text").attr("string", d => d).attr("solid", "false") .append("fontstyle").attr("family", "yahei").attr("size", "1.2"); //返回#groupAxisY子節點下面的子節點下面class為shapeAxisY的所有節點 d3.select("#groupAxisZ").selectAll(".shapeAxisZ") .append("appearance")//新增appearance子節點 .append("material").attr("diffuseColor", "0 0 0"); //draw arrow d3.select("#groupAxisZ").append("transform").attr("translation", "0 0 " + (axisLength + 0.25)).attr("rotation", "1 0 0 " + (3.14159) / 2) .append("shape").attr("id", "zAxisArrow").append("cone").attr("height", "0.5").attr("bottomRadius", "0.1").attr("lit", "true"); d3.select("#zAxisArrow").append("appearance").append("material").attr("diffuseColor", '0 0 1'); } function drawAxis() { const selectorRoot = "scene"; const countOfTick = 5; const lengthOfTick = 10; const heightOfTick = 2; drawAxisX(selectorRoot, countOfTick, lengthOfTick, heightOfTick); drawAxisY(selectorRoot, countOfTick, lengthOfTick, heightOfTick); drawAxisZ(selectorRoot, countOfTick, lengthOfTick, heightOfTick); }
gizmo.js
//function onMouseMove_detect_lineset(event) { // var x3dElement = document.getElementById("x3d"); // var viewArea = x3dElement.runtime.canvas.doc._viewarea; // var line = viewArea.calcViewRay(event.mouse_drag_x, event.mouse_drag_y); //} function resetSensor() { d3.select("#planeSensorX").remove(); d3.select("#planeSensorY").remove(); d3.select("#planeSensorZ").remove(); parent_translation = document.getElementById(gizmo_root_id).getFieldValue("translation");//因為Demo只有一級parent,下次得用遞迴代替。 } //Highlight the axis when mouse pointer hover a axis. function onMouseOverGizmoX(event) { //console.log("event.id = " + event.id); d3.select("#xGizmoAxis_material").attr("diffuseColor", "1 1 0"); //if (document.getElementById("planeSensorX") == null) //{ resetSensor(); d3.select("#groupGizmoX").append("planeSensor") .attr("id", "planeSensorX") .attr("axisRotation", "1 0 0 -1.57") .attr("autoOffset", "false") .attr("minPosition", "-600 0") .attr("maxPosition", "600 0") .attr("onoutputchange", "processTranslationGizmoEvent(event)"); //} } function onMouseOutGizmoX(event) { //console.log("event.id = " + event.id); d3.select("#xGizmoAxis_material").attr("diffuseColor", "1 0 0"); } function onMouseOverGizmoY(event) { d3.select("#yGizmoAxis_material").attr("diffuseColor", "1 1 0"); //if (document.getElementById("planeSensorY") == null) { resetSensor(); d3.select("#groupGizmoY").append("planeSensor") .attr("id", "planeSensorY") .attr("axisRotation", "0 1 0 -1.57") .attr("autoOffset", "false") .attr("minPosition", "0 -600 ") .attr("maxPosition", "0 600 ") .attr("onoutputchange", "processTranslationGizmoEvent(event)"); //} } function onMouseOutGizmoY(event) { d3.select("#yGizmoAxis_material").attr("diffuseColor", "0 1 0"); } function onMouseOverGizmoZ(event) { d3.select("#zGizmoAxis_material").attr("diffuseColor", "1 1 0"); resetSensor(); d3.select("#groupGizmoZ").append("planeSensor") .attr("id", "planeSensorZ") .attr("axisRotation", "0 1 0 -1.57")// .attr("autoOffset", "false") .attr("minPosition", "-600 0") .attr("maxPosition", "600 0") .attr("onoutputchange", "processTranslationGizmoEvent(event)"); } function onMouseOutGizmoZ(event) { d3.select("#zGizmoAxis_material").attr("diffuseColor", "0 0 1"); } var gizmo_root; var gizmo_root_id; var parent_translation = new x3dom.fields.SFVec3f(0, 0, 0);//記住translation前的世界座標 function processTranslationGizmoEvent(event) { var sensorToWorldMatrix, translationValue; if (event.fieldName === 'translation_changed') { //convert the sensor's output from sensor coordinates to world coordinates (i.e., include its 'axisRotation') sensorToWorldMatrix = x3dom.fields.SFMatrix4f.parseRotation(event.target.getAttribute("axisRotation")); //這個相對值,不是相對於上次的,而是相對於Gizmo重建後的第一次的"相對值"! translationValue = sensorToWorldMatrix.multMatrixVec(event.value); //console.log("translationValue=" + translationValue); //console.log("=" + document.getElementById(gizmo_root_id).getAttribute("translation"));//只能拿到物件初始設定的translation屬性,而不是已經修改過的translation屬性。 //console.log("2=" + gizmo_root.translation);//只能拿到物件初始設定的translation屬性,而不是已經修改過的translation屬性。 //返回兩個向量的加法運算 translationValue = translationValue.add(x3dom.fields.SFVec3f.parse(parent_translation)); //transform the affected sensor geometry document.getElementById(gizmo_root_id).setFieldValue('translation', translationValue); //console.log("3=" + document.getElementById(gizmo_root_id).getFieldValue("translation"));//只有這行能拿到當前值 console.log("10 event.fieldName=" + event.fieldName + ", event.value=" + event.value + ", event.target.id=" + event.target.id + ", translationValue=" + translationValue + ", x_translation=" + x_translation + ", y_translation=" + y_translation); } } //Horizontal axis function drawGizmoX(selectorRoot, lengthOfLine) { //draw axis var linesetX = selectorRoot.append("group").attr("id", "groupGizmoX") .append("transform").attr("rotation", "0 0 1 " + (3.14159) / 2).attr("translation", lengthOfLine/2 + " 0 0") .append("shape").attr("onMouseOver", "onMouseOverGizmoX(this)").attr("onMouseOut", "onMouseOutGizmoX(this)").attr("id", "xGizmoAxis") .append("cylinder").attr("radius", "0.08").attr("height", lengthOfLine); d3.select("#xGizmoAxis").append("appearance").append("material").attr("diffuseColor", '1 0 0').attr("id", 'xGizmoAxis_material'); //draw arrow d3.select("#groupGizmoX").append("transform").attr("translation", (lengthOfLine + 0.25) + " 0 0").attr("rotation", "0 0 1 " + (-3.14159) / 2) .append("shape").attr("onMouseOver", "onMouseOverGizmoX(this)").attr("onMouseOut", "onMouseOutGizmoX(this)").attr("id", "xGizmoArrow").append("cone").attr("height", "0.5").attr("bottomRadius", "0.1").attr("lit", "true"); d3.select("#xGizmoArrow").append("appearance").append("material").attr("diffuseColor", '1 0 0'); //add sensor //d3.select("#groupGizmoX").append("planeSensor") // .attr("id", "planeSensorX") // .attr("axisRotation", "1 0 0 -1.57") // .attr("autoOffset", "false") // .attr("minPosition", "-600 0") // .attr("maxPosition", "600 0") // .attr("onoutputchange", "processTranslationGizmoEvent(event)"); } //Vertical axis function drawGizmoY(selectorRoot, lengthOfLine) { //draw axis var lineset = selectorRoot.append("group").attr("id", "groupGizmoY") .append("transform").attr("translation", "0 " + lengthOfLine / 2 + " 0") .append("shape").attr("onMouseOver", "onMouseOverGizmoY(this)").attr("onMouseOut", "onMouseOutGizmoY(this)").attr("id", "yGizmoAxis") .append("cylinder").attr("radius", "0.08").attr("height", lengthOfLine); d3.select("#yGizmoAxis").append("appearance").append("material").attr("diffuseColor", '0 1 0').attr("id", 'yGizmoAxis_material'); //draw arrow d3.select("#groupGizmoY").append("transform").attr("translation", "0 " + (lengthOfLine + 0.25) + " 0") .append("shape").attr("onMouseOver", "onMouseOverGizmoY(this)").attr("onMouseOut", "onMouseOutGizmoY(this)").attr("id", "yGizmoArrow").append("cone").attr("height", "0.5").attr("bottomRadius", "0.1").attr("lit", "true"); d3.select("#yGizmoArrow").append("appearance").append("material").attr("diffuseColor", '0 1 0'); //add sensor //d3.select("#groupGizmoY").append("planeSensor") // .attr("id", "planeSensorY") // .attr("axisRotation", "0 1 0 -1.57") // .attr("autoOffset", "false") // .attr("minPosition", "0 -600 ") // .attr("maxPosition", "0 600 ") // .attr("onoutputchange", "processTranslationGizmoEvent(event)"); } //Depth axis function drawGizmoZ(selectorRoot, lengthOfLine) { //draw axis var lineset = selectorRoot.append("group").attr("id", "groupGizmoZ") .append("transform").attr("rotation", "1 0 0 " + (3.14159) / 2).attr("translation", "0 0 " + lengthOfLine / 2) .append("shape").attr("onMouseOver", "onMouseOverGizmoZ(this)").attr("onMouseOut", "onMouseOutGizmoZ(this)").attr("id", "zGizmoAxis") .append("cylinder").attr("radius", "0.08").attr("height", lengthOfLine); d3.select("#zGizmoAxis").append("appearance").append("material").attr("diffuseColor", '0 0 1').attr("id", 'zGizmoAxis_material'); //draw arrow d3.select("#groupGizmoZ").append("transform").attr("translation", "0 0 " + (lengthOfLine + 0.25)).attr("rotation", "1 0 0 " + (3.14159) / 2) .append("shape").attr("onMouseOver", "onMouseOverGizmoZ(this)").attr("onMouseOut", "onMouseOutGizmoZ(this)").attr("id", "zGizmoArrow").append("cone").attr("height", "0.5").attr("bottomRadius", "0.1").attr("lit", "true"); d3.select("#zGizmoArrow").append("appearance").append("material").attr("diffuseColor", '0 0 1'); } function setGizmo(selectorRoot) { d3.select("#gizmo").remove(); gizmo_root = selectorRoot; gizmo_root_id = selectorRoot.id; const lengthOfLine = 5; resetSensor(); var gizmoRoot = d3.select(selectorRoot).append("transform").attr("id","gizmo"); drawGizmoX(gizmoRoot, lengthOfLine); drawGizmoY(gizmoRoot, lengthOfLine); drawGizmoZ(gizmoRoot, lengthOfLine); }