Files
bim_engine/docs/SDK_USAGE.md
yuding a00d83e775 docs: 添加 SDK 使用文档
- 支持原生 HTML、Vue 2/3、React 框架
- 包含完整的 API 参考和类型定义
- 提供组件封装示例和 Hook 封装
- 添加常见问题解答

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 14:22:43 +08:00

22 KiB
Raw Blame History

BIM Engine SDK 使用文档

BIM Engine SDK 是一个用于 3D BIM 模型展示的 JavaScript SDK支持原生 HTML、Vue 2/3 和 React 框架。

目录


安装

NPM 安装

npm install bim-engine-sdk

CDN / 本地引入

<script src="./lib/bim-engine-sdk.umd.js"></script>

原生 HTML 使用

基础示例

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>BIM Engine Demo</title>
    <!-- 引入 SDK -->
    <script src="./lib/bim-engine-sdk.umd.js"></script>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        html, body { width: 100%; height: 100%; overflow: hidden; }
        #app { width: 100%; height: 100%; }
    </style>
</head>
<body>
    <div id="app"></div>

    <script>
        // 1. 创建引擎实例
        const engine = new LyzBimEngineSDK.BimEngine('app', {
            locale: 'zh-CN',  // 语言:'zh-CN' | 'en-US'
            theme: 'light'    // 主题:'light' | 'dark'
        });

        // 2. 初始化 3D 引擎
        const success = engine.engine.initialize({
            version: 'v2',        // WebGL 版本:'v1' | 'v2'
            showStats: false,     // 是否显示性能统计
            showViewCube: true    // 是否显示视图立方体
        });

        if (success) {
            console.log('3D 引擎初始化成功');

            // 3. 加载模型
            engine.engine.loadModel('./model/your-model', {
                position: [0, 0, 0],    // 位置 [x, y, z]
                rotation: [0, 0, 0],    // 旋转 [x, y, z](弧度)
                scale: [1, 1, 1]        // 缩放 [x, y, z]
            });
        }

        // 4. 页面卸载时销毁
        window.addEventListener('beforeunload', () => {
            engine.destroy();
        });
    </script>
</body>
</html>

完整功能示例

<script>
    let engine = null;

    // 初始化
    function init() {
        engine = new LyzBimEngineSDK.BimEngine('app', {
            locale: 'zh-CN',
            theme: 'light'
        });

        engine.engine.initialize({
            version: 'v2',
            showStats: false,
            showViewCube: true
        });

        // 加载模型
        engine.engine.loadModel('./model/building');
    }

    // 回到主视角
    function goHome() {
        engine.engine.CameraGoHome();
    }

    // 激活测量功能
    function activateMeasure(mode) {
        // mode: 'distance' | 'minDistance' | 'angle' | 'elevation' | 'volume' | 'laserDistance' | 'slope' | 'spaceVolume'
        engine.engine.activateMeasure(mode);
    }

    // 停用测量
    function deactivateMeasure() {
        engine.engine.deactivateMeasure();
    }

    // 切换主题
    function toggleTheme() {
        engine.setTheme('dark'); // 或 'light'
    }

    // 切换语言
    function toggleLocale() {
        engine.setLocale('en-US'); // 或 'zh-CN'
    }

    // 销毁
    function destroy() {
        engine.destroy();
    }

    window.onload = init;
</script>

Vue 3 使用

安装依赖

npm install bim-engine-sdk

组件封装

<!-- BimViewer.vue -->
<template>
    <div ref="containerRef" class="bim-viewer"></div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { BimEngine } from 'bim-engine-sdk';
import type { EngineOptions, ModelLoadOptions } from 'bim-engine-sdk';

// Props
interface Props {
    modelUrl?: string;
    modelOptions?: ModelLoadOptions;
    engineOptions?: Omit<EngineOptions, 'container'>;
    locale?: 'zh-CN' | 'en-US';
    theme?: 'light' | 'dark';
}

const props = withDefaults(defineProps<Props>(), {
    locale: 'zh-CN',
    theme: 'light'
});

// Emits
const emit = defineEmits<{
    (e: 'ready', engine: BimEngine): void;
    (e: 'error', error: Error): void;
}>();

// Refs
const containerRef = ref<HTMLElement | null>(null);
let engine: BimEngine | null = null;

