OSDN Git Service

グラフ一覧でラップタイムのところに線をつなぐようにした。
[gokigen/JoggingTimer.git] / wear / src / main / java / net / osdn / gokigen / joggingtimer / stopwatch / graphview / LapTimeGraphView.java
1 package net.osdn.gokigen.joggingtimer.stopwatch.graphview;
2
3 import android.content.Context;
4 import android.graphics.Canvas;
5 import android.graphics.Color;
6 import android.graphics.Paint;
7 import android.graphics.Path;
8 import android.graphics.Rect;
9 import android.graphics.RectF;
10 import android.util.AttributeSet;
11 import android.view.View;
12
13 import net.osdn.gokigen.joggingtimer.stopwatch.ITimerCounter;
14 import net.osdn.gokigen.joggingtimer.utilities.TimeStringConvert;
15
16 import java.util.ArrayList;
17 import java.util.List;
18
19 /**
20  *
21  *
22  */
23 public class LapTimeGraphView extends View
24 {
25     private Context context = null;
26     private ITimerCounter timerCounter = null;
27     private boolean isStarted = false;
28     private long maxLaptime = 0;
29     private long lastSystemLaptime = 0;
30     private int totalLaptimeCount = 0;
31
32     private List<Long> refTimeList = null;
33     private List<Long> refLapTimeList = null;
34
35     private List<Long> curTimeList = null;
36     private List<Long> curLapTimeList = null;
37
38     /**
39      *   コンストラクタ
40      *
41      */
42     public LapTimeGraphView(Context context)
43     {
44         super(context);
45         initComponent(context);
46     }
47
48     /**
49      *   コンストラクタ
50      *
51      */
52     public LapTimeGraphView(Context context, AttributeSet attrs)
53     {
54         super(context, attrs);
55         initComponent(context);
56     }
57
58     /**
59      *   コンストラクタ
60      *
61      */
62     public LapTimeGraphView(Context context, AttributeSet attrs, int defStyleAttr)
63     {
64         super(context, attrs, defStyleAttr);
65         initComponent(context);
66     }
67
68     /**
69      *   初期化ロジック
70      */
71     private void initComponent(Context context)
72     {
73         this.context = context;
74         setWillNotDraw(false);
75         curLapTimeList = new ArrayList<>();
76     }
77
78     /**
79      *
80      *
81      */
82     public void setITimerCounter(ITimerCounter counter)
83     {
84         timerCounter = counter;
85         parseReferenceTimeList();
86         parseLapTime();
87     }
88
89     /**
90      *
91      *
92      */
93     public void notifyStarted(long startTime)
94     {
95         curLapTimeList.clear();
96         lastSystemLaptime = startTime;
97         isStarted = true;
98     }
99
100     /**
101      *
102      *
103      */
104     public void notifyLapTime()
105     {
106         // ラップタイムの取得
107         parseLapTime();
108         isStarted = true;
109     }
110
111     /**
112      *
113      *
114      */
115     public void notifyStopped()
116     {
117         // ラップタイムの取得
118         parseLapTime();
119         isStarted = false;
120     }
121
122     /**
123      *
124      *
125      */
126     public void notifyReset()
127     {
128         curLapTimeList.clear();
129         isStarted = false;
130     }
131
132     /**
133      *
134      *
135      */
136     @Override
137     protected void onDraw(Canvas canvas)
138     {
139         super.onDraw(canvas);
140
141         try
142         {
143             // 背景の表示
144             drawBackground(canvas);
145
146             // 基準の値表示
147             drawReferenceLap(canvas);
148
149             // 現在の値表示
150             drawCurrentLap(canvas);
151
152             // メッセージの表示
153             drawMessage(canvas);
154         }
155         catch (Exception e)
156         {
157             e.printStackTrace();
158         }
159
160     }
161
162     /**
163      *
164      *
165      */
166     private void drawBackground(Canvas canvas)
167     {
168         int width = canvas.getWidth();
169         int height = canvas.getHeight();
170
171         Rect rect = new Rect(0,0, width, height);
172         Paint paint = new Paint();
173         paint.setColor(Color.BLACK);
174         paint.setStyle(Paint.Style.FILL);
175         canvas.drawRect(rect, paint);
176
177         // Log.v("Canvas", "("+ width + "," + height + ")");
178     }
179
180     /**
181      *
182      *
183      */
184     private void drawReferenceLap(Canvas canvas)
185     {
186         if ((refLapTimeList == null)||(refLapTimeList.size() <= 0))
187         {
188             return;
189         }
190
191         float width = canvas.getWidth();
192         float height = canvas.getHeight();
193
194         Paint paint = new Paint();
195         paint.setColor(Color.BLUE);
196         paint.setStyle(Paint.Style.STROKE);
197         paint.setStyle(Paint.Style.FILL);
198         paint.setStrokeWidth(0.0f);
199         paint.setAntiAlias(true);
200
201         float boxWidthUnit = width / (totalLaptimeCount);
202         float boxHeightUnit = height / (maxLaptime * 1.2f);
203
204         float startX = 0.0f;
205         for (Long time : refLapTimeList)
206         {
207             RectF barRect = new RectF(startX, (height - boxHeightUnit * time), (startX + boxWidthUnit), height);
208             canvas.drawRect(barRect, paint);
209             startX = startX + boxWidthUnit;
210         }
211     }
212
213
214     /**
215      *
216      *
217      */
218     private void drawCurrentLap(Canvas canvas)
219     {
220         if (curLapTimeList == null)
221         {
222             return;
223         }
224
225         float width = canvas.getWidth();
226         float height = canvas.getHeight();
227
228         Paint paint = new Paint();
229         paint.setColor(Color.WHITE);
230         paint.setColor(Color.GRAY);
231         paint.setStyle(Paint.Style.FILL_AND_STROKE);
232         paint.setStrokeWidth(0.0f);
233         paint.setAntiAlias(true);
234
235         int minimumLapTime = 15;
236         float boxWidthUnit = width / (totalLaptimeCount);
237         float boxHeightUnit = height / (maxLaptime * 1.2f);
238         float circleRadius = (totalLaptimeCount > minimumLapTime) ? (boxWidthUnit / 4.0f) : (width / minimumLapTime / 4.0f);
239
240         float startX = 0.0f;
241         if ((curLapTimeList.size() <= 0)&&(isStarted))
242         {
243             long currentLapTime = System.currentTimeMillis() - lastSystemLaptime;
244             canvas.drawCircle((startX + (boxWidthUnit / 2.0f)), (height - boxHeightUnit * currentLapTime), circleRadius, paint);
245             return;
246         }
247
248         Path linePath = new Path();
249         linePath.moveTo(0.0f, height);  // 0原点から線を引く
250         for (Long time : curLapTimeList)
251         {
252             float cX = (startX + (boxWidthUnit / 2.0f));
253             float cY = (height - boxHeightUnit * time);
254             linePath.lineTo(cX, cY);
255             canvas.drawCircle(cX, cY, circleRadius, paint);
256             startX = startX + boxWidthUnit;
257         }
258         if (isStarted)
259         {
260             long currentLapTime = System.currentTimeMillis() - lastSystemLaptime;
261             float cX = (startX + (boxWidthUnit / 2.0f));
262             float cY = (height - boxHeightUnit * currentLapTime);
263             linePath.lineTo(cX, cY);
264             canvas.drawCircle(cX, cY, circleRadius, paint);
265         }
266         paint.setStyle(Paint.Style.STROKE);
267         paint.setColor(Color.GRAY);
268         canvas.drawPath(linePath, paint);
269     }
270
271     /**
272      *
273      *
274      */
275     private void drawMessage(Canvas canvas)
276     {
277         boolean drawTextLeft = false;
278         int width = canvas.getWidth();
279         int height = canvas.getHeight();
280         Paint paint = new Paint();
281
282         paint.setColor(Color.WHITE);
283         paint.setStyle(Paint.Style.STROKE);
284         paint.setStrokeWidth(0.0f);
285         paint.setAntiAlias(true);
286         //canvas.drawRect(rect, paint);
287
288         int lapCount = 0;
289         int refCount = 0;
290         long diffTime = 0;
291         long lapTime = 0;
292         long currTime = 0;
293         try
294         {
295             if (curTimeList != null)
296             {
297                 lapCount = curTimeList.size();
298             }
299
300             if (refTimeList != null)
301             {
302                 refCount = refTimeList.size();
303             }
304
305             if (lapCount > 1)
306             {
307                 long totalTime = curTimeList.get(lapCount - 1) - curTimeList.get(0);
308                 currTime =  curTimeList.get(lapCount - 1) - curTimeList.get(lapCount - 2);
309                 //long currTime =  (lapCount > 2) ? curTimeList.get(lapCount - 1) - curTimeList.get(lapCount - 2) : 0;
310                 if ((lapCount <= refCount)&&(refTimeList != null))
311                 {
312                     diffTime = totalTime - (refTimeList.get(lapCount - 1) - refTimeList.get(0));
313                     lapTime = currTime - (refTimeList.get(lapCount - 1) - refTimeList.get(lapCount - 2));
314                     //lapTime = currTime - ((lapCount > 2) ? refTimeList.get(lapCount - 1) - refTimeList.get(lapCount - 2) : 0);
315                 }
316             }
317         }
318         catch (Exception e)
319         {
320             e.printStackTrace();
321         }
322
323         String textToDraw = "";
324         if ((lapTime == 0)&&(diffTime == 0)&&(lapCount > 1))
325         {
326             textToDraw = "[" + (lapCount - 1) + "] " + TimeStringConvert.getTimeString(currTime).toString();
327             drawTextLeft = true;
328         }
329         else
330         {
331             if (lapTime != 0)
332             {
333                 textToDraw = TimeStringConvert.getDiffTimeString(lapTime).toString();
334             }
335             if (diffTime != 0)
336             {
337                 //  「前回ラップ時間の遅れ・進み / 全体時間の遅れ・進み」
338                 textToDraw = textToDraw + " / " + TimeStringConvert.getDiffTimeString(diffTime).toString();
339             }
340         }
341
342         // 表示する文字の大きさの決定
343         try
344         {
345             float density = context.getResources().getDisplayMetrics().density;
346             paint.setTextSize(density * 20.0f + 0.5f);
347         }
348         catch (Exception e)
349         {
350             e.printStackTrace();
351             paint.setTextSize(32.0f);
352         }
353         paint.setAntiAlias(true);
354         Paint.FontMetrics fm = paint.getFontMetrics();
355         float textHeight = fm.descent - fm.ascent;
356         float textWidth = paint.measureText(textToDraw);
357
358         // 表示位置の調整...
359         float x = (width < textWidth) ? 0.0f : (width - textWidth - 8.0f);
360         float y = (height - textHeight - 2) - fm.ascent;
361         if (drawTextLeft)
362         {
363             x = 0.0f;
364         }
365         canvas.drawText(textToDraw, x , y, paint);
366     }
367
368     /**
369      *
370      *
371      */
372     private void parseReferenceTimeList()
373     {
374         if (timerCounter == null)
375         {
376             return;
377         }
378         refLapTimeList = null;
379
380         refTimeList = timerCounter.getReferenceLapTimeList();
381         if (refTimeList == null)
382         {
383             return;
384         }
385         totalLaptimeCount = refTimeList.size();
386         maxLaptime = 0;
387         if (totalLaptimeCount <= 1)
388         {
389             return;
390         }
391         refLapTimeList = new ArrayList<>();
392         long prevTime = refTimeList.get(0);
393         for (Long time : refTimeList)
394         {
395             long currTime = time - prevTime;
396             if (currTime > 0)
397             {
398                 refLapTimeList.add(currTime);
399             }
400             if (currTime > maxLaptime)
401             {
402                 maxLaptime = currTime;
403             }
404             prevTime = time;
405         }
406     }
407
408     /**
409      *
410      *
411      */
412     private void parseLapTime()
413     {
414         if (timerCounter == null)
415         {
416             return;
417         }
418         curTimeList = timerCounter.getLapTimeList();
419         int lapTimeCount = curTimeList.size();
420         if (lapTimeCount > totalLaptimeCount)
421         {
422             totalLaptimeCount = lapTimeCount;
423         }
424         if (lapTimeCount < 1)
425         {
426             // 開始前の場合...
427             return;
428         }
429         if (lapTimeCount == 1)
430         {
431             lastSystemLaptime = curTimeList.get(0);
432             return;
433         }
434
435         curLapTimeList.clear();
436         long prevTime = curTimeList.get(0);
437         for (Long time : curTimeList)
438         {
439             long currTime = time - prevTime;
440             if (currTime > 0)
441             {
442                 curLapTimeList.add(currTime);
443             }
444             if (currTime > maxLaptime)
445             {
446                 maxLaptime = currTime;
447             }
448             prevTime = time;
449         }
450         lastSystemLaptime = prevTime;
451     }
452
453     @Override
454     public boolean performClick()
455     {
456         return (super.performClick());
457     }
458 }