d2graph

package
v0.6.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 17, 2024 License: MPL-2.0 Imports: 27 Imported by: 35

Documentation

Index

Constants

View Source
const DEFAULT_SHAPE_SIZE = 100.
View Source
const INNER_LABEL_PADDING int = 5
View Source
const MIN_SEGMENT_LEN = 10
View Source
const MIN_SHAPE_SIZE = 5

Variables

View Source
var BoardKeywords = map[string]struct{}{
	"layers":    {},
	"scenarios": {},
	"steps":     {},
}

BoardKeywords contains the keywords that create new boards.

View Source
var CompositeReservedKeywords = map[string]struct{}{
	"classes":    {},
	"constraint": {},
	"label":      {},
	"icon":       {},
}

CompositeReservedKeywords are reserved keywords that can hold composites

View Source
var FillPatterns = []string{
	"none",
	"dots",
	"lines",
	"grain",
	"paper",
}
View Source
var LabelPositions map[string]struct{}
View Source
var LabelPositionsArray = []string{
	"top-left",
	"top-center",
	"top-right",

	"center-left",
	"center-center",
	"center-right",

	"bottom-left",
	"bottom-center",
	"bottom-right",

	"outside-top-left",
	"outside-top-center",
	"outside-top-right",

	"outside-left-top",
	"outside-left-center",
	"outside-left-bottom",

	"outside-right-top",
	"outside-right-center",
	"outside-right-bottom",

	"outside-bottom-left",
	"outside-bottom-center",
	"outside-bottom-right",
}

LabelPositionsArray are the values that labels and icons can set `near` to

View Source
var LabelPositionsMapping = map[string]label.Position{
	"top-left":   label.InsideTopLeft,
	"top-center": label.InsideTopCenter,
	"top-right":  label.InsideTopRight,

	"center-left":   label.InsideMiddleLeft,
	"center-center": label.InsideMiddleCenter,
	"center-right":  label.InsideMiddleRight,

	"bottom-left":   label.InsideBottomLeft,
	"bottom-center": label.InsideBottomCenter,
	"bottom-right":  label.InsideBottomRight,

	"outside-top-left":   label.OutsideTopLeft,
	"outside-top-center": label.OutsideTopCenter,
	"outside-top-right":  label.OutsideTopRight,

	"outside-left-top":    label.OutsideLeftTop,
	"outside-left-center": label.OutsideLeftMiddle,
	"outside-left-bottom": label.OutsideLeftBottom,

	"outside-right-top":    label.OutsideRightTop,
	"outside-right-center": label.OutsideRightMiddle,
	"outside-right-bottom": label.OutsideRightBottom,

	"outside-bottom-left":   label.OutsideBottomLeft,
	"outside-bottom-center": label.OutsideBottomCenter,
	"outside-bottom-right":  label.OutsideBottomRight,
}

convert to label.Position

View Source
var NearConstants map[string]struct{}
View Source
var NearConstantsArray = []string{
	"top-left",
	"top-center",
	"top-right",

	"center-left",
	"center-right",

	"bottom-left",
	"bottom-center",
	"bottom-right",
}

TODO maybe autofmt should allow other values, and transform them to conform e.g. left-center becomes center-left

View Source
var ReservedKeywordHolders = map[string]struct{}{
	"style":            {},
	"source-arrowhead": {},
	"target-arrowhead": {},
}

ReservedKeywordHolders are reserved keywords that are meaningless on its own and must hold composites

View Source
var ReservedKeywords map[string]struct{}

All reserved keywords. See init below.

View Source
var SimpleReservedKeywords = map[string]struct{}{
	"label":          {},
	"desc":           {},
	"shape":          {},
	"icon":           {},
	"constraint":     {},
	"tooltip":        {},
	"link":           {},
	"near":           {},
	"width":          {},
	"height":         {},
	"direction":      {},
	"top":            {},
	"left":           {},
	"grid-rows":      {},
	"grid-columns":   {},
	"grid-gap":       {},
	"vertical-gap":   {},
	"horizontal-gap": {},
	"class":          {},
	"vars":           {},
}

