diff --git a/core/wiki/chart/block.go b/core/wiki/chart/block.go new file mode 100644 index 00000000..2f2ce938 --- /dev/null +++ b/core/wiki/chart/block.go @@ -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{`").Dump(m) + } + item := wiki.NewItem([]string{`%v`, 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 +} diff --git a/core/wiki/chart/chain.go b/core/wiki/chart/chain.go new file mode 100644 index 00000000..7fb45c99 --- /dev/null +++ b/core/wiki/chart/chain.go @@ -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{"").Dump(m) + defer m.Echo("") + } + + // 当前节点 + 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, ``, + 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{} + }) +} diff --git a/core/wiki/chart/label.go b/core/wiki/chart/label.go new file mode 100644 index 00000000..58bf0dae --- /dev/null +++ b/core/wiki/chart/label.go @@ -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{} + }) +} diff --git a/core/wiki/chart/sequence.go b/core/wiki/chart/sequence.go new file mode 100644 index 00000000..cd62fc27 --- /dev/null +++ b/core/wiki/chart/sequence.go @@ -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{} + }) +}