熱圖
This commit is contained in:
parent
bc31e9134c
commit
6d3b82ec89
24
public/config.json
Normal file
24
public/config.json
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"heatmap": {
|
||||||
|
"temp": {
|
||||||
|
"range": [0, 50],
|
||||||
|
"color": ["#0023F5", "#FF1C05"],
|
||||||
|
"unit": "°C"
|
||||||
|
},
|
||||||
|
"humi": {
|
||||||
|
"range": [15, 95],
|
||||||
|
"color": ["#ADD8E6", "#00008B"],
|
||||||
|
"unit": "%"
|
||||||
|
},
|
||||||
|
"CO2": {
|
||||||
|
"range": [0, 5000],
|
||||||
|
"color": ["#FFDAB9", "#FF8C00"],
|
||||||
|
"unit": "ppm"
|
||||||
|
},
|
||||||
|
"CO": {
|
||||||
|
"range": [0, 1000],
|
||||||
|
"color": ["#FFFFE0", "#FFD700"],
|
||||||
|
"unit": "ppm"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@ import useSystemStatusByBaja from "@/hooks/baja/useSystemStatusByBaja";
|
|||||||
import ForgeInfoModal from "../../views/system/components/SystemInfoModal.vue";
|
import ForgeInfoModal from "../../views/system/components/SystemInfoModal.vue";
|
||||||
import useAlarmStore from "@/stores/useAlarmStore";
|
import useAlarmStore from "@/stores/useAlarmStore";
|
||||||
import useForgeSprite from "@/hooks/forge/useForgeSprite";
|
import useForgeSprite from "@/hooks/forge/useForgeSprite";
|
||||||
|
import useHeatmapBarStore from "@/stores/useHeatmapBarStore";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
initialData: Object,
|
initialData: Object,
|
||||||
@ -27,11 +28,7 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const store = useHeatmapBarStore();
|
||||||
const heat_bar_isShow = ref(false);
|
|
||||||
const updateHeatBarIsShow = (isShow) => {
|
|
||||||
heat_bar_isShow.value = isShow;
|
|
||||||
};
|
|
||||||
|
|
||||||
const { updateDataVisualization, createSprites, showSubSystemObjects, forgeClickListener, clear } = useForgeSprite()
|
const { updateDataVisualization, createSprites, showSubSystemObjects, forgeClickListener, clear } = useForgeSprite()
|
||||||
|
|
||||||
@ -92,9 +89,10 @@ const loadModel = (viewer, filePath) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// const loadModel = (viewer, urn) => {
|
// const loadModel = (viewer) => {
|
||||||
// return new Promise(function (resolve, reject) {
|
// return new Promise(function (resolve, reject) {
|
||||||
// async function onDocumentLoadSuccess(doc) {
|
// async function onDocumentLoadSuccess(doc) {
|
||||||
|
// console.log("模型加載完成");
|
||||||
// viewer.setGroundShadow(false);
|
// viewer.setGroundShadow(false);
|
||||||
// viewer.impl.renderer().setClearAlpha(0); //clear alpha channel
|
// viewer.impl.renderer().setClearAlpha(0); //clear alpha channel
|
||||||
// viewer.impl.glrenderer().setClearColor(0xffffff, 0); //set transparent background, color code does not matter
|
// viewer.impl.glrenderer().setClearColor(0xffffff, 0); //set transparent background, color code does not matter
|
||||||
@ -201,22 +199,18 @@ onUnmounted(() => {
|
|||||||
<template>
|
<template>
|
||||||
<ForgeInfoModal :data="currentInfoModalData" />
|
<ForgeInfoModal :data="currentInfoModalData" />
|
||||||
<div id="forge-preview" ref="forgeDom" class="relative w-full h-full min-h-full">
|
<div id="forge-preview" ref="forgeDom" class="relative w-full h-full min-h-full">
|
||||||
<div v-show="heat_bar_isShow" class="absolute z-10 heatbar">
|
<div v-show="store.heat_bar_isShow" class="absolute z-10 heatbar">
|
||||||
<div class="w-40 flex justify-between text-[10px] mb-1">
|
<div class="w-40 flex justify-between text-[10px] mb-1">
|
||||||
<span class="text-gradient-1">10 °C</span>
|
<span v-for="value in store.heatmapConfig?.range" class="text-gradient-1">{{ value }} {{
|
||||||
<span class="text-gradient-2">20 °C</span>
|
store.heatmapConfig?.unit }}</span>
|
||||||
<span class="text-gradient-3">30 °C</span>
|
|
||||||
<span class="text-gradient-4">40 °C</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="w-40 h-3" style="
|
<div class="w-40 h-3" :style="{
|
||||||
background: linear-gradient(
|
background: `linear-gradient(
|
||||||
to right,
|
to right,
|
||||||
#0000ff 0%,
|
${store.heatmapConfig?.color[0]} 0%,
|
||||||
#00ff00 33%,
|
${store.heatmapConfig?.color[1]} 100%
|
||||||
#ffff00 66%,
|
)`
|
||||||
#ff0000 100%
|
}"></div>
|
||||||
);
|
|
||||||
"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- label -->
|
<!-- label -->
|
||||||
<!-- https://github.com/augustogoncalves/forge-plant-operation/blob/master/forgeSample/wwwroot/js/iconExtension.js -->
|
<!-- https://github.com/augustogoncalves/forge-plant-operation/blob/master/forgeSample/wwwroot/js/iconExtension.js -->
|
||||||
@ -268,7 +262,7 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.heatbar {
|
.heatbar {
|
||||||
right: v-bind("`${props.cubeStyle.right + 2}%`") !important;
|
/* right: v-bind("`${props.cubeStyle.right + 2}%`") !important; */
|
||||||
top: 0% !important;
|
top: 0% !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
import { watch, inject, markRaw, ref } from "vue";
|
import { watch, inject, markRaw, ref, computed, onMounted } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
|
import useHeatmapBarStore from "@/stores/useHeatmapBarStore";
|
||||||
|
import useSystemShowData from "@/hooks/useSystemShowData";
|
||||||
|
|
||||||
export default function useForgeHeatmap() {
|
export default function useForgeHeatmap() {
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { subscribeData, realtimeData } = inject("system_deviceList");
|
const { subscribeData, realtimeData } = inject("system_deviceList");
|
||||||
|
|
||||||
|
const store = useHeatmapBarStore();
|
||||||
|
|
||||||
const forgeViewer = ref(null);
|
const forgeViewer = ref(null);
|
||||||
const dataVizExtn = ref(null);
|
const dataVizExtn = ref(null);
|
||||||
const updateViewExtension = (viewer, dataVisualization) => {
|
const updateViewExtension = (viewer, dataVisualization) => {
|
||||||
@ -17,12 +21,27 @@ export default function useForgeHeatmap() {
|
|||||||
const dev = realtimeData.value.find(
|
const dev = realtimeData.value.find(
|
||||||
({ device_number }) => device_number === device.id
|
({ device_number }) => device_number === device.id
|
||||||
);
|
);
|
||||||
const point = dev.data.find(({ point }) => point === route.query?.gas);
|
if (dev) {
|
||||||
console.log(9, device, dev, point);
|
const [min, max] = store.heatmapConfig?.range;
|
||||||
|
const point = dev.data.find(({ point }) => point === route.query?.gas);
|
||||||
|
console.log(9, device, dev, point, (point?.value - min || 0) / max);
|
||||||
|
|
||||||
return (point?.value || 0) / 40;
|
return Math.random();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { flatSubData } = useSystemShowData();
|
||||||
|
|
||||||
|
const data = computed(() =>
|
||||||
|
flatSubData.value?.map((d) => ({
|
||||||
|
...d,
|
||||||
|
...Object.fromEntries(
|
||||||
|
d.points.map(({ point, value }) => [point, 0]) || []
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => realtimeData,
|
() => realtimeData,
|
||||||
() => {
|
() => {
|
||||||
@ -45,29 +64,53 @@ export default function useForgeHeatmap() {
|
|||||||
SurfaceShadingNode,
|
SurfaceShadingNode,
|
||||||
SurfaceShadingGroup,
|
SurfaceShadingGroup,
|
||||||
} = Autodesk.DataVisualization.Core;
|
} = Autodesk.DataVisualization.Core;
|
||||||
const shadingGroup = new SurfaceShadingGroup(`${heatMapName}_group`);
|
const shadingGroup = new SurfaceShadingGroup(`${heatMapName}`);
|
||||||
const rooms = new Map();
|
const rooms = new Map();
|
||||||
|
|
||||||
subscribeData.value.forEach(
|
const roomSet = new Set(data.value.map(({ room_dbid }) => room_dbid));
|
||||||
({
|
|
||||||
device_number: id,
|
// 每個room是一個node
|
||||||
room_dbid: roomDbId,
|
[...roomSet].forEach((roomDbId) => {
|
||||||
device_coordinate_3d: position,
|
if (!roomDbId) {
|
||||||
sensorTypes,
|
return;
|
||||||
}) => {
|
|
||||||
if (!id || roomDbId == -1 || !roomDbId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!rooms.has(roomDbId)) {
|
|
||||||
const room = new SurfaceShadingNode(id, roomDbId);
|
|
||||||
shadingGroup.addChild(room);
|
|
||||||
rooms.set(roomDbId, room);
|
|
||||||
}
|
|
||||||
const room = rooms.get(roomDbId);
|
|
||||||
room.addPoint(new SurfaceShadingPoint(id, position, sensorTypes));
|
|
||||||
}
|
}
|
||||||
);
|
const room = new SurfaceShadingNode(`room_${roomDbId}`, roomDbId);
|
||||||
const shadingData = new SurfaceShadingData(`${heatMapName}_data`);
|
|
||||||
|
//相同room內的設備
|
||||||
|
data.value
|
||||||
|
.filter(({ room_dbid }) => room_dbid === roomDbId)
|
||||||
|
.forEach(
|
||||||
|
({
|
||||||
|
device_number: id,
|
||||||
|
device_coordinate_3d: position,
|
||||||
|
sensorTypes,
|
||||||
|
}) =>
|
||||||
|
room.addPoint(new SurfaceShadingPoint(id, position, sensorTypes))
|
||||||
|
);
|
||||||
|
|
||||||
|
shadingGroup.addChild(room);
|
||||||
|
});
|
||||||
|
|
||||||
|
// data.value.forEach(
|
||||||
|
// ({
|
||||||
|
// device_number: id,
|
||||||
|
// room_dbid: roomDbId,
|
||||||
|
// device_coordinate_3d: position,
|
||||||
|
// sensorTypes,
|
||||||
|
// }) => {
|
||||||
|
// if (!id || roomDbId == -1 || !roomDbId) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if (!rooms.has(roomDbId)) {
|
||||||
|
// const room = new SurfaceShadingNode(id, roomDbId);
|
||||||
|
// shadingGroup.addChild(room);
|
||||||
|
// rooms.set(roomDbId, room);
|
||||||
|
// }
|
||||||
|
// const room = rooms.get(roomDbId);
|
||||||
|
// room.addPoint(new SurfaceShadingPoint(id, position, route.query.gas));
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
const shadingData = new SurfaceShadingData(`${heatMapName}`);
|
||||||
shadingData.addChild(shadingGroup);
|
shadingData.addChild(shadingGroup);
|
||||||
shadingData.initialize(forgeViewer.value?.model);
|
shadingData.initialize(forgeViewer.value?.model);
|
||||||
await dataVizExtn.value.setupSurfaceShading(
|
await dataVizExtn.value.setupSurfaceShading(
|
||||||
@ -75,25 +118,24 @@ export default function useForgeHeatmap() {
|
|||||||
shadingData
|
shadingData
|
||||||
);
|
);
|
||||||
dataVizExtn.value.registerSurfaceShadingColors(
|
dataVizExtn.value.registerSurfaceShadingColors(
|
||||||
heatMapName,
|
route.query?.gas,
|
||||||
[0x0000ff, 0x00ff00, 0xffff00, 0xff0000]
|
store.heatmapConfig?.color
|
||||||
);
|
);
|
||||||
dataVizExtn.value.renderSurfaceShading(
|
dataVizExtn.value.renderSurfaceShading(
|
||||||
heatMapName,
|
heatMapName,
|
||||||
route.query.gas,
|
route.query?.gas,
|
||||||
getSensorValue
|
getSensorValue
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => route.query,
|
data,
|
||||||
(newValue, oldValue) => {
|
(newValue, oldValue) => {
|
||||||
if (newValue.gas !== oldValue.gas) {
|
debugger;
|
||||||
// createHeatMap(newValue.gas);
|
dataVizExtn.value?.removeSurfaceShading();
|
||||||
} else if (!newValue.gas) {
|
createHeatMap(route.query.gas);
|
||||||
dataVizExtn.value?.removeSurfaceShading();
|
},
|
||||||
}
|
{ deep: true }
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return { createHeatMap, updateViewExtension };
|
return { createHeatMap, updateViewExtension };
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import { watch, inject, markRaw, ref, computed, provide } from "vue";
|
import { watch, inject, markRaw, ref, computed, provide } from "vue";
|
||||||
import useAlarmStore from "@/stores/useAlarmStore";
|
import useAlarmStore from "@/stores/useAlarmStore";
|
||||||
import hexToRgb from "@/util/hexToRgb";
|
import hexToRgb from "@/util/hexToRgb";
|
||||||
import useSelectedFloor from "@/hooks/useSelectedFloor";
|
import useSystemShowData from "@/hooks/useSystemShowData"
|
||||||
import useForgeHeatmap from "./useForgeHeatmap";
|
import useForgeHeatmap from "./useForgeHeatmap";
|
||||||
import useForgeFloor from "./useForgeFloor";
|
import useForgeFloor from "./useForgeFloor";
|
||||||
|
|
||||||
export default function useForgeSprite() {
|
export default function useForgeSprite() {
|
||||||
const store = useAlarmStore();
|
|
||||||
const { subscribeData } = inject("system_deviceList");
|
const { subscribeData } = inject("system_deviceList");
|
||||||
const { getCurrentInfoModalData, clearSelectedDeviceInfo } = inject(
|
const { getCurrentInfoModalData, clearSelectedDeviceInfo } = inject(
|
||||||
"system_selectedDevice"
|
"system_selectedDevice"
|
||||||
@ -42,7 +41,6 @@ export default function useForgeSprite() {
|
|||||||
console.log("onSpriteClicked", event.target);
|
console.log("onSpriteClicked", event.target);
|
||||||
console.log("onSpriteClicked", data);
|
console.log("onSpriteClicked", data);
|
||||||
// modalContent.value = data;
|
// modalContent.value = data;
|
||||||
debugger;
|
|
||||||
if (data) {
|
if (data) {
|
||||||
getCurrentInfoModalData(
|
getCurrentInfoModalData(
|
||||||
event,
|
event,
|
||||||
@ -52,14 +50,7 @@ export default function useForgeSprite() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { selectedFloor } = useSelectedFloor();
|
const { flatSubData } = useSystemShowData()
|
||||||
const showData = computed(() =>
|
|
||||||
selectedFloor.value?.key === "main"
|
|
||||||
? subscribeData.value
|
|
||||||
: subscribeData.value.filter(
|
|
||||||
({ floor_guid }) => floor_guid === selectedFloor.value?.key
|
|
||||||
) || []
|
|
||||||
);
|
|
||||||
|
|
||||||
// 創建 sprites
|
// 創建 sprites
|
||||||
const createSprites = async () => {
|
const createSprites = async () => {
|
||||||
@ -77,7 +68,7 @@ export default function useForgeSprite() {
|
|||||||
);
|
);
|
||||||
const viewableData = new DataVizCore.ViewableData();
|
const viewableData = new DataVizCore.ViewableData();
|
||||||
viewableData.spriteSize = 24; // Sprites as points of size 24 x 24 pixels
|
viewableData.spriteSize = 24; // Sprites as points of size 24 x 24 pixels
|
||||||
showData.value?.forEach((d, index) => {
|
flatSubData.value?.forEach((d, index) => {
|
||||||
if (d.device_coordinate_3d) {
|
if (d.device_coordinate_3d) {
|
||||||
const position = d.device_coordinate_3d;
|
const position = d.device_coordinate_3d;
|
||||||
style.color = new THREE.Color(hexToRgb(d.device_normal_color));
|
style.color = new THREE.Color(hexToRgb(d.device_normal_color));
|
||||||
@ -105,7 +96,7 @@ export default function useForgeSprite() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => showData,
|
() => flatSubData,
|
||||||
() => {
|
() => {
|
||||||
if (forgeViewer.value?.isLoadDone()) {
|
if (forgeViewer.value?.isLoadDone()) {
|
||||||
createSprites();
|
createSprites();
|
||||||
|
27
src/hooks/useSystemShowData.js
Normal file
27
src/hooks/useSystemShowData.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import useSelectedFloor from "@/hooks/useSelectedFloor";
|
||||||
|
import { computed, inject, watch } from "vue";
|
||||||
|
|
||||||
|
function useSystemShowData() {
|
||||||
|
const { data } = inject("system_deviceList");
|
||||||
|
const { selectedFloor } = useSelectedFloor();
|
||||||
|
|
||||||
|
const showData = computed(() =>
|
||||||
|
selectedFloor.value?.key === "main"
|
||||||
|
? data.value
|
||||||
|
: data.value.filter(
|
||||||
|
({ floor_guid }) => floor_guid === selectedFloor.value?.key
|
||||||
|
) || []
|
||||||
|
);
|
||||||
|
|
||||||
|
const flatSubData = computed(() => {
|
||||||
|
let items = [];
|
||||||
|
showData.value.forEach((device) => {
|
||||||
|
items = [...items, ...device.device_list];
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
});
|
||||||
|
|
||||||
|
return { showData, flatSubData };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useSystemShowData;
|
27
src/stores/useHeatmapBarStore.js
Normal file
27
src/stores/useHeatmapBarStore.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { defineStore } from "pinia";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
import { computed, ref, onMounted } from "vue";
|
||||||
|
|
||||||
|
const useHeatmapBarStore = defineStore("heatmap", () => {
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const allHeatMaps = ref({});
|
||||||
|
const heatmapConfig = computed(() => allHeatMaps.value[route.query?.gas]);
|
||||||
|
|
||||||
|
const getConfig = async () => {
|
||||||
|
const res = await axios.get("/config.json");
|
||||||
|
console.log(res);
|
||||||
|
allHeatMaps.value = res.data.heatmap;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getConfig();
|
||||||
|
});
|
||||||
|
|
||||||
|
const heat_bar_isShow = computed(() => Boolean(heatmapConfig.value));
|
||||||
|
|
||||||
|
return { heatmapConfig, heat_bar_isShow };
|
||||||
|
});
|
||||||
|
|
||||||
|
export default useHeatmapBarStore;
|
@ -41,13 +41,11 @@ const getData = async () => {
|
|||||||
building_tag: buildingStore.selectedBuilding?.building_tag,
|
building_tag: buildingStore.selectedBuilding?.building_tag,
|
||||||
})
|
})
|
||||||
const devices = res.data.map(d => ({
|
const devices = res.data.map(d => ({
|
||||||
...d, key: d.full_name, device_list: d.device_list.map((dev, index) => ({
|
...d, key: d.full_name, device_list: d.device_list.filter(({ device_coordinate_3d }) => device_coordinate_3d).map((dev, index) => ({
|
||||||
...dev,
|
...dev,
|
||||||
forge_dbid: parseInt(dev.forge_dbid),
|
forge_dbid: parseInt(dev.forge_dbid),
|
||||||
room_dbid: parseInt(dev.room_dbid),
|
room_dbid: parseInt(dev.room_dbid),
|
||||||
device_coordinate_3d: dev.device_coordinate_3d
|
device_coordinate_3d: JSON.parse(dev.device_coordinate_3d),
|
||||||
? JSON.parse(dev.device_coordinate_3d)
|
|
||||||
: null,
|
|
||||||
alarmMsg: "",
|
alarmMsg: "",
|
||||||
is_show: true,
|
is_show: true,
|
||||||
currentColor: dev.device_normal_point_color,
|
currentColor: dev.device_normal_point_color,
|
||||||
|
@ -1,18 +1,11 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, inject, watch } from "vue"
|
import { computed, inject, watch } from "vue"
|
||||||
import useSelectedFloor from "@/hooks/useSelectedFloor"
|
import useSystemShowData from "@/hooks/useSystemShowData"
|
||||||
|
|
||||||
const { data } = inject("system_deviceList")
|
|
||||||
|
|
||||||
const { getCurrentInfoModalData } = inject("system_selectedDevice")
|
const { getCurrentInfoModalData } = inject("system_selectedDevice")
|
||||||
|
|
||||||
const { selectedFloor } = useSelectedFloor()
|
const { showData } = useSystemShowData()
|
||||||
|
|
||||||
const showData = computed(() => selectedFloor.value?.key === 'main' ? data.value : data.value.filter(({ floor_guid }) => floor_guid === selectedFloor.value?.key) || [])
|
|
||||||
|
|
||||||
watch(selectedFloor, (newValue) => {
|
|
||||||
console.log(newValue)
|
|
||||||
})
|
|
||||||
|
|
||||||
const fitToView = (forge_dbid) => {
|
const fitToView = (forge_dbid) => {
|
||||||
window.NOP_VIEWER.fitToView([forge_dbid])
|
window.NOP_VIEWER.fitToView([forge_dbid])
|
||||||
|
Loading…
Reference in New Issue
Block a user