Non Style/Holder keywords.

View Source
var StyleKeywords = map[string]struct{}{
	"opacity":       {},
	"stroke":        {},
	"fill":          {},
	"fill-pattern":  {},
	"stroke-width":  {},
	"stroke-dash":   {},
	"border-radius": {},

	"font":           {},
	"font-size":      {},
	"font-color":     {},
	"bold":           {},
	"italic":         {},
	"underline":      {},
	"text-transform": {},

	"shadow":        {},
	"multiple":      {},
	"double-border": {},

	"3d": {},

	"animated": {},
	"filled":   {},
}

StyleKeywords are reserved keywords which cannot exist outside of the "style" keyword

Functions

func CompareSerializedEdge added in v0.2.1

func CompareSerializedEdge(edge, other *Edge) error

func CompareSerializedGraph added in v0.2.1

func CompareSerializedGraph(g, other *Graph) error

func CompareSerializedObject added in v0.2.1

func CompareSerializedObject(obj, other *Object) error

func Convert added in v0.6.5

func Convert[T, Q any](from T, to *Q) error

func DeserializeGraph

func DeserializeGraph(bytes []byte, g *Graph) error

func GetTextDimensions added in v0.1.4

func GetTextDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler, t *d2target.MText, fontFamily *d2fonts.FontFamily) *d2target.TextDimensions

func Key

func Key(k *d2ast.KeyPath) []string

func SerializeGraph

func SerializeGraph(g *Graph) ([]byte, error)

Types

type Attributes

type Attributes struct {
	Label           Scalar                  `json:"label"`
	LabelDimensions d2target.TextDimensions `json:"labelDimensions"`

	Style   Style    `json:"style"`
	Icon    *url.URL `json:"icon,omitempty"`
	Tooltip *Scalar  `json:"tooltip,omitempty"`
	Link    *Scalar  `json:"link,omitempty"`

	WidthAttr  *Scalar `json:"width,omitempty"`
	HeightAttr *Scalar `json:"height,omitempty"`

	Top  *Scalar `json:"top,omitempty"`
	Left *Scalar `json:"left,omitempty"`

	// TODO consider separate Attributes struct for shape-specific and edge-specific
	// Shapes only
	NearKey  *d2ast.KeyPath `json:"near_key"`
	Language string         `json:"language,omitempty"`
	// TODO: default to ShapeRectangle instead of empty string
	Shape Scalar `json:"shape"`

	Direction  Scalar   `json:"direction"`
	Constraint []string `json:"constraint"`

	GridRows      *Scalar `json:"gridRows,omitempty"`
	GridColumns   *Scalar `json:"gridColumns,omitempty"`
	GridGap       *Scalar `json:"gridGap,omitempty"`
	VerticalGap   *Scalar `json:"verticalGap,omitempty"`
	HorizontalGap *Scalar `json:"horizontalGap,omitempty"`

	LabelPosition *Scalar `json:"labelPosition,omitempty"`
	IconPosition  *Scalar `json:"iconPosition,omitempty"`

	// These names are attached to the rendered elements in SVG
	// so that users can target them however they like outside of D2
	Classes []string `json:"classes,omitempty"`
}

func (*Attributes) ApplyTextTransform added in v0.4.0

func (a *Attributes) ApplyTextTransform()

ApplyTextTransform will alter the `Label.Value` of the current object based on the specification of the `text-transform` styling option. This function has side-effects!

func (*Attributes) ToArrowhead added in v0.4.2

func (a *Attributes) ToArrowhead() d2target.Arrowhead

type ContainerLevel

type ContainerLevel int

func (ContainerLevel) LabelSize

func (l ContainerLevel) LabelSize() int

type Edge

