1
0
mirror of https://shylinux.com/x/icebergs synced 2025-04-25 17:18:05 +08:00
This commit is contained in:
harveyshao 2021-12-11 17:30:23 +08:00
parent 87b675d294
commit 1ef53c5610
4 changed files with 455 additions and 0 deletions

92
core/wiki/chart/block.go Normal file
View File

@ -0,0 +1,92 @@
package chart
import (
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/core/wiki"
kit "shylinux.com/x/toolkits"
)
type Block struct {
Text string
FontSize int
FontColor string
BackGround string
TextData string
RectData string
Padding int
MarginX int
MarginY int
Height int
Width int
x, y int
}
func (b *Block) Init(m *ice.Message, arg ...string) wiki.Chart {
b.FontSize = kit.Int(kit.Select("24", m.Option(wiki.FONT_SIZE)))
b.Padding = kit.Int(kit.Select("10", m.Option(wiki.PADDING)))
b.MarginX = kit.Int(kit.Select("10", m.Option(wiki.MARGINX)))
b.MarginY = kit.Int(kit.Select("10", m.Option(wiki.MARGINY)))
if len(arg) > 0 {
b.Text = arg[0]
}
return b
}
func (b *Block) Data(m *ice.Message, meta interface{}) wiki.Chart {
b.Text = kit.Select(b.Text, kit.Value(meta, kit.MDB_TEXT))
kit.Fetch(meta, func(key string, value string) {
switch key {
case wiki.FG:
b.TextData += kit.Format("%s='%s' ", wiki.FILL, value)
case wiki.BG:
b.RectData += kit.Format("%s='%s' ", wiki.FILL, value)
}
})
kit.Fetch(kit.Value(meta, "data"), func(key string, value string) {
b.TextData += kit.Format("%s='%s' ", key, value)
})
kit.Fetch(kit.Value(meta, "rect"), func(key string, value string) {
b.RectData += kit.Format("%s='%s' ", key, value)
})
return b
}
func (b *Block) Draw(m *ice.Message, x, y int) wiki.Chart {
float := 3
if strings.Contains(m.Option(ice.MSG_USERUA), "iPhone") {
float += 0
}
if m.Option(HIDE_BLOCK) != ice.TRUE {
item := wiki.NewItem([]string{`<rect height="%d" width="%d" rx="4" ry="4" x="%d" y="%d"`}, b.GetHeight(), b.GetWidth(), x+b.MarginX/2, y+b.MarginY/2)
item.Push(`fill="%s"`, b.BackGround).Push(`%v`, b.RectData).Echo("/>").Dump(m)
}
item := wiki.NewItem([]string{`<text x="%d" y="%d"`}, x+b.GetWidths()/2, y+b.GetHeights()/2+float)
item.Push(`stroke="%s"`, b.FontColor).Push(`fill="%s"`, b.FontColor).Push("%v", b.TextData).Push(`>%v</text>`, b.Text).Dump(m)
return b
}
func (b *Block) GetHeight(str ...string) int {
if b.Height != 0 {
return b.Height
}
return b.FontSize + b.Padding
}
func (b *Block) GetWidth(str ...string) int {
if b.Width != 0 {
return b.Width
}
s := kit.Select(b.Text, str, 0)
cn := (len(s) - len([]rune(s))) / 2
en := len([]rune(s)) - cn
return cn*b.FontSize + en*b.FontSize*10/16 + b.Padding
}
func (b *Block) GetWidths(str ...string) int {
return b.GetWidth(str...) + b.MarginX
}
func (b *Block) GetHeights(str ...string) int {
return b.GetHeight() + b.MarginY
}

120
core/wiki/chart/chain.go Normal file
View File

