pkg/skoop/ui/graph.go (81 lines of code) (raw):
package ui
import (
"context"
"fmt"
"strings"
"github.com/alibaba/kubeskoop/pkg/skoop/model"
"oss.terrastruct.com/d2/d2layouts/d2dagrelayout"
"oss.terrastruct.com/d2/d2lib"
"oss.terrastruct.com/d2/d2renderers/d2svg"
"oss.terrastruct.com/d2/lib/textmeasure"
)
const (
graphSettings = `
direction: right
classes: {
node: {
shape: circle
style {
font-size: 10
stroke-width: 1
}
}
edge: {
style: {
font-size: 20
font-color: black
italic: true
stroke-width: 1
}
}
}
`
)
type D2 struct {
script string
}
func NewD2(p *model.PacketPath) (*D2, error) {
script, err := buildGraphScriptV2(p)
if err != nil {
return nil, err
}
d := &D2{
script: script,
}
return d, nil
}
func buildGraphScriptV2(p *model.PacketPath) (string, error) {
builder := strings.Builder{}
builder.WriteString(graphSettings)
for _, n := range p.Nodes() {
builder.WriteString(fmt.Sprintf("%q: %s { class: [node; %s] }\n", n.GetID(), trimID(n.GetID()), n.GetID()))
}
for _, l := range p.Links() {
builder.WriteString(fmt.Sprintf("%q->%q: %s { class: [edge; %s] }\n", l.Source.GetID(), l.Destination.GetID(), l.Type, l.GetID()))
}
return builder.String(), nil
}
func (d *D2) ToD2() ([]byte, error) {
return []byte(d.script), nil
}
func (d *D2) ToSvg() ([]byte, error) {
ruler, err := textmeasure.NewRuler()
if err != nil {
return nil, err
}
diag, _, err := d2lib.Compile(context.Background(), d.script, &d2lib.CompileOptions{
Layout: d2dagrelayout.DefaultLayout,
Ruler: ruler,
})
if err != nil {
return nil, err
}
out, err := d2svg.Render(diag, &d2svg.RenderOpts{
Pad: d2svg.DEFAULT_PADDING,
})
return out, err
}
func trimID(id string) string {
ids := strings.Split(id, "/")
return ids[len(ids)-1]
}