// 初始化引擎
const initEngine = () => {
    if (!containerRef.value) return;

    try {
        // 创建引擎实例
        engine = new BimEngine(containerRef.value, {
            locale: props.locale,
            theme: props.theme
        });

        // 初始化 3D 引擎
        const success = engine.engine?.initialize({
            version: 'v2',
            showStats: false,
            showViewCube: true,
            ...props.engineOptions
        });

        if (success) {
            emit('ready', engine);

            // 加载模型
            if (props.modelUrl) {
                engine.engine?.loadModel(props.modelUrl, props.modelOptions);
            }
        } else {
            throw new Error('3D 引擎初始化失败');
        }
    } catch (error) {
        emit('error', error as Error);
    }
};

// 暴露方法给父组件
defineExpose({
    // 获取引擎实例
    getEngine: () => engine,

    // 加载模型
    loadModel: (url: string, options?: ModelLoadOptions) => {
        engine?.engine?.loadModel(url, options);
    },

    // 回到主视角
    goHome: () => {
        engine?.engine?.CameraGoHome();
    },

    // 激活测量
    activateMeasure: (mode: string) => {
        engine?.engine?.activateMeasure(mode as any);
    },

    // 停用测量
    deactivateMeasure: () => {
        engine?.engine?.deactivateMeasure();
    },

    // 切换主题
    setTheme: (theme: 'light' | 'dark') => {
        engine?.setTheme(theme);
    },

    // 切换语言
    setLocale: (locale: 'zh-CN' | 'en-US') => {
        engine?.setLocale(locale);
    }
});

// 生命周期
onMounted(() => {
    initEngine();
});

onBeforeUnmount(() => {
    engine?.destroy();
    engine = null;
});
</script>

<style scoped>
.bim-viewer {
    width: 100%;
    height: 100%;
}
</style>

使用组件

<!-- App.vue -->
<template>
    <div class="app">
        <BimViewer
            ref="viewerRef"
            model-url="./model/building"
            :model-options="{ position: [0, 0, 0] }"
            locale="zh-CN"
            theme="light"
            @ready="onEngineReady"
            @error="onEngineError"
        />

        <div class="toolbar">
            <button @click="goHome">主视角</button>
            <button @click="measure('distance')">距离测量</button>
            <button @click="stopMeasure">停止测量</button>
        </div>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import BimViewer from './components/BimViewer.vue';
import type { BimEngine } from 'bim-engine-sdk';

const viewerRef = ref<InstanceType<typeof BimViewer> | null>(null);

const onEngineReady = (engine: BimEngine) => {
    console.log('引擎已就绪', engine);
};

const onEngineError = (error: Error) => {
    console.error('引擎错误', error);
};

const goHome = () => {
    viewerRef.value?.goHome();
};

const measure = (mode: string) => {
    viewerRef.value?.activateMeasure(mode);
};

const stopMeasure = () => {
    viewerRef.value?.deactivateMeasure();
};
</script>

<style>
.app {
    width: 100vw;
    height: 100vh;
    position: relative;
}

.toolbar {
    position: absolute;
    top: 20px;
    left: 20px;
    z-index: 100;
}
</style>

Vue 2 使用

安装依赖

npm install bim-engine-sdk

组件封装

<!-- BimViewer.vue -->
<template>
    <div ref="container" class="bim-viewer"></div>
</template>

<script>
import { BimEngine } from 'bim-engine-sdk';

