Commit 6e2dd6f5 authored by liming6's avatar liming6
Browse files

fix 修复timechart显示问题

parent 2636b033
......@@ -13,6 +13,7 @@ import (
"github.com/NimbleMarkets/ntcharts/canvas/runes"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
linkedlist "github.com/emirpasic/gods/v2/lists/doublylinkedlist"
zone "github.com/lrstanley/bubblezone"
)
......@@ -99,12 +100,12 @@ func NewTimeCharMsg(point []tchart.TimePoint, reset bool) MyTimeChartMsg {
// MyTimeChart 特化的时间流表,时间区域就是宽度的2倍,单位是秒
type MyTimeChart struct {
chart *tchart.Model // 原始图表
zM *zone.Manager // 区域管理
points []tchart.TimePoint // 数据点
width, height int // 图表的高度和宽度
max, min float64 // y轴的最值
lockPoints sync.RWMutex // 保护dataSet的并发读写
chart *tchart.Model // 原始图表
zM *zone.Manager // 区域管理
points *linkedlist.List[tchart.TimePoint] // 数据点,这里只存储put的数据,不存储自动添加的数据
width, height int // 图表的高度和宽度
max, min float64 // y轴的最值
lockPoints sync.RWMutex // 保护dataSet的并发读写
color []lipgloss.Color
}
......@@ -119,11 +120,12 @@ func NewTimeChart(width, height int, vmin, vmax float64, color []lipgloss.Color)
result.zM = zoneManager
result.lockPoints = sync.RWMutex{}
result.lockPoints.Lock()
result.points = make([]tchart.TimePoint, (result.width*2)+1)
// 准备数据,数据间隔为1秒
result.points = linkedlist.New[tchart.TimePoint]()
now := time.Now()
for i := result.width * 2; i >= 0; i-- {
result.points[i] = tchart.TimePoint{Time: now.Add(time.Duration(-i) * time.Second), Value: vmin}
t := result.width*2 + 1
tmpPoints := make([]tchart.TimePoint, 0, t)
for i := range t {
tmpPoints = append(tmpPoints, tchart.TimePoint{Time: now.Add(time.Duration(-i) * time.Second)})
}
result.lockPoints.Unlock()
s := tchart.New(width, height+1,
......@@ -131,37 +133,73 @@ func NewTimeChart(width, height int, vmin, vmax float64, color []lipgloss.Color)
tchart.WithZoneManager(zoneManager),
tchart.WithYRange(vmin, vmax),
tchart.WithXYSteps(0, 0),
tchart.WithTimeSeries(result.points),
tchart.WithTimeSeries(tmpPoints),
)
result.chart = &s
result.color = color
return &result
}
func (m *MyTimeChart) SortPoints() {
m.points.Sort(func(x, y tchart.TimePoint) int {
if x.Time.After(y.Time) {
return 1
}
if x.Time.Before(y.Time) {
return -1
}
return 0
})
}
func (m *MyTimeChart) RemoveUselessPoint() {
m.SortPoints()
th := time.Now().Add(time.Duration(m.width*-2) * time.Second)
for {
t, b := m.points.Get(0)
if !b {
break
}
if t.Time.Before(th) {
m.points.Remove(0)
} else {
break
}
}
}
// PutPoint 添加若干数据点
func (m *MyTimeChart) PutPoint(points []tchart.TimePoint) {
m.lockPoints.Lock()
ops := append(m.points, points...)
// 排序
sort.Slice(ops, func(i, j int) bool {
return ops[i].Time.Before(ops[j].Time)
})
threshold := time.Now().Add(time.Second * time.Duration(-2*m.width))
targetIndex := 0
for i, p := range ops {
if !p.Time.Before(threshold) {
targetIndex = i
break
if len(points) > 0 {
m.points.Add(points...)
}
m.RemoveUselessPoint()
threshold := time.Now().Add(time.Second * time.Duration(-2*m.width-1))
points = m.points.Values()
tmpPoint := make([]tchart.TimePoint, 0, m.width*2)
// 判断是否需要补充空点
if !points[0].Time.Before(threshold) {
t := points[0].Time.Add(-time.Second)
for {
if !t.Before(threshold) {
tmpPoint = append(tmpPoint, tchart.TimePoint{Time: t, Value: m.min})
t = t.Add(-time.Second)
} else {
break
}
}
}
nps := append(make([]tchart.TimePoint, 0, targetIndex+1), ops[targetIndex:]...)
m.points = nps
tmpPoint = append(tmpPoint, points...)
sort.Slice(tmpPoint, func(i, j int) bool {
return tmpPoint[i].Time.Before(tmpPoint[j].Time)
})
s := tchart.New(m.width, m.height+1,
tchart.WithLineStyle(runes.ThinLineStyle),
tchart.WithZoneManager(m.zM),
tchart.WithYRange(m.min, m.max),
tchart.WithXYSteps(0, 0),
tchart.WithTimeSeries(m.points),
tchart.WithTimeSeries(tmpPoint),
)
m.lockPoints.Unlock()
// 插入数据
......@@ -175,47 +213,37 @@ func (m *MyTimeChart) PutPoint(points []tchart.TimePoint) {
func (m *MyTimeChart) ResetPutPoint(points []tchart.TimePoint) {
// 清除原有的点
m.lockPoints.Lock()
m.points = m.points[:0]
m.points.Clear()
if len(points) > 0 {
m.points.Add(points...)
}
m.RemoveUselessPoint()
threshold := time.Now().Add(time.Second * time.Duration(-2*m.width-1))
points = m.points.Values()
tmpPoint := make([]tchart.TimePoint, 0, m.width*2)
// 排序输入数据
sort.Slice(points, func(i, j int) bool {
return points[i].Time.Before(points[j].Time)
})
// 补充数据 或 剔除数据
now := time.Now()
threshold := now.Add(time.Duration(m.width*-2) * time.Second)
first := points[0].Time
if first.Before(threshold) {
// 需要剔除数据
index := 0
for k, v := range points {
if v.Time.Before(threshold) {
continue
// 判断是否需要补充空点
if !points[0].Time.Before(threshold) {
t := points[0].Time.Add(-time.Second)
for {
if !t.Before(threshold) {
tmpPoint = append(tmpPoint, tchart.TimePoint{Time: t, Value: m.min})
t = t.Add(-time.Second)
} else {
index = k
break
}
}
m.points = append(make([]tchart.TimePoint, 0, len(points[index:])), points[index:]...)
} else if first.After(threshold) {
// 需要补充数据
max := m.width * 2
for i := 1; i < max; i++ {
ta := now.Add(time.Second * time.Duration(-i))
if !ta.Before(threshold) {
m.points = append(m.points, tchart.TimePoint{Time: ta, Value: m.min})
} else {
break
}
}
m.points = append(m.points, points...)
}
tmpPoint = append(tmpPoint, points...)
sort.Slice(tmpPoint, func(i, j int) bool {
return tmpPoint[i].Time.Before(tmpPoint[j].Time)
})
s := tchart.New(m.width, m.height+1,
tchart.WithLineStyle(runes.ThinLineStyle),
tchart.WithZoneManager(m.zM),
tchart.WithYRange(m.min, m.max),
tchart.WithXYSteps(0, 0),
tchart.WithTimeSeries(m.points),
tchart.WithTimeSeries(tmpPoint),
)
m.lockPoints.Unlock()
// 插入数据
......
......@@ -11,13 +11,6 @@ import (
"github.com/charmbracelet/lipgloss"
)
const S = `├───────────────────────────────┼──────────────────────┼──────────────────────┼
│ 2 BW200, manual │ 0000:5e:00.0 Off │ Off On │ DCU: ░░░░░░░░░░░░░░░░░░░░░░░░░ 0% │`
func TestLine(t *testing.T) {
t.Logf("%d", lipgloss.Width(S))
}
func TestHeader(t *testing.T) {
m := ModelHeader{}
cmd := m.Init()
......@@ -80,14 +73,15 @@ func TestSysloadInit(t *testing.T) {
func TestTimeChart(t *testing.T) {
chart1 := NewTimeChart(100, 20, 0, 100, nil)
chart2 := NewTimeChart(100, 20, 0, 100, nil)
// chart2 := NewTimeChart(100, 20, 0, 100, nil)
now := time.Now()
points := make([]tchart.TimePoint, 0, 200)
for i := range 200 {
points = append(points, tchart.TimePoint{Time: now.Add(time.Duration(-i) * time.Second), Value: rand.Float64() * 100})
}
chart1.PutPoint(points)
t.Logf("\n%s", chart1.View())
chart2.PutPoint(points)
t.Logf("\n%s", chart2.View())
chart1.ResetPutPoint(points)
t.Logf("\n%s", chart1.View())
}
......@@ -10,6 +10,7 @@ import (
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/tree"
"github.com/emirpasic/gods/v2/lists/doublylinkedlist"
"github.com/emirpasic/gods/v2/maps/treemap"
"github.com/shirou/gopsutil/v4/process"
)
......@@ -197,7 +198,28 @@ func TestChild(t *testing.T) {
}
func TestCHar(t *testing.T) {
c1 := "⣿⣿⣿⣿⣿⣿⣿⣿"
c2 := "├"
t.Log(lipgloss.JoinHorizontal(lipgloss.Top, c2, c1))
list := doublylinkedlist.New[time.Time]()
now := time.Now()
for i := range 10 {
if i%2 == 0 {
list.Add(now.Add(time.Duration(i) * time.Second))
} else {
list.Add(now.Add(time.Duration(-i) * time.Second))
}
}
list.Sort(func(x, y time.Time) int {
if x.After(y) {
return 1
}
if x.Before(y) {
return -1
}
return 0
})
for _ = range list.Size() {
time, b := list.Get(0)
list.Remove(0)
t.Logf("%v: %v", time, b)
}
}
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