@ -0,0 +1,120 @@
package chart
import (
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/core/wiki"
kit "shylinux.com/x/toolkits"
)
type Chain struct {
data map[string]interface{}
Group *wiki.Group
Block
}
func (c *Chain) Init(m *ice.Message, arg ...string) wiki.Chart {
(&c.Block).Init(m)
// 解析数据
m.Option(nfs.CAT_CONTENT, arg[0])
m.Option(lex.SPLIT_SPACE, "\t \n")
m.Option(lex.SPLIT_BLOCK, "\t \n")
c.data = lex.Split(m, "", kit.MDB_TEXT)
// 计算尺寸
c.Height = c.size(m, c.data) * c.GetHeights()
c.Draw(m, 0, 0)
c.Width += 200
m.Set(ice.MSG_RESULT)
return c
}
func (c *Chain) Draw(m *ice.Message, x, y int) wiki.Chart {
c.Group = wiki.NewGroup(m, SHIP)
defer c.Group.Dump(m, SHIP)
c.draw(m, c.data, x, y, &c.Block)
return c
}
func (c *Chain) size(m *ice.Message, root map[string]interface{}) (height int) {
meta := kit.GetMeta(root)
if list, ok := root[kit.MDB_LIST].([]interface{}); ok && len(list) > 0 {
kit.Fetch(root[kit.MDB_LIST], func(index int, value map[string]interface{}) {
height += c.size(m, value)
})
} else {
height = 1
}
meta[wiki.HEIGHT] = height
return height
}
func (c *Chain) draw(m *ice.Message, root map[string]interface{}, x, y int, p *Block) int {
meta := kit.GetMeta(root)
c.Height, c.Width = 0, 0
if kit.Format(meta[wiki.FG]) != "" {
items := wiki.NewItem([]string{"<g"})
items.Push("stroke=%s", meta[wiki.FG])
items.Push("fill=%s", meta[wiki.FG])
items.Echo(">").Dump(m)
defer m.Echo("</g>")
}
// 当前节点
item := &Block{
FontSize: p.FontSize,
Padding: p.Padding,
MarginX: p.MarginX,
MarginY: p.MarginY,
}
item.x, item.y = x, y+(kit.Int(meta[wiki.HEIGHT])-1)*c.GetHeights()/2
item.Init(m, kit.Format(meta[kit.MDB_TEXT])).Data(m, meta)
item.Draw(m, item.x, item.y)
// 画面尺寸
if item.y+item.GetHeight()+c.MarginY > c.Height {
c.Height = item.y + item.GetHeight() + c.MarginY
}
if item.x+item.GetWidth()+c.MarginX > c.Width {
c.Width = item.x + item.GetWidth() + c.MarginX
}
// 模块连线
if p != nil && p.y != 0 {
x1, y1 := p.x+p.GetWidths()-(p.MarginX+item.MarginX)/4, p.y+p.GetHeights()/2
x4, y4 := item.x+(p.MarginX+item.MarginX)/4, item.y+item.GetHeights()/2
c.Group.Echo(SHIP, `<path d="M %d,%d Q %d,%d %d,%d T %d %d"></path>`,
x1, y1, x1+(x4-x1)/4, y1, x1+(x4-x1)/2, y1+(y4-y1)/2, x4, y4)
}
// 递归节点
h, x := 0, x+item.GetWidths()
if kit.Fetch(root[kit.MDB_LIST], func(index int, value map[string]interface{}) {
h += c.draw(m, value, x, y+h, item)
}); h == 0 {
return item.GetHeights()
}
return h
}
const (
SHIP = "ship"
HIDE_BLOCK = "hide-block"
)
const CHAIN = "chain"
func init() {
wiki.AddChart(CHAIN, func(m *ice.Message) wiki.Chart {
m.Option(wiki.STROKE_WIDTH, "1")
m.Option(wiki.FILL, cli.BLUE)
m.Option(wiki.MARGINX, "40")
m.Option(wiki.MARGINY, "0")
m.Option(COMPACT, ice.TRUE)
m.Option(HIDE_BLOCK, ice.TRUE)
wiki.AddGroupOption(m, SHIP, wiki.STROKE_WIDTH, "1", wiki.STROKE, cli.CYAN, wiki.FILL, "none")
return &Chain{}
})
}

87
core/wiki/chart/label.go Normal file
View File

