Three.jsを使用して3Dの地球儀をヌルヌル回して緯度経度を表示する🌏

共有

Three.jsを使用して3Dグローブと位置ポインタを作成

Three.jsは、ウェブ上で3Dグラフィックスを扱うための強力なJavaScriptライブラリです。この記事では、Three.jsを使用して3Dグローブを作成し、位置ポインタを追加する方法を解説します。

プロジェクトのセットアップ

プロジェクトを開始するには、Three.jsのライブラリをHTMLファイルに組み込みます。以下のコードを使用して、Three.jsとOrbitControlsを読み込みます。

<script src="https://cdn.skypack.dev/three@0.133.1/build/three.module"></script>
<script src="https://cdn.skypack.dev/three@0.133.1/examples/jsm/controls/OrbitControls"></script>

プロジェクトのセットアップに関連する主要な要素は次のとおりです。

  1. グローブの表示領域を指定します。
const containerEl = document.querySelector(".globe-wrapper");
const canvas3D = containerEl.querySelector("#globe-3d");
const canvas2D = containerEl.querySelector("#globe-2d-overlay");
const popupEl = containerEl.querySelector(".globe-popup");
  1. Three.jsの必要なコンポーネントを初期化します。
let renderer, scene, camera, rayCaster, controls, group;
let overlayCtx = canvas2D.getContext("2d");
let coordinates2D = [0, 0];
let pointerPos;
let clock, mouse, pointer, globe, globeMesh;
let popupVisible;
let earthTexture, mapMaterial;
let popupOpenTl, popupCloseTl;
let dragged = false;
  1. シーンの初期化とOrbitControlsの設定を行います。
function initScene() {
    renderer = new THREE.WebGLRenderer({ canvas: canvas3D, alpha: true });
    // その他の初期化コード

    createOrbitControls();

    // その他の初期化コード
}
  1. グローブの作成とマテリアルの設定を行います。
function createGlobe() {
    // グローブのジオメトリとマテリアルを初期化
    // マテリアルにはシェーダーコードも含まれています
}
  1. ポインターを作成します。
function createPointer() {
    // ポインターのジオメトリとマテリアルを初期化
}
  1. マウスイベントをリッスンしてポインターの位置を更新します。
function addCanvasEvents() {
    containerEl.addEventListener("mousemove", (e) => {
        updateMousePosition(e.clientX, e.clientY);
    });

    containerEl.addEventListener("click", (e) => {
        // マウスクリック時の処理
    });
}
  1. レンダリングループを設定します。
function render() {
    // グローブやポインターの状態を更新し、レンダリングを行います
    requestAnimationFrame(render);
}
  1. ウィンドウのリサイズに対応します。
function updateSize() {
    // ウィンドウのリサイズに応じて表示領域のサイズを更新
}

ポップアップの表示

ポインターがグローブ上の位置を示すと、ポップアップが表示されます。このポップアップには、選択した地点の緯度と経度が表示されます。また、ポップアップの表示および非表示のアニメーションも設定されています。

ポップアップの表示や非表示アニメーションは、GreenSock Animation Platform(GSAP)を使用して制御されています。GSAPを使用することで、アニメーションを滑らかに制御できます。

ポップアップの内容

ポップアップの内容は、ポインターの位置を緯度と経度に変換して表示します。以下の関数がこれを行います。

function cartesianToLatLong() {
    // ポインターの位置を緯度と経度に変換して表示
}

ポップアップの表示と非表示

ポップアップの表示と非表示は、GSAPを使用して制御されています。ポップアップの表示時には、ポップアップが上昇するアニメーションがあります。

function showPopupAnimation(lifted) {
    if (lifted) {
        // ポップアップを持ち上げるアニメーション
    }
    popupCloseTl.pause(0);
    popupOpenTl.play(0);
}

オーバーレイ(ポインターとポップアップをつなぐ線)

