常用函数
webworker
在三维开发中,保持主线程尽可能空闲是很重要的,这样它就可以快速响应用户交互。UI线程应该仅用于UI工作。WebWorkers是一个web API,允许您在单独的线程中运行代码。为了与另一个线程通信,WebWorkers提供postMessage API。您可以使用myWorker.postMessage(someObject) 将JavaScript对象作为消息发送,从而触发worker内部的消息事件。vjmap3d通过对webworker的封装,使webworker调用像调用本地函数一样,使用更方便。
使用方法
方式一: 通过 createWorker 和 workerWrap 创建
- 1、通过 createWorker 通过本地函数创建worker
- 2、通过 workerWrap 以本地函数进行包裹
- 3、调用(并且异步调用)
- 4、终止
terminatewoker
function sum(num) {
let result = 0
for (let i = 0; i < num; i++) {
result = result + i
}
return result;
}
let myWorker = vjmap3d.createWorker(sum);
const sumWorker = vjmap3d.workerWrap(myWorker);
let result1 = await sumWorker(100000);
console.log(result1); // 结果将输出 4999950000
let result2 = await sumWorker(5000000);
console.log(result2); // 结果将输出 12499997500000
myWorker.terminate();
方式二、通过 createWorkerWrap 将上面的的 createWorker 和 workerWrap 合成一步
- 1、通过 createWorkerWrap 通过本地函数创建worker和本地函数进行包裹
- 2、调用(并且异步调用)
- 3、终止
terminatewoker
上面的代码用createWorkerWrap实现如下
function sum(num) {
let result = 0
for (let i = 0; i < num; i++) {
result = result + i
}
return result;
}
var {worker, wrap} = vjmap3d.createWorkerWrap(sum);
let result1 = await wrap(100000);
console.log(result1); // 结果将输出 4999950000
let result2 = await wrap(5000000);
console.log(result2); // 结果将输出 12499997500000
worker.terminate();
提示
用webworker进行wrap的函数或类,不能依赖其他的函数或类,如用了外部依赖的函数或类,需要把依赖的函数或类做为上下文传入。
⚠️ 上下文对象里的函数值会按
function 名(的固定格式截取源码再拼进 worker,只有普通function xxx(){}声明能正确转换;类、箭头函数、对象方法简写(foo(){})、async 函数会被截坏,worker 启动即SyntaxError。这类依赖请直接传源码字符串(字符串值会原样拼入 worker),如{ helper: "const helper = (a) => a + 1;", Point: Point.toString() }。
class MyClass {
constructor(init = 0) {
console.log(init);
console.log(randInt(100, 200))
this._counter = init;
}
get counter() {
return this._counter;
}
increment(delta = 1) {
this._counter += delta;
}
}
let myWorker = vjmap3d.createWorker(MyClass, {
randInt: vjmap3d.randInt
});
let instance1, instance2;
async function showState() {
console.log(`instance1.counter = ${await instance1.counter},instance2.counter = ${await instance2.counter}`);
}
const MyWorkerClass = vjmap3d.workerWrap(myWorker);
instance1 = await new MyWorkerClass();
instance2 = await new MyWorkerClass(42);
await showState();
console.time("increment");
for (let i = 0; i < 100000; i++) {
await instance1.increment();
}
console.timeEnd("increment");
await showState();
myWorker.terminate();
// 输出结果
/**
0
199
42
177
instance1.counter = 0,instance2.counter = 42
increment: 7185.27685546875 ms
instance1.counter = 100000,instance2.counter = 42
*/
模型分解
对物体进行爆炸分解 explodeGroup
/** 对物体进行爆炸分解 */
function explodeGroup(group: Object3D) {
/** 爆炸分解 */
explode: (opts?: {
/** 动画时长(毫秒),默认 3000 */
time?: number;
/** 爆炸分解分解距离,默认 3 */
distance?: number;
/** 允许旋转 */
enableRotation?: boolean;
/** 动画类型 */
easing?: Easing;
}) => Promise<any>;
/** 还原 */
reset: (opts?: {
/** 动画时长(毫秒),默认 3000 */
time?: number;
/** 允许旋转:须与 explode 时传的一致,否则 explode 产生的旋转不会被还原 */
enableRotation?: boolean;
/** 动画类型 */
easing?: Easing;
}) => Promise<any>;
};
用法
let ent = await vjmap3d.ResManager.loadModel(env.assetsPath + "models/heart.glb", {
anchor: "middle-bottom",
position: [-1, 0, 1]
});
ent.addTo(app);
let ep = vjmap3d.explodeGroup(ent.node.children[0])
await ep.explode({
time: 3000
})
await ep.reset()
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
stat: { show: true, left: "0" },
scene: {
gridHelper: { visible: true }, // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
}
})
let ent = await vjmap3d.ResManager.loadModel(env.assetsPath + "models/heart.glb", {
anchor: "middle-bottom",
position: [-1, 0, 1]
});
ent.addTo(app);
let ep = vjmap3d.explodeGroup(ent.node.children[0])
for(let n = 0; n < 1000; n++) {
// 动画循环
await ep.explode({
time: 3000
})
await ep.reset()
}
拉伸Geojson多段线或多边形
拉伸多段线 extrudePolyline
拉伸多边形 extrudePolygon
拉伸GeoJson extrudeGeoJSON
用法
// 查询CAD图中的多段线进行拉伸
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
stat: { show: true, left: "0" },
scene: {
gridHelper: { visible: true } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
},
control: { leftButtonPan: true } // 设置为左键用于平移 (同时右键将用于旋转) 和地图2d使用习惯一样
})
let res = await app.svc.openMap({
mapid: env.exampleMapId, // 地图ID,(请确保此ID已存在,可上传新图形新建ID)
mapopenway: vjmap3d.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
style: vjmap3d.openMapDarkStyle()
});
if (res.error) {
showError(res.error);
return;
}
let provider = new vjmap3d.MapProvider(
[
{
url: app.svc.rasterTileUrl()
}
],
{
transparent: true
}
);
let mapBounds = vjmap3d.GeoBounds.fromString(res.bounds)
let scale = 100;
let mapviewEnt = new vjmap3d.MapViewEntity({
provider,
baseScale: scale,
mapBounds: mapBounds.toArray()
});
mapviewEnt.addTo(app);
//
let cadPrj = new vjmap3d.GeoProjection(mapBounds);
let query = await svc.conditionQueryFeature({
// https://vjmap.com/app/visual/#/query?mapid=sys_zp&version=v1&mapopenway=GeomRender&theme=dark
condition: ` name = "1" or name = "2"`, // 查询所有的多段线和直线
fields: "isclosed,points",
limit: 100000 //设置很大,相当于把所有的都查出来。不传的话,默认只能取100条
}, pt => {
// 查询到的每个点进行坐标处理回调
return cadPrj.fromMercator(pt);// 转成cad的坐标
})
let polylines = [];
if (query.error) {
showError(query.error);
return;
} else {
if (query.recordCount > 0) {
for(let i = 0; i < query.result.length; i++) {
let points = query.result[i].points;
let lines = points.split(";;");
for(let n = 0; n < lines.length; n++) {
let line = lines[n].split(";");
let pts = []
for(let pt of line) {
if (!pt) continue;
let p = vjmap3d.GeoPoint.fromString(pt);
let world = vjmap3d.toWorld([p.x, p.y]);
pts.push( [world.x, world.z])
}
if (pts.length >= 2) {
if (query.result[i].isclosed) {
// 闭合
pts.push(pts[0])
}
polylines.push(pts);
}
}
}
}
}
const geometry = new THREE.BufferGeometry();
const material = new THREE.MeshStandardMaterial({
// wireframe: true
});
const {position, normal, indices,uv, boundingRect} = vjmap3d.extrudePolyline(polylines, {
depth: 1,
lineWidth: 0.02,
bevelSize: 0.01,
bevelSegments: 0,
miterLimit: 2,
});
geometry.setAttribute('position', new THREE.Float32BufferAttribute(position, 3));
geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normal, 3));
geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uv, 2));
geometry.setIndex(new THREE.Uint32BufferAttribute(indices, 1));
//
const mesh = new THREE.Mesh(geometry, material);
let waveWallMat = vjmap3d.createFlowGradientMaterial(app, {
object: mesh,
lightScale: 0.1,
circleTime: 1,
lightColor: 0xffff00,
color: 0x00ffff,
topColor: 0x9FFCFD,
opacity: 1,
transparent: false,
//topOpacity: 0.6
});
// @ts-ignore
mesh.material = waveWallMat;
app.scene.add(mesh);
// 查询CAD图中的多段线进行拉伸
let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
let app = new vjmap3d.App(svc, {
container: "map", // 容器id
stat: { show: true, left: "0" },
scene: {
gridHelper: { visible: true } // 是否显示坐标网格
},
camera: { // 相机设置
viewHelper: { enable: true, position: "leftBottom" } // 是否显示视角指示器
},
control: { leftButtonPan: true } // 设置为左键用于平移 (同时右键将用于旋转) 和地图2d使用习惯一样
})
let res = await app.svc.openMap({
mapid: env.exampleMapId, // 地图ID,(请确保此ID已存在,可上传新图形新建ID)
mapopenway: vjmap3d.MapOpenWay.GeomRender, // 以几何数据渲染方式打开
style: vjmap3d.openMapDarkStyle()
});
if (res.error) {
showError(res.error);
return;
}
let provider = new vjmap3d.MapProvider(
[
{
url: app.svc.rasterTileUrl()
}
],
{
transparent: true
}
);
let mapBounds = vjmap3d.GeoBounds.fromString(res.bounds)
let scale = 100;
let mapviewEnt = new vjmap3d.MapViewEntity({
provider,
baseScale: scale,
mapBounds: mapBounds.toArray()
});
mapviewEnt.addTo(app);
//
let cadPrj = new vjmap3d.GeoProjection(mapBounds);
let query = await svc.conditionQueryFeature({
// https://vjmap.com/app/visual/#/query?mapid=sys_zp&version=v1&mapopenway=GeomRender&theme=dark
condition: ` name = "1" or name = "2"`, // 查询所有的多段线和直线
fields: "isclosed,points",
limit: 100000 //设置很大,相当于把所有的都查出来。不传的话,默认只能取100条
}, pt => {
// 查询到的每个点进行坐标处理回调
return cadPrj.fromMercator(pt);// 转成cad的坐标
})
let polylines = [];
if (query.error) {
showError(query.error);
return;
} else {
if (query.recordCount > 0) {
for(let i = 0; i < query.result.length; i++) {
let points = query.result[i].points;
let lines = points.split(";;");
for(let n = 0; n < lines.length; n++) {
let line = lines[n].split(";");
let pts = []
for(let pt of line) {
if (!pt) continue;
let p = vjmap3d.GeoPoint.fromString(pt);
let world = vjmap3d.toWorld([p.x, p.y]);
pts.push( [world.x, world.z])
}
if (pts.length >= 2) {
if (query.result[i].isclosed) {
// 闭合
pts.push(pts[0])
}
polylines.push(pts);
}
}
}
}
}
const geometry = new THREE.BufferGeometry();
const material = new THREE.MeshStandardMaterial({
// wireframe: true
});
const {position, normal, indices,uv, boundingRect} = vjmap3d.extrudePolyline(polylines, {
depth: 1,
lineWidth: 0.02,
bevelSize: 0.01,
bevelSegments: 0,
miterLimit: 2,
});
geometry.setAttribute('position', new THREE.Float32BufferAttribute(position, 3));
geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normal, 3));
geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uv, 2));
geometry.setIndex(new THREE.Uint32BufferAttribute(indices, 1));
//
const mesh = new THREE.Mesh(geometry, material);
let waveWallMat = vjmap3d.createFlowGradientMaterial(app, {
object: mesh,
lightScale: 0.1,
circleTime: 1,
lightColor: 0xffff00,
color: 0x00ffff,
topColor: 0x9FFCFD,
opacity: 1,
transparent: false,
//topOpacity: 0.6
});
// @ts-ignore
mesh.material = waveWallMat;
app.scene.add(mesh);