改变鼠标位置

时间:2016-08-18 14:10:39

标签: javascript graphics three.js

我正在用鼠标绘制一个盒子,我正在使用raycast来获取鼠标在场景中的位置。因此当mouseDown事件触发时,我采取起点,当mouseMove发生时,我采取结束点,然后我在两点之间绘制一个框。 我开始在空白页面上尝试绘图,当一切都很好时,我将绘图代码移动到包含许多组件的主页面,当然还有绘图画布的容器。 将我的代码移动到主页面后,鼠标位置出现问题。框位置移动了x和y上画布容器的距离。

下图说明了问题:

Simplified case of the problem

红色标记显示我按下鼠标开始绘制框的位置,蓝色标记显示我停止鼠标的位置,此处的shiffting在Y轴上,因为我在页面顶部有两行组件。

这是一个简化的代码:

<body>

<div>
    <button class="btn btn-info" onclick="rotate_x()"><b>X</b></button>
    <button class="btn btn-info" onclick="rotate_y()"><b>Y</b></button>
    <button class="btn btn-info" onclick="rotate_z()"><b>Z</b></button>
    <button class="btn btn-info" onclick="reset_rotation()"><b>Reset</b></button>
    <input type="checkbox" name="selection" onchange="selection_mode_change()" checked><b>Selection mode</b>
</div>


<div>
    <button class="btn btn-info" onclick="rotate_x()"><b>X</b></button>
    <button class="btn btn-info" onclick="rotate_y()"><b>Y</b></button>
    <button class="btn btn-info" onclick="rotate_z()"><b>Z</b></button>
    <button class="btn btn-info" onclick="reset_rotation()"><b>Reset</b></button>
    <input type="checkbox" name="selection" onchange="selection_mode_change()" checked><b>Selection mode</b>
</div>
<script>

    var container;
    var camera, scene, renderer, dirLight;
    var raycaster;
    var mouse;
    var is_mouse_down = false;
    var area;
    var start, end;
    var objects = [];

    init();
    animate();

    function init() {

        container = document.createElement('div');
        document.body.appendChild(container);

        camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000000);
        camera.position.set(0, 0, 1000);

        scene = new THREE.Scene();           


        // Box
        var area_geometry = new THREE.BoxGeometry(1, 1, 1);
        area = new THREE.Mesh(area_geometry, new THREE.MeshBasicMaterial({
            color: 0x00ff00,
            opacity: 0.2,
            visible: true
        }));
        area.position.x = 0;
        area.position.y = 0;
        area.position.z = 0;
        area.scale.x = 1;
        area.scale.y = 1;
        area.scale.z = 1;

        scene.add(area);

        // plane for the raycast intersection

        var geometry = new THREE.BoxGeometry(100, 100, 100);
        var object = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
            color: Math.random() * 0xffffff,
            opacity: 0.1,
            visible: false
        }));
        object.position.x = 0;
        object.position.y = 0;
        object.position.z = -1000;
        object.scale.x = 100;
        object.scale.y = 100;
        object.scale.z = 1;
        scene.add(object);
        objects.push(object);



        raycaster = new THREE.Raycaster();
        mouse = new THREE.Vector2();


        // Light
        dirLight = new THREE.DirectionalLight(0xffffff, 1);
        dirLight.position.set(camera.position.x, camera.position.y, camera.position.z);
        scene.add(dirLight);

        renderer = new THREE.CanvasRenderer();
        renderer.setClearColor(0xffffff);
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        container.appendChild(renderer.domElement);

        document.addEventListener('mousedown', onDocumentMouseDown, false);
        document.addEventListener('mouseup', onDocumentMouseUp, false);
        document.addEventListener('mousemove', onDocumentMouseMove, false);
        document.addEventListener('touchstart', onDocumentTouchStart, false);

        window.addEventListener('resize', onWindowResize, false);

    }

    function onWindowResize() {

        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();

        renderer.setSize(window.innerWidth, window.innerHeight);

    }

    function onDocumentTouchStart(event) {

        event.preventDefault();

        event.clientX = event.touches[0].clientX;
        event.clientY = event.touches[0].clientY;
        onDocumentMouseDown(event);

    }

    function onDocumentMouseDown(event) {

        event.preventDefault();
        start = get_intersection_point(event);
        is_mouse_down = true;
    }

    function onDocumentMouseUp(event) {

        event.preventDefault();
        is_mouse_down = false;
    }

    function onDocumentMouseMove(event) {

        if (is_mouse_down) {

            end = intersection(event);
            update_selection_area_view(start, end);
        }
    }

    function animate() {

        requestAnimationFrame(animate);

        render();
    }

    function render() {

        camera.lookAt(scene.position);

        renderer.render(scene, camera);

    }

    function get_intersection_point(event) {
        mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
        mouse.y = -( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;

        raycaster.setFromCamera(mouse, camera);

        var intersects = raycaster.intersectObjects(objects);

        if (intersects.length > 0) {

            return intersects[0].point;

        }
        return null;
    }


    function update_selection_area_view(start, end) {

        width = Math.abs(start.x - end.x);
        height = Math.abs(start.y - end.y);

        center = new THREE.Vector3(-(start.x + end.x) / 2, -(start.y + end.y) / 2, (start.z + end.z) / 2);

        area.position.x = center.x;
        area.position.y = center.y;
        area.position.z = center.z;
        area.scale.x = width;
        area.scale.y = height;
        area.scale.z = 1;
    }

</script>

</body>

我不知道为什么会这样,以及如何解决这个问题。

谢谢

1 个答案:

答案 0 :(得分:1)

如果仔细观察图片,您会注意到点击次数偏移Y值(就屏幕像素而言)。如果你看得更近,看起来移位与标题相同(XYZ /选择模式标题)。这是因为您创建了一个div,并将其大小设置为innerWidth / innerHeight。它会创建一个具有指定大小的div,但会降低。所以如果你没有那个标题你的鼠标点击是正确的(因为threejs在屏幕上以40px注册它们,它会将它转换为div上的40px)

如何修复: 当我遇到这个问题时,我使用JQuery来获得TOP并且只是将偏移量添加到我的raycaster鼠标点击,在你的情况下,我认为你可以得到renderer.domElement.top(我不太确定,console.log(渲染器) .domElement以查看是否存在顶部位置值)并将其减去鼠标Y(减去因为您想要将矩形向上移动)