3D-Demo/1_wind/index.html

555 lines
16 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>风机Demo</title>
<style>
body {
margin:0;
overflow: hidden;
color: #FFF;
position: relative
/* 隐藏body窗口区域滚动条 */
}
.header-box{
width: 100%;
height: 126px;
position:absolute;
background: url(./assets/images/header-bg.png) no-repeat;
background-size: 100% 100%;
top: -30px;
z-index: 200;
}
.titile{
font-size: 36px;
margin-top: 40px;
font-weight: 500;
font-family: FZLanTingHeiS-B-GB;
text-align: center;
}
.echarts-box{
height: 28vh;
width: 35.08vw;
left: 20px;
bottom: 40px;
position:absolute
}
.equipmentLabel {
z-index: 999;
width: 988px;
height: 451px;
}
.equipmentLabel > li:nth-child(1) {
color: transparent;
width: 191px;
height: 225px;
background-image: url("./assets/images/1.png");
background-size: 191px auto;
position: absolute;
right: 302px;
top: 0;
}
.equipmentLabel .labelInfo {
color: transparent;
width: 302px;
height: 225px;
background-image: url("./assets/images/2.png");
background-size: 302px auto;
position: absolute;
right: 0;
top: 0;
padding: 10px;
box-sizing: border-box;
}
.equipmentLabel .labelInfo > div {
width: 100%;
height: 100%;
background-color: #04669e73;
border: 1px solid #15c5e8;
box-sizing: border-box;
padding: 20px 20px;
}
.equipmentLabel .labelInfo > div header {
width: 100%;
text-align: left;
font-size: 14px;
line-height: 20px;
color: #fff;
border-bottom: 1px dashed aqua;
padding-bottom: 14px;
}
.equipmentLabel .labelInfo > div header .en {
font-size: 12px;
color: aqua;
}
.equipmentLabel .labelInfo > div ul {
width: 100%;
color: #fff;
}
.equipmentLabel .labelInfo > div ul li {
line-height: 30px;
font-size: 14px;
display: flex;
text-align: left;
align-items: center;
}
.equipmentLabel .labelInfo > div ul li span:nth-child(1) {
width: 40%;
}
.equipmentLabel .labelInfo > div ul li span:nth-child(2) {
width: 15%;
color: #f0c002;
text-align: right;
margin-right: 10px;
}
.equipmentLabel .labelInfo > div ul li span:nth-child(3) {
width: 30%;
}
</style>
<!-- 引入echarts文件 -->
<script src="./assets/js/echarts.min.js"></script>
</head>
<body style="background-color: #030B1A;">
<div class="header-box">
<div class="titile">智慧风机监测系统</div>
</div>
<div class="echarts-box"></div>
<!-- 我们将把three.js渲染的效果显示在这个div中div为容器 -->
<div id="puiedu-webgl-output" ></div>
<!-- 2D信息弹窗 -->
<ul id='equipmentLabelRef' class='equipmentLabel' >
<li></li>
<li class='labelInfo' >
<div>
<header>
<div id="cn">{labelData.cn}</div>
<span id="en">{labelData.en}</span>
</header>
<ul id="valueUl"></ul>
</div>
</li>
</ul>
<script type="module">
import * as THREE from "../src/Three.js"
import { GLTFLoader } from '../jsm/loaders/GLTFLoader.js';
import { OrbitControls } from '../jsm/controls/OrbitControls.js';
//后处理js
// EffectComposer(效果组合器)对象
import { EffectComposer } from '../jsm/postprocessing/EffectComposer.js'
// RenderPass该通道在指定的场景和相机的基础上渲染出一个新场景
import { RenderPass } from '../jsm/postprocessing/RenderPass.js'
import { OutlinePass } from '../jsm/postprocessing/OutlinePass.js'
//2D信息
import {CSS2DRenderer,CSS2DObject} from "../jsm/renderers/CSS2DRenderer.js";
//导入模拟数据
import {labelData} from './assets/labelData/labelData.js'
/*
*定义变量
*/
const scale = 0.0003
let size = {
w: window.innerWidth,
h: window.innerHeight
}
//存储各个部件
let equipmentMaterialMap = new Map()
//风机涡轮转动参数
let matrixTurbine = null
//颜色材质
let metal = null
//线框材质
let wireframe = null
//动画帧
let mixers = new Map()
//创建一个动画时钟对象Clock
let clock = new THREE.Clock()
let mixer = null
/*
*点击事件相关变量
*/
//获取所有内部结构网格对象,用于判断射线相交对象
let equipment = null
//鼠标点击-屏幕坐标
let mouse = new THREE.Vector2();
//用于检测的射线
let raycaster = new THREE.Raycaster();
//效果组合
let compose = null
//弹出信息框总数据
let equipmentLabelData = labelData()[0]
//当前选中模型的数据
let nowLabelData = null
let labelCSS2D = null
//创建场景对象
var scene = new THREE.Scene()
//创建相机
var camera = createdCamera(30, size.w, size.h, [-4, -3.5, 4], 1)
//创建光源
createdLight()
//创建渲染器
var renderer = createdRender()
//信息窗2D渲染器
let labelRenderer = createTurbineLabel()
// 辅助坐标系 参数250表示坐标系大小可以根据场景大小去设置
// var axesHelper = new THREE.AxesHelper(250)
// scene.add(axesHelper)
//加载地板
loadPlane()
//加载内部结构
loadEquipment()
//加载外壳涡轮
loadTurbine()
//执行渲染
render()
//鼠标操作
mouseMove()
/*
*创建相机
*/
function createdCamera(fov,width,height,position,zoom){
var camera = new THREE.PerspectiveCamera(fov,width/height,0.1,1000,zoom)
camera.position.set(position[0],position[1],position[2])
return camera
}
/*
*创建光源
*/
function createdLight(){
const arr = [
[100,100,100],
[-100,100,100],
[100,-100,100]
]
arr.forEach(lightArr=>{
let spotLight = new THREE.DirectionalLight(0xffffff,3)
let [x,y,z] = lightArr
spotLight.position.set(x, y, z);
scene.add(spotLight);
})
}
//渲染器
function createdRender() {
let renderer = new THREE.WebGLRenderer({antialias: true, alpha: true})
renderer.shadowMap.enabled = true
renderer.setSize(size.w,size.h)
renderer.setClearColor(0x030B1A)
//获取容器,并加入渲染器
document.getElementById('puiedu-webgl-output').appendChild(renderer.domElement)
return renderer
}
//加载地板
function loadPlane(){
const loader = new GLTFLoader();
loader.load('assets/models/plane.glb',(obj)=>{
let mesh = obj.scene
mesh.scale.set(scale,scale,scale)
mesh.position.set(0,-2,0)
scene.add(mesh)
})
}
//加载内部结构
function loadEquipment(){
const loader = new GLTFLoader();
loader.load('assets/models/equipment.glb',(obj)=>{
let mesh = obj.scene
mesh.name = 'equipment'
//将网格对象给equipment用于鼠标点击时检测与射线相交的物体
equipment = mesh
console.log("内部结构equipment",equipment)
mesh.traverse(child =>{
if (child.isMesh) {
child.material = child.material.clone()
equipmentMaterialMap.set(child.name,child)
}
})
mesh.scale.set(scale,scale,scale)
mesh.position.set(0,-2,0)
scene.add(mesh)
})
}
//加载外壳涡轮
function loadTurbine(){
const loader = new GLTFLoader();
if (scene.getObjectByName('turbine')) {
let removeTurbine = scene.getObjectByName('turbine')
scene.remove(removeTurbine)
}
loader.load('assets/models/turbine.glb',(obj)=>{
console.log("模型",obj)
matrixTurbine = obj
let mesh = obj.scene
mesh.name = 'turbine'
metal = mesh.getObjectByName('颜色材质')
wireframe = mesh.getObjectByName('线框材质')
//设置颜色材质的显示和隐藏
metal.visible = false
mesh.scale.set(scale, scale, scale)
mesh.position.set(0,-2,0)
scene.add(mesh)
changeAnimation(mesh,'Anim_0')
})
}
//风机旋转动画
function changeAnimation(turbine,animationName){
const animations = matrixTurbine.animations
//创建混合器播放turbine包含的帧动画数据
mixer = new THREE.AnimationMixer(turbine)
//AnimationClip 是一组可重复使用的关键帧轨迹,代表一个动画
const clip = THREE.AnimationClip.findByName(animations,animationName)
const key = "AA"
if (clip) {
const action = mixer.clipAction(clip)
action.play()
mixers.set(key, mixer)
}else{
mixers.delete(key)
}
}
//鼠标点击事件
function onPointerClick(event) {
const [w,h] = [window.innerWidth,window.innerHeight]
mouse.x = (event.clientX / w) * 2 - 1
mouse.y = -(event.clientY / h) * 2 + 1
//更新射线
raycaster.setFromCamera(mouse, camera)
console.log('参数',equipment)
//返回被击中的信息
const intersects = raycaster.intersectObject(equipment, true)
if (intersects.length <= 0) {
return false;
}
const selectedObject = intersects[0].object
if (selectedObject.isMesh) {
outline([selectedObject])
//显示弹窗
updateLabel(intersects[0],equipmentLabelData[selectedObject.name])
}
}
//点击后高亮线框渲染
function outline(selectedObjects,color = 0x15c5e8) {
const [w,h] = [window.innerWidth,window.innerHeight]
//RenderPass这个通道会渲染场景但不会将渲染结果输出到屏幕上
let renderPass = new RenderPass(scene,camera)
//高亮数据
let outlinePass = new OutlinePass(
new THREE.Vector2(w,h),//分辨率
scene,
camera,
selectedObjects//选中的物体对象,传入需要边界线进行高亮处理的对象
)
outlinePass.renderToScreen = true
outlinePass.selectedObjects = selectedObjects
outlinePass.edgeStrength = 3//粗
outlinePass.edgeGlow = 0//发光
outlinePass.visibleEdgeColor.set(color);//设置显示的颜色
outlinePass.hiddenEdgeColor.set(color);//设置隐藏的颜色
//创建效果组合器对象,可以在该对象上添加后期处理通道,通过配置该对象,
//使它可以渲染我们的场景并应用额外的后期处理步骤在render循环中
//使用EffectComposer渲染场景、应用通道并输出结果
compose = new EffectComposer(renderer)
compose.addPass(renderPass)
compose.addPass(outlinePass)
compose.render(scene,camera)
}
//创建2D信息窗
function createTurbineLabel(){
let labelRenderer = new CSS2DRenderer();
labelRenderer.setSize( window.innerWidth, window.innerHeight );
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0px';
document.body.appendChild( labelRenderer.domElement );
labelCSS2D = new CSS2DObject(document.getElementById('equipmentLabelRef'));
scene.add(labelCSS2D);
labelCSS2D.visible = false
return labelRenderer
// labelCSS2D.element.addEventListener('click',()=>{
// consoe.log("dianji")
// labelCSS2D.visible = false
// })
}
//更新信息窗位置
function updateLabel(intersect,labelData){
var cnDiv = document.getElementById('cn')
cnDiv.innerHTML = labelData.cn
var enDiv = document.getElementById('en')
enDiv.innerHTML = labelData.en
var str = ""
labelData.list.forEach(item=>{
str+= `<li>
<span>${item.name}</span>
<span>${item.value}</span>
<span>${item.unit}</span>
</li>`
})
document.getElementById('valueUl').innerHTML=str
const point = intersect.point;
labelCSS2D.position.set(point.x-0.01, point.y+0.01, point.z-0.03);
labelCSS2D.visible = true
}
/*
*执行渲染
*/
function render(){
//执行渲染操作
if (scene && camera) {
renderer.render(scene,camera)
labelRenderer.render(scene,camera)
}
// 用于跟踪时间的对象
const delta = new THREE.Clock().getDelta(); //获取自设置 oldTime 时间以来经过的秒数,并将 oldTime 设置为当前时间在此delta基本为0
if (compose) {
compose.render(delta);
}
requestAnimationFrame(render)
//获得两帧的时间间隔
const mixerUpdateDelta = clock.getDelta();
//更新混合器相关的时间
mixers.forEach(mixer =>{
mixer.update(mixerUpdateDelta)
})
}
/*
*鼠标操作-放大、缩小、旋转
*/
function mouseMove(){
//创建控件对象
var controls = new OrbitControls(camera,labelRenderer.domElement)
//初始化鼠标点击事件
document.addEventListener("click", onPointerClick);
}
/*
*三维场景自适应
*/
window.addEventListener('resize',onWindowResize,false)
function onWindowResize(){
camera.aspect = window.innerWidth/window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth,window.innerHeight)
labelRenderer.setSize( window.innerWidth, window.innerHeight );
}
</script>
<script type="module">
//初始化echarts实例
var myChart = echarts.init(document.querySelector(".echarts-box"))
//制定图表的配置项和数据
var options = {
title: {
text: '风机功率和风速折线图',
textStyle:{
color:'#fffff0',
fontSize : 16,
},
left : 5
},
tooltip: {
trigger: "axis",
},
legend: {
textStyle:{
color:'#ffffff'
},
data: ['功率', '风速']
},
grid: {
left: 10,
right: 10,
bottom: 20,
top: 30,
containLabel: true,
},
xAxis: {
name: "时间/小时",
type: "category",
// boundaryGap: false,
data: ["1", "3", "5", "7", "9", "11", "13","15", "17", "19", "21", "23"],
axisLine: {
// show: false,
lineStyle: {
color: "#028ab5ad",
},
},
},
yAxis: {
// name: "风速/功率",
type: "value",
axisLine: {
show: false,
lineStyle: {
color: "#028ab5ad",
},
},
splitLine: {
lineStyle: {
color: ["#028ab545"],
},
},
},
series: [
{
name: "功率",
type: "line",
data: [12, 6, 13, 5, 18, 15, 8,2, 4, 12, 15, 10],
lineStyle: {
color: "#15c5e8",
},
itemStyle: {
normal: {
color: "#15c5e8",
},
},
},
{
name: "风速",
type: "line",
// stack: "总量",
data: [2, 4, 12, 15, 10, 11, 5,12, 6, 13, 5, 18],
lineStyle: {
color: "#c8a818",
},
itemStyle: {
normal: {
color: "#c8a818",
},
},
},
],
}
//使用刚指定的配置项和数据显示图表
myChart.setOption(options)
</script>
</body>
</html>