export default {
    name: 'BimViewer',

    props: {
        modelUrl: {
            type: String,
            default: ''
        },
        modelOptions: {
            type: Object,
            default: () => ({})
        },
        engineOptions: {
            type: Object,
            default: () => ({})
        },
        locale: {
            type: String,
            default: 'zh-CN'
        },
        theme: {
            type: String,
            default: 'light'
        }
    },

    data() {
        return {
            engine: null
        };
    },

    mounted() {
        this.initEngine();
    },

    beforeDestroy() {
        this.destroyEngine();
    },

    methods: {
        initEngine() {
            try {
                // 创建引擎实例
                this.engine = new BimEngine(this.$refs.container, {
                    locale: this.locale,
                    theme: this.theme
                });

                // 初始化 3D 引擎
                const success = this.engine.engine.initialize({
                    version: 'v2',
                    showStats: false,
                    showViewCube: true,
                    ...this.engineOptions
                });

                if (success) {
                    this.$emit('ready', this.engine);

                    // 加载模型
                    if (this.modelUrl) {
                        this.engine.engine.loadModel(this.modelUrl, this.modelOptions);
                    }
                } else {
                    throw new Error('3D 引擎初始化失败');
                }
            } catch (error) {
                this.$emit('error', error);
            }
        },

        destroyEngine() {
            if (this.engine) {
                this.engine.destroy();
                this.engine = null;
            }
        },

        // 公开方法
        getEngine() {
            return this.engine;
        },

        loadModel(url, options) {
            this.engine?.engine?.loadModel(url, options);
        },

        goHome() {
            this.engine?.engine?.CameraGoHome();
        },

        activateMeasure(mode) {
            this.engine?.engine?.activateMeasure(mode);
        },

        deactivateMeasure() {
            this.engine?.engine?.deactivateMeasure();
        },

        setTheme(theme) {
            this.engine?.setTheme(theme);
        },

        setLocale(locale) {
            this.engine?.setLocale(locale);
        }
    }
};
</script>

<style scoped>
.bim-viewer {
    width: 100%;
    height: 100%;
}
</style>

使用组件

<!-- App.vue -->
<template>
    <div class="app">
        <BimViewer
            ref="viewer"
            model-url="./model/building"
            :model-options="{ position: [0, 0, 0] }"
            locale="zh-CN"
            theme="light"
            @ready="onEngineReady"
            @error="onEngineError"
        />

        <div class="toolbar">
            <button @click="goHome">主视角</button>
            <button @click="measure('distance')">距离测量</button>
            <button @click="stopMeasure">停止测量</button>
        </div>
    </div>
</template>

<script>
import BimViewer from './components/BimViewer.vue';

export default {
    name: 'App',

    components: {
        BimViewer
    },

    methods: {
        onEngineReady(engine) {
            console.log('引擎已就绪', engine);
        },

        onEngineError(error) {
            console.error('引擎错误', error);
        },

        goHome() {
            this.$refs.viewer.goHome();
        },

        measure(mode) {
            this.$refs.viewer.activateMeasure(mode);
        },

        stopMeasure() {
            this.$refs.viewer.deactivateMeasure();
        }
    }
};
</script>

<style>
.app {
    width: 100vw;
    height: 100vh;
    position: relative;
}

.toolbar {
    position: absolute;
    top: 20px;
    left: 20px;
    z-index: 100;
}
</style>

React 使用

安装依赖

npm install bim-engine-sdk

Hook 封装

// hooks/useBimEngine.ts
import { useEffect, useRef, useState, useCallback } from 'react';
import { BimEngine } from 'bim-engine-sdk';
import type { EngineOptions, ModelLoadOptions } from 'bim-engine-sdk';

type MeasureMode = 'distance' | 'minDistance' | 'angle' | 'elevation' | 'volume' | 'laserDistance' | 'slope' | 'spaceVolume';

interface UseBimEngineOptions {
    locale?: 'zh-CN' | 'en-US';
    theme?: 'light' | 'dark';
    engineOptions?: Omit<EngineOptions, 'container'>;
    onReady?: (engine: BimEngine) => void;
    onError?: (error: Error) => void;
}

