• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 package ohos.devtools.views.layout.chartview;
17 
18 import com.intellij.ui.JBColor;
19 import com.intellij.ui.components.JBPanel;
20 import ohos.devtools.views.charts.utils.ChartUtils;
21 import ohos.devtools.views.layout.chartview.utils.OperationUtils;
22 
23 import java.awt.Dimension;
24 import java.awt.Font;
25 import java.awt.Graphics;
26 import java.math.BigDecimal;
27 
28 import static ohos.devtools.views.common.ColorConstants.TIMELINE_SCALE;
29 import static ohos.devtools.views.layout.chartview.utils.ChartViewConstants.TIMELINE_FONT_SIZE;
30 import static ohos.devtools.views.layout.chartview.utils.ChartViewConstants.TIMELINE_MARK_COUNTS;
31 
32 /**
33  * User-defined timeline component of Profiler
34  *
35  * @since 2021/11/22
36  */
37 public class ProfilerTimeline extends JBPanel {
38     /**
39      * Offset in point
40      */
41     private static final int OFFSET_POINT = 5;
42 
43     /**
44      * draw line top border
45      */
46     private static final int TOP_BORDER = 6;
47 
48     /**
49      * Offset in seconds
50      */
51     private static final int OFFSET_SECONDS = 10;
52 
53     /**
54      * Unit value of minutes converted to seconds
55      */
56     private static final int SECONDS_UNIT = 60;
57 
58     /**
59      * Conversion rate for time conversion
60      */
61     private static final int CONVERSION_RATE = 1000;
62 
63     /**
64      * The maximum time that can be displayed on the timeline
65      */
66     private int maxDisplayTime;
67 
68     /**
69      * Minimum interval between timescales
70      */
71     private int minMarkInterval;
72 
73     /**
74      * Right coordinates of timeline
75      */
76     private int right;
77 
78     /**
79      * Top coordinates of timeline
80      */
81     private int top;
82 
83     /**
84      * The start time of the timeline when drawing
85      */
86     private int startTime;
87 
88     /**
89      * The end time of the timeline when drawing
90      */
91     private int endTime;
92 
93     /**
94      * Coordinate axis X0 point when drawing timeline
95      *
96      * @see "It is the coordinate axis X0 point used in daily drawing, not the coordinate axis origin of Swing"
97      */
98     private int x0;
99 
100     /**
101      * Coordinate axis Y0 point when drawing timeline
102      *
103      * @see "It is the coordinate axis Y0 point used in daily drawing, not the coordinate axis origin of Swing"
104      */
105     private int y0;
106 
107     /**
108      * The start time offset when the scale is drawn when the timeline is full of panels
109      */
110     private int offsetTime = 0;
111 
112     /**
113      * The x-axis is the coordinate of the starting plot
114      *
115      * @see "The dynamic timeline and chart appear from right to left"
116      */
117     private int startCoordinate;
118 
119     /**
120      * Number of pixels per X-axis time unit
121      */
122     private BigDecimal pixelPerTime;
123 
124     /**
125      * Constructor
126      *
127      * @param width Width of timeline
128      * @param height Height of timeline
129      */
ProfilerTimeline(int width, int height)130     public ProfilerTimeline(int width, int height) {
131         this.setPreferredSize(new Dimension(width, height));
132     }
133 
134     /**
135      * paintComponent
136      *
137      * @param graphics graphics
138      */
139     @Override
paintComponent(Graphics graphics)140     protected void paintComponent(Graphics graphics) {
141         super.paintComponent(graphics);
142         initPoints();
143         drawAxis(graphics);
144     }
145 
146     /**
147      * Initialization of points and scale information
148      */
initPoints()149     private void initPoints() {
150         // Determine the origin of the drawn axis
151         x0 = this.getX();
152         right = x0 + this.getWidth();
153         top = this.getY();
154         y0 = top + this.getHeight() - 1;
155         if (right == 0 || maxDisplayTime == 0) {
156             return;
157         }
158         // Calculate how many pixels a time unit takes
159         pixelPerTime = OperationUtils.divide(right, maxDisplayTime);
160         // If the current time is greater than the maximum time, the offset is calculated
161         if (endTime > maxDisplayTime && minMarkInterval != 0) {
162             startCoordinate = x0;
163             // Determine if there is offset time
164             if (endTime % minMarkInterval == 0) {
165                 offsetTime = 0;
166             } else {
167                 // If the remainder of current time and minMarkInterval is not 0,
168                 // the offset is calculated: minimum interval - current time% minimum interval
169                 offsetTime = minMarkInterval - endTime % minMarkInterval;
170             }
171         } else {
172             // If the current time is less than the maximum time,
173             // the timeline needs to be drawn from the middle with an offset of 0
174             offsetTime = 0;
175             startCoordinate = x0 + right - OperationUtils.multiply(pixelPerTime, endTime);
176         }
177     }
178 
179     /**
180      * Draw the coordinate axis of the timeline
181      *
182      * @param graphics Graphics
183      */
drawAxis(Graphics graphics)184     private void drawAxis(Graphics graphics) {
185         graphics.setColor(TIMELINE_SCALE);
186         // Draw the vertical line to the left of the timeline
187         graphics.drawLine(x0, top, x0, y0);
188         // Draw a horizontal line at the bottom of the timeline
189         graphics.drawLine(x0, y0, right, y0);
190         // The time line is drawn from offset time (the scale is drawn in fact)
191         for (int drawTime = offsetTime; drawTime <= maxDisplayTime; drawTime += minMarkInterval) {
192             int pointX = startCoordinate + ChartUtils.multiply(pixelPerTime, drawTime);
193             // Calculate the actual time to show
194             int showTime = startTime + drawTime;
195             int result = (showTime / minMarkInterval) % TIMELINE_MARK_COUNTS;
196             // Draw coordinate axis numbers and large scale every minMarkInterval
197             graphics.setColor(TIMELINE_SCALE);
198             if (result == 0) {
199                 // Draw a long scale
200                 graphics.drawLine(pointX, y0, pointX, top);
201                 graphics.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, TIMELINE_FONT_SIZE));
202                 // Time after conversion
203                 String str = millisecondToTime(showTime);
204                 graphics.setColor(JBColor.foreground());
205                 graphics.drawString(str, pointX + OFFSET_POINT, y0 - OFFSET_SECONDS);
206             } else {
207                 graphics.drawLine(pointX, top, pointX, top + TOP_BORDER);
208             }
209         }
210     }
211 
212     /**
213      * Draw the coordinate number of the timeline
214      *
215      * @param time time
216      * @return String
217      */
millisecondToTime(int time)218     private String millisecondToTime(int time) {
219         String timeStr;
220         int hour;
221         int minute;
222         int second;
223         int millisecond;
224         if (time <= 0) {
225             return "0";
226         } else {
227             second = time / CONVERSION_RATE;
228             minute = second / SECONDS_UNIT;
229             millisecond = time % CONVERSION_RATE;
230             if (second < SECONDS_UNIT) {
231                 timeStr = secondFormat(second) + "." + millisecondFormat(millisecond);
232             } else if (minute < SECONDS_UNIT) {
233                 second = second % SECONDS_UNIT;
234                 timeStr = secondFormat(minute) + ":" + secondFormat(second) + "." + millisecondFormat(millisecond);
235             } else {
236                 hour = minute / SECONDS_UNIT;
237                 minute = minute % SECONDS_UNIT;
238                 int num3600 = SECONDS_UNIT * SECONDS_UNIT;
239                 second = second - hour * num3600 - minute * SECONDS_UNIT;
240                 timeStr = secondFormat(hour) + ":" + secondFormat(minute) + ":" + secondFormat(second) + "."
241                     + millisecondFormat(millisecond);
242             }
243         }
244         return timeStr;
245     }
246 
247     /**
248      * Format conversion of hour, minute and second
249      *
250      * @param secondTime secondTime
251      * @return String
252      */
secondFormat(int secondTime)253     private String secondFormat(int secondTime) {
254         String formatTime;
255         if (secondTime == 0) {
256             formatTime = "00";
257         } else if (secondTime > 0 && secondTime < OFFSET_SECONDS) {
258             formatTime = Integer.toString(secondTime);
259         } else {
260             formatTime = "" + secondTime;
261         }
262         return formatTime;
263     }
264 
265     /**
266      * Millisecond format conversion
267      *
268      * @param millisecondTime millisecondTime
269      * @return String
270      */
millisecondFormat(int millisecondTime)271     private String millisecondFormat(int millisecondTime) {
272         String formatTime;
273         if (millisecondTime == 0) {
274             formatTime = "000";
275         } else if (millisecondTime > 0 && millisecondTime < OFFSET_SECONDS) {
276             formatTime = Integer.toString(millisecondTime);
277         } else if (millisecondTime >= OFFSET_SECONDS && millisecondTime < OFFSET_SECONDS * OFFSET_SECONDS) {
278             formatTime = Integer.toString(millisecondTime);
279         } else {
280             formatTime = "" + millisecondTime;
281         }
282         return formatTime;
283     }
284 
285     /**
286      * setMaxDisplayTime
287      *
288      * @param maxDisplayTime maxDisplayTime
289      */
setMaxDisplayTime(int maxDisplayTime)290     public void setMaxDisplayTime(int maxDisplayTime) {
291         this.maxDisplayTime = maxDisplayTime;
292     }
293 
294     /**
295      * setMinMarkInterval
296      *
297      * @param minMarkInterval minMarkInterval
298      */
setMinMarkInterval(int minMarkInterval)299     public void setMinMarkInterval(int minMarkInterval) {
300         this.minMarkInterval = minMarkInterval;
301     }
302 
303     /**
304      * getStartTime
305      *
306      * @return int
307      */
getStartTime()308     public int getStartTime() {
309         return startTime;
310     }
311 
312     /**
313      * setStartTime
314      *
315      * @param startTime startTime
316      */
setStartTime(int startTime)317     public void setStartTime(int startTime) {
318         this.startTime = startTime;
319     }
320 
321     /**
322      * getEndTime
323      *
324      * @return int
325      */
getEndTime()326     public int getEndTime() {
327         return endTime;
328     }
329 
330     /**
331      * setEndTime
332      *
333      * @param endTime endTime
334      */
setEndTime(int endTime)335     public void setEndTime(int endTime) {
336         this.endTime = endTime;
337     }
338 }
339