• 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.charts;
17 
18 import ohos.devtools.views.charts.model.ChartDataModel;
19 import ohos.devtools.views.layout.chartview.ProfilerChartsView;
20 
21 import java.awt.Graphics;
22 import java.awt.Polygon;
23 import java.awt.event.MouseEvent;
24 import java.util.Comparator;
25 import java.util.List;
26 
27 import static ohos.devtools.views.charts.model.ChartType.FILLED_LINE;
28 import static ohos.devtools.views.charts.utils.ChartUtils.divideInt;
29 import static ohos.devtools.views.charts.utils.ChartUtils.multiply;
30 import static ohos.devtools.views.common.LayoutConstants.INITIAL_VALUE;
31 
32 /**
33  * Filled line chart
34  *
35  * @since 2021/5/19 16:39
36  */
37 public class FilledLineChart extends ProfilerChart {
38     private static final int NUM_2 = 2;
39     private static final int NUM_3 = 3;
40     private static final int Y_AXIS_COORDINATE_MAX_VALUE = 100;
41 
42 
43     /**
44      * Do line charts need to be stacked
45      */
46     private final boolean stacked;
47 
48     /**
49      * y Axis Coordinate Fixed
50      */
51     private boolean yAxisCoordinateFixed = false;
52 
53     /**
54      * Constructor
55      *
56      * @param bottomPanel ProfilerChartsView
57      * @param name chart name
58      * @param stacked Do line charts need to be stacked
59      */
FilledLineChart(ProfilerChartsView bottomPanel, String name, boolean stacked)60     public FilledLineChart(ProfilerChartsView bottomPanel, String name, boolean stacked) {
61         super(bottomPanel, name);
62         this.stacked = stacked;
63         chartType = FILLED_LINE;
64     }
65 
66     /**
67      * Constructor
68      *
69      * @param bottomPanel ProfilerChartsView
70      * @param name chart name
71      * @param stacked Do line charts need to be stacked
72      * @param yAxisCoordinateFixed yAxisCoordinateFixed
73      */
FilledLineChart(ProfilerChartsView bottomPanel, String name, boolean stacked, boolean yAxisCoordinateFixed)74     public FilledLineChart(ProfilerChartsView bottomPanel, String name, boolean stacked, boolean yAxisCoordinateFixed) {
75         super(bottomPanel, name);
76         this.stacked = stacked;
77         this.yAxisCoordinateFixed = yAxisCoordinateFixed;
78         chartType = FILLED_LINE;
79     }
80 
81     /**
82      * Init legends
83      */
84     @Override
initLegends()85     protected void initLegends() {
86     }
87 
88     /**
89      * Build legends of chart
90      *
91      * @param lastModels Data on the far right side of the panel
92      * @see "The legend shows the y value corresponding to the rightmost X axis, not the mouse hover position"
93      */
94     @Override
buildLegends(List<ChartDataModel> lastModels)95     protected void buildLegends(List<ChartDataModel> lastModels) {
96     }
97 
98     /**
99      * Paint chart
100      *
101      * @param graphics Graphics
102      */
103     @Override
paintChart(Graphics graphics)104     protected void paintChart(Graphics graphics) {
105         if (dataMap == null || dataMap.size() == 0) {
106             return;
107         }
108         List<ChartDataModel> lines = dataMap.entrySet().iterator().next().getValue();
109         // Sort from small to large according to [index]
110         lines.sort(Comparator.comparingInt(ChartDataModel::getIndex));
111         lines.forEach((line) -> paintFilledLine(line.getIndex(), graphics));
112     }
113 
114     /**
115      * Draw filled poly line
116      *
117      * @param index index of line chart
118      * @param graphics Graphics
119      * @see "Stacked method: the y value of the current broken line point is the sum of all the Y values below
120      * the current broken line. After the Y point is added, the Y point of the line below it should be added from
121      * right to left to form a closed figure."
122      * @see "If line charts do not need to be stacked, The model should go from [small to large] according to the index,
123      * and the value should go from [large to small]. Otherwise, smaller values will be masked."
124      */
paintFilledLine(int index, Graphics graphics)125     private void paintFilledLine(int index, Graphics graphics) {
126         Polygon polygon = new Polygon();
127         int[] timeArray = dataMap.keySet().stream().mapToInt(Integer::valueOf).toArray();
128         graphics.setColor(getCurrentLineColor(index, dataMap.get(timeArray[0])));
129         /*
130          * Stacked scheme: add the point of the current index line from left to back, and then add the point of
131          * the next index line from right to left
132          */
133         // Adds the point of the current polyline from left to right
134         for (int time : timeArray) {
135             int pointX = startXCoordinate + multiply(pixelPerX, time - startTime);
136             int valueY;
137             if (stacked) {
138                 valueY = getListSum(dataMap.get(time), index);
139             } else {
140                 valueY = getModelValueByIndex(dataMap.get(time), index);
141             }
142             // If the current value exceeds the maximum, the maximum update value is 1.5 times the current value
143             if (yAxisCoordinateFixed) {
144                 maxUnitY = Y_AXIS_COORDINATE_MAX_VALUE;
145             } else {
146                 if (valueY > maxUnitY) {
147                     maxUnitY = divideInt(valueY * NUM_3, NUM_2);
148                 }
149             }
150             int pointY = yZero + multiply(pixelPerY, valueY);
151             polygon.addPoint(pointX, pointY);
152         }
153         // Draw the line below
154         paintAssistLine(index, polygon, timeArray);
155         // Use the brush to fill the polygon to form a filled poly line
156         graphics.fillPolygon(polygon);
157     }
158 
paintAssistLine(int index, Polygon polygon, int[] timeArray)159     private void paintAssistLine(int index, Polygon polygon, int[] timeArray) {
160         // If nextLine does not exist, it indicates that index is the last line. You can directly add Y0 points
161         // at the beginning and end of the line. You don't need to cycle through all the points
162         int nextLineIndex = getNextLineIndex(index, dataMap.get(timeArray[0]));
163         if (nextLineIndex == INITIAL_VALUE || !stacked) {
164             int endX = startXCoordinate + multiply(pixelPerX, timeArray[timeArray.length - 1] - startTime);
165             int startX = startXCoordinate + multiply(pixelPerX, timeArray[0] - startTime);
166             polygon.addPoint(endX, yZero);
167             polygon.addPoint(startX, yZero);
168         } else {
169             // Add the point of the next index line from right to left
170             for (int time = timeArray.length - 1; time >= 0; time--) {
171                 // Calculate the X and Y points of the data on the line chart
172                 int pointX = startXCoordinate + multiply(pixelPerX, timeArray[time] - startTime);
173                 int sum = getListSum(dataMap.get(timeArray[time]), nextLineIndex);
174                 // If the current value exceeds the maximum, the maximum update value is 1.5 times the current value
175                 if (yAxisCoordinateFixed) {
176                     maxUnitY = Y_AXIS_COORDINATE_MAX_VALUE;
177                 } else {
178                     if (sum > maxUnitY) {
179                         maxUnitY = divideInt(sum * NUM_3, NUM_2);
180                     }
181                 }
182                 int pointY = yZero + multiply(pixelPerY, sum);
183                 polygon.addPoint(pointX, pointY);
184             }
185         }
186     }
187 
188     /**
189      * Build tooltip content
190      *
191      * @param showKey Key to show
192      * @param actualKey The actual value of the key in the data map
193      * @param newChart Is it a new chart
194      */
195     @Override
buildTooltip(int showKey, int actualKey, boolean newChart)196     protected void buildTooltip(int showKey, int actualKey, boolean newChart) {
197     }
198 
199     /**
200      * User defined events
201      *
202      * @param event MouseEvent
203      */
204     @Override
leftMouseClickEvent(MouseEvent event)205     protected void leftMouseClickEvent(MouseEvent event) {
206     }
207 
208     /**
209      * User defined events
210      *
211      * @param event MouseEvent
212      */
213     @Override
rightMouseClickEvent(MouseEvent event)214     protected void rightMouseClickEvent(MouseEvent event) {
215     }
216 
217     /**
218      * User defined events
219      *
220      * @param event MouseEvent
221      */
222     @Override
mouseDraggedEvent(MouseEvent event)223     protected void mouseDraggedEvent(MouseEvent event) {
224     }
225 
226     /**
227      * User defined events
228      *
229      * @param event MouseEvent
230      */
231     @Override
mouseReleaseEvent(MouseEvent event)232     protected void mouseReleaseEvent(MouseEvent event) {
233     }
234 }
235