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>