type Edge struct {
	Index int `json:"index"`

	SrcTableColumnIndex *int `json:"srcTableColumnIndex,omitempty"`
	DstTableColumnIndex *int `json:"dstTableColumnIndex,omitempty"`

	LabelPosition   *string  `json:"labelPosition,omitempty"`
	LabelPercentage *float64 `json:"labelPercentage,omitempty"`

	IsCurve bool         `json:"isCurve"`
	Route   []*geo.Point `json:"route,omitempty"`

	Src          *Object     `json:"-"`
	SrcArrow     bool        `json:"src_arrow"`
	SrcArrowhead *Attributes `json:"srcArrowhead,omitempty"`
	Dst          *Object     `json:"-"`
	// TODO alixander (Mon Sep 12 2022): deprecate SrcArrow and DstArrow and just use SrcArrowhead and DstArrowhead
	DstArrow     bool        `json:"dst_arrow"`
	DstArrowhead *Attributes `json:"dstArrowhead,omitempty"`

	References []EdgeReference `json:"references,omitempty"`
	Attributes `json:"attributes,omitempty"`

	ZIndex int `json:"zIndex"`
}

func (*Edge) AbsID

func (e *Edge) AbsID() string

func (*Edge) ArrowString

func (e *Edge) ArrowString() string

func (*Edge) ContainedBy added in v0.1.0

func (e *Edge) ContainedBy(obj *Object) bool

func (*Edge) GetAstEdge added in v0.4.0

func (e *Edge) GetAstEdge() *d2ast.Edge

func (*Edge) GetGroup added in v0.2.0

func (e *Edge) GetGroup() *Object

func (*Edge) GetStroke

func (e *Edge) GetStroke(dashGapSize interface{}) string

func (*Edge) Move added in v0.6.1

func (e *Edge) Move(dx, dy float64)

func (*Edge) ShiftEnd added in v0.5.0

func (edge *Edge) ShiftEnd(delta float64, isHorizontal bool)

ShiftEnd moves the ending point of the route by delta either horizontally or vertically if prior points are in line with the movement, they will be removed (unless it is the first point)

func (*Edge) ShiftStart added in v0.5.0

func (edge *Edge) ShiftStart(delta float64, isHorizontal bool)

ShiftStart moves the starting point of the route by delta either horizontally or vertically if subsequent points are in line with the movement, they will be removed (unless it is the last point) start end . ├────┼────┼───┼────┼───┤ before . ├──dx──► . ├──┼───┼────┼───┤ after

func (*Edge) Text

func (e *Edge) Text() *d2target.MText

func (*Edge) TraceToShape added in v0.5.0

func (edge *Edge) TraceToShape(points []*geo.Point, startIndex, endIndex int) (newStart, newEnd int)

type EdgeReference

type EdgeReference struct {
	Edge *d2ast.Edge `json:"-"`

	MapKey          *d2ast.Key `json:"-"`
	MapKeyEdgeIndex int        `json:"map_key_edge_index"`
	Scope           *d2ast.Map `json:"-"`
	ScopeObj        *Object    `json:"-"`
	ScopeAST        *d2ast.Map `json:"-"`
}

type Graph

type Graph struct {
	FS     fs.FS  `json:"-"`
	Parent *Graph `json:"-"`
	Name   string `json:"name"`
	// IsFolderOnly indicates a board or scenario itself makes no modifications from its
	// base. Folder only boards do not have a render and are used purely for organizing
	// the board tree.
	IsFolderOnly bool       `json:"isFolderOnly"`
	AST          *d2ast.Map `json:"ast"`
	// BaseAST is the AST of the original graph without inherited fields and edges
	BaseAST *d2ast.Map `json:"-"`

	Root    *Object   `json:"root"`
	Edges   []*Edge   `json:"edges"`
	Objects []*Object `json:"objects"`

	Layers    []*Graph `json:"layers,omitempty"`
	Scenarios []*Graph `json:"scenarios,omitempty"`
	Steps     []*Graph `json:"steps,omitempty"`

	Theme *d2themes.Theme `json:"theme,omitempty"`

	// Object.Level uses the location of a nested graph
	RootLevel int `json:"rootLevel,omitempty"`
}

func NewGraph

func NewGraph() *Graph

func (*Graph) ApplyTheme added in v0.2.5

func (g *Graph) ApplyTheme(themeID int64) error

