darksky.GetWeatherImage   F
last analyzed

Complexity

Conditions 14

Size

Total Lines 144
Code Lines 92

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 92
nop 1
dl 0
loc 144
rs 2.7818
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like darksky.GetWeatherImage often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
package darksky
2
3
import (
4
	"bytes"
5
	"encoding/json"
6
	"fmt"
7
	"github.com/FlameInTheDark/dtbot/api/location"
8
	"github.com/FlameInTheDark/dtbot/bot"
9
	"github.com/fogleman/gg"
10
	"image/png"
11
	"net/http"
12
	"strings"
13
	"time"
14
)
15
16
// DarkSkyResponse contains main structures of API response
17
type DarkSkyResponse struct {
0 ignored issues
show
introduced by
type name will be used as darksky.DarkSkyResponse by other packages, and that stutters; consider calling this Response
Loading history...
18
	Latitude  float32       `json:"latitude"`
19
	Longitude float32       `json:"longitude"`
20
	Timezone  string        `json:"timezone"`
21
	Currently DarkSkyData   `json:"currently"`
22
	Hourly    DarkSkyHourly `json:"hourly"`
23
	Daily     DarkSkyDaily  `json:"daily"`
24
	Flags     DarkSkyFlags  `json:"flags"`
25
	Offset    float64         `json:"offset"`
26
}
27
28
// DarkSkyData contains main hourly weather data
29
type DarkSkyData struct {
0 ignored issues
show
introduced by
type name will be used as darksky.DarkSkyData by other packages, and that stutters; consider calling this Data
Loading history...
30
	Time                int64   `json:"time"`
31
	Summary             string  `json:"summary"`
32
	Icon                string  `json:"icon"`
33
	PrecipIntensity     float32 `json:"precipIntensity"`
34
	PrecipProbability   float32 `json:"precipProbability"`
35
	Temperature         float32 `json:"temperature"`
36
	ApparentTemperature float32 `json:"apparentTemperature"`
37
	DewPoint            float32 `json:"dewPoint"`
38
	Humidity            float32 `json:"humidity"`
39
	Pressure            float32 `json:"pressure"`
40
	WindSpeed           float32 `json:"windSpeed"`
41
	WindGust            float32 `json:"windGust"`
42
	WindBearing         int64   `json:"windBearing"`
43
	CloudCover          float32 `json:"cloudCover"`
44
	UVIndex             int64   `json:"uvIndex"`
45
	Visibility          float32 `json:"visibility"`
46
	Ozone               float32 `json:"ozone"`
47
}
48
49
// DarkSkyHourly contains hourly weather data array
50
type DarkSkyHourly struct {
0 ignored issues
show
introduced by
type name will be used as darksky.DarkSkyHourly by other packages, and that stutters; consider calling this Hourly
Loading history...
51
	Summary string        `json:"summary"`
52
	Icon    string        `json:"icon"`
53
	Data    []DarkSkyData `json:"data"`
54
}
55
56
// DarkSkyDaily contains daily weather data array
57
type DarkSkyDaily struct {
0 ignored issues
show
introduced by
type name will be used as darksky.DarkSkyDaily by other packages, and that stutters; consider calling this Daily
Loading history...
58
	Summary string           `json:"summary"`
59
	Icon    string           `json:"icon"`
60
	Data    []DarkSkyDayData `json:"data"`
61
}
62
63
// DarkSkyDayData contains main daily weather data
64
type DarkSkyDayData struct {
0 ignored issues
show
introduced by
type name will be used as darksky.DarkSkyDayData by other packages, and that stutters; consider calling this DayData
Loading history...
65
	Time                        int64   `json:"time"`
66
	Summary                     string  `json:"summary"`
67
	Icon                        string  `json:"icon"`
68
	SunriseTime                 int64   `json:"sunriseTime"`
69
	SunsetTime                  int64   `json:"sunsetTime"`
70
	MoonPhase                   float32 `json:"moonPhase"`
71
	PrecipIntensity             float32 `json:"precipIntensity"`
72
	PrecipIntensityMax          float32 `json:"precipIntensityMax"`
73
	PrecipIntensityMaxTime      int64   `json:"precipIntensityMaxTime"`
74
	PrecipProbability           float32 `json:"precipProbability"`
75
	PrecipAccumulation          float32 `json:"precipAccumulation"`
76
	PrecipType                  string  `json:"precipType"`
77
	TemperatureHigh             float32 `json:"temperatureHigh"`
78
	TemperatureHighTime         int64   `json:"temperatureHighTime"`
79
	TemperatureLow              float32 `json:"temperatureLow"`
80
	TemperatureLowTime          int64   `json:"temperatureLowTime"`
81
	ApparentTemperatureHigh     float32 `json:"apparentTemperatureHigh"`
82
	ApparentTemperatureHighTime int64   `json:"apparentTemperatureHighTime"`
83
	ApparentTemperatureLow      float32 `json:"apparentTemperatureLow"`
84
	ApparentTemperatureLowTime  int64   `json:"apparentTemperatureLowTime"`
85
	DewPoint                    float32 `json:"dewPoint"`
86
	Humidity                    float32 `json:"humidity"`
87
	Pressure                    float32 `json:"pressure"`
88
	WindSpeed                   float32 `json:"windSpeed"`
89
	WindGust                    float32 `json:"windGust"`
90
	WindGustTime                int64   `json:"windGustTime"`
91
	WindBearing                 int64   `json:"windBearing"`
92
	CloudCover                  float32 `json:"cloudCover"`
93
	UVIndex                     int64   `json:"uvIndex"`
94
	UVIndexTime                 int64   `json:"uvIndexTime"`
95
	Visibility                  float32 `json:"visibility"`
96
	Ozone                       float32 `json:"ozone"`
97
	TemperatureMin              float32 `json:"temperatureMin"`
98
	TemperatureMinTime          int64   `json:"temperatureMinTime"`
99
	TemperatureMax              float32 `json:"temperatureMax"`
100
	TemperatureMaxTime          int64   `json:"temperatureMaxTime"`
101
	ApparentTemperatureMin      float32 `json:"apparentTemperatureMin"`
102
	ApparentTemperatureMinTime  int64   `json:"apparentTemperatureMinTime"`
103
	ApparentTemperatureMax      float32 `json:"apparentTemperatureMax"`
104
	ApparentTemperatureMaxTime  int64   `json:"apparentTemperatureMaxTime"`
105
}
106
107
// DarkSkyFlags contains response flags
108
type DarkSkyFlags struct {
0 ignored issues
show
introduced by
type name will be used as darksky.DarkSkyFlags by other packages, and that stutters; consider calling this Flags
Loading history...
109
	Sources        []string `json:"sources"`
110
	NearestStation float32  `json:"nearest-station"`
111
	Units          string   `json:"units"`
112
}
113
114
func (d *DarkSkyData) GetTime(location string, tz int) time.Time {
0 ignored issues
show
introduced by
exported method DarkSkyData.GetTime should have comment or be unexported
Loading history...
115
	fLoc, fLocErr := time.LoadLocation(location)
116
	if fLocErr != nil {
117
		fmt.Println("Weather timezone error: ", fLocErr.Error())
118
		return d.TZTime(tz)
119
	}
120
	return time.Unix(d.Time, 0).UTC().In(fLoc)
121
}
122
123
func (d *DarkSkyDayData) GetTime(location string, tz int) time.Time {
0 ignored issues
show
introduced by
exported method DarkSkyDayData.GetTime should have comment or be unexported
Loading history...
124
	fLoc, fLocErr := time.LoadLocation(location)
125
	if fLocErr != nil {
126
		fmt.Println("Weather timezone error: ", fLocErr.Error())
127
		return d.TZTime(tz)
128
	}
129
	return time.Unix(d.Time, 0).UTC().In(fLoc)
130
}
131
132
// TZTime converts epoch date to normal with timezone
133
func (d *DarkSkyData) TZTime(tz int) time.Time {
134
	return time.Unix(d.Time, 0).UTC().Add(time.Hour * time.Duration(tz))
135
}
136
137
func (d *DarkSkyDayData) TZTime(tz int) time.Time {
0 ignored issues
show
introduced by
exported method DarkSkyDayData.TZTime should have comment or be unexported
Loading history...
138
	return time.Unix(d.Time, 0).UTC().Add(time.Hour * time.Duration(tz))
139
}
140
141
// GetWeatherImage returns weather image widget
142
func GetWeatherImage(ctx *bot.Context) (buf *bytes.Buffer, err error) {
143
	var (
144
		forecast DarkSkyResponse
145
		city     = ctx.GetGuild().WeatherCity
146
	)
147
148
	if len(ctx.Args) > 0 {
149
		city = strings.Join(ctx.Args, "+")
150
	}
151
152
	loc, err := location.New(ctx.Conf.General.GeonamesUsername, city)
153
	if err != nil {
154
		fmt.Printf("Location API: %v\n", err)
155
		return
156
	}
157
158
	cityName := loc.Geonames[0].CountryName + ", " + loc.Geonames[0].Name
159
160
	// Get coordinates and get weather data
161
	newlat, newlng := loc.GetCoordinates()
162
	resp, err := http.Get(fmt.Sprintf("https://api.darksky.net/forecast/%v/%v,%v?units=ca&lang=%v",
163
		ctx.Conf.DarkSky.Token, newlat, newlng, ctx.Conf.General.Language))
164
	if err != nil {
165
		fmt.Printf("Weather API: %v\n", err)
166
		return
167
	}
168
169
	err = json.NewDecoder(resp.Body).Decode(&forecast)
170
	if err != nil {
171
		fmt.Printf("Weather Decode: %v\n", err)
172
		return
173
	}
174
175
	// Drawing weather widget
176
	gc := gg.NewContext(400, 650)
177
	gc.SetRGBA(0, 0, 0, 0)
178
	gc.Clear()
179
180
	// Template
181
	gc.SetRGB255(242, 97, 73)
182
	gc.DrawRoundedRectangle(0, 0, 400, 650, 10)
183
	gc.Fill()
184
185
	// Weather lines
186
	gc.SetRGB255(234, 89, 65)
187
	gc.DrawRectangle(0, 250, 400, 100)
188
	gc.DrawRectangle(0, 450, 400, 100)
189
	gc.Fill()
190
191
	gc.SetLineWidth(2)
192
	gc.SetRGBA(0, 0, 0, 0.05)
193
	gc.DrawLine(0, 250, 400, 250)
194
	gc.DrawLine(0, 349, 400, 348)
195
	gc.DrawLine(0, 450, 400, 450)
196
	gc.DrawLine(0, 549, 400, 548)
197
	gc.Stroke()
198
199
	// Text
200
	if err := gc.LoadFontFace("lato.ttf", 20); err != nil {
201
		panic(err)
202
	}
203
204
	// Header (place and date)
205
	gc.SetRGBA(1, 1, 1, 0.7)
206
	gc.DrawStringAnchored(cityName, 10, 15, 0, 0.5)
207
	gc.SetRGBA(1, 1, 1, 0.4)
208
	gc.DrawStringAnchored(time.Now().Format("Jan 2, 2006"), 270, 15, 0, 0.5)
209
210
	// First weather data
211
	gc.SetRGBA(1, 1, 1, 0.5)
212
	if err := gc.LoadFontFace("lato.ttf", 30); err != nil {
213
		panic(err)
214
	}
215
216
	gc.DrawStringAnchored(fmt.Sprintf("%.2v:00", forecast.Currently.GetTime(forecast.Timezone, ctx.Conf.General.Timezone).Hour()), 50, 200, 0.5, 0.5)
217
	gc.DrawStringAnchored(fmt.Sprintf("H:%v%%", int(forecast.Currently.Humidity*100)), 200, 200, 0.5, 0.5)
218
	gc.DrawStringAnchored(fmt.Sprintf("C:%v%%", int(forecast.Currently.CloudCover*100)), 350, 200, 0.5, 0.5)
219
220
	gc.SetRGBA(1, 1, 1, 1)
221
	if err := gc.LoadFontFace("lato.ttf", 90); err != nil {
222
		panic(err)
223
	}
224
225
	gc.DrawStringAnchored(fmt.Sprintf("%v°", int(forecast.Currently.Temperature)), 100, 120, 0.5, 0.5)
226
227
	if err := gc.LoadFontFace("weathericons.ttf", 70); err != nil {
228
		panic(err)
229
	}
230
231
	gc.DrawStringAnchored(ctx.WeatherCode(fmt.Sprintf("%v", forecast.Currently.Icon)), 250, 120, 0, 0.7)
232
233
	if err := gc.LoadFontFace("lato.ttf", 30); err != nil {
234
		panic(err)
235
	}
236
237
	// Time
238
	gc.DrawStringAnchored(fmt.Sprintf("%.2v:00", forecast.Hourly.Data[2].GetTime(forecast.Timezone, ctx.Conf.General.Timezone).Hour()), 100, 285, 0, 0.5)
239
	gc.DrawStringAnchored(fmt.Sprintf("%.2v:00", forecast.Hourly.Data[4].GetTime(forecast.Timezone, ctx.Conf.General.Timezone).Hour()), 100, 385, 0, 0.5)
240
	gc.DrawStringAnchored(fmt.Sprintf("%.2v:00", forecast.Hourly.Data[6].GetTime(forecast.Timezone, ctx.Conf.General.Timezone).Hour()), 100, 485, 0, 0.5)
241
	gc.DrawStringAnchored(fmt.Sprintf("%.2v:00", forecast.Hourly.Data[8].GetTime(forecast.Timezone, ctx.Conf.General.Timezone).Hour()), 100, 585, 0, 0.5)
242
243
	// Humidity and cloudiness
244
	if err := gc.LoadFontFace("lato.ttf", 20); err != nil {
245
		panic(err)
246
	}
247
	gc.SetRGBA(1, 1, 1, 0.5)
248
249
	gc.DrawStringAnchored(fmt.Sprintf("H:%v%%", int(forecast.Hourly.Data[2].Humidity*100)), 100, 315, 0, 0.5)
250
	gc.DrawStringAnchored(fmt.Sprintf("H:%v%%", int(forecast.Hourly.Data[4].Humidity*100)), 100, 415, 0, 0.5)
251
	gc.DrawStringAnchored(fmt.Sprintf("H:%v%%", int(forecast.Hourly.Data[6].Humidity*100)), 100, 515, 0, 0.5)
252
	gc.DrawStringAnchored(fmt.Sprintf("H:%v%%", int(forecast.Hourly.Data[8].Humidity*100)), 100, 615, 0, 0.5)
253
254
	gc.DrawStringAnchored(fmt.Sprintf("C:%v%%", int(forecast.Hourly.Data[2].CloudCover*100)), 170, 315, 0, 0.5)
255
	gc.DrawStringAnchored(fmt.Sprintf("C:%v%%", int(forecast.Hourly.Data[4].CloudCover*100)), 170, 415, 0, 0.5)
256
	gc.DrawStringAnchored(fmt.Sprintf("C:%v%%", int(forecast.Hourly.Data[6].CloudCover*100)), 170, 515, 0, 0.5)
257
	gc.DrawStringAnchored(fmt.Sprintf("C:%v%%", int(forecast.Hourly.Data[8].CloudCover*100)), 170, 615, 0, 0.5)
258
259
	gc.SetRGBA(1, 1, 1, 1)
260
	if err := gc.LoadFontFace("lato.ttf", 50); err != nil {
261
		panic(err)
262
	}
263
264
	// Temperature
265
	gc.DrawStringAnchored(fmt.Sprintf("%v°", int(forecast.Hourly.Data[2].Temperature)), 320, 300, 0.5, 0.5)
266
	gc.DrawStringAnchored(fmt.Sprintf("%v°", int(forecast.Hourly.Data[4].Temperature)), 320, 400, 0.5, 0.5)
267
	gc.DrawStringAnchored(fmt.Sprintf("%v°", int(forecast.Hourly.Data[6].Temperature)), 320, 500, 0.5, 0.5)
268
	gc.DrawStringAnchored(fmt.Sprintf("%v°", int(forecast.Hourly.Data[8].Temperature)), 320, 600, 0.5, 0.5)
269
270
	if err := gc.LoadFontFace("weathericons.ttf", 40); err != nil {
271
		panic(err)
272
	}
273
274
	// Weather icon
275
	gc.DrawStringAnchored(ctx.WeatherCode(fmt.Sprintf("%v", forecast.Hourly.Data[2].Icon)), 20, 300, 0, 0.7)
276
	gc.DrawStringAnchored(ctx.WeatherCode(fmt.Sprintf("%v", forecast.Hourly.Data[4].Icon)), 20, 400, 0, 0.7)
277
	gc.DrawStringAnchored(ctx.WeatherCode(fmt.Sprintf("%v", forecast.Hourly.Data[6].Icon)), 20, 500, 0, 0.7)
278
	gc.DrawStringAnchored(ctx.WeatherCode(fmt.Sprintf("%v", forecast.Hourly.Data[8].Icon)), 20, 600, 0, 0.7)
279
280
	buf = new(bytes.Buffer)
281
	pngerr := png.Encode(buf, gc.Image())
282
	if pngerr != nil {
283
		fmt.Printf("Image: %v\n", pngerr)
284
	}
285
	return
286
}
287
288
// GetWeatherImage returns weather image widget
0 ignored issues
show
introduced by
comment on exported function GetWeatherWeekImage should be of the form "GetWeatherWeekImage ..."
Loading history...
289
func GetWeatherWeekImage(ctx *bot.Context) (buf *bytes.Buffer, err error) {
290
	var (
291
		forecast DarkSkyResponse
292
		city     = ctx.GetGuild().WeatherCity
293
	)
294
295
	if len(ctx.Args) > 0 {
296
		city = strings.Join(ctx.Args, "+")
297
	}
298
299
	loc, err := location.New(ctx.Conf.General.GeonamesUsername, city)
300
	if err != nil {
301
		fmt.Printf("Location API: %v\n", err)
302
		return
303
	}
304
305
	cityName := loc.Geonames[0].CountryName + ", " + loc.Geonames[0].Name
306
307
	// Get coordinates and get weather data
308
	newlat, newlng := loc.GetCoordinates()
309
	resp, err := http.Get(fmt.Sprintf("https://api.darksky.net/forecast/%v/%v,%v?units=ca&lang=%v",
310
		ctx.Conf.DarkSky.Token, newlat, newlng, ctx.Conf.General.Language))
311
	if err != nil {
312
		fmt.Printf("Weather API: %v\n", err)
313
		return
314
	}
315
316
	err = json.NewDecoder(resp.Body).Decode(&forecast)
317
	if err != nil {
318
		fmt.Printf("Weather Decode: %v\n", err)
319
		return
320
	}
321
322
	// Drawing weather widget
323
	gc := gg.NewContext(400, 650)
324
	gc.SetRGBA(0, 0, 0, 0)
325
	gc.Clear()
326
327
	// Template
328
	gc.SetRGB255(242, 97, 73)
329
	gc.DrawRoundedRectangle(0, 0, 400, 650, 10)
330
	gc.Fill()
331
332
	// Weather lines
333
	gc.SetRGB255(234, 89, 65)
334
	gc.DrawRectangle(0, 250, 400, 100)
335
	gc.DrawRectangle(0, 450, 400, 100)
336
	gc.Fill()
337
338
	gc.SetLineWidth(2)
339
	gc.SetRGBA(0, 0, 0, 0.05)
340
	gc.DrawLine(0, 250, 400, 250)
341
	gc.DrawLine(0, 349, 400, 348)
342
	gc.DrawLine(0, 450, 400, 450)
343
	gc.DrawLine(0, 549, 400, 548)
344
	gc.Stroke()
345
346
	// Text
347
	if err := gc.LoadFontFace("lato.ttf", 20); err != nil {
348
		panic(err)
349
	}
350
351
	// Header (place and date)
352
	gc.SetRGBA(1, 1, 1, 0.7)
353
	gc.DrawStringAnchored(cityName, 10, 15, 0, 0.5)
354
	gc.SetRGBA(1, 1, 1, 0.4)
355
	gc.DrawStringAnchored(time.Now().Format("Jan 2, 2006"), 270, 15, 0, 0.5)
356
357
	// First weather data
358
	gc.SetRGBA(1, 1, 1, 0.5)
359
	if err := gc.LoadFontFace("lato.ttf", 30); err != nil {
360
		panic(err)
361
	}
362
363
	gc.DrawStringAnchored(fmt.Sprintf("%s", forecast.Daily.Data[0].GetTime(forecast.Timezone, ctx.Conf.General.Timezone).Weekday()), 80, 200, 0.5, 0.5)
364
	gc.DrawStringAnchored(fmt.Sprintf("H:%v%%", int(forecast.Daily.Data[0].Humidity*100)), 200, 200, 0.5, 0.5)
365
	gc.DrawStringAnchored(fmt.Sprintf("C:%v%%", int(forecast.Daily.Data[0].CloudCover*100)), 350, 200, 0.5, 0.5)
366
367
	gc.SetRGBA(1, 1, 1, 1)
368
	if err := gc.LoadFontFace("lato.ttf", 90); err != nil {
369
		panic(err)
370
	}
371
372
	gc.DrawStringAnchored(fmt.Sprintf("%v°", int(forecast.Currently.Temperature)), 100, 120, 0.5, 0.5)
373
374
	if err := gc.LoadFontFace("weathericons.ttf", 70); err != nil {
375
		panic(err)
376
	}
377
378
	gc.DrawStringAnchored(ctx.WeatherCode(fmt.Sprintf("%v", forecast.Currently.Icon)), 250, 120, 0, 0.7)
379
380
	if err := gc.LoadFontFace("lato.ttf", 30); err != nil {
381
		panic(err)
382
	}
383
384
	// Time
385
	gc.DrawStringAnchored(fmt.Sprintf("%s", forecast.Daily.Data[1].GetTime(forecast.Timezone, ctx.Conf.General.Timezone).Weekday()), 100, 285, 0, 0.5)
386
	gc.DrawStringAnchored(fmt.Sprintf("%s", forecast.Daily.Data[2].GetTime(forecast.Timezone, ctx.Conf.General.Timezone).Weekday()), 100, 385, 0, 0.5)
387
	gc.DrawStringAnchored(fmt.Sprintf("%s", forecast.Daily.Data[3].GetTime(forecast.Timezone, ctx.Conf.General.Timezone).Weekday()), 100, 485, 0, 0.5)
388
	gc.DrawStringAnchored(fmt.Sprintf("%s", forecast.Daily.Data[4].GetTime(forecast.Timezone, ctx.Conf.General.Timezone).Weekday()), 100, 585, 0, 0.5)
389
390
	// Humidity and cloudiness
391
	if err := gc.LoadFontFace("lato.ttf", 20); err != nil {
392
		panic(err)
393
	}
394
	gc.SetRGBA(1, 1, 1, 0.5)
395
396
	gc.DrawStringAnchored(fmt.Sprintf("H:%v%%", int(forecast.Daily.Data[1].Humidity*100)), 100, 315, 0, 0.5)
397
	gc.DrawStringAnchored(fmt.Sprintf("H:%v%%", int(forecast.Daily.Data[2].Humidity*100)), 100, 415, 0, 0.5)
398
	gc.DrawStringAnchored(fmt.Sprintf("H:%v%%", int(forecast.Daily.Data[3].Humidity*100)), 100, 515, 0, 0.5)
399
	gc.DrawStringAnchored(fmt.Sprintf("H:%v%%", int(forecast.Daily.Data[4].Humidity*100)), 100, 615, 0, 0.5)
400
401
	gc.DrawStringAnchored(fmt.Sprintf("C:%v%%", int(forecast.Daily.Data[1].CloudCover*100)), 170, 315, 0, 0.5)
402
	gc.DrawStringAnchored(fmt.Sprintf("C:%v%%", int(forecast.Daily.Data[2].CloudCover*100)), 170, 415, 0, 0.5)
403
	gc.DrawStringAnchored(fmt.Sprintf("C:%v%%", int(forecast.Daily.Data[3].CloudCover*100)), 170, 515, 0, 0.5)
404
	gc.DrawStringAnchored(fmt.Sprintf("C:%v%%", int(forecast.Daily.Data[4].CloudCover*100)), 170, 615, 0, 0.5)
405
406
	gc.SetRGBA(1, 1, 1, 1)
407
	if err := gc.LoadFontFace("lato.ttf", 35); err != nil {
408
		panic(err)
409
	}
410
411
	// Temperature max
412
	gc.DrawStringAnchored(fmt.Sprintf("%v°/%v°", int(forecast.Daily.Data[1].TemperatureMax), int(forecast.Daily.Data[1].TemperatureMin)), 330, 300, 0.5, 0.5)
413
	gc.DrawStringAnchored(fmt.Sprintf("%v°/%v°", int(forecast.Daily.Data[2].TemperatureMax), int(forecast.Daily.Data[2].TemperatureMin)), 330, 400, 0.5, 0.5)
414
	gc.DrawStringAnchored(fmt.Sprintf("%v°/%v°", int(forecast.Daily.Data[3].TemperatureMax), int(forecast.Daily.Data[3].TemperatureMin)), 330, 500, 0.5, 0.5)
415
	gc.DrawStringAnchored(fmt.Sprintf("%v°/%v°", int(forecast.Daily.Data[4].TemperatureMax), int(forecast.Daily.Data[4].TemperatureMin)), 330, 600, 0.5, 0.5)
416
417
	if err := gc.LoadFontFace("weathericons.ttf", 40); err != nil {
418
		panic(err)
419
	}
420
421
	// Weather icon
422
	gc.DrawStringAnchored(ctx.WeatherCode(fmt.Sprintf("%v", forecast.Daily.Data[1].Icon)), 20, 300, 0, 0.7)
423
	gc.DrawStringAnchored(ctx.WeatherCode(fmt.Sprintf("%v", forecast.Daily.Data[2].Icon)), 20, 400, 0, 0.7)
424
	gc.DrawStringAnchored(ctx.WeatherCode(fmt.Sprintf("%v", forecast.Daily.Data[3].Icon)), 20, 500, 0, 0.7)
425
	gc.DrawStringAnchored(ctx.WeatherCode(fmt.Sprintf("%v", forecast.Daily.Data[4].Icon)), 20, 600, 0, 0.7)
426
427
	buf = new(bytes.Buffer)
428
	pngerr := png.Encode(buf, gc.Image())
429
	if pngerr != nil {
430
		fmt.Printf("Image: %v\n", pngerr)
431
	}
432
	return
433
}
434