在高德地图上使用threejs,tweenjs,引入外部模型,实现动画效果

init

展示地图

展示地图-入门教程-地图 JS API 2.0|高德地图API (amap.com) 在vue3项目中使用新版高德地图_vue3使用高德地图-CSDN博客

踩坑:<AMap JSAPI> KEY异常,错误信息:USERKEY_PLAT_NOMATCH 原因:申请的key和使用的服务不匹配,展示地图使用JS-API的key,地理信息解析是web服务

  1. npm包安装
css 复制代码
npm i @amap/amap-jsapi-loader --save
  1. 引入
js 复制代码
import AMapLoader from '@amap/amap-jsapi-loader';
  1. 初始化
js 复制代码
var AMap, map
window._AMapSecurityConfig = {
  securityJsCode: "d0543d6e1c9f40e8272aa30af54e8ded",
};
AMapLoader.load({
  key: "d0543d6e1c9f40e8272aa30af54e8ded", //申请好的Web端开发者key,调用 load 时必填
  version: "2.0", //指定要加载的 JS API 的版本,缺省时默认为 1.4.15
})
  .then((res) => {
    //JS API 加载完成后获取AMap对象
    AMap = res
    initMap()
  })
  .catch((e) => {
    console.error(e); //加载错误提示
  });
function initMap () {
  map = new AMap.Map("map", {
    viewMode: '2D', //默认使用 2D 模式
    zoom: 11, //地图级别
    center: [116.397428, 39.90923], //地图中心点,背景天安门为例
  });
}

此时,一个平平无奇的高德地图跃然纸上

结合THREE

自定义图层-GLCustomLayer 结合 THREE-自有数据图层-示例中心-JS API 2.0 示例 | 高德地图API (amap.com)

环境搭建:

  1. 高德地图环境搭建看上一章
  2. three环境搭建 :一定要下载对应版本的three,在官网示例中可以查看其引入的three版本
css 复制代码
npm i three@0.142 # 24/2/1日数据

入门小案例-引入外部模型

照搬官网案例就行

我这里做了些许改动

  1. 引入外部模型猴头
  2. 创建mesh,参考官网案例
  3. 添加移动功能,将猴头移动入mesh中

效果如图

代码如下:

  1. 引入
JS 复制代码
import AMapLoader from '@amap/amap-jsapi-loader'
import * as THREE from 'three';
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import {reactive } from 'vue'
  1. 地图准备
js 复制代码
// step map 
var AMap, map

window._AMapSecurityConfig = {
  securityJsCode: "d0543d6e1c9f40e8272aa30af54e8ded",
};
AMapLoader.load({
  key: "d0543d6e1c9f40e8272aa30af54e8ded", //申请好的Web端开发者key,调用 load 时必填
  version: "2.0", //指定要加载的 JS API 的版本,缺省时默认为 1.4.15
})
  .then((res) => {
    //JS API 加载完成后获取AMap对象
    AMap = res
    createMap() // 创建地图
    createThree() // 创建three
  })
  .catch((e) => {
    console.error(e); //加载错误提示
  });
function createMap () {
  map = new AMap.Map("map", {
    center: [116.54, 39.79],
    zooms: [2, 20],
    zoom: 14,
    viewMode: '3D',
    pitch: 50,
  });
}
  1. three 准备 核心内容是创建GL图层,里面的 render 基本没什么变化
js 复制代码
// step three init
var camera, renderer, scene
var model, monkey, mesh
// 数据转换工具
var customCoords
// 测试用数据
var data
function createThree () {
  customCoords = map.customCoords;
  data = customCoords.lngLatsToCoords([
    [116.52, 39.79],
    [116.54, 39.79],
    [116.56, 39.79],
  ])
  // 创建 GL 图层
  var gllayer = new AMap.GLCustomLayer({
    // 图层的层级
    zIndex: 10,
    // 初始化的操作,创建图层过程中执行一次。
    init: (gl) => {
      initThree(gl)
    },
    render: () => {
      // 这里必须执行!!重新设置 three 的 gl 上下文状态。
      renderer.resetState();
      // 重新设置图层的渲染中心点,将模型等物体的渲染中心点重置
      // 否则和 LOCA 可视化等多个图层能力使用的时候会出现物体位置偏移的问题
      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);

      // 这里必须执行!!重新设置 three 的 gl 上下文状态。
      renderer.resetState();
    },
  });
  map.add(gllayer)
  window.addEventListener('resize', onWindowResize);
}
function onWindowResize () {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}

然后我们来看initThree

JS 复制代码
function initThree (gl) {
  // 这里我们的地图模式是 3D,所以创建一个透视相机,相机的参数初始化可以随意设置,因为在 render 函数中,每一帧都需要同步相机参数,因此这里变得不那么重要。
  // 如果你需要 2D 地图(viewMode: '2D'),那么你需要创建一个正交相机
  camera = new THREE.PerspectiveCamera(
    60,
    window.innerWidth / window.innerHeight,
    100,
    1 << 30
  );

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

  // 自动清空画布这里必须设置为 false,否则地图底图将无法显示
  renderer.autoClear = false;
  scene = new THREE.Scene();

  // 环境光照和平行光
  var aLight = new THREE.AmbientLight(0xffffff, 3);
  var dLight = new THREE.DirectionalLight(0xffffff, 10);
  dLight.position.set(1000, -100, 900);
  scene.add(dLight);
  scene.add(aLight);
  // 加载模型、mesh
  addModel()
  addMesh()
}

