基于 Baidu JSAPI Three 的三维模型交互控制 Demo

基于 Baidu JSAPI Three 的三维模型交互控制 Demo

项目简介

本项目演示如何在 React 环境下,结合 @baidumap/mapv-three 和 Three.js,在真实的百度三维地图上实现对三维模型的交互式控制。你可以加载一个三维模型,并通过 UI 控件对其进行移动、旋转和缩放操作。

效果截图

环境准备

  • Node.js
  • VSCode (或其它代码编辑器)

依赖安装

在项目根目录下依次执行:

bash 复制代码
# 安装核心依赖
npm install --save react react-dom @baidumap/mapv-three three

# 安装开发与构建相关依赖
npm install --save-dev webpack webpack-cli copy-webpack-plugin html-webpack-plugin @babel/core @babel/preset-env @babel/preset-react babel-loader

# 安装 UI 控制面板依赖
npm install --save dat.gui

资源与构建配置

本项目采用 Webpack 进行打包,静态资源(如地图底图、官方模型、自定义模型等)通过 CopyWebpackPlugin 自动拷贝到输出目录。

webpack.config.js 关键配置如下:

js 复制代码
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist'),
        clean: true,
    },
    plugins: [
        new CopyWebpackPlugin({
            patterns: [
                {
                    from: path.resolve(__dirname, 'node_modules/@baidumap/mapv-three/dist/assets'),
                    to: 'mapvthree/assets',
                },
            ],
        }),
        new HtmlWebpackPlugin({
            templateContent: ({htmlWebpackPlugin}) => `
                <!DOCTYPE html>
                <html lang="zh-CN">
                <head>
                    <meta charset="UTF-8">
                    <title>MapV Three Demo</title>
                    <script>
                        window.MAPV_BASE_URL = 'mapvthree/';
                    </script>
                </head>
                <body>
                    <h1>MapV Three Demo</h1>
                    <div id="container" style="width: 100vw; height: 100vh; position: fixed; left: 0; top: 0; margin: 0; padding: 0;"/>
                </body>
                </html>
            `,
            inject: 'body',
        }),
    ],
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env', '@babel/preset-react'],
                    },
                },
            },
            // 可根据需要添加loader配置
        ],
    },
    mode: 'development', // 可改为'production'
    resolve: {
        extensions: ['.js', '.jsx'],
    },
}; 

运行与构建

bash 复制代码
# 打包
npx webpack

# 生成的文件在 dist/ 目录下
# 用浏览器打开 dist/index.html 即可预览 Demo 效果

操作指南

  1. 等待地图和巴士模型加载完成。
  2. 点击页面右上角 UI 面板中的 1. 附加控件 (Attach) 按钮。
  3. 点击 移动模式缩放模式旋转模式 按钮来切换不同的操作。
  4. 在三维视图中拖动出现的辅助控件,即可对巴士模型进行变换。

目录结构说明

bash 复制代码
control/
├── dist/                        # 构建输出目录
│   ├── main.js
│   ├── index.html
│   └── mapvthree/assets/        # 地图与模型等静态资源
├── image/                       # 效果截图
├── node_modules/                # 依赖包
├── src/                         # 源码目录
│   ├── Demo.jsx                 # Demo主组件
│   └── index.js                 # 入口文件
├── webpack.config.js            # 构建配置
├── package.json                 # 项目依赖
└── README.md                    # 项目说明

主要代码 (src/Demo.jsx)

该文件是整个交互控制功能的核心,负责地图初始化、模型加载、UI面板创建和事件绑定。

js 复制代码
import React, { useRef, useEffect } from 'react';
import * as mapvthree from '@baidumap/mapv-three';
import * as THREE from 'three';
import * as dat from 'dat.gui';

const Demo = () => {
    const ref = useRef();
    const guiRef = useRef();

    useEffect(() => {
        mapvthree.BaiduMapConfig.ak = '您的AK';

        const center = [120.213, 30.21, 0];
        const engine = new mapvthree.Engine(ref.current, {
            map: {
                provider: new mapvthree.BaiduVectorTileProvider(),
                center: center,
                pitch: 60,
                heading: 70,
                range: 50,
                projection: 'ECEF'
            },
            rendering: {
                enableAnimationLoop: true
            },
        });

        const model = new mapvthree.SimpleModel({
            name: 'bus',
            point: center,
            scale: 50,
            object: 'mapvthree/assets/models/twin/REALISTIC/BUS.glb',
        });
        engine.add(model);

        const transformControl = engine.selection.transformControl;
        transformControl.addEventListener('objectChange', e => {
            console.log('Model details changed:', e.target.object);
        });

        if (guiRef.current) {
            guiRef.current.destroy();
        }
        const gui = new dat.GUI();
        guiRef.current = gui;

        const events = {
            attach: () => {
                console.log('Attaching transform to model...');
                engine.selection.attachTransform(model);
            },
            detach: () => {
                console.log('Detaching transform...');
                engine.selection.detachTransform();
            },
            translate: () => {
                transformControl.setMode('translate');
            },
            scale: () => {
                transformControl.setMode('scale');
            },
            rotate: () => {
                transformControl.setMode('rotate');
            },
        };

        gui.add(events, 'attach').name('1. 附加控件 (Attach)');
        gui.add(events, 'detach').name('2. 分离控件 (Detach)');
        gui.add(events, 'translate').name('移动模式 (Translate)');
        gui.add(events, 'scale').name('缩放模式 (Scale)');
        gui.add(events, 'rotate').name('旋转模式 (Rotate)');
        ref.current.appendChild(gui.domElement);
        gui.domElement.style.position = 'absolute';
        gui.domElement.style.top = '10px';
        gui.domElement.style.right = '10px';
        gui.domElement.style.zIndex = '9999';

        return () => {
            if (guiRef.current) {
                guiRef.current.destroy();
            }
            engine.dispose();
        };
    }, []);

    return <div ref={ref} style={{ width: '100vw', height: '100vh', position: 'fixed', left: 0, top: 0 }} />;
};

export default Demo;

注意!

  • 需要将 src/Demo.jsxmapvthree.BaiduMapConfig.ak 的值替换为你的百度地图开发者密钥 (AK)。
  • 如何获取百度地图 AK?
    访问百度地图开放平台-控制台注册并创建应用获取 (要创建浏览器端类型)。

参考资料

相关推荐
海天胜景2 分钟前
vue3 el-table 列增加 自定义排序逻辑
javascript·vue.js·elementui
今晚打老虎z6 分钟前
dotnet-env: .NET 开发者的环境变量加载工具
前端·chrome·.net
用户38022585982412 分钟前
vue3源码解析:diff算法之patchChildren函数分析
前端·vue.js
烛阴17 分钟前
XPath 进阶:掌握高级选择器与路径表达式
前端·javascript
小鱼小鱼干21 分钟前
【JS/Vue3】关于Vue引用透传
前端
JavaDog程序狗23 分钟前
【前端】HTML+JS 实现超燃小球分裂全过程
前端
独立开阀者_FwtCoder27 分钟前
URL地址末尾加不加 "/" 有什么区别
前端·javascript·github
独立开阀者_FwtCoder30 分钟前
Vue3 新特性:原来watch 也能“暂停”和“恢复”了!
前端·javascript·github
snakeshe101031 分钟前
优化 Mini React:实现组件级别的精准更新
前端
前端小盆友32 分钟前
从零实现一个GPT 【React + Express】--- 【2】实现对话流和停止生成
前端·gpt·react.js