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)); // 将参数数组转换成点数组的形式
// 方法一:自定义三维路径 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.5m³', ],
['进水电导:', '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)