mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-14 21:20:48 +08:00
perf(traffic): reuse canvas pixels while scrolling
This commit is contained in:
Generated
+1
-1
@@ -1079,7 +1079,7 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
||||
|
||||
[[package]]
|
||||
name = "clash-verge"
|
||||
version = "2.5.7"
|
||||
version = "2.5.8"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"anyhow",
|
||||
|
||||
+5
-20
@@ -1,35 +1,20 @@
|
||||
## v2.5.7
|
||||
## v2.5.8
|
||||
|
||||
<details>
|
||||
<summary><strong> 🐞 修复问题 </strong></summary>
|
||||
|
||||
- 修复读屏软件将普通模式下的侧边栏导航项播报为不可用的可拖拽控件的问题
|
||||
- 修复订阅包含自定义 DNS 时,确认开启的 DNS 覆写在重启应用后被自动关闭的问题
|
||||
|
||||
**🖥️ Windows**
|
||||
</details>
|
||||
|
||||
- 修复 Windows 系统盘根目录的删除权限被误判,导致服务模式和 TUN 无法使用的问题
|
||||
- 修复 Windows 部分系统安装服务失败,提示「program not found」的问题
|
||||
<details>
|
||||
<summary><strong> ✨ 新增功能 </strong></summary>
|
||||
|
||||
**🍎 macOS**
|
||||
|
||||
- macOS 修复启动或重启应用时偶发内核启动失败,并误提示「需要更新系统服务」的问题
|
||||
- macOS 修复 VPN 接管网络或开机网络未就绪时的问题:服务模式内核无法启动、TUN 不可用、系统代理状态读取报错
|
||||
- macOS 修复用 `ipconfig set` 手动配置网卡后无法设置系统代理的问题
|
||||
|
||||
**🍎/🐧 macOS/Linux**
|
||||
|
||||
- 修复 macOS/Linux 服务模式停止或重启内核时直接强制结束的问题:内核来不及正常退出、最后的日志丢失
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong> 🚀 优化改进 </strong></summary>
|
||||
|
||||
- 优化服务模式的问题排查:服务自身的运行日志会保存到文件,便于追查内核被停止的原因
|
||||
|
||||
**🖥️ Windows**
|
||||
|
||||
- 优化 Windows 服务安全检查未通过时的启动提示:不再只显示「服务无法启动内核」,直接说明原因并提供修复文档链接
|
||||
- 优化侧边栏流量图表的 CPU 占用
|
||||
|
||||
</details>
|
||||
|
||||
@@ -1,3 +1,40 @@
|
||||
## v2.5.7
|
||||
|
||||
<details>
|
||||
<summary><strong> 🐞 修复问题 </strong></summary>
|
||||
|
||||
- 修复读屏软件将普通模式下的侧边栏导航项播报为不可用的可拖拽控件的问题
|
||||
- 修复订阅包含自定义 DNS 时,确认开启的 DNS 覆写在重启应用后被自动关闭的问题
|
||||
|
||||
**🖥️ Windows**
|
||||
|
||||
- 修复 Windows 系统盘根目录的删除权限被误判,导致服务模式和 TUN 无法使用的问题
|
||||
- 修复 Windows 部分系统安装服务失败,提示「program not found」的问题
|
||||
|
||||
**🍎 macOS**
|
||||
|
||||
- macOS 修复启动或重启应用时偶发内核启动失败,并误提示「需要更新系统服务」的问题
|
||||
- macOS 修复 VPN 接管网络或开机网络未就绪时的问题:服务模式内核无法启动、TUN 不可用、系统代理状态读取报错
|
||||
- macOS 修复用 `ipconfig set` 手动配置网卡后无法设置系统代理的问题
|
||||
|
||||
**🍎/🐧 macOS/Linux**
|
||||
|
||||
- 修复 macOS/Linux 服务模式停止或重启内核时直接强制结束的问题:内核来不及正常退出、最后的日志丢失
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong> 🚀 优化改进 </strong></summary>
|
||||
|
||||
- 优化服务模式的问题排查:服务自身的运行日志会保存到文件,便于追查内核被停止的原因
|
||||
|
||||
**🖥️ Windows**
|
||||
|
||||
- 优化 Windows 服务安全检查未通过时的启动提示:不再只显示「服务无法启动内核」,直接说明原因并提供修复文档链接
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
## v2.5.6
|
||||
|
||||
<details>
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "clash-verge",
|
||||
"version": "2.5.7",
|
||||
"version": "2.5.8",
|
||||
"license": "GPL-3.0-only",
|
||||
"scripts": {
|
||||
"prepare": "husky || true",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "clash-verge"
|
||||
version = "2.5.7"
|
||||
version = "2.5.8"
|
||||
description = "clash verge"
|
||||
authors = ["zzzgydi", "Tunglies", "wonfen", "MystiPanda"]
|
||||
license = "GPL-3.0-only"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "2.5.7",
|
||||
"version": "2.5.8",
|
||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||
"bundle": {
|
||||
"active": true,
|
||||
|
||||
@@ -13,7 +13,6 @@ const upLineWidth = 4
|
||||
const downLineAlpha = 1
|
||||
const downLineWidth = 4
|
||||
const sampleIntervalMs = 1000
|
||||
const frameIntervalMs = 1000 / 15
|
||||
const animationDurationMs = sampleIntervalMs
|
||||
|
||||
const zeroTraffic: Traffic = { up: 0, down: 0, upTotal: 0, downTotal: 0 }
|
||||
@@ -36,7 +35,7 @@ type TrafficValueKey = 'up' | 'down'
|
||||
* draw the traffic graph
|
||||
*/
|
||||
export function TrafficGraph({ ref }: { ref?: Ref<TrafficRef> }) {
|
||||
const countRef = useRef(0)
|
||||
const animationStartRef = useRef<number | null>(null)
|
||||
const styleRef = useRef(true)
|
||||
const listRef = useRef<Traffic[]>(createDefaultList())
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null!)
|
||||
@@ -69,7 +68,6 @@ export function TrafficGraph({ ref }: { ref?: Ref<TrafficRef> }) {
|
||||
if (shouldAppend) {
|
||||
if (list.length > maxPoint + 2) list.shift()
|
||||
list.push(data)
|
||||
countRef.current = 0
|
||||
requestDrawRef.current(true)
|
||||
}
|
||||
|
||||
@@ -84,11 +82,8 @@ export function TrafficGraph({ ref }: { ref?: Ref<TrafficRef> }) {
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
let raf = 0
|
||||
let frameTimer: ReturnType<typeof setTimeout> | null = null
|
||||
let animation: Animation | null = null
|
||||
let resizeObserver: ResizeObserver | null = null
|
||||
let animationStart = 0
|
||||
let lastFrameTime = 0
|
||||
const canvas = canvasRef.current!
|
||||
|
||||
if (!canvas) return
|
||||
@@ -102,25 +97,13 @@ export function TrafficGraph({ ref }: { ref?: Ref<TrafficRef> }) {
|
||||
const upLineColor = secondary.main || '#9c27b0'
|
||||
const downLineColor = primary.main || '#5b5c9d'
|
||||
|
||||
const cancelPendingDraw = () => {
|
||||
if (frameTimer !== null) {
|
||||
clearTimeout(frameTimer)
|
||||
frameTimer = null
|
||||
}
|
||||
|
||||
if (raf) {
|
||||
cancelAnimationFrame(raf)
|
||||
raf = 0
|
||||
}
|
||||
}
|
||||
|
||||
const drawGraph = (offset = countRef.current) => {
|
||||
const drawGraph = () => {
|
||||
const list = listRef.current
|
||||
const lineStyle = styleRef.current
|
||||
|
||||
const width = canvas.width
|
||||
const height = canvas.height
|
||||
const dx = width / maxPoint
|
||||
const dx = width / (maxPoint + 1)
|
||||
const dy = height / 7
|
||||
const l1 = dy
|
||||
const l2 = dy * 4
|
||||
@@ -142,17 +125,17 @@ export function TrafficGraph({ ref }: { ref?: Ref<TrafficRef> }) {
|
||||
const drawBezier = (list: Traffic[], valueKey: TrafficValueKey) => {
|
||||
if (list.length === 0) return
|
||||
|
||||
const firstX = (dx * -1 - offset + 3) | 0
|
||||
const firstX = (dx * -1 + 3) | 0
|
||||
const firstY = countY(list[0]?.[valueKey] ?? 0)
|
||||
|
||||
context.moveTo(firstX, firstY)
|
||||
|
||||
for (let i = 1; i < list.length; i++) {
|
||||
const p1x = (dx * (i - 1) - offset + 3) | 0
|
||||
const p1x = (dx * (i - 1) + 3) | 0
|
||||
const p1y = countY(list[i]?.[valueKey] ?? 0)
|
||||
|
||||
const hasNext = i + 1 < list.length
|
||||
const p2x = hasNext ? (dx * i - offset + 3) | 0 : p1x
|
||||
const p2x = hasNext ? (dx * i + 3) | 0 : p1x
|
||||
const p2y = hasNext ? countY(list[i + 1]?.[valueKey] ?? 0) : p1y
|
||||
|
||||
context.quadraticCurveTo(p1x, p1y, (p1x + p2x) / 2, (p1y + p2y) / 2)
|
||||
@@ -162,13 +145,10 @@ export function TrafficGraph({ ref }: { ref?: Ref<TrafficRef> }) {
|
||||
const drawLine = (list: Traffic[], valueKey: TrafficValueKey) => {
|
||||
if (list.length === 0) return
|
||||
|
||||
context.moveTo((dx * -1 - offset) | 0, countY(list[0]?.[valueKey] ?? 0))
|
||||
context.moveTo((dx * -1) | 0, countY(list[0]?.[valueKey] ?? 0))
|
||||
|
||||
for (let i = 1; i < list.length; i++) {
|
||||
context.lineTo(
|
||||
(dx * (i - 1) - offset) | 0,
|
||||
countY(list[i]?.[valueKey] ?? 0),
|
||||
)
|
||||
context.lineTo((dx * (i - 1)) | 0, countY(list[i]?.[valueKey] ?? 0))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,51 +191,28 @@ export function TrafficGraph({ ref }: { ref?: Ref<TrafficRef> }) {
|
||||
context.closePath()
|
||||
}
|
||||
|
||||
const drawAnimatedFrame = (timestamp: number) => {
|
||||
raf = 0
|
||||
|
||||
const timeSinceLastFrame = timestamp - lastFrameTime
|
||||
if (timeSinceLastFrame < frameIntervalMs) {
|
||||
frameTimer = setTimeout(() => {
|
||||
frameTimer = null
|
||||
raf = requestAnimationFrame(drawAnimatedFrame)
|
||||
}, frameIntervalMs - timeSinceLastFrame)
|
||||
return
|
||||
}
|
||||
|
||||
lastFrameTime = timestamp
|
||||
|
||||
const dx = canvas.width / maxPoint
|
||||
const progress = Math.min(
|
||||
(timestamp - animationStart) / animationDurationMs,
|
||||
1,
|
||||
)
|
||||
const offset = progress * dx
|
||||
countRef.current = offset
|
||||
drawGraph(offset)
|
||||
|
||||
if (progress < 1) {
|
||||
raf = requestAnimationFrame(drawAnimatedFrame)
|
||||
return
|
||||
}
|
||||
|
||||
countRef.current = dx
|
||||
}
|
||||
|
||||
const requestDraw = (animate = false) => {
|
||||
cancelPendingDraw()
|
||||
if (animate) animationStartRef.current = performance.now()
|
||||
animation?.cancel()
|
||||
drawGraph()
|
||||
|
||||
if (!animate) {
|
||||
raf = requestAnimationFrame(() => {
|
||||
raf = 0
|
||||
drawGraph()
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
animationStart = performance.now()
|
||||
lastFrameTime = animationStart - frameIntervalMs
|
||||
raf = requestAnimationFrame(drawAnimatedFrame)
|
||||
const elapsed =
|
||||
animationStartRef.current === null
|
||||
? 0
|
||||
: Math.min(
|
||||
performance.now() - animationStartRef.current,
|
||||
animationDurationMs,
|
||||
)
|
||||
const step = canvas.getBoundingClientRect().width / (maxPoint + 1)
|
||||
animation = canvas.animate(
|
||||
[
|
||||
{ transform: 'translateX(0)' },
|
||||
{ transform: `translateX(${-step}px)` },
|
||||
],
|
||||
{ duration: animationDurationMs, easing: 'linear', fill: 'forwards' },
|
||||
)
|
||||
animation.currentTime = elapsed
|
||||
if (animationStartRef.current === null) animation.pause()
|
||||
}
|
||||
|
||||
requestDrawRef.current = requestDraw
|
||||
@@ -263,7 +220,7 @@ export function TrafficGraph({ ref }: { ref?: Ref<TrafficRef> }) {
|
||||
|
||||
if (typeof ResizeObserver !== 'undefined') {
|
||||
resizeObserver = new ResizeObserver(() => requestDraw(false))
|
||||
resizeObserver.observe(canvas)
|
||||
resizeObserver.observe(canvas.parentElement!)
|
||||
}
|
||||
|
||||
return () => {
|
||||
@@ -271,9 +228,20 @@ export function TrafficGraph({ ref }: { ref?: Ref<TrafficRef> }) {
|
||||
requestDrawRef.current = () => {}
|
||||
}
|
||||
resizeObserver?.disconnect()
|
||||
cancelPendingDraw()
|
||||
animation?.cancel()
|
||||
}
|
||||
}, [palette])
|
||||
|
||||
return <canvas ref={canvasRef} style={{ width: '100%', height: '100%' }} />
|
||||
return (
|
||||
<div style={{ width: '100%', height: '100%', overflow: 'hidden' }}>
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
width={310}
|
||||
style={{
|
||||
width: `${((maxPoint + 1) / maxPoint) * 100}%`,
|
||||
height: '100%',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user