JavaScript-X3DOM学习笔记(二)-对象的选取

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);
}

猜你喜欢

转载自blog.csdn.net/lee353086/article/details/79581361