improve grid expand evenly
This commit is contained in:
parent
8409702ef0
commit
3937e37589
1 changed files with 112 additions and 120 deletions
|
|
@ -266,40 +266,17 @@ func (gd *gridDiagram) layoutDynamic(g *d2graph.Graph, obj *d2graph.Object) {
|
||||||
cursor := geo.NewPoint(0, 0)
|
cursor := geo.NewPoint(0, 0)
|
||||||
var maxY, maxX float64
|
var maxY, maxX float64
|
||||||
if gd.rowDirected {
|
if gd.rowDirected {
|
||||||
// if we have 2 rows, then each row's objects should have the same height
|
// measure row widths
|
||||||
// . ┌A─────────────┐ ┌B──┐ ┌C─────────┐ ┬ maxHeight(A,B,C)
|
|
||||||
// . ├ ─ ─ ─ ─ ─ ─ ─┤ │ │ │ │ │
|
|
||||||
// . │ │ │ │ ├ ─ ─ ─ ─ ─┤ │
|
|
||||||
// . │ │ │ │ │ │ │
|
|
||||||
// . └──────────────┘ └───┘ └──────────┘ ┴
|
|
||||||
// . ┌D────────┐ ┌E────────────────┐ ┬ maxHeight(D,E)
|
|
||||||
// . │ │ │ │ │
|
|
||||||
// . │ │ │ │ │
|
|
||||||
// . │ │ ├ ─ ─ ─ ─ ─ ─ ─ ─ ┤ │
|
|
||||||
// . │ │ │ │ │
|
|
||||||
// . └─────────┘ └─────────────────┘ ┴
|
|
||||||
rowWidths := []float64{}
|
rowWidths := []float64{}
|
||||||
for _, row := range layout {
|
for _, row := range layout {
|
||||||
rowHeight := 0.
|
x := 0.
|
||||||
for _, o := range row {
|
for _, o := range row {
|
||||||
o.TopLeft = cursor.Copy()
|
x += o.Width + horizontalGap
|
||||||
cursor.X += o.Width + horizontalGap
|
|
||||||
rowHeight = math.Max(rowHeight, o.Height)
|
|
||||||
}
|
}
|
||||||
rowWidth := cursor.X - horizontalGap
|
rowWidth := x - horizontalGap
|
||||||
rowWidths = append(rowWidths, rowWidth)
|
rowWidths = append(rowWidths, rowWidth)
|
||||||
maxX = math.Max(maxX, rowWidth)
|
maxX = math.Max(maxX, rowWidth)
|
||||||
|
|
||||||
// set all objects in row to the same height
|
|
||||||
for _, o := range row {
|
|
||||||
o.Height = rowHeight
|
|
||||||
}
|
|
||||||
|
|
||||||
// new row
|
|
||||||
cursor.X = 0
|
|
||||||
cursor.Y += rowHeight + verticalGap
|
|
||||||
}
|
}
|
||||||
maxY = cursor.Y - horizontalGap
|
|
||||||
|
|
||||||
// then expand thinnest objects to make each row the same width
|
// then expand thinnest objects to make each row the same width
|
||||||
// . ┌A─────────────┐ ┌B──┐ ┌C─────────┐ ┬ maxHeight(A,B,C)
|
// . ┌A─────────────┐ ┌B──┐ ┌C─────────┐ ┬ maxHeight(A,B,C)
|
||||||
|
|
@ -319,80 +296,79 @@ func (gd *gridDiagram) layoutDynamic(g *d2graph.Graph, obj *d2graph.Object) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
delta := maxX - rowWidth
|
delta := maxX - rowWidth
|
||||||
objects := []*d2graph.Object{}
|
|
||||||
var widest float64
|
var widest float64
|
||||||
for _, o := range row {
|
for _, o := range row {
|
||||||
widest = math.Max(widest, o.Width)
|
widest = math.Max(widest, o.Width)
|
||||||
objects = append(objects, o)
|
|
||||||
}
|
}
|
||||||
sort.Slice(objects, func(i, j int) bool {
|
diffs := make([]float64, len(row))
|
||||||
return objects[i].Width < objects[j].Width
|
totalDiff := 0.
|
||||||
})
|
for i, o := range row {
|
||||||
// expand smaller objects to fill remaining space
|
diffs[i] = widest - o.Width
|
||||||
for _, o := range objects {
|
totalDiff += diffs[i]
|
||||||
if o.Width < widest {
|
}
|
||||||
var index int
|
if totalDiff > 0 {
|
||||||
for i, rowObj := range row {
|
// expand smaller nodes up to the size of the larger ones with delta
|
||||||
if o == rowObj {
|
// percentage diff
|
||||||
index = i
|
for i := range diffs {
|
||||||
break
|
diffs[i] /= totalDiff
|
||||||
}
|
}
|
||||||
}
|
growth := math.Min(delta, totalDiff)
|
||||||
grow := math.Min(widest-o.Width, delta)
|
// expand smaller objects to fill remaining space
|
||||||
o.Width += grow
|
for i, o := range row {
|
||||||
// shift following objects
|
o.Width += diffs[i] * growth
|
||||||
for i := index + 1; i < len(row); i++ {
|
|
||||||
row[i].TopLeft.X += grow
|
|
||||||
}
|
|
||||||
delta -= grow
|
|
||||||
if delta <= 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if delta > 0 {
|
if delta > totalDiff {
|
||||||
grow := delta / float64(len(row))
|
growth := (delta - totalDiff) / float64(len(row))
|
||||||
for i := len(row) - 1; i >= 0; i-- {
|
for _, o := range row {
|
||||||
o := row[i]
|
o.Width += growth
|
||||||
o.TopLeft.X += grow * float64(i)
|
|
||||||
o.Width += grow
|
|
||||||
delta -= grow
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// if we have 3 columns, then each column's objects should have the same width
|
// if we have 2 rows, then each row's objects should have the same height
|
||||||
// . ├maxWidth(A,B)─┤ ├maxW(C,D)─┤ ├maxWidth(E)──────┤
|
// . ┌A─────────────┐ ┌B──┐ ┌C─────────┐ ┬ maxHeight(A,B,C)
|
||||||
// . ┌A─────────────┐ ┌C─────────┐ ┌E────────────────┐
|
// . ├ ─ ─ ─ ─ ─ ─ ─┤ │ │ │ │ │
|
||||||
// . └──────────────┘ │ │ │ │
|
// . │ │ │ │ ├ ─ ─ ─ ─ ─┤ │
|
||||||
// . ┌B──┬──────────┐ └──────────┘ │ │
|
// . │ │ │ │ │ │ │
|
||||||
// . │ │ ┌D────────┬┐ └─────────────────┘
|
// . └──────────────┘ └───┘ └──────────┘ ┴
|
||||||
// . │ │ │ │ │
|
// . ┌D────────┐ ┌E────────────────┐ ┬ maxHeight(D,E)
|
||||||
// . │ │ │ ││
|
// . │ │ │ │ │
|
||||||
// . └───┴──────────┘ │ │
|
// . │ │ │ │ │
|
||||||
// . │ ││
|
// . │ │ ├ ─ ─ ─ ─ ─ ─ ─ ─ ┤ │
|
||||||
// . └─────────┴┘
|
// . │ │ │ │ │
|
||||||
colHeights := []float64{}
|
// . └─────────┘ └─────────────────┘ ┴
|
||||||
for _, column := range layout {
|
for _, row := range layout {
|
||||||
colWidth := 0.
|
rowHeight := 0.
|
||||||
for _, o := range column {
|
for _, o := range row {
|
||||||
o.TopLeft = cursor.Copy()
|
o.TopLeft = cursor.Copy()
|
||||||
cursor.Y += o.Height + verticalGap
|
cursor.X += o.Width + horizontalGap
|
||||||
colWidth = math.Max(colWidth, o.Width)
|
rowHeight = math.Max(rowHeight, o.Height)
|
||||||
}
|
|
||||||
colHeight := cursor.Y - verticalGap
|
|
||||||
colHeights = append(colHeights, colHeight)
|
|
||||||
maxY = math.Max(maxY, colHeight)
|
|
||||||
// set all objects in column to the same width
|
|
||||||
for _, o := range column {
|
|
||||||
o.Width = colWidth
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// new column
|
// set all objects in row to the same height
|
||||||
cursor.Y = 0
|
for _, o := range row {
|
||||||
cursor.X += colWidth + horizontalGap
|
o.Height = rowHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
// new row
|
||||||
|
cursor.X = 0
|
||||||
|
cursor.Y += rowHeight + verticalGap
|
||||||
}
|
}
|
||||||
maxX = cursor.X - horizontalGap
|
maxY = cursor.Y - horizontalGap
|
||||||
|
} else {
|
||||||
|
// measure column heights
|
||||||
|
colHeights := []float64{}
|
||||||
|
for _, column := range layout {
|
||||||
|
y := 0.
|
||||||
|
for _, o := range column {
|
||||||
|
y += o.Height + verticalGap
|
||||||
|
}
|
||||||
|
colHeight := y - verticalGap
|
||||||
|
colHeights = append(colHeights, colHeight)
|
||||||
|
maxY = math.Max(maxY, colHeight)
|
||||||
|
}
|
||||||
|
|
||||||
// then expand shortest objects to make each column the same height
|
// then expand shortest objects to make each column the same height
|
||||||
// . ├maxWidth(A,B)─┤ ├maxW(C,D)─┤ ├maxWidth(E)──────┤
|
// . ├maxWidth(A,B)─┤ ├maxW(C,D)─┤ ├maxWidth(E)──────┤
|
||||||
// . ┌A─────────────┐ ┌C─────────┐ ┌E────────────────┐
|
// . ┌A─────────────┐ ┌C─────────┐ ┌E────────────────┐
|
||||||
|
|
@ -410,47 +386,63 @@ func (gd *gridDiagram) layoutDynamic(g *d2graph.Graph, obj *d2graph.Object) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
delta := maxY - colHeight
|
delta := maxY - colHeight
|
||||||
objects := []*d2graph.Object{}
|
|
||||||
var tallest float64
|
var tallest float64
|
||||||
for _, o := range column {
|
for _, o := range column {
|
||||||
tallest = math.Max(tallest, o.Height)
|
tallest = math.Max(tallest, o.Height)
|
||||||
objects = append(objects, o)
|
|
||||||
}
|
}
|
||||||
sort.Slice(objects, func(i, j int) bool {
|
diffs := make([]float64, len(column))
|
||||||
return objects[i].Height < objects[j].Height
|
totalDiff := 0.
|
||||||
})
|
for i, o := range column {
|
||||||
// expand smaller objects to fill remaining space
|
diffs[i] = tallest - o.Height
|
||||||
for _, o := range objects {
|
totalDiff += diffs[i]
|
||||||
if o.Height < tallest {
|
}
|
||||||
var index int
|
if totalDiff > 0 {
|
||||||
for i, colObj := range column {
|
// expand smaller nodes up to the size of the larger ones with delta
|
||||||
if o == colObj {
|
// percentage diff
|
||||||
index = i
|
for i := range diffs {
|
||||||
break
|
diffs[i] /= totalDiff
|
||||||
}
|
}
|
||||||
}
|
growth := math.Min(delta, totalDiff)
|
||||||
grow := math.Min(tallest-o.Height, delta)
|
// expand smaller objects to fill remaining space
|
||||||
o.Height += grow
|
for i, o := range column {
|
||||||
// shift following objects
|
o.Height += diffs[i] * growth
|
||||||
for i := index + 1; i < len(column); i++ {
|
|
||||||
column[i].TopLeft.Y += grow
|
|
||||||
}
|
|
||||||
delta -= grow
|
|
||||||
if delta <= 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if delta > 0 {
|
if delta > totalDiff {
|
||||||
grow := delta / float64(len(column))
|
growth := (delta - totalDiff) / float64(len(column))
|
||||||
for i := len(column) - 1; i >= 0; i-- {
|
for _, o := range column {
|
||||||
o := column[i]
|
o.Height += growth
|
||||||
o.TopLeft.Y += grow * float64(i)
|
|
||||||
o.Height += grow
|
|
||||||
delta -= grow
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// if we have 3 columns, then each column's objects should have the same width
|
||||||
|
// . ├maxWidth(A,B)─┤ ├maxW(C,D)─┤ ├maxWidth(E)──────┤
|
||||||
|
// . ┌A─────────────┐ ┌C─────────┐ ┌E────────────────┐
|
||||||
|
// . └──────────────┘ │ │ │ │
|
||||||
|
// . ┌B──┬──────────┐ └──────────┘ │ │
|
||||||
|
// . │ │ ┌D────────┬┐ └─────────────────┘
|
||||||
|
// . │ │ │ │ │
|
||||||
|
// . │ │ │ ││
|
||||||
|
// . └───┴──────────┘ │ │
|
||||||
|
// . │ ││
|
||||||
|
// . └─────────┴┘
|
||||||
|
for _, column := range layout {
|
||||||
|
colWidth := 0.
|
||||||
|
for _, o := range column {
|
||||||
|
o.TopLeft = cursor.Copy()
|
||||||
|
cursor.Y += o.Height + verticalGap
|
||||||
|
colWidth = math.Max(colWidth, o.Width)
|
||||||
|
}
|
||||||
|
// set all objects in column to the same width
|
||||||
|
for _, o := range column {
|
||||||
|
o.Width = colWidth
|
||||||
|
}
|
||||||
|
|
||||||
|
// new column
|
||||||
|
cursor.Y = 0
|
||||||
|
cursor.X += colWidth + horizontalGap
|
||||||
|
}
|
||||||
|
maxX = cursor.X - horizontalGap
|
||||||
}
|
}
|
||||||
gd.width = maxX
|
gd.width = maxX
|
||||||
gd.height = maxY
|
gd.height = maxY
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue