Vue3+Three JS高德地图自定义经纬度实现围栏

 Vue3实现代码

index.html需要引入three.js

    <script src="https://cdn.jsdelivr.net/npm/three@0.142/build/three.js"></script>

 围栏组件

<template>
  <div id="mapContainer" ref="mapContainer"></div>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import AMapLoader from '@amap/amap-jsapi-loader'
const AMAP_KEY = ''
const mapContainer = ref(null)
onMounted(() => {
  AMapLoader.load({
    key: AMAP_KEY,
    version: '2.0',
    plugins: ['AMap.GeometryUtil', "AMap.Object3DLayer", "AMap.Object3D"]
  })
    .then((AMap) => {
      const map = new AMap.Map(mapContainer.value, {
        center: [116.397428, 39.90923],
        zooms: [2, 20],
        zoom: 14,
        viewMode: '3D',
        pitch: 50,
      })
      var THREE = window.THREE;
      var camera;
      var renderer;
      var scene;
      var customCoords = map.customCoords;
      console.log(THREE);
      const fenceCoords = [
        [116.397428, 39.90923],
        [116.407428, 39.90923],
        [116.407428, 39.91923],
        [116.397428, 39.91923]
      ];
      var gllayer = new AMap.GLCustomLayer({
        zIndex: 10,
        init: (gl) => {
          camera = new THREE.PerspectiveCamera(
            60,
            window.innerWidth / window.innerHeight,
            100,
            1 << 30
          );

          renderer = new THREE.WebGLRenderer({
            context: gl, // 地图的 gl 上下文
            antialias: true,
          });

          renderer.autoClear = false;
          scene = new THREE.Scene();

          var aLight = new THREE.AmbientLight(0xffffff, 0.5);
          var dLight = new THREE.DirectionalLight(0xffffff, 1);
          dLight.position.set(1000, -100, 900);
          scene.add(dLight);
          scene.add(aLight);
        },
        render: () => {
          renderer.resetState();
          customCoords.setCenter([116.52, 39.79]);
          var { near, far, fov, up, lookAt, position } =
            customCoords.getCameraParams();
          camera.near = near;
          camera.far = far;
          camera.fov = fov;
          camera.position.set(...position);
          camera.up.set(...up);
          camera.lookAt(...lookAt);
          camera.updateProjectionMatrix();
          renderer.render(scene, camera);
          renderer.resetState();
        },
      });
      map.add(gllayer);

      // 添加地图加载完成监听
      map.on('complete', function () {
        // 在此处初始化围栏
        const { planeMesh, lineMesh } = createFence();
        scene.add(planeMesh, lineMesh);
        const testCoord = map.customCoords.lngLatToCoord([116.397428, 39.90923]);
        console.log('验证坐标转换:', testCoord); // 应输出非零值
      });

      // 围栏创建方法
      function createFence() {
        const shape = new THREE.Shape();
        const linePoints = [];
        fenceCoords.forEach(([lng, lat], index) => {
          // 添加转换验证
          if (!map.customCoords) {
            console.error('CustomCoords未初始化');
            return;
          }

          let coords = map.customCoords.lngLatToCoord([lng, lat]);
          console.log(`坐标转换结果:${coords}`); // 添加调试日志
          let coord = {
            x: coords[0],
            y: coords[1],
          }
          if (index === 0) {
            shape.moveTo(coord.x, coord.y);
            linePoints.push(new THREE.Vector3(coord.x, coord.y, 50));
          } else {
            shape.lineTo(coord.x, coord.y);
            linePoints.push(new THREE.Vector3(coord.x, coord.y, 50));
          }
        });
        linePoints.push(linePoints[0].clone());

        return {
          planeMesh: createPlaneMesh(shape),
          lineMesh: createLineMesh(linePoints)
        };
      }
      // 创建渐变几何体
      function createPlaneMesh(shape) {
        // 创建侧面材质(红色渐变)
        const sideMaterial = new THREE.MeshBasicMaterial({
          map: createGradientTexture(), // 使用渐变纹理
          transparent: true, // 启用透明度以显示渐变效果
          side: THREE.DoubleSide, // 双面渲染,从内外都能看到材质
          opacity: 1, // 设置为1以确保渐变纹理完全可见
          depthWrite: false // 禁用深度写入,确保材质在内外都可见
        });

        // 创建几何体
        const extrudeSettings = {
          depth: 50,
          bevelEnabled: false
        };
        const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings);

        // 为几何体的每个面设置不同的材质
        const materials = [
          null,  // 顶部材质
          sideMaterial,  // 底部材质
          sideMaterial,       // 前侧面材质
          sideMaterial,       // 后侧面材质
          sideMaterial,       // 左侧面材质
          sideMaterial        // 右侧面材质
        ];

        // 创建网格对象
        const mesh = new THREE.Mesh(geometry, materials);

        // 创建组并添加网格
        const group = new THREE.Group();
        group.add(mesh);
        return group;
      }

      // 创建顶部线条
      function createLineMesh(points) {
        const geometry = new THREE.BufferGeometry().setFromPoints(points);
        const material = new THREE.LineBasicMaterial({
          color: 0xff0000,
          linewidth: 3
        });
        return new THREE.LineLoop(geometry, material);
      }

      // 创建渐变纹理
      function createGradientTexture() {
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        canvas.width = 256;
        canvas.height = 256;

        const gradient = ctx.createLinearGradient(0, 0, 0, 256);
        gradient.addColorStop(0, 'rgba(255, 0, 0, 1)'); // 顶部完全不透明红色
        gradient.addColorStop(1, 'rgba(255, 0, 0, 0)'); // 底部完全透明

        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, 256, 256);
        return new THREE.CanvasTexture(canvas);
      }

      // 动画
      function animate() {
        map.render();
        requestAnimationFrame(animate);
      }
      animate();
      function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
      }
      window.addEventListener('resize', onWindowResize);

    }).catch(e => {
      console.error('加载高德地图JS API失败: ', e)
    })
})
</script>

<style>
#mapContainer {
  width: 100%;
  height: 900px;
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值