export function useBimEngine(options: UseBimEngineOptions = {}) {
    const containerRef = useRef<HTMLDivElement>(null);
    const engineRef = useRef<BimEngine | null>(null);
    const [isReady, setIsReady] = useState(false);
    const [error, setError] = useState<Error | null>(null);

    // 初始化引擎
    useEffect(() => {
        if (!containerRef.current) return;

        try {
            // 创建引擎实例
            const engine = new BimEngine(containerRef.current, {
                locale: options.locale || 'zh-CN',
                theme: options.theme || 'light'
            });

            // 初始化 3D 引擎
            const success = engine.engine?.initialize({
                version: 'v2',
                showStats: false,
                showViewCube: true,
                ...options.engineOptions
            });

            if (success) {
                engineRef.current = engine;
                setIsReady(true);
                options.onReady?.(engine);
            } else {
                throw new Error('3D 引擎初始化失败');
            }
        } catch (err) {
            const error = err as Error;
            setError(error);
            options.onError?.(error);
        }

        // 清理
        return () => {
            engineRef.current?.destroy();
            engineRef.current = null;
            setIsReady(false);
        };
    }, []);

    // 加载模型
    const loadModel = useCallback((url: string, modelOptions?: ModelLoadOptions) => {
        engineRef.current?.engine?.loadModel(url, modelOptions);
    }, []);

    // 回到主视角
    const goHome = useCallback(() => {
        engineRef.current?.engine?.CameraGoHome();
    }, []);

    // 激活测量
    const activateMeasure = useCallback((mode: MeasureMode) => {
        engineRef.current?.engine?.activateMeasure(mode);
    }, []);

    // 停用测量
    const deactivateMeasure = useCallback(() => {
        engineRef.current?.engine?.deactivateMeasure();
    }, []);

    // 切换主题
    const setTheme = useCallback((theme: 'light' | 'dark') => {
        engineRef.current?.setTheme(theme);
    }, []);

    // 切换语言
    const setLocale = useCallback((locale: 'zh-CN' | 'en-US') => {
        engineRef.current?.setLocale(locale);
    }, []);

    return {
        containerRef,
        engine: engineRef.current,
        isReady,
        error,
        loadModel,
        goHome,
        activateMeasure,
        deactivateMeasure,
        setTheme,
        setLocale
    };
}

组件封装

// components/BimViewer.tsx
import React, { useEffect } from 'react';
import { useBimEngine } from '../hooks/useBimEngine';
import type { ModelLoadOptions } from 'bim-engine-sdk';

interface BimViewerProps {
    modelUrl?: string;
    modelOptions?: ModelLoadOptions;
    locale?: 'zh-CN' | 'en-US';
    theme?: 'light' | 'dark';
    className?: string;
    style?: React.CSSProperties;
    onReady?: (engine: any) => void;
    onError?: (error: Error) => void;
}

export const BimViewer = React.forwardRef<any, BimViewerProps>((props, ref) => {
    const {
        modelUrl,
        modelOptions,
        locale = 'zh-CN',
        theme = 'light',
        className,
        style,
        onReady,
        onError
    } = props;

    const {
        containerRef,
        engine,
        isReady,
        loadModel,
        goHome,
        activateMeasure,
        deactivateMeasure,
        setTheme,
        setLocale
    } = useBimEngine({
        locale,
        theme,
        onReady,
        onError
    });

    // 暴露方法给父组件
    React.useImperativeHandle(ref, () => ({
        getEngine: () => engine,
        loadModel,
        goHome,
        activateMeasure,
        deactivateMeasure,
        setTheme,
        setLocale
    }));

    // 加载模型
    useEffect(() => {
        if (isReady && modelUrl) {
            loadModel(modelUrl, modelOptions);
        }
    }, [isReady, modelUrl, modelOptions, loadModel]);

    return (
        <div
            ref={containerRef}
            className={className}
            style={{
                width: '100%',
                height: '100%',
                ...style
            }}
        />
    );
});

BimViewer.displayName = 'BimViewer';

使用组件

// App.tsx
import React, { useRef } from 'react';
import { BimViewer } from './components/BimViewer';

function App() {
    const viewerRef = useRef<any>(null);

    const handleReady = (engine: any) => {
        console.log('引擎已就绪', engine);
    };

    const handleError = (error: Error) => {
        console.error('引擎错误', error);
    };

    const goHome = () => {
        viewerRef.current?.goHome();
    };

    const measure = (mode: string) => {
        viewerRef.current?.activateMeasure(mode);
    };

    const stopMeasure = () => {
        viewerRef.current?.deactivateMeasure();
    };

    return (
        <div style={{ width: '100vw', height: '100vh', position: 'relative' }}>
            <BimViewer
                ref={viewerRef}
                modelUrl="./model/building"
                modelOptions={{ position: [0, 0, 0] }}
                locale="zh-CN"
                theme="light"
                onReady={handleReady}
                onError={handleError}
            />

            <div style={{ position: 'absolute', top: 20, left: 20, zIndex: 100 }}>
                <button onClick={goHome}>主视角</button>
                <button onClick={() => measure('distance')}>距离测量</button>
                <button onClick={stopMeasure}>停止测量</button>
            </div>
        </div>
    );
}

