Added the possibilty to not only make quadratic items

This commit is contained in:
2026-05-26 17:35:50 +02:00
parent be58c5941d
commit bca4fcc936
15 changed files with 371 additions and 134 deletions
+63 -27
View File
@@ -1,41 +1,77 @@
package svgtemplate
import "math"
// Data holds dynamic values for the SVG mask template.
type Data struct {
Size float64
Bleed float64
Margin float64
Padding float64
ViewBoxMin float64
ViewBoxSize float64
MaskSize float64
OuterSize float64
OuterOffset float64
InnerSize float64
InnerOffset float64
MarkLength float64
Width, Height float64
CornerRadius float64
Bleed float64
Margin float64
Padding float64
ViewBoxMin float64
ViewBoxWidth float64
ViewBoxHeight float64
MaskWidth float64
MaskHeight float64
OuterWidth float64
OuterHeight float64
OuterOffsetX float64
OuterOffsetY float64
InnerWidth float64
InnerHeight float64
InnerOffsetX float64
InnerOffsetY float64
InnerRadius float64
MarkLength float64
}
const defaultMarkLength = 6.0 // mm
// Build computes template data from product dimensions.
func Build(size, bleed, margin, padding float64) Data {
func Build(width, height, bleed, margin, padding, cornerRadius float64) Data {
offset := bleed + margin + defaultMarkLength
viewBoxMin := -offset
viewBoxSize := size + (offset * 2)
viewBoxW := width + (offset * 2)
viewBoxH := height + (offset * 2)
innerW := width - (padding * 2)
innerH := height - (padding * 2)
if innerW < 0 {
innerW = 0
}
if innerH < 0 {
innerH = 0
}
innerR := cornerRadius - padding
if innerR < 0 {
innerR = 0
}
maxInnerR := math.Min(innerW, innerH) / 2
if innerR > maxInnerR && maxInnerR > 0 {
innerR = maxInnerR
}
return Data{
Size: size,
Bleed: bleed,
Margin: margin,
Padding: padding,
ViewBoxMin: viewBoxMin,
ViewBoxSize: viewBoxSize,
MarkLength: defaultMarkLength,
MaskSize: size,
OuterSize: size + (bleed * 2),
OuterOffset: -bleed,
InnerSize: size - (padding * 2),
InnerOffset: padding,
Width: width,
Height: height,
CornerRadius: cornerRadius,
Bleed: bleed,
Margin: margin,
Padding: padding,
ViewBoxMin: -offset,
ViewBoxWidth: viewBoxW,
ViewBoxHeight: viewBoxH,
MarkLength: defaultMarkLength,
MaskWidth: width,
MaskHeight: height,
OuterWidth: width + (bleed * 2),
OuterHeight: height + (bleed * 2),
OuterOffsetX: -bleed,
OuterOffsetY: -bleed,
InnerWidth: innerW,
InnerHeight: innerH,
InnerOffsetX: padding,
InnerOffsetY: padding,
InnerRadius: innerR,
}
}
+12 -12
View File
@@ -10,35 +10,35 @@ import (
)
const svgTemplate = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" width="{{.Size}}mm" height="{{.Size}}mm" viewBox="{{.ViewBoxMin}} {{.ViewBoxMin}} {{.ViewBoxSize}} {{.ViewBoxSize}}">
<svg xmlns="http://www.w3.org/2000/svg" width="{{.ViewBoxWidth}}mm" height="{{.ViewBoxHeight}}mm" viewBox="{{.ViewBoxMin}} {{.ViewBoxMin}} {{.ViewBoxWidth}} {{.ViewBoxHeight}}">
<defs>
<clipPath id="item-mask">
<rect x="0" y="0" width="{{.MaskSize}}" height="{{.MaskSize}}" rx="5" ry="5" />
<rect x="0" y="0" width="{{.MaskWidth}}" height="{{.MaskHeight}}" rx="{{.CornerRadius}}" ry="{{.CornerRadius}}" />
</clipPath>
</defs>
<rect x="{{.ViewBoxMin}}" y="{{.ViewBoxMin}}" width="{{.ViewBoxSize}}" height="{{.ViewBoxSize}}" fill="#f9f9f9" />
<rect x="{{.ViewBoxMin}}" y="{{.ViewBoxMin}}" width="{{.ViewBoxWidth}}" height="{{.ViewBoxHeight}}" fill="#f9f9f9" />
<g clip-path="url(#item-mask)">
<rect x="{{.OuterOffset}}" y="{{.OuterOffset}}" width="{{.OuterSize}}" height="{{.OuterSize}}" fill="#00FF00" opacity="0.7" />
<rect x="{{.OuterOffsetX}}" y="{{.OuterOffsetY}}" width="{{.OuterWidth}}" height="{{.OuterHeight}}" fill="#00FF00" opacity="0.7" />
</g>
<rect x="{{.InnerOffset}}" y="{{.InnerOffset}}" width="{{.InnerSize}}" height="{{.InnerSize}}" fill="none" stroke="#0000FF" stroke-width="0.3" stroke-dasharray="1,1" />
<rect x="{{.InnerOffsetX}}" y="{{.InnerOffsetY}}" width="{{.InnerWidth}}" height="{{.InnerHeight}}" rx="{{.InnerRadius}}" ry="{{.InnerRadius}}" fill="none" stroke="#0000FF" stroke-width="0.3" stroke-dasharray="1,1" />
<rect x="0" y="0" width="{{.MaskSize}}" height="{{.MaskSize}}" fill="none" stroke="#ccc" stroke-width="0.2" stroke-dasharray="2,2" />
<rect x="0" y="0" width="{{.MaskWidth}}" height="{{.MaskHeight}}" rx="{{.CornerRadius}}" ry="{{.CornerRadius}}" fill="none" stroke="#ccc" stroke-width="0.2" stroke-dasharray="2,2" />
<g stroke="#000000" stroke-width="0.3">
<line x1="0" y1="-{{.Bleed}}" x2="0" y2="-{{appendBleed .Bleed .MarkLength}}" />
<line x1="-{{.Bleed}}" y1="0" x2="-{{appendBleed .Bleed .MarkLength}}" y2="0" />
<line x1="{{.Size}}" y1="-{{.Bleed}}" x2="{{.Size}}" y2="-{{appendBleed .Bleed .MarkLength}}" />
<line x1="{{add .Size .Bleed}}" y1="0" x2="{{addThree .Size .Bleed .MarkLength}}" y2="0" />
<line x1="{{.Width}}" y1="-{{.Bleed}}" x2="{{.Width}}" y2="-{{appendBleed .Bleed .MarkLength}}" />
<line x1="{{add .Width .Bleed}}" y1="0" x2="{{addThree .Width .Bleed .MarkLength}}" y2="0" />
<line x1="0" y1="{{add .Size .Bleed}}" x2="0" y2="{{addThree .Size .Bleed .MarkLength}}" />
<line x1="-{{.Bleed}}" y1="{{.Size}}" x2="-{{appendBleed .Bleed .MarkLength}}" y2="{{.Size}}" />
<line x1="0" y1="{{add .Height .Bleed}}" x2="0" y2="{{addThree .Height .Bleed .MarkLength}}" />
<line x1="-{{.Bleed}}" y1="{{.Height}}" x2="-{{appendBleed .Bleed .MarkLength}}" y2="{{.Height}}" />
<line x1="{{.Size}}" y1="{{add .Size .Bleed}}" x2="{{.Size}}" y2="{{addThree .Size .Bleed .MarkLength}}" />
<line x1="{{add .Size .Bleed}}" y1="{{.Size}}" x2="{{addThree .Size .Bleed .MarkLength}}" y2="{{.Size}}" />
<line x1="{{.Width}}" y1="{{add .Height .Bleed}}" x2="{{.Width}}" y2="{{addThree .Height .Bleed .MarkLength}}" />
<line x1="{{add .Width .Bleed}}" y1="{{.Height}}" x2="{{addThree .Width .Bleed .MarkLength}}" y2="{{.Height}}" />
</g>
</svg>
`
+20
View File
@@ -0,0 +1,20 @@
package svgtemplate
import (
"bytes"
"strings"
"testing"
)
func TestBuildSVGRootMatchesViewBox(t *testing.T) {
data := Build(10, 80, 1, 1, 1, 1)
var buf bytes.Buffer
if err := Write(&buf, data); err != nil {
t.Fatal(err)
}
s := buf.String()
want := `width="26mm" height="96mm" viewBox="-8 -8 26 96"`
if !strings.Contains(s, want) {
t.Fatalf("expected root %q in:\n%s", want, s)
}
}