Threejs物联网,工厂3D可视化,加载模型,水流监测,标签动态数据展示

9 篇文章 4 订阅

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) 

  • 5
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
### 回答1: three.js物联网3d可视化是一种现代化的技术,利用三维模型和图形化界面来展示物联网设备的数据和状态。对于粮仓等储藏性质的设备而言,可采用这种技术进行实时的监控和管理,从而极大的提升了粮仓的运维效率和安全性。 粮仓案例源码是基于three.js物联网3d可视化技术开发的,利用现代化的WebGL技术,实现了粮仓3d可视化界面的设计和搭建。该源码采用基于前端技术的开发方式,充分发挥Web端数据可视化交互性的优势。 该源码提供了丰富的功能模块,包括粮仓结构的构建、粮仓温湿度数据的采集、数据可视化展示和粮仓灾害预警等功能。通过该源码,用户可以实现多种交互式操作,包括缩放、旋转、拖拽等,来实时查看粮仓内部的情况,提高数据可视化程度。 综上所述,粮仓案例源码为用户提供了一种高效、可靠的监控和管理方式,有助于提升粮仓运维的效率、安全性和可靠性。该技术在粮仓等储藏性质的行业应用广泛。 ### 回答2: 物联网3D可视化技术在实际应用中,与人们的生活息息相关。其中,粮仓案例源码是一个非常实用的应用案例。 该案例源码基于Three.js开发,可以在浏览器中通过3D可视化展示粮食仓库的储存情况。通过该案例,我们可以清晰地了解到每一个仓库中的粮食储量情况,从而可以方便地管理粮食的存储、领取以及补充等方面。 在该案例中,设计师采用了人性化的UI设计,使得用户可以轻松地进行各项操作。同时,其交互操作也非常简单自然。不仅如此,该案例的源码还非常规范,代码结构相当清晰,便于阅读与修改。值得一提的是,该案例也有详细的开发文档,为有意愿学习或者开发的用户提供了很好的指导。 总体来说,该粮仓案例源码是一个具有实践意义的案例,其代码规范、可读性以及人性化的UI,都体现了其开发者的专业素养和工作态度,是物联网3D可视化技术方面的一个难得的优秀案例。 ### 回答3: 粮仓案例是利用three.js技术实现的一种物联网3D可视化方案。这种方案主要是针对对粮仓的物理参数进行数据采集和计算,然后通过传感器将数据发送到控制器,控制器可将数据转换为3D可视化图像。这种方案可用于实时监测粮仓内温度、湿度、质量等参数,及时发现异常情况并进行处理。 源码方面,这个项目主要使用了JavaScript编程语言和three.js库进行开发。整个项目代码非常详细,包括三维建模、数据采集、传感器接口配置、数据可视化等多个部分。此外,源码还提供了详细的说明和注释,方便技术人员进行开发和调试。 这个案例的优势在于它结合了物联网3D可视化技术。通过物联网,可以实现对粮仓内多参数的实时监测数据采集;而通过three.js库,可以将这些采集到的数据转换为生动的3D模型,提供更好的可视化效果。此外,这个案例还具有高度的可扩展性和可定制性,可以针对不同行业和应用场景进行定制开发。 总之,这个案例是物联网3D可视化技术的有力实践,推动了这两种技术的结合与发展,对于实现智能化系统具有重要意义。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

左本Web3D

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值