export default App;

API 参考

BimEngine

主引擎类,用于创建和管理 BIM 引擎实例。

构造函数

new BimEngine(container: HTMLElement | string, options?: {
    locale?: 'zh-CN' | 'en-US';
    theme?: 'light' | 'dark';
})
参数 类型 说明
container HTMLElement | string 容器元素或容器 ID
options.locale string 语言设置,默认 'zh-CN'
options.theme string 主题设置,默认 'light'

属性

属性 类型 说明
engine EngineManager 3D 引擎管理器
toolbar ToolbarManager 工具栏管理器
dialog DialogManager 弹窗管理器
measure MeasureDialogManager 测量面板管理器

方法

方法 参数 返回值 说明
setLocale locale: 'zh-CN' | 'en-US' void 设置语言
getLocale - string 获取当前语言
setTheme theme: 'light' | 'dark' void 设置主题
setCustomTheme theme: ThemeConfig void 设置自定义主题
destroy - void 销毁引擎

EngineManager

3D 引擎管理器,通过 engine.engine 访问。

方法

方法 参数 返回值 说明
initialize options?: EngineOptions boolean 初始化 3D 引擎
isInitialized - boolean 检查是否已初始化
loadModel url: string, options?: ModelLoadOptions void 加载模型
CameraGoHome - void 回到主视角
activateMeasure mode: MeasureMode void 激活测量功能
deactivateMeasure - void 停用测量功能
getCurrentMeasureType - MeasureMode | null 获取当前测量类型
getEngine - any 获取原始引擎实例
destroy - void 销毁引擎

类型定义

EngineOptions

interface EngineOptions {
    container: HTMLElement;                    // 容器元素
    backgroundColor?: number | string;         // 背景色
    version?: 'v1' | 'v2';                    // WebGL 版本
    showStats?: boolean;                       // 是否显示性能统计
    showViewCube?: boolean;                    // 是否显示视图立方体
}

ModelLoadOptions

interface ModelLoadOptions {
    position?: [number, number, number];       // 位置 [x, y, z]
    rotation?: [number, number, number];       // 旋转 [x, y, z](弧度)
    scale?: [number, number, number];          // 缩放 [x, y, z]
    id?: string;                               // 模型 ID
}

MeasureMode

type MeasureMode =
    | 'distance'        // 距离测量
    | 'minDistance'     // 最小距离测量
    | 'angle'           // 角度测量
    | 'elevation'       // 标高测量
    | 'volume'          // 体积测量
    | 'laserDistance'   // 激光测距
    | 'slope'           // 坡度测量
    | 'spaceVolume';    // 空间体积测量

注意事项

  1. 容器尺寸:确保容器元素有明确的宽度和高度,否则 3D 引擎可能无法正常渲染。

  2. 模型路径:模型路径应为相对于 HTML 页面的路径,或者完整的 URL。

  3. 销毁清理:在组件卸载或页面关闭前,务必调用 destroy() 方法释放资源。

  4. 浏览器兼容性SDK 需要浏览器支持 WebGL。建议使用现代浏览器Chrome、Firefox、Safari、Edge

  5. 静态资源:确保 Draco 解码器等静态资源正确部署:

    /static/js/draco/
    ├── DRACOLoader.js
    ├── draco_decoder.js
    ├── draco_decoder.wasm
    ├── draco_encoder.js
    └── draco_wasm_wrapper.js
    

常见问题

Q: 模型加载失败怎么办?

A: 检查以下几点:

  • 模型路径是否正确
  • 模型格式是否支持
  • 网络请求是否正常F12 查看 Network
  • Draco 解码器是否正确部署

Q: 如何自定义主题?

A: 使用 setCustomTheme 方法:

engine.setCustomTheme({
    background: '#1a1a2e',
    textPrimary: '#ffffff',
    textSecondary: '#cccccc',
    // ... 更多配置
});

Q: 如何监听引擎事件?

A: 使用 on 方法监听事件:

engine.on('modelLoaded', (data) => {
    console.log('模型已加载', data);
});

技术支持

如有问题,请联系技术支持或提交 Issue。