以上内容也基本不变,但最后加载模型、mesh按照你需要加载的物体变化。

加载外部模型

JS 复制代码
function addModel () {
  const glftLoader = new GLTFLoader()
  glftLoader.load("/public/models/monkeyAndCube.glb", function (gltf) {
    model = gltf.scene
    model.traverse((child) => {
      child.scale.set(500, 500, 500); // 放大模型
      child.rotation.x = 0.5 * Math.PI;
      child.position.z = 0.8;
      console.log(child.name)
      if (child.name === "monkey") { monkey = child }
    })
    monkey.position.set(data[0][0], data[0][1], 500); // 设置位置
    scene.add(monkey)
  })
}

加载mesh

js 复制代码
function addMesh () {
  //  这里可以使用 three 的各种材质
  var mat = new THREE.MeshLambertMaterial({
    side: THREE.DoubleSide,
    color: 0x1e2f97,
    transparent: true,
    opacity: .4,
    depthWrite: false
  })
  var geo = new THREE.BoxBufferGeometry(1200, 1200, 1200);
  const d = data[2];
  mesh = new THREE.Mesh(geo, mat);
  mesh.position.set(d[0], d[1], 500);
  scene.add(mesh);
  animate()
}
// 动画
function animate () {
  mesh.rotateZ((1 / 180) * Math.PI);
  map.render();
  requestAnimationFrame(animate);
}

移动猴头! 记得自己给这个函数加个按钮

js 复制代码
function moveMonkey (checked) {
  console.log(checked, 'moveMonkey')
  if (checked) {
    monkey.position.set(data[2][0], data[2][1], 500);
  } else {
    monkey.position.set(data[0][0], data[0][1], 500);
  }
}

[!TIP] 这里面地图和three好像是一起渲染的。如果你只加载了猴头,没加载mesh,此时是没有动画效果的,所以移动猴头的话,这个效果有延迟,缩放平移一下地图就好了。但是如果添加了动画,由于一直调用 map.render() 函数,因此不会出现此问题

大功告成!

结合tween.js

是不是觉得猴头的移动还不够顺滑,加个tween的动画试试

  1. 引入 npm install @tweenjs/tween.js
js 复制代码
import * as TWEEN from '@tweenjs/tween.js'
  1. 更改 moveMonkey函数
js 复制代码
function moveMonkey (checked) {
  console.log(checked, 'moveMonkey')
  if (checked) {
    // monkey.position.set(data[2][0], data[2][1], 500);
    const tween = new TWEEN.Tween(monkey.position)
      .to({ x: data[2][0], y: data[2][1], z: 500 }, 2000)
      .start()
  } else {
    // monkey.position.set(data[0][0], data[0][1], 500);
    const tween = new TWEEN.Tween(monkey.position)
      .to({ x: data[0][0], y: data[0][1], z: 500 }, 2000)
      .start()
  }
}
  1. render 函数中加入 ( 这里指Three 函数中的 创建GL图层的 render 函数)
js 复制代码
 TWEEN.update()

大功告成!Tween的其他功能也可以使用

相关推荐
ReBeX2 天前
【GeoJSON在线编辑平台】(1)创建地图+要素绘制+折点编辑+拖拽移动
前端·javascript·gis·openlayers·webgis
supermapsupport3 天前
SuperMap GIS基础产品FAQ集锦(20241104)
java·javascript·gis·supermap·webgis
GIS思维10 天前
零代码实现下载高德地图AOI矢量shp边界,如武夷山风景区矢量边界
arcgis·gis·qgis·高德地图·aoi
刘一哥GIS11 天前
神州19号载人飞船即将发射!
arcgis·gis·神州19·宇宙飞船
GIS数据转换器12 天前
智慧城市综合管理应用服务平台
大数据·人工智能·gis·生活·智慧城市·1024程序员节
希艾席蒂恩12 天前
GISBox vs CesiumLab:哪款GIS工具更适合你的项目?
arcgis·gis·数字孪生·cesiumlab·地形切片·gis工具箱·gisbox
GIS思维13 天前
ArcGIS必会的选择要素方法(AND、OR、R、IN等)位置选择等
arcgis·gis·地理信息·arcgis位置选择·arcgis模糊查询
MagicUrban14 天前
三维管线管网建模工具MagicPipe3D V3.5.3
3d·gis·智慧城市·1024程序员节·bim·地下管网
Johaden16 天前
利用Arcgis进行沟道形态分析
arcgis·gis·水文分析·地理学·沟道形态分析
GIS数据转换器18 天前
城市大脑顶层设计:构建智慧城市的新引擎
大数据·人工智能·gis·生活·智慧城市