@ -0,0 +1,87 @@
package chart
import (
"strings"
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/core/wiki"
kit "shylinux.com/x/toolkits"
)
type Label struct {
data [][]string
max map[int]int
Block
}
func (l *Label) Init(m *ice.Message, arg ...string) wiki.Chart {
(&l.Block).Init(m)
// 解析数据
l.max = map[int]int{}
for _, v := range strings.Split(arg[0], ice.NL) {
ls := kit.Split(v, ice.SP, ice.SP)
l.data = append(l.data, ls)
for i, v := range ls {
switch data := kit.Parse(nil, "", kit.Split(v)...).(type) {
case map[string]interface{}:
v = kit.Select("", data[kit.MDB_TEXT])
}
if w := l.GetWidth(v); w > l.max[i] {
l.max[i] = w
}
}
}
// 计算尺寸
l.Height = len(l.data) * l.GetHeights()
for _, v := range l.max {
l.Width += v + l.MarginX
}
return l
}
func (l *Label) Draw(m *ice.Message, x, y int) wiki.Chart {
var item *Block
top := y
for _, line := range l.data {
left := x
for i, text := range line {
// 数据
item = &Block{FontSize: l.FontSize, Padding: l.Padding, MarginX: l.MarginX, MarginY: l.MarginY}
switch data := kit.Parse(nil, "", kit.Split(text)...).(type) {
case map[string]interface{}:
item.Init(m, kit.Select(text, data[kit.MDB_TEXT])).Data(m, data)
default:
item.Init(m, text)
}
// 输出
switch m.Option(COMPACT) {
case "max":
item.Width = l.Width/len(line) - l.MarginX
case ice.TRUE:
default:
item.Width = l.max[i]
}
item.Draw(m, left, top)
left += item.GetWidths()
}
top += item.GetHeights()
}
return l
}
const (
COMPACT = "compact"
)
const LABEL = "label"
func init() {
wiki.AddChart(LABEL, func(m *ice.Message) wiki.Chart {
return &Label{}
})
}

156
core/wiki/chart/sequence.go Normal file
View File

