MapConductor React SDK Samples

Objeto Three.js (solo web) | MapLibre | MapConductor React SDK

Ejemplo de Objeto Three.js (solo web) de MapConductor React SDK con MapLibre.

Este ejemplo interactivo muestra Objeto Three.js (solo web) mediante la abstracción de MapConductor sobre MapLibre.

Ejemplo de código

import { useEffect, useMemo } from 'react';
import * as THREE from 'three';
import { createGeoPoint, createMapCameraPosition } from '@mapconductor/js-sdk-core';
import { useMapLoaded } from '@mapconductor/js-sdk-react';
import { MapLibreDesign, MapLibreMapView2D, useMapLibreViewState } from '@mapconductor/react-for-maplibre';


// (1) Crear el mapa


const initialCamera = createMapCameraPosition({
  position: createGeoPoint({ latitude: 35.6812, longitude: 139.7671 }),
  zoom: 12,
});


const mapViewState = useMapLibreViewState({
  mapDesignType: MapLibreDesign.OsmBrightJa,
  cameraPosition: initialCamera,
});


// (2) Preparar los datos y el estado de interacción
const position = useMemo(() => createGeoPoint({
  latitude: 35.6812,
  longitude: 139.7671,
}), []);


// (3) Renderizar el mapa y sus capas


function ThreeMapObject({ mapViewState, position }) {
  const isMapLoaded = useMapLoaded();


  useEffect(() => {
    if (!isMapLoaded) return;
    const holder = mapViewState.getMapViewHolder();
    if (!holder) return;


    const scene = new THREE.Scene();
    const camera = new THREE.OrthographicCamera(0, 1, 1, 0, 0.1, 1000);
    camera.position.z = 200;
    const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
    const width = holder.mapView.clientWidth;
    const height = holder.mapView.clientHeight;
    renderer.setSize(width, height);
    camera.right = width;
    camera.top = height;
    camera.updateProjectionMatrix();
    renderer.domElement.style.position = 'absolute';
    renderer.domElement.style.inset = '0';
    holder.mapView.appendChild(renderer.domElement);


    const object = new THREE.Mesh(
      new THREE.TorusKnotGeometry(13, 4),
      new THREE.MeshNormalMaterial(),
    );
    scene.add(object);


    let frame = 0;
    const draw = () => {
      const offset = holder.toScreenOffset(position);
      if (offset && !(offset instanceof Promise)) {
        object.position.set(offset.x, height - offset.y, 0);
      }
      object.rotation.y += 0.02;
      renderer.render(scene, camera);
      frame = requestAnimationFrame(draw);
    };
    draw();


    return () => {
      cancelAnimationFrame(frame);
      renderer.domElement.remove();
      renderer.dispose();
    };
  }, [isMapLoaded, mapViewState, position]);


  return null;
}


<MapLibreMapView2D state={mapViewState}>
  <ThreeMapObject mapViewState={mapViewState} position={position} />
</MapLibreMapView2D>

Cómo funciona el código

Superpone un lienzo transparente de Three.js sobre el mapa y ancla su objeto 3D con la proyección MapViewHolder.toScreenOffset(), independiente del proveedor.

useMapLoaded retiene el efecto hasta que el mapa existe, y luego getMapViewHolder() devuelve un holder cuyo lienzo WebGL se agrega sobre el mapa.

En cada fotograma holder.toScreenOffset(position) convierte la coordenada geográfica en un desplazamiento en píxeles, de modo que el objeto 3D permanece fijo mientras el mapa se mueve, con la misma llamada en cada proveedor.