Commit fa79ae06 by licheng

feat: 瀑布图

parent e898d322
......@@ -4,7 +4,7 @@ NODE_ENV=development
VITE_DEV=true
# 请求路径
VITE_BASE_URL='http://192.168.0.253:25280'
VITE_BASE_URL='http://192.168.0.253:48080'
# 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务
VITE_UPLOAD_TYPE=server
......
<template>
<el-card class="mb-20px" shadow="hover">
<el-card class="mb-20px relative" shadow="hover">
<div class="absolute right-2 top-2 text-xs text-gray-500 z-10">
数据: {{ lineInfo.size }} 条 | FPS: {{ lineInfo.fps }}
</div>
<el-skeleton :loading="loading" :rows="4" animated>
<Echart :height="350" :options="lineOptionsData" />
</el-skeleton>
</el-card>
<el-card class="mb-20px px-[40px] relative" shadow="hover">
<div class="absolute right-2 top-2 text-xs text-gray-500 z-10">
大小: {{ waterfallInfo.size }} | FPS: {{ waterfallInfo.fps }}
</div>
<el-skeleton :loading="loading" :rows="4" animated>
<div class="flex justify-center font-700 text-[18px] mb-2">瀑布图</div>
<img id="waterfall" :src="waterfallImg" alt="waterfall" class="w-full h-[200px]" />
</el-skeleton>
</el-card>
</template>
<script lang="ts" setup>
import { set } from 'lodash-es'
import { EChartsOption } from 'echarts'
import 'echarts/lib/component/dataZoom'
import { lineOptions } from './echarts-data'
defineOptions({ name: 'Home2' })
......@@ -19,10 +32,24 @@ const loading = ref(true)
const lineOptionsData = reactive<EChartsOption>(lineOptions) as EChartsOption
let data: any[] = [] // 波形图数据
const waterfallImg = ref('') // 瀑布图图片
// 左上角显示用的数据
const lineInfo = ref({ size: 0, fps: 0 })
const waterfallInfo = ref({ size: '0 KB', fps: 0 })
// FPS 统计
let lineFrameCount = 0
let waterfallFrameCount = 0
setInterval(() => {
lineInfo.value.fps = lineFrameCount
waterfallInfo.value.fps = waterfallFrameCount
lineFrameCount = 0
waterfallFrameCount = 0
}, 1000)
// 初始数据
const getLineData = async () => {
// data = createData(1000000, 1)
set(
lineOptionsData,
'xAxis.data',
......@@ -31,87 +58,69 @@ const getLineData = async () => {
set(lineOptionsData, 'series', [
{
name: 'data1',
smooth: false, // 是否平滑曲线
smooth: false,
type: 'line',
showSymbol: false, // 不显示数据点
progressive: 1000, // 每次增量渲染的数据量
progressiveThreshold: 5000, // 总数据量超过此值触发增量渲染
showSymbol: false,
progressive: 1000,
progressiveThreshold: 5000,
lineStyle: {
width: 1 // 细线
width: 1
},
sampling: 'lttb', // 使用 LTTB 采样算法降低数据量
// samplingThreshold: 10000, // 采样阈值,超过此值将进行采样
animation: false, // 动画
animationDuration: 1000, // 动画持续时间
animationEasing: 'linear', // 动画缓动效果
sampling: 'lttb',
animation: false,
animationDuration: 1000,
animationEasing: 'linear',
data: data.map((v) => v.data1)
}
// {
// name: 'data2',
// smooth: false, // 是否平滑曲线
// type: 'line',
// showSymbol: false, // 不显示数据点
// progressive: 1000, // 每次增量渲染的数据量
// progressiveThreshold: 5000, // 总数据量超过此值触发增量渲染
// animation: false, // 关闭动画
// lineStyle: {
// width: 0.5 // 细线
// },
// sampling: 'lttb', // 使用 LTTB 采样算法
// samplingThreshold: 10000, // 采样阈值,超过此值将进行采样
// data: data.map((v) => v.data2)
// }
])
}
const connect = () => {
// 连接到 WebSocket 服务器(替换成你的服务器地址)
const socket = new WebSocket('ws://localhost:8080')
const socket = new WebSocket('ws://localhost:8025/ws/combined')
// const socket = new WebSocket('ws://localhost:8080')
// 监听连接成功
socket.addEventListener('open', (event) => {
socket.addEventListener('open', () => {
console.log('WebSocket 连接成功')
})
// 接收服务器消息
socket.addEventListener('message', (event) => {
const newData = JSON.parse(event.data)
const parsed = JSON.parse(event.data)
const newData = parsed.lineData
// 更新瀑布图
waterfallImg.value = `data:image/png;base64,${parsed.waterfallImg}`
// ---- 更新波形图信息 ----
lineInfo.value.size = newData.length
lineFrameCount++
// ---- 更新瀑布图信息 (计算 base64 大小) ----
const base64Str = parsed.waterfallImg
const strLen = base64Str.length
const fileSizeKB = (strLen * 3 / 4 / 1024).toFixed(2)
waterfallInfo.value.size = `${fileSizeKB} KB`
waterfallFrameCount++
// 更新图表数据
const newXAxisData = [...lineOptionsData!.xAxis!.data, ...newData.map((item) => item.name)]
console.log(newXAxisData.length)
const newXAxisData = newData.map((item) => item.frequency)
set(lineOptionsData, 'xAxis.data', newXAxisData)
set(lineOptionsData, 'series', [
{
name: 'data1',
smooth: false,
type: 'line',
// 启用大数据优化
progressive: 1000,
progressiveThreshold: 5000,
showSymbol: false, // 不显示数据点
showSymbol: false,
lineStyle: {
width: 0.5 // 细线
width: 0.5
},
sampling: 'lttb', // 使用 LTTB 采样算法
animation: false, // 动画
animationDuration: 1000, // 动画持续时间
animationEasing: 'linear', // 动画缓动效果
data: [...lineOptionsData!.series![0].data, ...newData.map((item) => item.data1)]
sampling: 'lttb',
animation: false,
animationDuration: 1000,
animationEasing: 'linear',
data: [...newData.map((item) => item.value)]
}
// {
// name: 'data2',
// smooth: false,
// type: 'line',
// itemStyle: {},
// // 启用大数据优化
// progressive: 1000,
// progressiveThreshold: 5000,
// lineStyle: {
// width: 0.5 // 细线
// },
// data: [...lineOptionsData.series[1].data, ...newData.map((item) => item.data2)]
// }
])
})
}
......@@ -123,76 +132,6 @@ const getAllApi = async () => {
}
getAllApi()
interface DataItem {
[key: string]: number | string
name: string
}
function formatDate(date: Date, format: string): string {
const pad = (num: number) => num.toString().padStart(2, '0')
return format
.replace('HH', pad(date.getHours()))
.replace('mm', pad(date.getMinutes()))
.replace('ss', pad(date.getSeconds()))
}
function createData(
count: number,
dataCount: 1 | 2 | 3 = 2,
minValue: number = 50,
maxValue: number = 250
): DataItem[] {
const result: DataItem[] = []
const now = new Date()
// 生成时间点(从当前时间往前递减)
const timeStamps: Date[] = []
for (let i = count - 1; i >= 0; i--) {
const time = new Date(now.getTime() - i * 1000)
timeStamps.push(time)
}
// 初始化各数据项的值和方向
const dataValues: Record<string, number> = {}
const dataDirections: Record<string, number> = {}
for (let i = 1; i <= dataCount; i++) {
const key = `data${i}`
dataValues[key] = minValue + Math.random() * (maxValue - minValue) // 初始随机值
dataDirections[key] = Math.random() > 0.5 ? 1 : -1 // 随机初始方向
}
for (let i = 0; i < count; i++) {
const item: DataItem = { name: formatDate(timeStamps[i], 'HH:mm:ss') }
// 为每个数据项生成波形数据
for (let j = 1; j <= dataCount; j++) {
const key = `data${j}`
const change = 10 + Math.random() * 30 // 变化幅度10~40(可调整)
// 随机决定是否改变方向(更自然的波动)
if (Math.random() < 0.2) {
// 20%概率改变方向
dataDirections[key] *= -1
}
dataValues[key] += dataDirections[key] * change
// 限制在合理范围内(但不强制反转)
dataValues[key] = Math.max(
minValue * 0.9, // 允许稍微低于最小值(避免卡边界)
Math.min(maxValue * 1.1, dataValues[key]) // 允许稍微高于最大值
)
item[key] = Math.round(dataValues[key])
}
result.push(item)
}
return result
}
</script>
<style lang="scss" scoped></style>
......@@ -27,6 +27,9 @@ export const lineOptions: EChartsOption = {
axisPointer: {
type: 'cross'
},
// position: function (pt) {
// return [pt[0], '10%'];
// },
padding: [5, 10]
},
yAxis: {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment