...

Source file src/oss.terrastruct.com/d2/lib/shape/shape_callout.go

Documentation: oss.terrastruct.com/d2/lib/shape

     1  package shape
     2  
     3  import (
     4  	"math"
     5  
     6  	"oss.terrastruct.com/d2/lib/geo"
     7  	"oss.terrastruct.com/d2/lib/svg"
     8  	"oss.terrastruct.com/util-go/go2"
     9  )
    10  
    11  type shapeCallout struct {
    12  	*baseShape
    13  }
    14  
    15  const (
    16  	defaultTipWidth  = 30.
    17  	defaultTipHeight = 45.
    18  )
    19  
    20  func NewCallout(box *geo.Box) Shape {
    21  	shape := shapeCallout{
    22  		baseShape: &baseShape{
    23  			Type: CALLOUT_TYPE,
    24  			Box:  box,
    25  		},
    26  	}
    27  	shape.FullShape = go2.Pointer(Shape(shape))
    28  	return shape
    29  }
    30  
    31  func getTipWidth(box *geo.Box) float64 {
    32  	tipWidth := defaultTipWidth
    33  	if box.Width < tipWidth*2 {
    34  		tipWidth = box.Width / 2.0
    35  	}
    36  	return tipWidth
    37  }
    38  
    39  func getTipHeight(box *geo.Box) float64 {
    40  	tipHeight := defaultTipHeight
    41  	if box.Height < tipHeight*2 {
    42  		tipHeight = box.Height / 2.0
    43  	}
    44  	return tipHeight
    45  }
    46  
    47  func (s shapeCallout) GetInnerBox() *geo.Box {
    48  	tipHeight := getTipHeight(s.Box)
    49  	height := s.Box.Height - tipHeight
    50  	return geo.NewBox(s.Box.TopLeft.Copy(), s.Box.Width, height)
    51  }
    52  
    53  func calloutPath(box *geo.Box) *svg.SvgPathContext {
    54  	tipWidth := getTipWidth(box)
    55  	tipHeight := getTipHeight(box)
    56  	pc := svg.NewSVGPathContext(box.TopLeft, 1, 1)
    57  	pc.StartAt(pc.Absolute(0, 0))
    58  	pc.V(true, box.Height-tipHeight)
    59  	pc.H(true, box.Width/2.0)
    60  	pc.V(true, tipHeight)
    61  	pc.L(true, tipWidth, -tipHeight)
    62  	pc.H(true, box.Width/2.0-tipWidth)
    63  	pc.V(true, -(box.Height - tipHeight))
    64  	pc.H(true, -box.Width)
    65  	pc.Z()
    66  	return pc
    67  }
    68  
    69  func (s shapeCallout) Perimeter() []geo.Intersectable {
    70  	return calloutPath(s.Box).Path
    71  }
    72  
    73  func (s shapeCallout) GetSVGPathData() []string {
    74  	return []string{
    75  		calloutPath(s.Box).PathData(),
    76  	}
    77  }
    78  
    79  func (s shapeCallout) GetDimensionsToFit(width, height, paddingX, paddingY float64) (float64, float64) {
    80  	// return the minimum shape dimensions needed to fit content (width x height)
    81  	// in the shape's innerBox with padding
    82  	baseHeight := height + paddingY
    83  	if baseHeight < defaultTipHeight {
    84  		baseHeight *= 2
    85  	} else {
    86  		baseHeight += defaultTipHeight
    87  	}
    88  	return math.Ceil(width + paddingX), math.Ceil(baseHeight)
    89  }
    90  
    91  func (s shapeCallout) GetDefaultPadding() (paddingX, paddingY float64) {
    92  	return defaultPadding, defaultPadding / 2
    93  }
    94  

View as plain text