ApplyTheme applies themes on the graph level This is different than on the render level, which only changes colors A theme applied on the graph level applies special rules that change the graph

func (*Graph) ExtractAsNestedGraph added in v0.5.0

func (g *Graph) ExtractAsNestedGraph(obj *Object) *Graph

remove obj and all descendants from graph, as a new Graph

func (*Graph) GetBoard added in v0.2.0

func (g *Graph) GetBoard(name string) *Graph

func (*Graph) InjectNestedGraph added in v0.5.0

func (g *Graph) InjectNestedGraph(tempGraph *Graph, parent *Object)

func (*Graph) PrintString added in v0.5.0

func (g *Graph) PrintString() string

func (*Graph) RootBoard added in v0.2.4

func (g *Graph) RootBoard() *Graph

func (*Graph) SetDimensions

func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler, fontFamily *d2fonts.FontFamily) error

func (*Graph) SortEdgesByAST added in v0.2.0

func (g *Graph) SortEdgesByAST()

func (*Graph) SortObjectsByAST added in v0.2.0

func (g *Graph) SortObjectsByAST()

func (*Graph) Texts

func (g *Graph) Texts() []*d2target.MText

type LayoutGraph added in v0.4.0

type LayoutGraph func(context.Context, *Graph) error

type Object

type Object struct {
	Graph  *Graph  `json:"-"`
	Parent *Object `json:"-"`

	// IDVal is the actual value of the ID whereas ID is the value in d2 syntax.
	// e.g. ID:    "yes'\""
	//      IDVal: yes'"
	//
	// ID allows joining on . naively and construct a valid D2 key path
	ID         string      `json:"id"`
	IDVal      string      `json:"id_val"`
	Map        *d2ast.Map  `json:"-"`
	References []Reference `json:"references,omitempty"`

	*geo.Box      `json:"box,omitempty"`
	LabelPosition *string `json:"labelPosition,omitempty"`
	IconPosition  *string `json:"iconPosition,omitempty"`

	ContentAspectRatio *float64 `json:"contentAspectRatio,omitempty"`

	Class    *d2target.Class    `json:"class,omitempty"`
	SQLTable *d2target.SQLTable `json:"sql_table,omitempty"`

	Children      map[string]*Object `json:"-"`
	ChildrenArray []*Object          `json:"-"`

	Attributes `json:"attributes"`

	ZIndex int `json:"zIndex"`
}

TODO maybe rename to Shape

func ResolveUnderscoreKey

func ResolveUnderscoreKey(ida []string, obj *Object) (resolvedObj *Object, resolvedIDA []string, _ error)

TODO: remove once not used anywhere

func (*Object) AbsID

func (obj *Object) AbsID() string

func (*Object) AbsIDArray

func (obj *Object) AbsIDArray() []string

func (*Object) AppendReferences

func (obj *Object) AppendReferences(ida []string, ref Reference, unresolvedObj *Object)

func (*Object) ClosestGridCell added in v0.6.2

func (obj *Object) ClosestGridCell() *Object

func (*Object) ClosestGridDiagram added in v0.4.0

func (obj *Object) ClosestGridDiagram() *Object

func (*Object) Connect

func (obj *Object) Connect(srcID, dstID []string, srcArrow, dstArrow bool, label string) (*Edge, error)

func (*Object) ContainedBy added in v0.1.0

func (o *Object) ContainedBy(obj *Object) bool

func (*Object) ContainsAnyEdge added in v0.1.0

func (obj *Object) ContainsAnyEdge(edges []*Edge) bool

func (*Object) ContainsAnyObject added in v0.1.0

func (obj *Object) ContainsAnyObject(objects []*Object) bool

func (*Object) EnsureChild

func (obj *Object) EnsureChild(ida []string) *Object

EnsureChild grabs the child by ids or creates it if it does not exist including all intermediate nodes.

func (*Object) FindEdges

func (obj *Object) FindEdges(mk *d2ast.Key) ([]*Edge, bool)

TODO: remove edges []edge and scope each edge inside Object.

