Skip to content
This repository was archived by the owner on Dec 27, 2024. It is now read-only.

Commit 1295ca9

Browse files
authored
make the timeline graph an area graph (#434)
Co-authored-by: Jian-Syuan (Shane) Wong <[email protected]>
1 parent df23aa8 commit 1295ca9

File tree

4 files changed

+157
-11
lines changed

4 files changed

+157
-11
lines changed

desktop/ConstraintLayoutInspector/app/src/androidx/constraintLayout/desktop/ui/adapters/MEUI.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ public static Color makeColor(int rgb, int darkRGB) {
5151
return !dark ? new Color(rgb) : new Color(darkRGB);
5252
}
5353

54+
public static Color makeColorWithAlpha(int rgba, int darkRGBA) {
55+
return !dark ? new Color(rgba, true) : new Color(darkRGBA, true);
56+
}
57+
5458
private static Color makeColor(String name, int rgb, int darkRGB) {
5559
return makeColor(rgb, darkRGB);
5660
}
@@ -110,15 +114,32 @@ public static void invokeLater(Runnable runnable) {
110114
public static final Color ourMySelectedLineColor = new Color(0x3879d9);
111115
public static final Color ourAddConstraintColor = makeColor("UIDesigner.motion.AddConstraintColor", 0xff838383, 0xff666666);
112116
public static final Color ourAddConstraintPlus = makeColor("UIDesigner.motion.AddConstraintPlus", 0xffc9c9c9, 0xff333333);
113-
117+
public static final Color ourDashedLineColor = makeColor(0xA0A0A0, 0xBBBBBB);
114118

115119
public static void copy(MTag tag) {
116120
}
117121

118122
public static void cut(MTag mSelectedKeyFrame) {
119123
}
120124

121-
125+
/** List of colors with alpha = 0.7 for graphs. */
126+
public static Color[] graphColors = {
127+
makeColorWithAlpha(0xa6bcc9b3, 0x8da9bab3),
128+
makeColorWithAlpha(0xaee3feb3, 0xaee3feb3),
129+
makeColorWithAlpha(0xf8a981b3, 0xf68f5bb3),
130+
makeColorWithAlpha(0x89e69ab3, 0x67df7db3),
131+
makeColorWithAlpha(0xb39bdeb3, 0x9c7cd4b3),
132+
makeColorWithAlpha(0xea85aab3, 0xe46391b3),
133+
makeColorWithAlpha(0x6de9d6b3, 0x49e4cdb3),
134+
makeColorWithAlpha(0xe3d2abb3, 0xd9c28cb3),
135+
makeColorWithAlpha(0x0ab4ffb3, 0x0095d6b3),
136+
makeColorWithAlpha(0x1bb6a2b3, 0x138173b3),
137+
makeColorWithAlpha(0x9363e3b3, 0x7b40ddb3),
138+
makeColorWithAlpha(0xe26b27b3, 0xc1571ab3),
139+
makeColorWithAlpha(0x4070bfb3, 0x335a99b3),
140+
makeColorWithAlpha(0xc6c54eb3, 0xadac38b3),
141+
makeColorWithAlpha(0xcb53a3b3, 0xb8388eb3),
142+
makeColorWithAlpha(0x3d8effb3, 0x1477ffb3)};
122143

123144
public static final int DIR_LEFT = 0;
124145
public static final int DIR_RIGHT = 1;

desktop/ConstraintLayoutInspector/app/src/androidx/constraintLayout/desktop/ui/timeline/GraphRender.java

Lines changed: 110 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@
2222
import androidx.constraintLayout.desktop.ui.timeline.graph.Oscillator;
2323
import androidx.constraintLayout.desktop.ui.ui.MeModel;
2424
import androidx.constraintLayout.desktop.ui.utils.Debug;
25+
import java.awt.BasicStroke;
2526
import java.awt.Color;
2627
import java.awt.Graphics;
28+
import java.awt.Graphics2D;
29+
import java.awt.RenderingHints;
30+
import java.awt.Stroke;
2731
import java.util.Arrays;
2832
import java.util.Comparator;
2933
import java.util.HashMap;
@@ -36,6 +40,7 @@ public class GraphRender {
3640
private Cycle mCycle = null;
3741
private Attribute[] mAttribute = null;
3842
private String[] mStartEndString = new String[2];
43+
private static boolean mShowNewGraph = false;
3944

4045
static String[] ourWaveTypes = {"sin", "square", "triangle", "sawtooth", "reverseSawtooth", "cos", "bounce"};
4146
static HashMap<String, Integer> ourWaveTypeMap = new HashMap<>();
@@ -67,6 +72,10 @@ public boolean setUp(MeModel model, TimeLineRowData row) {
6772
return false;
6873
}
6974

75+
public void setShowNewGraph(boolean isNewGraph) {
76+
mShowNewGraph = isNewGraph;
77+
}
78+
7079
public String getValue(MTag kf, String keyProp) {
7180
MTag[] tag = kf.getChildTags();
7281
if (tag != null && tag.length > 0) {
@@ -120,7 +129,7 @@ public int compare(MTag t1, MTag t2) {
120129
}
121130

122131
mCycle = new Cycle();
123-
mCycle.setCycle(pos, period, amp, offset, curveType);
132+
mCycle.setCycle(pos, period, amp, offset, curveType, row);
124133
mCycle.fixRange(row.mKeyProp);
125134
return true;
126135
}
@@ -185,13 +194,27 @@ public void draw(Graphics g, TimelineStructure mTimelineStructure, int x, int y,
185194
g.drawRect(x, y, w, h - 1);
186195
g.setColor(MEUI.Graph.ourG_line);
187196

197+
// with the new graph design, the ticks are drawn before the actual graph.
198+
if (mShowNewGraph) {
199+
g.setColor(MEUI.myGridColor);
200+
TimeLineRow.drawTicks(g, mTimelineStructure, h, y);
201+
}
202+
188203
if (mCycle != null) {
189-
mCycle.plot(g, gx, y, gw, h);
204+
if (mShowNewGraph) {
205+
mCycle.plotAreaGraph(g, gx, y, gw, h);
206+
} else {
207+
mCycle.plot(g, gx, y, gw, h);
208+
}
190209
}
191210
if (mAttribute != null) {
192211
for (int i = 0; i < mAttribute.length; i++) {
193212
Attribute attribute = mAttribute[i];
194-
attribute.plot(g, gx, y, gw, h);
213+
if (mShowNewGraph) {
214+
attribute.plotAreaGraph(g, gx, y, gw, h);
215+
} else {
216+
attribute.plot(g, gx, y, gw, h);
217+
}
195218
}
196219
}
197220

@@ -251,9 +274,11 @@ static class Attribute {
251274
int[] yPoints = new int[2000];
252275
double mMin;
253276
double mMax;
277+
int colorIndex = 0;
254278

255279
public Attribute(TimeLineRowData row, String attr, double startValue, double endValue) {
256280
mType = attr;
281+
colorIndex = row.mKeyPropIndex;
257282
setup(row, attr, startValue, endValue);
258283
}
259284

@@ -334,6 +359,29 @@ public void plot(Graphics g, int x, int y, int w, int h) {
334359
g.drawPolyline(xPoints, yPoints, count);
335360
}
336361
}
362+
363+
// plot the attribute with an Area Graph
364+
public void plotAreaGraph(Graphics g, int x, int y, int w, int h) {
365+
366+
if (spline != null) {
367+
double steps = 1.0 / w;
368+
// add the starting point for drawing a polygon instead of a ployline
369+
xPoints[0] = x;
370+
yPoints[0] = y + h;
371+
int count = 1;
372+
for (double i = steps; i <= 1; i += steps) {
373+
double yp = spline.getPos(i, 0);
374+
xPoints[count] = (int)(x + i * w);
375+
yPoints[count] = (int)(y + h - (yp - mMin) * h / (mMax - mMin));
376+
count++;
377+
}
378+
// add the ending point for drawing a polygon instead of a ployline
379+
xPoints[count] = x + w;
380+
yPoints[count] = yPoints[0];
381+
g.setColor(MEUI.graphColors[colorIndex % MEUI.graphColors.length]);
382+
g.fillPolygon(xPoints, yPoints, count + 1);
383+
}
384+
}
337385
}
338386

339387
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -346,11 +394,18 @@ static class Cycle {
346394
float[] yMax = new float[xpos.length];
347395
float[] yMin = new float[xpos.length];
348396
float mMaxY, mMinY;
349-
int[] xPoints = new int[xpos.length];
350-
int[] yPoints = new int[xpos.length];
397+
// add two more points (in start and end) for drawing a polygon
398+
int numPoints = mShowNewGraph ? xpos.length + 2 : xpos.length;
399+
int[] xPoints = new int[numPoints];
400+
int[] yPoints = new int[numPoints];
401+
int colorIndex = 0; // index for picking a color for the graph.
402+
String attr = "";
403+
// Store the waveOffest Y position.
404+
double[] offsetY = new double[xpos.length];
405+
int[] offsetYPoints = new int[xpos.length];
351406

352407
void setCycle(double[] pos, double[] period, double[] amplitude, double[] offset,
353-
int curveType) {
408+
int curveType, TimeLineRowData row) {
354409
if (pos.length == 1) {
355410
pos = new double[]{0.0, pos[0], 1.0};
356411
period = new double[]{period[0], period[0], period[0]};
@@ -384,13 +439,16 @@ void setCycle(double[] pos, double[] period, double[] amplitude, double[] offset
384439
mOscillator = osc;
385440
mMaxY = -Float.MAX_VALUE;
386441
mMinY = Float.MAX_VALUE;
442+
colorIndex = row.mKeyPropIndex;
443+
attr = row.mKeyProp;
387444

388445
for (int i = 0; i < xpos.length; i++) {
389446
xpos[i] = (float)(i / (xpos.length - 1.0f));
390447
double amp = mMonotoneSpline.getPos(xpos[i], 0);
391448
double off = mMonotoneSpline.getPos(xpos[i], 1);
392449
try {
393450
ypos[i] = mOscillator.getValue(xpos[i]) * amp + off;
451+
offsetY[i] = off;
394452
}
395453
catch (Exception e) {
396454
ypos[i] = Math.random(); // visual hint that it is broken
@@ -427,6 +485,52 @@ void plot(Graphics g, int x, int y, int w, int h) {
427485
g.drawPolyline(xPoints, yPoints, xPoints.length);
428486
}
429487

488+
void plotAreaGraph(Graphics g, int x, int y, int w, int h) {
489+
490+
((Graphics2D) g)
491+
.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
492+
493+
// add the starting point to draw the polygon
494+
xPoints[0] = x;
495+
yPoints[0] = y + (int)(h - h * (0 - mMinY) / (mMaxY - mMinY));
496+
int count = 1;
497+
for (int i = 0; i < xpos.length; i++) {
498+
int xp = (int)(w * xpos[i] + x);
499+
int yp = y + (int)(h - h * (ypos[i] - mMinY) / (mMaxY - mMinY));
500+
xPoints[count] = xp;
501+
yPoints[count] = yp;
502+
count++;
503+
504+
// points for drawing the waveOffset polyline
505+
int offsetYP = y + (int)(h - h * (offsetY[i] - mMinY) / (mMaxY - mMinY));
506+
offsetYPoints[i] = offsetYP;
507+
}
508+
// add the ending point to draw the polygon
509+
xPoints[count] = x + w;
510+
yPoints[count] = yPoints[0];
511+
512+
// Draw a baseline where the y position is 0
513+
g.setColor(MEUI.myGridColor);
514+
g.drawPolyline(Arrays.copyOfRange(xPoints, 1, xPoints.length - 1), Arrays.copyOfRange(yPoints, 1, yPoints.length - 1), count - 1);
515+
516+
// Draw a line where the y position is 1 when the attribute is scaleX or scaleY
517+
if (attr.equals("scaleX") || attr.equals("scaleY")) {
518+
int yTop = y + (int)(h - h * (1 - mMinY) / (mMaxY - mMinY));
519+
g.drawLine(x, yTop, x + w, yTop);
520+
}
521+
522+
// Draw the animation graph
523+
g.setColor(MEUI.graphColors[colorIndex % MEUI.graphColors.length]);
524+
g.fillPolygon(xPoints, yPoints, count + 1);
525+
526+
// Draw the waveOffset dashed line
527+
Stroke dashed = new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0f,
528+
new float[]{9}, 0f);
529+
((Graphics2D) g).setStroke(dashed);
530+
g.setColor(MEUI.ourDashedLineColor);
531+
g.drawPolyline(Arrays.copyOfRange(xPoints, 1, xPoints.length - 1), offsetYPoints, count - 1);
532+
}
533+
430534
float getComputedValue(float v) {
431535
if (mMonotoneSpline == null) {
432536
return 0;

desktop/ConstraintLayoutInspector/app/src/androidx/constraintLayout/desktop/ui/timeline/TimeLineRow.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public class TimeLineRow extends JPanel {
4949
private boolean mHasGraph = true;
5050
private boolean mGraphOpen = false;
5151
GraphRender mGraph = new GraphRender();
52+
private boolean mShowNewGraph = true;
5253

5354
@Override
5455
public void updateUI() {
@@ -70,6 +71,7 @@ public void updateUI() {
7071
TimeLineRow(TimelineStructure timelineStructure) {
7172
setPreferredSize(MEUI.size(100, 20));
7273
mTimelineStructure = timelineStructure;
74+
mGraph.setShowNewGraph(mShowNewGraph);
7375
}
7476

7577
@Override
@@ -186,8 +188,10 @@ public void paint(Graphics g) {
186188
int gy = myRowHeight + ((mShowTitle) ? myTitleHeight : 0);
187189
mGraph.draw(g, mTimelineStructure, MEUI.ourLeftColumnWidth, gy, w - MEUI.ourLeftColumnWidth, myGraphHeight);
188190
}
189-
g.setColor(MEUI.myGridColor);
190-
drawTicks(g, mTimelineStructure, h);
191+
if (!mShowNewGraph) {
192+
g.setColor(MEUI.myGridColor);
193+
TimeLineRow.drawTicks(g, mTimelineStructure, h);
194+
}
191195
}
192196

193197
public void drawArrow(Graphics g, int y) {
@@ -216,9 +220,13 @@ public void drawArrow(Graphics g, int y) {
216220
}
217221

218222
public static void drawTicks(Graphics g, TimelineStructure mTimelineStructure, int h) {
223+
drawTicks(g, mTimelineStructure, h, 0);
224+
}
225+
226+
public static void drawTicks(Graphics g, TimelineStructure mTimelineStructure, int h, int y) {
219227
for (int i = 0; i < mTimelineStructure.myXTicksPixels.length; i++) {
220228
int x = mTimelineStructure.myXTicksPixels[i] + MEUI.ourLeftColumnWidth;
221-
g.fillRect(x, 0, 1, h);
229+
g.fillRect(x, y, 1, h);
222230
}
223231
}
224232

desktop/ConstraintLayoutInspector/app/src/androidx/constraintLayout/desktop/ui/timeline/TimeLineRowData.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class TimeLineRowData {
3232
String mKeyProp;
3333
String mKeyPropToolTip;
3434
String mType; // Pos, Trig, Att, TCyc, Cyc
35+
int mKeyPropIndex = 0; // used to map a property to a color
3536

3637
private static String[] properties =
3738
{
@@ -78,6 +79,15 @@ public class TimeLineRowData {
7879
nameMap.put("KeyAttribute", TYPE_KEY_ATTRIBUTE);
7980
}
8081

82+
// map a property to an index that is associated with a specific color
83+
private static HashMap<String, Integer> propertyMap = new HashMap<>();
84+
85+
static {
86+
for (int i = 0; i < properties.length; i++) {
87+
propertyMap.put(properties[i], i);
88+
}
89+
}
90+
8191
ArrayList<MTag> mKeyFrames = new ArrayList<>();
8292
MTag mStartConstraintSet;
8393
MTag mEndConstraintSet;
@@ -108,12 +118,15 @@ public void buildTargetStrings(MTag keyFrame) {
108118
Debug.log(count + " " + properties[i]);
109119
}
110120
mKeyProp = properties[i];
121+
mKeyPropIndex = propertyMap.getOrDefault(mKeyProp, properties.length - 1);
111122
}
112123
}
113124
if (count > 1) {
114125
count = 0;
115126
mKeyProp = "";
116127
mKeyPropToolTip = "";
128+
// show the a specific color for a composite of propierties
129+
mKeyPropIndex = properties.length - 1;
117130
for (int i = 0; i < properties.length; i++) {
118131
if ((mask & (1 << i)) != 0) {
119132
if (count > 0) {

0 commit comments

Comments
 (0)