唯杰地图 logo唯杰地图
VJMAP
EN

设计理念

vjmap3d/references/guide/design.md 9.5 KB289 行
原文

模块化设计

vjmap3d的模块化设计灵感来源于whs.js(具有组件系统和插件支持)。

vjmap3d基于模块化开发遵循 组合优于继承 的开发设计原则,实现了自己的模块系统。我们将传统复杂的逻辑划分为独立的、可重复利用的部分,每个部分可以单独封装运行逻辑。然后通过灵活组合的形式,将多个简单模块合并在一起运行从而表现复杂的功能和逻辑。

vjmap3d中的 App 和 Entity 都是基于模块化开发。

示例:

可以给一个实体增加一个事件模块,让实体响应鼠标事件,高亮显示

let entity = vjmap3d.Entity.fromObject3d(mesh);
entity.addTo(app);

// 增加一个事件模块,用来高亮提示
entity.add(vjmap3d.EventModule, {
    hoverSelect: true,
    hoverHtmlText: '我是用vjmap3d创建的Box',
    popupOptions: {
        anchor: "bottom"
    }
});
// 可以获取模块,调用模块中的方法
// let mod = entity.getModule(vjmap3d.EventModule);
// mod.removeEvent();

// 移除事件模块,移除后实体将不会响应鼠标事件
// entity.removeModule(vjmap3d.EventModule)
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    render: { // 渲染参数
        alpha: true,
        antialias: true
    },
    scene: {  // 场景设置
        gridHelper: { visible: true } // 是否显示坐标网格
    }
})
//
let box = new THREE.BoxGeometry(2, 2, 2)
const material = new THREE.MeshStandardMaterial({
    color: "#0f0",
    side: THREE.DoubleSide
});
let mesh = new THREE.Mesh(box, material);
let entity = vjmap3d.Entity.fromObject3d(mesh);
entity.addTo(app);
// 增加一个事件模块,用来高亮提示
entity.add(vjmap3d.EventModule, {
    hoverSelect: true,
    hoverHtmlText: '我是用vjmap3d创建的Box',
    popupOptions: {
        anchor: "bottom"
    }
});
setTimeout(() => {
    // 过二十秒后移除事件模块,移除后实体将不会响应鼠标事件
    entity.removeModule(vjmap3d.EventModule)
}, 20000)

兼容性设计

vjmap3d基于threejs开发,threejs拥有庞大的开发者社区和丰富的教程资源,vjmap3d能兼容threejs写法,利用threejs生态资源。 同时vjmap3d提供了一些的预设对象和材质,以及粒子系统、后期处理等高级特性,便于快速实现复杂视觉效果, 同时提供丰富的交互组件和事件处理机制,增强用户体验和应用互动性。支持场景中的对象拾取与交互,简化了交互逻辑的实现。

原生threejs写法

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.getElementById("map").appendChild( renderer.domElement );

const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );

camera.position.z = 5;

function animate() {
    requestAnimationFrame( animate );

    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;

    renderer.render( scene, camera );
}

animate();
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
//
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.getElementById("map").appendChild( renderer.domElement );
//
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
//
camera.position.z = 5;
const controls = new OrbitControls(camera, renderer.domElement);
controls.update();
//
function animate() {
    requestAnimationFrame( animate );
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    renderer.render( scene, camera );
}
animate();

vjmap3d模仿threejs原生写法

vjmap3d中 scene可通过 app.scene 获取,camera可通过 app.camera 获取,renderer可通过 app.renderer 获取

let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    camera: {
        fov: 75,
        near: 0.1, 
        far: 1000,
        position: new THREE.Vector3(0, 0, 5)
    }
})
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
app.scene.add( cube );

function animate() {
    requestAnimationFrame( animate );

    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    app.renderer.render( app.scene, app.camera );
}

animate();
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    camera: {
        fov: 75,
        near: 0.1, 
        far: 1000,
        position: new THREE.Vector3(0, 0, 5)
    }
})
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
app.scene.add( cube );
//
function animate() {
    requestAnimationFrame( animate );
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    app.renderer.render( app.scene, app.camera );
}
animate();

vjmap3d封装写法

也可以用vjmap3d封装的一些函数进上面的进行改进,达到更好的效果,如对上面的立方体辉光处理,只需创建一个实体和立方体对象进行关联。

let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    camera: {
        fov: 75,
        near: 0.1, 
        far: 1000,
        position: new THREE.Vector3(0, 0, 5)
    }
})
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
app.scene.add( cube );
let entity = vjmap3d.Entity.attchObject(cube); // 创建一个实体与对象关联
// 或者 上面的两行也可以用下面的两行代替
//let entity = vjmap3d.Entity.fromObject3d(cube); // 创建一个来源于object3d的实体对象
//entity.addTo(app);// 把实体加进应用中
entity.bloom = true; // 设置实体辉光
entity.selected = true; // 设置实体选择
// 原生的requestAnimationFrame可用事件回调来处理,更简洁
app.signal.onAppRender.add(() => {
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
})
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    camera: {
        fov: 75,
        near: 0.1, 
        far: 1000,
        position: new THREE.Vector3(0, 0, 5)
    }
})
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
const cube = new THREE.Mesh( geometry, material );
app.scene.add( cube );
let entity = vjmap3d.Entity.attchObject(cube); // 创建一个实体与对象关联
// 或者 上面的两行也可以用下面的两行代替
//let entity = vjmap3d.Entity.fromObject3d(cube); // 创建一个来源于object3d的实体对象
//entity.addTo(app);// 把实体加进应用中
entity.bloom = true; // 设置实体辉光
entity.selected = true; // 设置实体选择
// 原生的requestAnimationFrame可用事件回调来处理,更简洁
app.signal.onAppRender.add(() => {
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
})

插件化设计

vjmap3d将额外的功能和特性作为独立的模块添加到做为插件库,通过加载插件来使用。这样不仅使核心库保持简洁和高效,还使用更新和维护变得更加简便,而不需要修改核心代码。

加载几何扩展插件库示例:

let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
    container: "map", // 容器id
    scene: {
        gridHelper: { visible: true } // 是否显示坐标网格
    }
})
// 加载几何插件库,对几何图形进行交差并补计算
let amLib = await vjmap3d.loadPluginAlgorithm();
const sphere = new amLib.Brush( new THREE.SphereGeometry(1) );
sphere.material.color = new THREE.Color("#0f0")
sphere.position.set(0, 0, 0)
sphere.updateMatrixWorld();
const box = new amLib.Brush( new THREE.BoxGeometry(1, 1, 1) );
box.position.set(0, 0.5, 0)
box.material.color = new THREE.Color("#f00")
box.updateMatrixWorld();
const evaluator = new amLib.Evaluator();
// 在球的表面挖去立方体的表面
const result = evaluator.evaluate( sphere, box, amLib.HOLLOW_SUBTRACTION );
app.scene.add(result)