func (*Object) GetDefaultSize added in v0.1.4

func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.Ruler, fontFamily *d2fonts.FontFamily, labelDims d2target.TextDimensions, withLabelPadding bool) (*d2target.TextDimensions, error)

func (*Object) GetFill

func (obj *Object) GetFill() string

func (*Object) GetIconTopLeft added in v0.6.0

func (obj *Object) GetIconTopLeft() *geo.Point

func (*Object) GetLabelSize added in v0.1.4

func (obj *Object) GetLabelSize(mtexts []*d2target.MText, ruler *textmeasure.Ruler, fontFamily *d2fonts.FontFamily) (*d2target.TextDimensions, error)

func (*Object) GetLabelTopLeft added in v0.5.0

func (obj *Object) GetLabelTopLeft() *geo.Point

func (*Object) GetMargin added in v0.6.2

func (obj *Object) GetMargin() geo.Spacing

func (*Object) GetModifierElementAdjustments added in v0.5.0

func (obj *Object) GetModifierElementAdjustments() (dx, dy float64)

GetModifierElementAdjustments returns width/height adjustments to account for shapes with 3d or multiple

func (*Object) GetStroke

func (obj *Object) GetStroke(dashGapSize interface{}) string

func (*Object) HasChild

func (obj *Object) HasChild(ids []string) (*Object, bool)

func (*Object) HasEdge

func (obj *Object) HasEdge(mk *d2ast.Key) (*Edge, bool)

func (*Object) HasIcon added in v0.6.3

func (obj *Object) HasIcon() bool

func (*Object) HasLabel added in v0.4.1

func (obj *Object) HasLabel() bool

func (*Object) HasOutsideBottomLabel added in v0.2.4

func (obj *Object) HasOutsideBottomLabel() bool

func (*Object) Is3D added in v0.5.0

func (obj *Object) Is3D() bool

func (*Object) IsConstantNear added in v0.6.1

func (obj *Object) IsConstantNear() bool

func (*Object) IsContainer

func (obj *Object) IsContainer() bool

func (*Object) IsDescendantOf added in v0.2.1

func (obj *Object) IsDescendantOf(ancestor *Object) bool

func (*Object) IsGridDiagram added in v0.4.0

func (obj *Object) IsGridDiagram() bool

func (*Object) IsMultiple added in v0.5.0

func (obj *Object) IsMultiple() bool

func (*Object) IsSequenceDiagram added in v0.1.0

func (obj *Object) IsSequenceDiagram() bool

func (*Object) IsSequenceDiagramGroup added in v0.1.0

func (obj *Object) IsSequenceDiagramGroup() bool