ポインターとポップアップをつなぐオーバーレイの線は、HTML5のCanvas要素を使用して描画されています。この線を描画する関数は以下のとおりです。

function drawPopupConnector(startX, startY, midX, midY, endX, endY) {
    // オーバーレイに線を描画
}

これにより、Three.jsとGSAPを使用して、魅力的な3Dグローブとポインターを作成し、ポップアップを表示および非表示にするウェブページが構築されます。三次元空間で位置情報を視覚化するには、Three.jsは非常に強力なツールです。

グローブの表示

このプロジェクトでは、Three.jsを使用して3Dグローブを作成しています。グローブは地球の表面を表現し、マウスポインターを地球の上に移動させて特定の場所をクリックすることができます。このコードでは、IcosahedronGeometryを使用して球体を作成し、シェーダーマテリアルを適用して地球のマップを表示します。

function createGlobe() {
    const globeGeometry = new THREE.IcosahedronGeometry(1, 22);
    mapMaterial = new THREE.ShaderMaterial({
        vertexShader: document.getElementById("vertex-shader-map").textContent,
        fragmentShader: document.getElementById("fragment-shader-map").textContent,
        uniforms: {
            u_map_tex: { type: "t", value: earthTexture },
            u_dot_size: { type: "f", value: 0 },
            u_pointer: { type: "v3", value: new THREE.Vector3(.0, .0, 1.) },
            u_time_since_click: { value: 0 },
        },
        alphaTest: false,
        transparent: true
    });

    globe = new THREE.Points(globeGeometry, mapMaterial);
    scene.add(globe);

    globeMesh = new THREE.Mesh(globeGeometry, new THREE.MeshBasicMaterial({
        color: 0x222222,
        transparent: true,
        opacity: .05
    }));
    scene.add(globeMesh);
}

グローブの表示にはシェーダーマテリアルが使用されており、このマテリアルは地球のテクスチャマップを読み込んで描画します。

マウスイベントのリスナー

このプロジェクトでは、マウスイベントをリッスンして、ポインターが地球上の特定の場所をクリックしたときに情報を表示します。マウスの移動やクリックのイベントは以下のコードでリッスンされます。

function addCanvasEvents() {
    containerEl.addEventListener("mousemove", (e) => {
        updateMousePosition(e.clientX, e.clientY);
    });

    containerEl.addEventListener("click", (e) => {
        if (!dragged) {
            updateMousePosition(
                e.targetTouches ? e.targetTouches[0].pageX : e.clientX,
                e.targetTouches ? e.targetTouches[0].pageY : e.clientY,
            );

            const res = checkIntersects();
            if (res.length) {
                pointerPos = res[0].face.normal.clone();
                pointer.position.set(res[0].face.normal.x, res[0].face.normal.y, res[0].face.normal.z);
                mapMaterial.uniforms.u_pointer.value = res[0].face.normal;
                popupEl.innerHTML = cartesianToLatLong();
                showPopupAnimation(true);
                clock.start()
            }
        }
    });
}

マウスの位置情報を更新し、ポインターが特定の場所をクリックしたときには3D空間上の位置情報も更新されます。

レンダリング

Three.jsを使用して3Dシーンをレンダリングするためには、レンダリングループが必要です。このループはブラウザのフレームごとに3Dシーンを描画し続けます。

function render() {
    mapMaterial.uniforms.u_time_since_click.value = clock.getElapsedTime();
    checkIntersects();
    if (pointer) {
        updateOverlayGraphic();
    }
    controls.update();
    renderer.render(scene, camera);
    requestAnimationFrame(render);
}

このコードはThree.jsを使用して3Dグローブと位置ポインタを作成し、ユーザーが地球上の特定の場所をクリックするとポップアップが表示されるウェブアプリケーションの基本的なセットアップと動作の概要を提供しています。 Three.jsを活用して、3Dグラフィックスをブラウザ上で簡単に実装できます。

共有

🌐公式サイト