<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name = "viewport" content = "width=device-width, initial-scale = 1.0">
<title>テスト</title>
<style>
#canvas {
    display: block;
    margin-bottom: 10px;
}
#increase, #decrease {
    width: 100px;
    height: 50px;
}
</style>
</head>

<body>
<canvas id="canvas"></canvas>
<div>
    <label for="position-x">position-x</label><input type="checkbox" id = "position-x">
    <label for="position-y">position-y</label><input type="checkbox" id = "position-y">
    <label for="position-z">position-z</label><input type="checkbox" id = "position-z">
</div>
<div>
    <label for="rotate-x">rotate-x</label><input type="checkbox" id = "rotate-x">
    <label for="rotate-y">rotate-y</label><input type="checkbox" id = "rotate-y">
    <label for="rotate-z">rotate-z</label><input type="checkbox" id = "rotate-z">
</div>
<button id = "increase">増加</button>
<button id = "decrease">減少</button>

<script type="module">
    import * as THREE from "https://cdn.jsdelivr.net/npm/three@0.167.0/build/three.module.js";

    // サイズを指定
    const width = 360;
    const height = 360;

    // レンダラー,シーン,カメラを作成
    const renderer = new THREE.WebGLRenderer({
        canvas: document.getElementById('canvas'),
    });
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(45, width / height);

    // 箱
    /** @type {THREE.Mesh} */
    let box;

    window.onload = () => {
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(width, height);
        camera.position.set(0, 0, 150);

        addEventListeners();
        addObjects();

        const INTERVAL = 1000 / 60;
        let nextUpdateTime = new Date().getTime() + INTERVAL;
        frameProc();

        function frameProc(){
            const curTime = new Date().getTime();
            if(nextUpdateTime < curTime){
                nextUpdateTime +=  INTERVAL;
                update();
            }
            requestAnimationFrame(() => frameProc());
        }
    }

    // 増加・減少のボタンが押下されているかどうか?
    let pressIncrease = false;
    let pressDecrease = false;

    function addEventListeners(){
        const $increase = document.getElementById('increase');
        const $decrease = document.getElementById('decrease');

        const arr1 = ['mousedown', 'touchstart'];
        const arr2 = ['mouseup', 'touchend'];
        for(let i=0; i<arr1.length; i++){
            $increase?.addEventListener(arr1[i], () => pressIncrease = true);
            $decrease?.addEventListener(arr1[i], () => pressDecrease = true);
        }
        for(let i=0; i<arr2.length; i++){
            $increase?.addEventListener(arr2[i], () => pressIncrease = false);
            $decrease?.addEventListener(arr2[i], () => pressDecrease = false);
        }

        // スマホでボタンを長時間タップしたときのデフォルトの動作を抑止する
        const arr3 = ['touchstart', 'touchend'];
        for(let i=0; i<arr3.length; i++){
            $increase?.addEventListener(arr3[i], (ev) => ev.preventDefault());
            $decrease?.addEventListener(arr3[i], (ev) => ev.preventDefault());
        }
    }

    function addObjects(){
        // 細長い直方体を追加する
        const geometry = new THREE.BoxGeometry(24, 24, 48);
        const material = new THREE.MeshNormalMaterial();
        box = new THREE.Mesh(geometry, material);
        scene.add(box);
    
        const lineX = createLine(1000, 0, 0, -1000, 0, 0, 0xff0000)
        scene.add(lineX);
    
        const lineY = createLine(0, 1000, 0, 0, -1000, 0, 0x00ff00)
        scene.add(lineY);
    }

    // 色がcolorの(x1, y1, z1)と(x2, y2, z2)を結ぶ直線を生成する
    function createLine(x1, y1, z1, x2, y2, z2, color){
        const lineMaterial = new THREE.LineBasicMaterial({ color: color });
        const lineGeometry = new THREE.BufferGeometry();
        const vertices = new Float32Array( [
            x1, y1,  z1,
            x2, y2,  z2,
        ] );
        lineGeometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
        return new THREE.Line(lineGeometry, lineMaterial);
    }

    const $positionX = document.getElementById('position-x');
    const $positionY = document.getElementById('position-y');
    const $positionZ = document.getElementById('position-z');

    const $rotateX = document.getElementById('rotate-x');
    const $rotateY = document.getElementById('rotate-y');
    const $rotateZ = document.getElementById('rotate-z');

    // 更新処理
    function update() {
        if(pressIncrease){
            if($positionX.checked)
                box.position.x += 0.4;
            if($positionY.checked)
                box.position.y += 0.4;
            if($positionZ.checked)
                box.position.z += 0.4;
            if($rotateX.checked)
                box.rotation.x += 0.02;
            if($rotateY.checked)
                box.rotation.y += 0.02;
            if($rotateZ.checked)
                box.rotation.z += 0.02;
        }
        if(pressDecrease){
            if($positionX.checked)
                box.position.x -= 0.4;
            if($positionY.checked)
                box.position.y -= 0.4;
            if($positionZ.checked)
                box.position.z -= 0.4;
            if($rotateX.checked)
                box.rotation.x -= 0.02;
            if($rotateY.checked)
                box.rotation.y -= 0.02;
            if($rotateZ.checked)
                box.rotation.z -= 0.02;
        }
        renderer.render(scene, camera);
    }
</script>
</body>
</html>