groups are objects in sequence diagrams that have no messages connected and does not have a note as a child (a note can appear within a group, but it's a child of an actor)

func (*Object) IsSequenceDiagramNote added in v0.1.0

func (obj *Object) IsSequenceDiagramNote() bool

notes are descendant of actors with no edges and no children

func (*Object) IterDescendants added in v0.5.0

func (obj *Object) IterDescendants(apply func(parent, child *Object))

func (*Object) Level

func (obj *Object) Level() ContainerLevel

func (*Object) MoveWithDescendants added in v0.5.0

func (obj *Object) MoveWithDescendants(dx, dy float64)

func (*Object) MoveWithDescendantsTo added in v0.5.0

func (obj *Object) MoveWithDescendantsTo(x, y float64)

func (*Object) OuterNearContainer added in v0.4.0

func (obj *Object) OuterNearContainer() *Object

func (*Object) OuterSequenceDiagram added in v0.1.0

func (obj *Object) OuterSequenceDiagram() *Object

func (*Object) RemoveChild added in v0.6.1

func (parent *Object) RemoveChild(child *Object)

func (*Object) ShiftDescendants added in v0.5.0

func (obj *Object) ShiftDescendants(dx, dy float64)

ShiftDescendants moves Object's descendants (not including itself) descendants' edges are also moved by the same dx and dy (the whole route is moved if both ends are a descendant)

func (*Object) SizeToContent added in v0.5.0

func (obj *Object) SizeToContent(contentWidth, contentHeight, paddingX, paddingY float64)

resizes the object to fit content of the given width and height in its inner box with the given padding. this accounts for the shape of the object, and if there is a desired width or height set for the object

func (*Object) Spacing added in v0.6.2

func (obj *Object) Spacing() (margin, padding geo.Spacing)

func (*Object) SpacingOpt added in v0.6.3

func (obj *Object) SpacingOpt(labelPadding, iconPadding float64, maxIconSize bool) (margin, padding geo.Spacing)

func (*Object) Text

func (obj *Object) Text() *d2target.MText

func (*Object) ToShape added in v0.5.0

func (obj *Object) ToShape() shape.Shape

func (*Object) TopGridDiagram added in v0.6.1

func (obj *Object) TopGridDiagram() *Object

TopGridDiagram returns the least nested (outermost) grid diagram

type Reference

type Reference struct {
	Key          *d2ast.KeyPath `json:"key"`
	KeyPathIndex int            `json:"key_path_index"`

	MapKey          *d2ast.Key `json:"-"`
	MapKeyEdgeIndex int        `json:"map_key_edge_index"`
	Scope           *d2ast.Map `json:"-"`
	ScopeObj        *Object    `json:"-"`
	ScopeAST        *d2ast.Map `json:"-"`
}

func (Reference) InEdge

func (r Reference) InEdge() bool

func (Reference) MapKeyEdgeDest

func (r Reference) MapKeyEdgeDest() bool

type RouteEdges added in v0.6.2

type RouteEdges func(context.Context, *Graph, []*Edge) error

type Scalar

type Scalar struct {
	Value  string     `json:"value"`
	MapKey *d2ast.Key `json:"-"`
}

TODO consider having different Scalar types Right now we'll hold any types in Value and just convert, e.g. floats

type SerializedEdge

type SerializedEdge map[string]interface{}

func ToSerializedEdge added in v0.6.5

func ToSerializedEdge(e *Edge) (SerializedEdge, error)

type SerializedGraph

type SerializedGraph struct {
	Root      SerializedObject   `json:"root"`
	Edges     []SerializedEdge   `json:"edges"`
	Objects   []SerializedObject `json:"objects"`
	RootLevel int                `json:"rootLevel"`
}

type SerializedObject

type SerializedObject map[string]interface{}

type Style

type Style struct {
	Opacity       *Scalar `json:"opacity,omitempty"`
	Stroke        *Scalar `json:"stroke,omitempty"`
	Fill          *Scalar `json:"fill,omitempty"`
	FillPattern   *Scalar `json:"fillPattern,omitempty"`
	StrokeWidth   *Scalar `json:"strokeWidth,omitempty"`
	StrokeDash    *Scalar `json:"strokeDash,omitempty"`
	BorderRadius  *Scalar `json:"borderRadius,omitempty"`
	Shadow        *Scalar `json:"shadow,omitempty"`
	ThreeDee      *Scalar `json:"3d,omitempty"`
	Multiple      *Scalar `json:"multiple,omitempty"`
	Font          *Scalar `json:"font,omitempty"`
	FontSize      *Scalar `json:"fontSize,omitempty"`
	FontColor     *Scalar `json:"fontColor,omitempty"`
	Animated      *Scalar `json:"animated,omitempty"`
	Bold          *Scalar `json:"bold,omitempty"`
	Italic        *Scalar `json:"italic,omitempty"`
	Underline     *Scalar `json:"underline,omitempty"`
	Filled        *Scalar `json:"filled,omitempty"`
	DoubleBorder  *Scalar `json:"doubleBorder,omitempty"`
	TextTransform *Scalar `json:"textTransform,omitempty"`
}

func (*Style) Apply

func (s *Style) Apply(key, value string) error

func (Style) NoneTextTransform added in v0.4.0

func (s Style) NoneTextTransform() bool

NoneTextTransform will return a boolean if the text should not have any transformation applied. This should overwrite theme specific transformations like `CapsLock` from the `terminal` theme.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL