-
Notifications
You must be signed in to change notification settings - Fork 0
/
circular.go
112 lines (99 loc) · 3.46 KB
/
circular.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package gps
import (
"fmt"
"strings"
"text/template"
"github.com/kevincobain2000/go-progress-svg/utils"
)
var circularTPL = `
<svg width="{{.CircleSize}}" height="{{.Hsize}}" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg">
{{if .BackgroundColor}}
<circle r="90" cx="100" cy="100" fill="{{.BackgroundColor}}" />
{{end}}
<circle r="90" cx="100" cy="100" fill="transparent" stroke="{{.CircleColor}}" stroke-width="{{.CircleWidth}}px" stroke-dasharray="{{.CircleDashArray}}" stroke-dashoffset="0"></circle>
<circle r="90" cx="100" cy="100" stroke="{{.ProgressColor}}" stroke-width="{{.ProgressWidth}}px" stroke-linecap="round" stroke-dasharray="{{.ProgressDashArray}}" stroke-dashoffset="{{.Offset}}px" fill="transparent" style="transform:rotate(-90deg); transform-origin: 50% 50%;"></circle>
<text x="100" y="100" font-family="Tohma,Helvetica,Arial,sans-serif,sans-serif" fill="{{.TextColor}}" font-size="{{.TextSize}}px" font-weight="bold" text-anchor="middle" alignment-baseline="middle">{{.Progress}}%</text>
{{if .Caption}}
<text x="100" y="220" font-family="Tohma,Helvetica,Arial,sans-serif,sans-serif" fill="{{.CaptionColor}}" font-size="{{.CaptionSize}}px" text-anchor="middle">{{.Caption}}</text>
{{end}}
</svg>
`
type Circular struct {
options *CircularOptions
strings *utils.Strings
}
type CircularOptions struct {
Progress int
CircleSize int
Hsize int
CircleWidth int
ProgressWidth int
CircleColor string
ProgressColor string
TextColor string
TextSize int
BackgroundColor string
Caption string
CaptionSize int
CaptionColor string
Offset float64
SegmentCount int
SegmentGap float64
CircleDashArray string
ProgressDashArray string
}
type Option func(*CircularOptions) error
func NewCircular(opts ...Option) (*Circular, error) {
options := &CircularOptions{
Progress: 0,
CircleSize: 200,
Hsize: 200,
CircleWidth: 16,
ProgressWidth: 16,
CircleColor: "#e0e0e0",
ProgressColor: "#76e5b1",
TextColor: "#6bdba7",
TextSize: 52,
BackgroundColor: "",
Caption: "",
CaptionSize: 20,
CaptionColor: "#000000",
SegmentCount: 10,
SegmentGap: 2,
}
for _, opt := range opts {
err := opt(options)
if err != nil {
return nil, err
}
}
if options.Caption != "" {
options.Hsize = options.CircleSize + options.CircleSize*30/100
}
totalCircumference := 565.48
segmentLength := (totalCircumference - options.SegmentGap*float64(options.SegmentCount)) / float64(options.SegmentCount)
options.CircleDashArray = fmt.Sprintf("%f %f", segmentLength, options.SegmentGap)
progressSegments := float64(options.SegmentCount) * float64(options.Progress) / 100
progressSegmentLength := progressSegments*(segmentLength+options.SegmentGap) - options.SegmentGap
options.ProgressDashArray = fmt.Sprintf("%f %f", progressSegmentLength, totalCircumference-progressSegmentLength)
options.Offset = 0
return &Circular{
options: options,
strings: utils.NewStrings(),
}, nil
}
func (c *Circular) SVG() string {
tpl := c.strings.StripXMLWhitespace(circularTPL)
tmpl, err := template.New("svg").Parse(tpl)
if err != nil {
fmt.Println("Error parsing template:", err)
return ""
}
var rendered strings.Builder
err = tmpl.Execute(&rendered, c.options)
if err != nil {
fmt.Println("Error rendering template:", err)
return ""
}
return rendered.String()
}