Skip to content

Commit be58ac0

Browse files
committed
v1.5
1 parent 0585197 commit be58ac0

File tree

18 files changed

+1009
-232
lines changed

18 files changed

+1009
-232
lines changed

README.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
# Web Serial Debugger
1+
# [Web Serial Debugger](https://qdsang.github.io/web-serial-debug/)
22

3-
一个基于 Web Serial API 的串口调试工具,使用 Vue 3 + TypeScript + Vite 构建。
3+
一个基于 Web Serial 的串口调试工具。 [https://qdsang.github.io/web-serial-debug/](https://qdsang.github.io/web-serial-debug/)
4+
5+
## Demo
6+
7+
![Image](./docs/preview.png "LV GUI Builder Preview")
48

59

610
## 功能特点
@@ -68,13 +72,7 @@ yarn build
6872
yarn preview
6973
```
7074

71-
## 浏览器支持
72-
73-
- Chrome >= 89
74-
- Edge >= 89
75-
- Opera >= 76
76-
77-
> 注意:需要浏览器支持 Web Serial API
75+
https://github.com/devanlai/webstlink
7876

7977
## 许可证
8078

docs/preview.png

101 KB
Loading

index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<head>
44
<meta charset="UTF-8" />
55
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
6+
<link rel="manifest" href="/manifest.json" />
67
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
78
<title>Web Serial Debuger - 串口调试工具</title>
89
<meta name="description" content="Web Serial 串口调试工具" />

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "web-serial",
33
"private": true,
4-
"version": "1.2.0",
4+
"version": "1.5.0",
55
"type": "module",
66
"scripts": {
77
"dev": "vite",
@@ -15,14 +15,16 @@
1515
"@codemirror/state": "^6.4.1",
1616
"@codemirror/theme-one-dark": "^6.1.2",
1717
"@codemirror/view": "^6.36.2",
18-
"@element-plus/icons-vue": "^2.3.1",
1918
"@vueuse/core": "^12.5.0",
2019
"@xterm/addon-search": "^0.15.0",
20+
"@element-plus/icons-vue": "^2.3.1",
2121
"element-plus": "^2.9.3",
2222
"less": "^4.2.2",
2323
"pinia": "^2.3.1",
2424
"splitpanes": "^3.1.8",
25+
"stats.js": "^0.17.0",
2526
"three": "^0.173.0",
27+
"uplot": "^1.6.31",
2628
"vue": "^3.5.13",
2729
"vue-router": "^4.5.0",
2830
"xterm": "^5.3.0",

public/manifest.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "Web Serial Debugger",
3+
"short_name": "Serial Debug",
4+
"description": "Web Serial 串口调试工具",
5+
"start_url": "./",
6+
"display": "standalone",
7+
"background_color": "#ffffff",
8+
"theme_color": "#409eff",
9+
"icons": [
10+
{
11+
"src": "vite.svg",
12+
"sizes": "192x192",
13+
"type": "image/svg+xml"
14+
}
15+
]
16+
}

public/sw.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
const CACHE_NAME = 'web-serial-debug-cache-v1';
33
const urlsToCache = [
44
'./',
5-
'./index.html'
5+
'./index.html',
6+
'./manifest.json',
7+
'./vite.svg'
68
];
79

810
self.addEventListener('install', (event) => {

src/App.vue

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@ import { ref } from 'vue'
33
import SerialConfig from './components/SerialConfig.vue'
44
import SerialLog from './components/SerialLog.vue'
55
import Chart3D from './components/Chart3D.vue'
6+
import ChartPanel from './components/ChartPanel.vue'
67
import DataTable from './components/DataTable.vue'
78
import SerialQuickSend from './components/SerialQuickSend.vue'
89
import SerialScripts from './components/SerialScript.vue'
910
import { useDark, useToggle } from '@vueuse/core'
1011
// @ts-ignore
1112
import { Splitpanes, Pane } from 'splitpanes'
1213
import 'splitpanes/dist/splitpanes.css'
14+
import { ConfigManager } from './utils/ConfigManager'
15+
16+
const configManager = ConfigManager.getInstance()
17+
const layoutConfig = configManager.useConfig('layout')
1318
1419
const isDark = useDark({
1520
initialValue: 'dark',
@@ -28,14 +33,33 @@ const toggleFullscreen = () => {
2833
isFullscreen.value = false
2934
}
3035
}
36+
37+
const handleSplitResize = (options: { size: number}[]) => {
38+
layoutConfig.value.splitPaneSize = options[0].size
39+
handleResize()
40+
}
41+
42+
const handleTabChange = () => {
43+
handleResize()
44+
}
45+
46+
let resizeTimer: number
47+
const handleResize = () => {
48+
clearTimeout(resizeTimer)
49+
resizeTimer = setTimeout(() => {
50+
window.dispatchEvent(new CustomEvent('resize', { }))
51+
}, 100)
52+
}
53+
handleResize()
54+
3155
</script>
3256

3357
<template>
3458
<el-container class="app-container">
3559
<el-header class="app-header">
3660
<div class="header-content">
3761
<div class="header-left">
38-
<h1><a href="https://github.com/qdsang/web-serial" target="_blank">Web Serial</a></h1>
62+
<h1><a href="https://github.com/qdsang/web-serial-debug" target="_blank">Web Serial</a></h1>
3963
<SerialConfig class="header-serial-config" />
4064
</div>
4165
<div class="header-links">
@@ -51,27 +75,29 @@ const toggleFullscreen = () => {
5175
circle
5276
@click="toggleFullscreen()"
5377
/>
54-
<a href="https://github.com/qdsang/web-serial" target="_blank">Github</a>
5578
</div>
5679
</div>
5780
</el-header>
5881
<el-container class="main-container">
59-
<Splitpanes class="default-theme">
60-
<Pane :size="75" class="w75">
61-
<el-tabs type="card" class="lv-card lv-tabs">
62-
<el-tab-pane label="日志">
82+
<Splitpanes class="default-theme" @resize="handleSplitResize">
83+
<Pane :size="layoutConfig.splitPaneSize" class="w75">
84+
<el-tabs type="card" class="lv-card lv-tabs" v-model="layoutConfig.leftActiveTab" @tab-click="handleTabChange">
85+
<el-tab-pane label="日志" lazy>
6386
<SerialLog />
6487
</el-tab-pane>
65-
<el-tab-pane label="图表" lazy>
88+
<el-tab-pane label="可视化" lazy>
89+
<ChartPanel />
90+
</el-tab-pane>
91+
<el-tab-pane label="姿态" lazy>
6692
<Chart3D />
6793
</el-tab-pane>
6894
<el-tab-pane label="数据表">
6995
<DataTable />
7096
</el-tab-pane>
7197
</el-tabs>
7298
</Pane>
73-
<Pane :size="25" :min-size="10" :max-size="80" class="w25">
74-
<el-tabs type="card" class="lv-card lv-tabs">
99+
<Pane class="w25">
100+
<el-tabs type="card" class="lv-card lv-tabs" v-model="layoutConfig.rightActiveTab">
75101
<el-tab-pane label="快捷发送">
76102
<SerialQuickSend />
77103
</el-tab-pane>
@@ -222,6 +248,8 @@ html.dark .el-button {
222248
margin: 8px 0 0 8px;
223249
padding: 0px 6px;
224250
height: 24px;
251+
transition: all .1s;
252+
user-select:none;
225253
}
226254
&.el-tabs.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item.is-active {
227255
background-color: #f5f5f5;

src/components/Chart3D.vue

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
<script setup lang="ts">
22
import { ref, onMounted, onUnmounted, computed } from 'vue'
3-
// @ts-ignore
3+
// @ts-ignore
44
import * as THREE from 'three'
5-
// @ts-ignore
5+
// @ts-ignore
66
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
7-
// @ts-ignore
7+
// @ts-ignore
88
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
9-
// @ts-ignore
9+
// @ts-ignore
1010
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
1111
import { useDark } from '@vueuse/core'
1212
import { ElMessage } from 'element-plus'
13+
// @ts-ignore
14+
import Stats from 'stats.js'
1315
1416
const container = ref<HTMLDivElement | null>(null)
1517
const pitch = ref(0)
@@ -30,11 +32,24 @@ let renderer: THREE.WebGLRenderer
3032
let model: THREE.Group
3133
let controls: OrbitControls
3234
let animationFrameId: number
35+
let stats: Stats
3336
3437
const initScene = () => {
3538
scene = new THREE.Scene()
3639
scene.background = new THREE.Color(sceneBackground.value)
3740
41+
// 添加坐标轴辅助器
42+
const axesHelper = new THREE.AxesHelper(5)
43+
scene.add(axesHelper)
44+
45+
// 初始化性能监视器
46+
stats = new Stats()
47+
stats.showPanel(0) // 0: fps, 1: ms, 2: mb, 3+: custom
48+
stats.dom.style.position = 'absolute'
49+
stats.dom.style.left = '0px'
50+
stats.dom.style.top = '0px'
51+
container.value!.appendChild(stats.dom)
52+
3853
camera = new THREE.PerspectiveCamera(75, container.value!.clientWidth / container.value!.clientHeight, 0.1, 1000)
3954
camera.position.set(2, 2, 2)
4055
camera.lookAt(0, 0, 0)
@@ -191,6 +206,7 @@ const addLights = () => {
191206
192207
const animate = () => {
193208
animationFrameId = requestAnimationFrame(animate)
209+
stats.begin()
194210
195211
if (model) {
196212
model.rotation.set(
@@ -202,6 +218,7 @@ const animate = () => {
202218
203219
controls.update()
204220
renderer.render(scene, camera)
221+
stats.end()
205222
}
206223
207224
const handleResize = () => {
@@ -213,7 +230,10 @@ const handleResize = () => {
213230
}
214231
215232
const handleImuData = (event: CustomEvent) => {
216-
const { pitch: p, roll: r, yaw: y } = event.detail
233+
const data = event.detail
234+
if (!data || typeof data.pitch !== 'number') return
235+
236+
const { pitch: p, roll: r, yaw: y } = data
217237
pitch.value = p
218238
roll.value = r
219239
yaw.value = y
@@ -238,15 +258,15 @@ onMounted(() => {
238258
initScene()
239259
animate()
240260
window.addEventListener('resize', handleResize)
241-
window.addEventListener('data-imu', handleImuData as EventListener)
261+
window.addEventListener('data-update', handleImuData as EventListener)
242262
})
243263
244264
onUnmounted(() => {
245265
if (animationFrameId) {
246266
cancelAnimationFrame(animationFrameId)
247267
}
248268
window.removeEventListener('resize', handleResize)
249-
window.removeEventListener('data-imu', handleImuData as EventListener)
269+
window.removeEventListener('data-update', handleImuData as EventListener)
250270
renderer.dispose()
251271
})
252272
</script>

0 commit comments

Comments
 (0)