@@ -3,6 +3,7 @@ package ui
33import  (
44	"fmt" 
55	"math" 
6+ 	"time" 
67
78	"github.com/gotk3/gotk3/cairo" 
89	"github.com/gotk3/gotk3/gtk" 
@@ -128,8 +129,8 @@ type graphLayout struct {
128129	multisLowZoneHeight  float64 
129130	binWidth             float64 
130131	divX                 []float64 
131- 	axisWidth             float64 
132- 	divisionWidth         float64 
132+ 	axisLineWidth        float64 
133+ 	divisionLineWidth    float64 
133134	leftLegendWidth      float64 
134135	timeIndicatorHeight  float64 
135136}
@@ -139,7 +140,6 @@ func (g *scoreGraph) Draw(da *gtk.DrawingArea, cr *cairo.Context) {
139140	defer  cr .Restore ()
140141
141142	// preparations 
142- 
143143	valueCount  :=  0 
144144	if  len (g .graphs ) >  0  {
145145		valueCount  =  len (g .graphs [0 ].DataPoints )
@@ -169,32 +169,33 @@ func (g *scoreGraph) Draw(da *gtk.DrawingArea, cr *cairo.Context) {
169169
170170func  (g  * scoreGraph ) calculateLayout (da  * gtk.DrawingArea , cr  * cairo.Context , valueCount  int ) graphLayout  {
171171	result  :=  graphLayout {
172- 		width :         float64 (da .GetAllocatedWidth ()),
173- 		height :        float64 (da .GetAllocatedHeight ()),
174- 		marginY :       10.0 ,
175- 		axisWidth :     1.0 ,
176- 		divisionWidth : .5 ,
172+ 		width :              float64 (da .GetAllocatedWidth ()),
173+ 		height :             float64 (da .GetAllocatedHeight ()),
174+ 		marginY :            10.0 ,
175+ 		axisLineWidth :     1.0 ,
176+ 		divisionLineWidth : .5 ,
177177	}
178178
179179	cr .SetFontSize (g .style .fontSize )
180180	result .leftLegendWidth  =  cr .TextExtents ("00:00" ).Width  +  2.0 
181181	result .timeIndicatorHeight  =  cr .TextExtents ("Hg" ).Height  +  2.0 
182+ 	graphWidth  :=  result .width  -  result .leftLegendWidth 
182183
183184	result .zeroY  =  (result .height  -  result .timeIndicatorHeight ) /  2.0 
184185	result .maxHeight  =  result .zeroY  -  result .marginY 
185186	result .pointsLowZoneHeight  =  math .Min (result .maxHeight / 2.0 , (result .maxHeight / float64 (g .maxPoints ))* g .pointsBinGoal )
186187	result .multisLowZoneHeight  =  math .Min (result .maxHeight / 2.0 , (result .maxHeight / float64 (g .maxMultis ))* g .multisBinGoal )
187188	if  valueCount  >  0  {
188- 		result .binWidth  =  result . width  /  float64 (valueCount )
189+ 		result .binWidth  =  graphWidth  /  float64 (valueCount )
189190	} else  {
190- 		result .binWidth  =  result . width 
191+ 		result .binWidth  =  graphWidth 
191192	}
192193
193194	const  divCount  =  8 
194195	if  len (result .divX ) !=  divCount  {
195196		result .divX  =  make ([]float64 , divCount - 1 )
196197	}
197- 	divWidth  :=  result . width  /  float64 (divCount )
198+ 	divWidth  :=  graphWidth  /  float64 (divCount )
198199	for  i  :=  range  result .divX  {
199200		result .divX [i ] =  float64 (i + 1 ) *  divWidth 
200201	}
@@ -211,32 +212,60 @@ func (g *scoreGraph) fillBackground(cr *cairo.Context) {
211212}
212213
213214func  (g  * scoreGraph ) drawZeroLine (cr  * cairo.Context , layout  graphLayout ) {
215+ 	// the line 
214216	cr .SetSourceRGB (g .style .axisColor .ToRGB ())
215- 	cr .SetLineWidth (layout .axisWidth )
216- 	cr .MoveTo (0 , layout .zeroY )
217+ 	cr .SetLineWidth (layout .axisLineWidth )
218+ 	cr .MoveTo (layout . leftLegendWidth , layout .zeroY )
217219	cr .LineTo (layout .width , layout .zeroY )
218220	cr .Stroke ()
221+ 
222+ 	// the legend 
223+ 	g .drawYLegendAt (cr , layout , layout .zeroY , "0" )
224+ }
225+ 
226+ func  (g  * scoreGraph ) drawYLegendAt (cr  * cairo.Context , layout  graphLayout , y  float64 , text  string ) {
227+ 	textExtents  :=  cr .TextExtents (text )
228+ 	left  :=  layout .leftLegendWidth  -  textExtents .Width  -  2.0 
229+ 	bottom  :=  y  +  textExtents .Height / 2.0 
230+ 	cr .SetSourceRGB (g .style .axisColor .ToRGB ())
231+ 	cr .SetFontSize (g .style .fontSize )
232+ 	cr .MoveTo (left , bottom )
233+ 	cr .ShowText (text )
219234}
220235
221236func  (g  * scoreGraph ) drawTimeDivisions (cr  * cairo.Context , layout  graphLayout ) {
222237	cr .SetSourceRGB (g .style .axisColor .ToRGB ())
223- 	cr .SetLineWidth (layout .divisionWidth )
238+ 	cr .SetLineWidth (layout .divisionLineWidth )
239+ 	cr .SetFontSize (g .style .fontSize )
240+ 
241+ 	// the zero line 
242+ 	cr .MoveTo (layout .leftLegendWidth , layout .zeroY - layout .maxHeight )
243+ 	cr .LineTo (layout .leftLegendWidth , layout .zeroY + layout .maxHeight )
244+ 	cr .Stroke ()
245+ 
246+ 	// the vertical divisions 
224247	for  _ , x  :=  range  layout .divX  {
225- 		cr .MoveTo (x , layout .zeroY - layout .maxHeight )
226- 		cr .LineTo (x , layout .zeroY + layout .maxHeight )
248+ 		cr .MoveTo (x + layout . leftLegendWidth , layout .zeroY - layout .maxHeight )
249+ 		cr .LineTo (x + layout . leftLegendWidth , layout .zeroY + layout .maxHeight )
227250		cr .Stroke ()
228251	}
229252}
230253
231254func  (g  * scoreGraph ) drawTimeIndicator (cr  * cairo.Context , layout  graphLayout ) {
232- 	if  g .timeFrameIndex  <=  0  {
233- 		return 
234- 	}
235255	now  :=  g .clock .Now ()
236256
257+ 	var  elapsedTime  time.Duration 
258+ 	var  elapsedTimePercent  float64 
259+ 	if  g .timeFrameIndex  >=  0  &&  len (g .graphs ) >  0  {
260+ 		elapsedTime  =  g .graphs [0 ].ElapsedTime (now )
261+ 		elapsedTimePercent  =  g .graphs [0 ].ElapsedTimePercent (now )
262+ 	} else  {
263+ 		elapsedTime  =  0 
264+ 		elapsedTimePercent  =  0.0 
265+ 	}
266+ 
237267	// the time bar 
238- 	elapsedTimePercent  :=  g .graphs [0 ].ElapsedTimePercent (now )
239- 	left  :=  0.0 
268+ 	left  :=  layout .leftLegendWidth 
240269	right  :=  left  +  (layout .width - left )* elapsedTimePercent 
241270	bottom  :=  layout .height  -  layout .marginY 
242271	top  :=  bottom  -  layout .timeIndicatorHeight 
@@ -250,45 +279,61 @@ func (g *scoreGraph) drawTimeIndicator(cr *cairo.Context, layout graphLayout) {
250279	cr .Fill ()
251280
252281	// the elapsed time 
253- 	elapsedTime  :=  g .graphs [0 ].ElapsedTime (now )
254- 	elapsedTimeText  :=  fmt .Sprintf ("%02d:%02d" , int (elapsedTime .Hours ()), int (elapsedTime .Minutes ())% 60 )
282+ 	elapsedTimeText  :=  formatDuration (elapsedTime )
255283
256284	cr .SetSourceRGB (g .style .axisColor .ToRGB ())
257285	cr .SetFontSize (g .style .fontSize )
258286	cr .MoveTo (1 , layout .height - layout .marginY - 1 )
259287	cr .ShowText (elapsedTimeText )
260288
261- 	// the old box 
262- 	startX  :=  float64 (g .timeFrameIndex ) *  layout .binWidth 
263- 	endX  :=  float64 (g .timeFrameIndex + 1 ) *  layout .binWidth 
289+ 	// the time legend 
290+ 	for  i , x  :=  range  layout .divX  {
291+ 		if  i % 2  ==  1  &&  len (g .graphs ) >  0  {
292+ 			percent  :=  float64 (i + 1 ) /  float64 (len (layout .divX )+ 1 )
293+ 			text  :=  formatDuration (g .graphs [0 ].PercentAsDuration (percent ))
294+ 			textExtents  :=  cr .TextExtents (text )
295+ 			cr .MoveTo (x + layout .leftLegendWidth - textExtents .Width / 2.0 , layout .zeroY + layout .maxHeight + textExtents .Height + 2 )
296+ 			cr .ShowText (text )
297+ 		}
298+ 	}
264299
265- 	cr .SetSourceRGBA (g .style .timeFrameColor .ToRGBA ())
266- 	cr .SetLineWidth (layout .divisionWidth )
267- 	cr .MoveTo (startX , layout .zeroY - layout .maxHeight )
268- 	cr .LineTo (endX , layout .zeroY - layout .maxHeight )
269- 	cr .LineTo (endX , layout .zeroY + layout .maxHeight )
270- 	cr .LineTo (startX , layout .zeroY + layout .maxHeight )
271- 	cr .ClosePath ()
272- 	cr .Stroke ()
300+ 	// the old box 
301+ 	if  g .timeFrameIndex  >=  0  {
302+ 		startX  :=  float64 (g .timeFrameIndex )* layout .binWidth  +  layout .leftLegendWidth 
303+ 		endX  :=  float64 (g .timeFrameIndex + 1 )* layout .binWidth  +  layout .leftLegendWidth 
304+ 
305+ 		cr .SetSourceRGBA (g .style .timeFrameColor .ToRGBA ())
306+ 		cr .SetLineWidth (layout .divisionLineWidth )
307+ 		cr .MoveTo (startX , layout .zeroY - layout .maxHeight )
308+ 		cr .LineTo (endX , layout .zeroY - layout .maxHeight )
309+ 		cr .LineTo (endX , layout .zeroY + layout .maxHeight )
310+ 		cr .LineTo (startX , layout .zeroY + layout .maxHeight )
311+ 		cr .ClosePath ()
312+ 		cr .Stroke ()
313+ 	}
273314}
274315
275316func  (g  * scoreGraph ) drawLowZone (cr  * cairo.Context , layout  graphLayout ) {
276317	cr .SetSourceRGBA (g .style .lowZoneColor .WithAlpha (g .style .areaAlpha ))
277- 	cr .MoveTo (0 , layout .zeroY - layout .pointsLowZoneHeight )
318+ 	cr .MoveTo (layout . leftLegendWidth , layout .zeroY - layout .pointsLowZoneHeight )
278319	cr .LineTo (layout .width , layout .zeroY - layout .pointsLowZoneHeight )
279320	cr .LineTo (layout .width , layout .zeroY + layout .multisLowZoneHeight )
280- 	cr .LineTo (0 , layout .zeroY + layout .multisLowZoneHeight )
321+ 	cr .LineTo (layout . leftLegendWidth , layout .zeroY + layout .multisLowZoneHeight )
281322	cr .ClosePath ()
282323	cr .Fill ()
283324
284325	cr .SetSourceRGBA (g .style .lowZoneColor .WithAlpha (g .style .borderAlpha ))
285- 	cr .SetLineWidth (layout .divisionWidth )
286- 	cr .MoveTo (0 , layout .zeroY - layout .pointsLowZoneHeight )
326+ 	cr .SetLineWidth (layout .divisionLineWidth )
327+ 	cr .MoveTo (layout . leftLegendWidth , layout .zeroY - layout .pointsLowZoneHeight )
287328	cr .LineTo (layout .width , layout .zeroY - layout .pointsLowZoneHeight )
288329	cr .LineTo (layout .width , layout .zeroY + layout .multisLowZoneHeight )
289- 	cr .LineTo (0 , layout .zeroY + layout .multisLowZoneHeight )
330+ 	cr .LineTo (layout . leftLegendWidth , layout .zeroY + layout .multisLowZoneHeight )
290331	cr .ClosePath ()
291332	cr .Stroke ()
333+ 
334+ 	// the legend 
335+ 	g .drawYLegendAt (cr , layout , layout .zeroY - layout .pointsLowZoneHeight , fmt .Sprintf ("%d" , int (g .pointsGoal )))
336+ 	g .drawYLegendAt (cr , layout , layout .zeroY + layout .multisLowZoneHeight , fmt .Sprintf ("%d" , int (g .multisGoal )))
292337}
293338
294339func  (g  * scoreGraph ) drawDataPointsRectangular (cr  * cairo.Context , layout  graphLayout , datapoints  []core.BandScore ) {
@@ -397,3 +442,7 @@ func (g *scoreGraph) drawDataPointsCurved(cr *cairo.Context, layout graphLayout,
397442	cr .ClosePath ()
398443	cr .Fill ()
399444}
445+ 
446+ func  formatDuration (d  time.Duration ) string  {
447+ 	return  fmt .Sprintf ("%02d:%02d" , int (d .Hours ()), int (d .Minutes ())% 60 )
448+ }
0 commit comments