Commit
+125 -2 +/-3 browse
1 | diff --git a/README.md b/README.md |
2 | index c4e192d..052a0c9 100644 |
3 | --- a/README.md |
4 | +++ b/README.md |
5 | @@ -38,5 +38,8 @@ set the query parameters as appropriate: |
6 | - **label**: template for the chart legend in Go's text/template format. All |
7 | values provided by prometheus as tags are available - to label each matching |
8 | result by the instance, for instance, use `{{.instance}}` |
9 | + - **colors**: comma separated list of RGB/RGBA colors |
10 | + - **foreground-color**: the foreground color of the generated chart |
11 | + - **background-color**: the background color of the generated chart |
12 | |
13 | [1]: https://golang.org/pkg/time/#ParseDuration |
14 | diff --git a/main.go b/main.go |
15 | index 06d6ff5..e5bd427 100644 |
16 | --- a/main.go |
17 | +++ b/main.go |
18 | @@ -2,6 +2,7 @@ package main |
19 | |
20 | import ( |
21 | "bytes" |
22 | + "encoding/hex" |
23 | "encoding/json" |
24 | "fmt" |
25 | "image/color" |
26 | @@ -147,6 +148,83 @@ func handleLabel(p *plot.Plot, l *plotter.Line, label string, metric map[string] |
27 | } |
28 | } |
29 | |
30 | + func hexToColor(hexstr string) (color.RGBA, error) { |
31 | + if hexstr[0] == '#' { |
32 | + hexstr = hexstr[1:] |
33 | + } |
34 | + |
35 | + decoded, err := hex.DecodeString(hexstr) |
36 | + if err != nil { |
37 | + return color.RGBA{}, err |
38 | + } |
39 | + |
40 | + if len(decoded) != 3 && len(decoded) != 4 { |
41 | + return color.RGBA{}, fmt.Errorf("Hex string should be 3 or 4 bytes long") |
42 | + } |
43 | + |
44 | + if len(decoded) == 3 { |
45 | + return color.RGBA{R: decoded[0], G: decoded[1], B: decoded[2], A: 255}, nil |
46 | + } else { |
47 | + return color.RGBA{R: decoded[0], G: decoded[1], B: decoded[2], A: decoded[3]}, nil |
48 | + } |
49 | + } |
50 | + |
51 | + func getColors(args url.Values) ([]color.Color, error) { |
52 | + colorsArg := args.Get("colors") |
53 | + if colorsArg == "" { |
54 | + // default to soft colors |
55 | + return plotutil.SoftColors, nil |
56 | + } |
57 | + colors := []color.Color{} |
58 | + for _, hexString := range strings.Split(colorsArg, ",") { |
59 | + color, err := hexToColor(hexString) |
60 | + if err != nil { |
61 | + return nil, err |
62 | + } |
63 | + colors = append(colors, color) |
64 | + } |
65 | + return colors, nil |
66 | + } |
67 | + |
68 | + // set the various colors of the plot configured in url arguments |
69 | + func setColors(plot *plot.Plot, args url.Values) ([]color.Color, error) { |
70 | + foregroundColor := color.RGBA{0, 0, 0, 0} |
71 | + if textArg, ok := args["foreground-color"]; ok { |
72 | + text, err := hexToColor(textArg[0]) |
73 | + if err != nil { |
74 | + return nil, err |
75 | + } |
76 | + foregroundColor = text |
77 | + } |
78 | + |
79 | + backgroundColor := color.RGBA{255, 255, 255, 255} |
80 | + if bgArg, ok := args["background-color"]; ok { |
81 | + bg, err := hexToColor(bgArg[0]) |
82 | + if err != nil { |
83 | + return nil, err |
84 | + } |
85 | + backgroundColor = bg |
86 | + } |
87 | + |
88 | + plot.Title.Color = foregroundColor |
89 | + plot.Legend.Color = foregroundColor |
90 | + |
91 | + plot.X.Color = foregroundColor |
92 | + plot.X.Label.Color = foregroundColor |
93 | + plot.X.LineStyle.Color = foregroundColor |
94 | + plot.X.Tick.Label.Color = foregroundColor |
95 | + |
96 | + plot.Y.Color = foregroundColor |
97 | + plot.Y.Label.Color = foregroundColor |
98 | + plot.Y.LineStyle.Color = foregroundColor |
99 | + plot.Y.Tick.Label.Color = foregroundColor |
100 | + |
101 | + plot.BackgroundColor = backgroundColor |
102 | + |
103 | + return getColors(args) |
104 | + |
105 | + } |
106 | + |
107 | func registerExtension(router chi.Router, extension string, mime string) { |
108 | router.Get("/chart."+extension, func(w http.ResponseWriter, r *http.Request) { |
109 | args := r.URL.Query() |
110 | @@ -206,6 +284,15 @@ func registerExtension(router chi.Router, extension string, mime string) { |
111 | if err != nil { |
112 | panic(err) |
113 | } |
114 | + |
115 | + colors, err := setColors(p, args) |
116 | + |
117 | + if err != nil { |
118 | + w.WriteHeader(400) |
119 | + w.Write([]byte(fmt.Sprintf("%v", err))) |
120 | + return |
121 | + } |
122 | + |
123 | if t, ok := args["title"]; ok { |
124 | p.Title.Text = t[0] |
125 | } |
126 | @@ -227,7 +314,6 @@ func registerExtension(router chi.Router, extension string, mime string) { |
127 | |
128 | plotters := make([]plot.Plotter, len(data)) |
129 | var nextColor int |
130 | - colors := plotutil.SoftColors |
131 | for i, res := range data { |
132 | var points plotter.XYs |
133 | for j, d := range res.Values { |
134 | diff --git a/static/index.html b/static/index.html |
135 | index e1e6bcf..f363bb6 100644 |
136 | --- a/static/index.html |
137 | +++ b/static/index.html |
138 | @@ -165,6 +165,39 @@ |
139 | <td colspan="3"></td> |
140 | <td colspan="6"> |
141 | <div class="form-field"> |
142 | + <label for="colors">Plot Colors</label> |
143 | + <input type="text" id="colors" /> |
144 | + <span class="help"> |
145 | + Comma separated RGB/RGBA values |
146 | + </span> |
147 | + </div> |
148 | + </td> |
149 | + </tr> |
150 | + <tr> |
151 | + <td colspan="3"></td> |
152 | + <td colspan="3"> |
153 | + <div class="form-field"> |
154 | + <label for="background-color">Background Color</label> |
155 | + <input type="text" id="background-color" /> |
156 | + <span class="help"> |
157 | + RGB/RGBA value |
158 | + </span> |
159 | + </div> |
160 | + </td> |
161 | + <td colspan="3"> |
162 | + <div class="form-field"> |
163 | + <label for="foreground-color">Foreground Color</label> |
164 | + <input type="text" id="foreground-color" /> |
165 | + <span class="help"> |
166 | + RGB/RGBA value |
167 | + </span> |
168 | + </div> |
169 | + </td> |
170 | + </tr> |
171 | + <tr> |
172 | + <td colspan="3"></td> |
173 | + <td colspan="6"> |
174 | + <div class="form-field"> |
175 | <label for="url">Chart URL</label> |
176 | <input type="text" id="url" disabled /> |
177 | </div> |
178 | @@ -210,7 +243,8 @@ |
179 | src += "chart." + getValue("format") + "?"; |
180 | |
181 | var params = ["query", "title", "stacked", "since", "until", "width", |
182 | - "height", "step", "min", "max", "label"]; |
183 | + "height", "step", "min", "max", "label", "colors", "background-color", |
184 | + "foreground-color"]; |
185 | var first = true; |
186 | for (var i = 0; i < params.length; ++i) { |
187 | var value = getValue(params[i]); |