1,介绍
使用这个例子 r95版本Three.js库。
主要功能:引用水厂模型显示,模拟水流效果,动态显示数据信息。效果图如下:

2,主要说明
1.加载模型设置模型的颜色效果,并添加到场景中。
2.创建管道并添加纹理。在这里,您可以查看上一篇文章。
3.添加标签并实时刷新渲染实时数据
引入模型设置颜色效果并添加到场景中,只介绍添加模型的方法
function initShuiChang() { var loader = new THREE.GLTFLoader(); // assets/models/fang/shapan.glb' loader.load('assets/models/shuichang/shuichang.glb', function(result) { var object = result.scene; console.log(object) object.traverse(function(item) { if (item instanceof THREE.Mesh) { item.material.color.set(0x1DA9FC); item.material.transparent = true; item.material.opacity = 0.5; } }); object.scale.set(2, 2, 2); object.rotateY(3.14); scene.add(object); }); }
添加标签并实时刷新渲染实时数据
function createPath(pointsArr) { pointsArr = pointsArr.map((point) => new THREE.Vector3(...point)); // 将参数组转换为点数组 // 方法1:自定义三维路径 curvePath const path = new THREE.CurvePath(); for (let i = 0; i < pointsArr.length - 1; i ) { const lineCurve = new THREE.LineCurve3(pointsArr[i], pointsArr[i 1]); // 每两点之间形成一条三维直线 path.curves.push(lineCurve); // curvePath有一个curves属性,存储在构成三维路径的每个子路径中 } return path; } const count = 200 const gColor = '#28f260' const prop1 = { width: 416, height: 112, pos: [60, 35, 30], // scale:[24, 6, 0] scale: [0.24375 * count, 0.065625 * count, 0] } const tab1 = [ 一级高压泵后压力: '20.2bar', gColor], 一级循环泵后压力: '0.2bar', ] ] const prop2 = { width: 352, height: 196, pos: [-60, 40, 0], scale: [0.20625 * count, 0.11484375 * count, 0], } const tab2 = [ [进水情况’, ''], 进水温度: '25.6℃', gColor], 进水流量: '2.5m3', ], 进水电导: '28.5ms/cm', gColor], ] const prop3 = { width: 384, height: 256, pos: [5, 60, -60], scale: [0.225 * count, 0.15 * count, 0] } const tab3 = [ [产水情况, ''], 一级回收率: '58%', gColor], 一级产水流量: '1.75㎡', ], 一级产水电量: '980.5/cm', gColor], 一级产水电量: '0.5bar', gColor], ] const prop4 = { width: 256, height: 64, pos: [-85, 30, 40], scale: [0.15 * count, 0.0375 * count, 0], } const tab4 = [ [泵机状态 ', '? 开启', gColor], ] const prop5 = { width: 256, height: 64, pos: [-10, 50, 30], scale: [0.15 * count, 0.0375 * count, 0], } const tab5 = [ [阀门状态 ', '? 开启', gColor], ] const props = [prop1, prop2, prop3, prop4, prop5] const tabs = [tab1, tab2, tab3, tab4, tab5] // 调用渲染标签,并定时刷新 handleDatachange(); setInterval(handleDatachange, 2000) function handleDatachange() { let r = (Math.random() * 10 20).toFixed(2) tab2[1][1] = r '℃' if (r > 25) tab2[1][2] = 'red' else tab2[1][2] = gColor r = Math.random().toFixed(2) tab3[4][1] = r 'bar' if (r > 0.5) tab3[4][2] = 'red'; else tab3[4][2] = gColor if (Math.random() > 0.5) { tab5[0][1] = '? 开启' tab5[0][2] = gColor } else { tab5[0][1] = '? 关闭' tab5[0][2] = 'red' } console.time('render sprite') initSprite() console.timeEnd('render sprite') } function initSprite() { clearSprite(); (scene.children || []).forEach((v, idx) => { if (v.type == 'Mesh') { const borderColor = 'rgba(39, 179, 236, 1)' const color = 'rgba(255,255,255, 1)' makeTextSprite(scene, tabs, props, { color: color, borderColor, backgroundColor: 'rgba(255,255,255,0.05)' }); } }); } // 清空雪碧图 function clearSprite(type = 'Sprite') { const children = []; (scene.children || []).forEach((v, idx) => { if (v.type !== type) { children.push(v); } }); scene.children = children; }
/* 创造字体精灵 */ function makeTextSprite(scene, tabs, props, parameters) { if (parameters === undefined) parameters = {} tabs.forEach((tab, k) => { let { width, height } = props[k] /* 创建画布 */ let canvas = document.createElement('canvas'); let context = canvas.getContext('2d') canvas.width = width canvas.height = height let gap = 10 let fontface = parameters.hasOwnProperty("fontface") ? parameters["fontface"] : "sans-serif" /* 字体大小 */ let fontsize = parameters.hasOwnProperty("fontsize") ? parameters["fontsize"] : 30 let color = parameters.hasOwnProperty("color") ? parameters["color"] : 'rgba(0, 0, 0, 1.0)' /* 边框厚度 */ let borderWith = parameters.hasOwnProperty("borderWith") ? parameters["borderWith"] : 2 /* 边框颜色 */ let borderColor = parameters.hasOwnProperty("borderColor") ? parameters["borderColor"] : { r: 0, g: 0, b: 0, a: 1.0 } /* 背景颜色 */ let backgroundColor = parameters.hasOwnProperty("backgroundColor") ? parameters["backgroundColor"] : { r: 255, g: 255, b:255,
a: 1.0
}
/* 字体加粗 */
// context.font = "Bold " + fontsize + "px " + fontface
context.font = fontsize + "px " + fontface
let unit = gap + fontsize
/* 背景颜色 */
context.fillStyle = backgroundColor
/* 边框的颜色 */
context.strokeStyle = borderColor
context.lineWidth = borderWith
/* 绘制圆角矩形 */
roundRect(context, gap, gap, width - gap, height - gap, 4)
tab.forEach((d, i) => {
context.fillStyle = color;
context.fillText(d[0], gap * 2, gap + unit * (i + 1))
if (d[2]) {
context.fillStyle = d[2]
}
context.fillText(d[1], gap * 2 + measureText(d[0], context), gap + unit * (i + 1))
})
/* 画布内容用于纹理贴图 */
let texture = new THREE.Texture(canvas);
texture.needsUpdate = true
let spriteMaterial = new THREE.SpriteMaterial({
map: texture,
// sizeAttenuation:false,
// transparent:true
});
let sprite = new THREE.Sprite(spriteMaterial)
// console.log(sprite.spriteMaterial)
/* 缩放比例 */
sprite.scale.set(...props[k].scale)
sprite.center = new THREE.Vector2(0, 0);
scene.add(sprite);
sprite.position.set(...props[k].pos);
})
}
function measureText(text, ctx, font) {
if (font) ctx.font = font
return ctx.measureText(text).width;
}
/* 绘制圆角矩形 */
function roundRect(ctx, x, y, w, h, r) {
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.lineTo(x + w - r, y);
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
ctx.lineTo(x + w, y + h - r);
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
ctx.lineTo(x + r, y + h);
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
ctx.lineTo(x, y + r);
ctx.quadraticCurveTo(x, y, x + r, y);
ctx.closePath();
// ctx.shadowColor = "#qb95cf";
// ctx.shadowOffsetX = 0;
// ctx.shadowOffsetY = 0;
// ctx.shadowBlur = 4;
ctx.fill();
ctx.stroke();
ctx.shadowColor = "";
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = 0;
}
在线预览:左本的博客 (zuoben.top)