const DEFAULT_SHAPE_SIZE = 100.
const INNER_LABEL_PADDING int = 5
const MIN_SEGMENT_LEN = 10
const MIN_SHAPE_SIZE = 5
BoardKeywords contains the keywords that create new boards.
var BoardKeywords = map[string]struct{}{ "layers": {}, "scenarios": {}, "steps": {}, }
CompositeReservedKeywords are reserved keywords that can hold composites
var CompositeReservedKeywords = map[string]struct{}{ "classes": {}, "constraint": {}, "label": {}, "icon": {}, }
var FillPatterns = []string{ "dots", "lines", "grain", "paper", }
var LabelPositions map[string]struct{}
LabelPositionsArray are the values that labels and icons can set `near` to
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", }
convert to label.Position
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, }
var NearConstants map[string]struct{}
TODO maybe autofmt should allow other values, and transform them to conform e.g. left-center becomes center-left
var NearConstantsArray = []string{ "top-left", "top-center", "top-right", "center-left", "center-right", "bottom-left", "bottom-center", "bottom-right", }
ReservedKeywordHolders are reserved keywords that are meaningless on its own and must hold composites
var ReservedKeywordHolders = map[string]struct{}{ "style": {}, "source-arrowhead": {}, "target-arrowhead": {}, }
All reserved keywords. See init below.
var ReservedKeywords map[string]struct{}
Non Style/Holder keywords.
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": {}, }
StyleKeywords are reserved keywords which cannot exist outside of the "style" keyword
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": {}, }
func CompareSerializedEdge(edge, other *Edge) error
func CompareSerializedGraph(g, other *Graph) error
func CompareSerializedObject(obj, other *Object) error
func DeserializeGraph(bytes []byte, g *Graph) error
func GetTextDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler, t *d2target.MText, fontFamily *d2fonts.FontFamily) *d2target.TextDimensions
func Key(k *d2ast.KeyPath) []string
func SerializeGraph(g *Graph) ([]byte, error)
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 (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 (a *Attributes) ToArrowhead() d2target.Arrowhead
type ContainerLevel int
func (l ContainerLevel) LabelSize() int
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 (e *Edge) AbsID() string
func (e *Edge) ArrowString() string
func (e *Edge) ContainedBy(obj *Object) bool
func (e *Edge) GetAstEdge() *d2ast.Edge
func (e *Edge) GetGroup() *Object
func (e *Edge) GetStroke(dashGapSize interface{}) string
func (e *Edge) Move(dx, dy float64)
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 *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 (e *Edge) Text() *d2target.MText
func (edge *Edge) TraceToShape(points []*geo.Point, startIndex, endIndex int) (newStart, newEnd int)
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 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() *Graph
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 (g *Graph) ExtractAsNestedGraph(obj *Object) *Graph
remove obj and all descendants from graph, as a new Graph
func (g *Graph) GetBoard(name string) *Graph
func (g *Graph) InjectNestedGraph(tempGraph *Graph, parent *Object)
func (g *Graph) PrintString() string
func (g *Graph) RootBoard() *Graph
func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler, fontFamily *d2fonts.FontFamily) error
func (g *Graph) SortEdgesByAST()
func (g *Graph) SortObjectsByAST()
func (g *Graph) Texts() []*d2target.MText
type LayoutGraph func(context.Context, *Graph) error
TODO maybe rename to Shape
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"` }
func ResolveUnderscoreKey(ida []string, obj *Object) (resolvedObj *Object, resolvedIDA []string, _ error)
TODO: remove once not used anywhere
func (obj *Object) AbsID() string
func (obj *Object) AbsIDArray() []string
func (obj *Object) AppendReferences(ida []string, ref Reference, unresolvedObj *Object)
func (obj *Object) ClosestGridCell() *Object
func (obj *Object) ClosestGridDiagram() *Object
func (obj *Object) Connect(srcID, dstID []string, srcArrow, dstArrow bool, label string) (*Edge, error)
func (o *Object) ContainedBy(obj *Object) bool
func (obj *Object) ContainsAnyEdge(edges []*Edge) bool
func (obj *Object) ContainsAnyObject(objects []*Object) bool
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 (obj *Object) FindEdges(mk *d2ast.Key) ([]*Edge, bool)
TODO: remove edges []edge and scope each edge inside Object.
func (obj *Object) GetDefaultSize(mtexts []*d2target.MText, ruler *textmeasure.Ruler, fontFamily *d2fonts.FontFamily, labelDims d2target.TextDimensions, withLabelPadding bool) (*d2target.TextDimensions, error)
func (obj *Object) GetFill() string
func (obj *Object) GetIconTopLeft() *geo.Point
func (obj *Object) GetLabelSize(mtexts []*d2target.MText, ruler *textmeasure.Ruler, fontFamily *d2fonts.FontFamily) (*d2target.TextDimensions, error)
func (obj *Object) GetLabelTopLeft() *geo.Point
func (obj *Object) GetMargin() geo.Spacing
func (obj *Object) GetModifierElementAdjustments() (dx, dy float64)
GetModifierElementAdjustments returns width/height adjustments to account for shapes with 3d or multiple
func (obj *Object) GetStroke(dashGapSize interface{}) string
func (obj *Object) HasChild(ids []string) (*Object, bool)
func (obj *Object) HasEdge(mk *d2ast.Key) (*Edge, bool)
func (obj *Object) HasIcon() bool
func (obj *Object) HasLabel() bool
func (obj *Object) HasOutsideBottomLabel() bool
func (obj *Object) Is3D() bool
func (obj *Object) IsConstantNear() bool
func (obj *Object) IsContainer() bool
func (obj *Object) IsDescendantOf(ancestor *Object) bool
func (obj *Object) IsGridDiagram() bool
func (obj *Object) IsMultiple() bool
func (obj *Object) IsSequenceDiagram() bool
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 (obj *Object) IsSequenceDiagramNote() bool
notes are descendant of actors with no edges and no children
func (obj *Object) IterDescendants(apply func(parent, child *Object))
func (obj *Object) Level() ContainerLevel
func (obj *Object) MoveWithDescendants(dx, dy float64)
func (obj *Object) MoveWithDescendantsTo(x, y float64)
func (obj *Object) OuterNearContainer() *Object
func (obj *Object) OuterSequenceDiagram() *Object
func (parent *Object) RemoveChild(child *Object)
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 (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 (obj *Object) Spacing() (margin, padding geo.Spacing)
func (obj *Object) SpacingOpt(labelPadding, iconPadding float64, maxIconSize bool) (margin, padding geo.Spacing)
func (obj *Object) Text() *d2target.MText
func (obj *Object) ToShape() shape.Shape
func (obj *Object) TopGridDiagram() *Object
TopGridDiagram returns the least nested (outermost) grid diagram
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 (r Reference) InEdge() bool
func (r Reference) MapKeyEdgeDest() bool
type RouteEdges func(context.Context, *Graph, []*Edge) error
TODO consider having different Scalar types Right now we'll hold any types in Value and just convert, e.g. floats
type Scalar struct { Value string `json:"value"` MapKey *d2ast.Key `json:"-"` }
type SerializedEdge map[string]interface{}
type SerializedGraph struct { Root SerializedObject `json:"root"` Edges []SerializedEdge `json:"edges"` Objects []SerializedObject `json:"objects"` RootLevel int `json:"rootLevel"` }
type SerializedObject map[string]interface{}
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 (s *Style) Apply(key, value string) error
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.