@ -0,0 +1,156 @@
package chart
import (
ice "shylinux.com/x/icebergs"
"shylinux.com/x/icebergs/base/cli"
"shylinux.com/x/icebergs/base/lex"
"shylinux.com/x/icebergs/base/nfs"
"shylinux.com/x/icebergs/core/wiki"
kit "shylinux.com/x/toolkits"
)
type Sequence struct {
Head []string
List [][]map[string]interface{}
pos []int
Block
}
func (s *Sequence) push(m *ice.Message, list string, arg ...interface{}) map[string]interface{} {
node, node_list := kit.Dict(arg...), kit.Int(list)
s.List[node_list] = append(s.List[node_list], node)
_max := kit.Max(len(s.List[node_list])-1, s.pos[node_list])
node[kit.MDB_ORDER], s.pos[node_list] = _max, _max+1
return node
}
func (s *Sequence) Init(m *ice.Message, arg ...string) wiki.Chart {
(&s.Block).Init(m)
// 解析数据
m.Cmd(lex.SPLIT, "", kit.Dict(nfs.CAT_CONTENT, arg[0]), func(ls []string, data map[string]interface{}) []string {
if len(s.Head) == 0 {
s.Head, s.pos = ls, make([]int, len(ls))
for i := 0; i < len(ls); i++ {
s.List = append(s.List, []map[string]interface{}{})
}
return ls
}
from_node := s.push(m, ls[0])
list := map[string]map[string]interface{}{ls[0]: from_node}
for i := 1; i < len(ls)-1; i += 2 {
to_node := list[ls[i+1]]
if to_node == nil {
to_node = s.push(m, ls[i+1])
list[ls[i+1]] = to_node
_max := kit.Max(kit.Int(from_node[kit.MDB_ORDER]), kit.Int(to_node[kit.MDB_ORDER]))
s.pos[kit.Int(ls[i-1])], s.pos[kit.Int(ls[i+1])] = _max+1, _max+1
from_node[kit.MDB_ORDER], to_node[kit.MDB_ORDER] = _max, _max
from_node[kit.MDB_TEXT], from_node[kit.MDB_NEXT] = ls[i], ls[i+1]
} else {
from_node[kit.MDB_ECHO], from_node[kit.MDB_PREV] = ls[i], ls[i+1]
}
from_node = to_node
}
return ls
})
// 计算尺寸
width := 0
for _, v := range s.Head {
width += s.Block.GetWidths(v)
}
rect_height := kit.Int(m.Option(RECT + "-" + wiki.HEIGHT))
s.Width, s.Height = width, kit.Max(s.pos...)*(rect_height+s.MarginY)+s.MarginY+s.GetHeights()
return s
}
func (s *Sequence) Draw(m *ice.Message, x, y int) wiki.Chart {
g := wiki.NewGroup(m, ARROW, HEAD, LINE, RECT, NEXT, PREV, TEXT, ECHO)
arrow_height := kit.Int(g.Option(ARROW, wiki.HEIGHT))
arrow_width := kit.Int(g.Option(ARROW, wiki.WIDTH))
rect_height := kit.Int(g.Option(RECT, wiki.HEIGHT))
rect_width := kit.Int(g.Option(RECT, wiki.WIDTH))
g.DefsArrow(NEXT, arrow_height, arrow_width)
height := s.Height
s.Block.Height, s.Block.Width = 0, 0
line_pos := make([]int, len(s.List))
for i := range s.List {
s.Block.Text = s.Head[i]
s.Block.Draw(g.Get(HEAD), x, y)
line_pos[i], x = x+s.Block.GetWidths()/2, x+s.Block.GetWidths()
}
y += s.Block.GetHeight() + s.MarginY/2
for _, x := range line_pos {
g.EchoLine(LINE, x, y, x, height-s.MarginY/2)
}
for i, x := range line_pos {
for _, v := range s.List[i] {
pos := kit.Int(v[kit.MDB_ORDER])
g.EchoRect(RECT, rect_height, rect_width, x-rect_width/2, y+pos*(rect_height+s.MarginY)+s.MarginY, "2", "2")
yy := y + pos*(rect_height+s.MarginY) + s.MarginY + rect_height/4
if kit.Format(v[kit.MDB_NEXT]) != "" {
xx := line_pos[kit.Int(v[kit.MDB_NEXT])]
if x < xx {
g.EchoArrowLine(NEXT, x+rect_width/2, yy, xx-rect_width/2-arrow_width, yy)
} else {
g.EchoArrowLine(NEXT, x-rect_width/2, yy, xx+rect_width/2+arrow_width, yy)
}
g.EchoText(TEXT, (x+xx)/2, yy, kit.Format(v[kit.MDB_TEXT]))
}
yy += rect_height / 2
if kit.Format(v[kit.MDB_PREV]) != "" {
xx := line_pos[kit.Int(v[kit.MDB_PREV])]
if x < xx {
g.EchoArrowLine(PREV, x+rect_width/2, yy, xx-rect_width/2-arrow_width, yy)
} else {
g.EchoArrowLine(PREV, x-rect_width/2, yy, xx+rect_width/2+arrow_width, yy)
}
g.EchoText(ECHO, (x+xx)/2, yy, kit.Format(v[kit.MDB_ECHO]))
}
}
}
g.Dump(m, HEAD).Dump(m, LINE)
g.Dump(m, RECT).Dump(m, NEXT).Dump(m, PREV)
g.Dump(m, TEXT).Dump(m, ECHO)
return s
}
const (
ARROW = "arrow"
HEAD = "head"
LINE = "line"
RECT = "rect"
NEXT = "next"
PREV = "prev"
TEXT = "text"
ECHO = "echo"
)
const SEQUENCE = "sequence"
func init() {
wiki.AddChart(SEQUENCE, func(m *ice.Message) wiki.Chart {
m.Option(wiki.MARGINX, "60")
m.Option(wiki.MARGINY, "20")
m.Option(wiki.STROKE_WIDTH, "1")
m.Option(wiki.STROKE, cli.WHITE)
m.Option(wiki.FILL, cli.WHITE)
wiki.AddGroupOption(m, ARROW, wiki.HEIGHT, "8", wiki.WIDTH, "18", wiki.FILL, cli.GLASS)
wiki.AddGroupOption(m, HEAD, wiki.FILL, cli.GLASS)
wiki.AddGroupOption(m, LINE, wiki.STROKE_DASHARRAY, "20 4 4 4")
wiki.AddGroupOption(m, RECT, wiki.HEIGHT, "40", wiki.WIDTH, "14")
wiki.AddGroupOption(m, NEXT, wiki.FILL, cli.GLASS)
wiki.AddGroupOption(m, PREV, wiki.STROKE_DASHARRAY, "10 2")
wiki.AddGroupOption(m, TEXT, wiki.FONT_SIZE, "16")
wiki.AddGroupOption(m, ECHO, wiki.FONT_SIZE, "12")
return &Sequence{}
})
}