color selection for bar graph

This commit is contained in:
Bane Stojkovic
2026-10-06 22:23:13 +02:00
parent 5075a566c6
commit 1404f1773c
2 changed files with 170 additions and 16 deletions
@@ -87,6 +87,9 @@ public class LEDBarGraph extends AbstractLabeledComponent<String> {
public static Color SEGMENT_GREEN = Color.decode("#43A047");
public static Color SEGMENT_YELLOW = Color.decode("#FDD835");
public static Color SEGMENT_RED = Color.decode("#E53935");
public static Color SEGMENT_BLUE = Color.decode("#1E88E5");
public static Color SEGMENT_ORANGE = Color.decode("#FB8C00");
public static Color SEGMENT_WHITE = Color.decode("#EEEEEE");
public static int EDGE_RADIUS = 4;
public static Size PIN_SIZE = new Size(0.04d, SizeUnit.in);
@@ -106,6 +109,7 @@ public class LEDBarGraph extends AbstractLabeledComponent<String> {
private String value = "";
private Orientation orientation = Orientation.DEFAULT;
private Segments segments = Segments._10;
private BarColor barColor = BarColor.GREEN_YELLOW_RED;
private Color bodyColor = BODY_COLOR;
private Color borderColor = BORDER_COLOR;
private Point2D[] controlPoints = new Point2D[] {new Point2D.Double(0, 0)};
@@ -158,23 +162,24 @@ public class LEDBarGraph extends AbstractLabeledComponent<String> {
body = null;
}
@EditableProperty(name = "Color")
public BarColor getBarColor() {
if (barColor == null) {
barColor = BarColor.GREEN_YELLOW_RED;
}
return barColor;
}
public void setBarColor(BarColor barColor) {
this.barColor = barColor;
}
/**
* The colour of one segment, counted from the top of the scale. Red marks the top of the range,
* the two below it are yellow and everything under that is green, so the proportions shift with
* the segment count rather than the bands being fixed fractions: nine green on a twelve segment
* part, five on an eight.
*
* <p>This is a rule rather than a property. The trade is that a single-colour bar -- all red or
* all green, both of which are sold -- can no longer be drawn.
* The colour of one segment, counted from the top of the scale. Delegates to the selected
* {@link BarColor}.
*/
private Color getSegmentColor(int index) {
if (index == 0) {
return SEGMENT_RED;
}
if (index <= 2) {
return SEGMENT_YELLOW;
}
return SEGMENT_GREEN;
return getBarColor().getSegmentColor(index, getSegments().getCount());
}
@EditableProperty(name = "Body")
@@ -202,8 +207,8 @@ public class LEDBarGraph extends AbstractLabeledComponent<String> {
}
/**
* Puts the segment count in the BOM's value column, so an eight, a ten and a twelve segment part
* are three rows rather than one. Without this they would collapse: the inherited implementation
* Puts the segment count and color in the BOM's value column, so different variants are
* separate rows rather than one. Without this they would collapse: the inherited implementation
* returns {@link #getValue()}, which is the part number and is usually blank, and {@code
* BomMaker} groups on the type name and the value together.
*
@@ -215,6 +220,9 @@ public class LEDBarGraph extends AbstractLabeledComponent<String> {
@Override
public String getValueForDisplay() {
String variant = getSegments().toString();
if (getBarColor() != BarColor.GREEN_YELLOW_RED) {
variant += ", " + getBarColor();
}
String partNumber = getValue();
return partNumber == null || partNumber.trim().isEmpty() ? variant
: variant + ", " + partNumber.trim();
@@ -524,4 +532,83 @@ public class LEDBarGraph extends AbstractLabeledComponent<String> {
/** Anode and cathode per segment, split evenly between the two rows. */
public int getPinCount() { return count * 2; }
}
public enum BarColor {
GREEN_YELLOW_RED("Green-Yellow-Red"),
BLUE_GREEN_YELLOW_RED("Blue-Green-Yellow-Red"),
RED("Red"),
GREEN("Green"),
YELLOW("Yellow"),
BLUE("Blue"),
ORANGE("Orange"),
WHITE("White");
private final String label;
BarColor(String label) {
this.label = label;
}
@Override
public String toString() {
return label;
}
public Color getSegmentColor(int index, int totalSegments) {
switch (this) {
case RED:
return SEGMENT_RED;
case GREEN:
return SEGMENT_GREEN;
case YELLOW:
return SEGMENT_YELLOW;
case BLUE:
return SEGMENT_BLUE;
case ORANGE:
return SEGMENT_ORANGE;
case WHITE:
return SEGMENT_WHITE;
case BLUE_GREEN_YELLOW_RED:
int redCount;
int yellowCount;
int blueCount;
if (totalSegments >= 12) {
redCount = 2;
yellowCount = 3;
blueCount = 2;
} else if (totalSegments >= 10) {
redCount = 2;
yellowCount = 3;
blueCount = 1;
} else if (totalSegments >= 8) {
redCount = 1;
yellowCount = 2;
blueCount = 1;
} else {
redCount = 1;
yellowCount = 1;
blueCount = 1;
}
if (index < redCount) {
return SEGMENT_RED;
}
if (index < redCount + yellowCount) {
return SEGMENT_YELLOW;
}
if (index >= totalSegments - blueCount) {
return SEGMENT_BLUE;
}
return SEGMENT_GREEN;
case GREEN_YELLOW_RED:
default:
if (index == 0) {
return SEGMENT_RED;
}
if (index <= 2) {
return SEGMENT_YELLOW;
}
return SEGMENT_GREEN;
}
}
}
}
@@ -27,6 +27,7 @@ import java.awt.geom.Rectangle2D;
import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.common.IComponentTransformer;
import org.diylc.common.Orientation;
import org.diylc.components.displays.LEDBarGraph.BarColor;
import org.diylc.components.displays.LEDBarGraph.Segments;
import org.diylc.components.transform.LEDBarGraphTransformer;
import org.junit.Assert;
@@ -349,6 +350,72 @@ public class LEDBarGraphTest {
Assert.assertEquals(Orientation._180, vertical.getOrientation());
}
@Test
public void singleColorsRenderUniformSegments() throws Exception {
java.lang.reflect.Method segmentColor =
LEDBarGraph.class.getDeclaredMethod("getSegmentColor", int.class);
segmentColor.setAccessible(true);
BarColor[] singleColors = new BarColor[] {
BarColor.RED, BarColor.GREEN, BarColor.YELLOW, BarColor.BLUE, BarColor.ORANGE,
BarColor.WHITE
};
for (BarColor color : singleColors) {
LEDBarGraph graph = bar(Segments._10);
graph.setBarColor(color);
for (int i = 0; i < 10; i++) {
Assert.assertEquals("segment " + i + " for " + color,
color.getSegmentColor(i, 10), segmentColor.invoke(graph, i));
}
}
}
@Test
public void blueGreenYellowRedDistribution() throws Exception {
java.lang.reflect.Method segmentColor =
LEDBarGraph.class.getDeclaredMethod("getSegmentColor", int.class);
segmentColor.setAccessible(true);
LEDBarGraph graph10 = bar(Segments._10);
graph10.setBarColor(BarColor.BLUE_GREEN_YELLOW_RED);
Assert.assertEquals(LEDBarGraph.SEGMENT_RED, segmentColor.invoke(graph10, 0));
Assert.assertEquals(LEDBarGraph.SEGMENT_RED, segmentColor.invoke(graph10, 1));
Assert.assertEquals(LEDBarGraph.SEGMENT_YELLOW, segmentColor.invoke(graph10, 2));
Assert.assertEquals(LEDBarGraph.SEGMENT_YELLOW, segmentColor.invoke(graph10, 3));
Assert.assertEquals(LEDBarGraph.SEGMENT_YELLOW, segmentColor.invoke(graph10, 4));
Assert.assertEquals(LEDBarGraph.SEGMENT_GREEN, segmentColor.invoke(graph10, 5));
Assert.assertEquals(LEDBarGraph.SEGMENT_GREEN, segmentColor.invoke(graph10, 8));
Assert.assertEquals(LEDBarGraph.SEGMENT_BLUE, segmentColor.invoke(graph10, 9));
LEDBarGraph graph4 = bar(Segments._4);
graph4.setBarColor(BarColor.BLUE_GREEN_YELLOW_RED);
Assert.assertEquals(LEDBarGraph.SEGMENT_RED, segmentColor.invoke(graph4, 0));
Assert.assertEquals(LEDBarGraph.SEGMENT_YELLOW, segmentColor.invoke(graph4, 1));
Assert.assertEquals(LEDBarGraph.SEGMENT_GREEN, segmentColor.invoke(graph4, 2));
Assert.assertEquals(LEDBarGraph.SEGMENT_BLUE, segmentColor.invoke(graph4, 3));
}
@Test
public void colorVariantDistinguishesBomRow() {
LEDBarGraph defaultGraph = bar(Segments._10);
LEDBarGraph redGraph = bar(Segments._10);
redGraph.setBarColor(BarColor.RED);
LEDBarGraph bgyrGraph = bar(Segments._10);
bgyrGraph.setBarColor(BarColor.BLUE_GREEN_YELLOW_RED);
Assert.assertEquals("10 Segment", defaultGraph.getValueForDisplay());
Assert.assertEquals("10 Segment, Red", redGraph.getValueForDisplay());
Assert.assertEquals("10 Segment, Blue-Green-Yellow-Red", bgyrGraph.getValueForDisplay());
}
@Test
public void barColorDefaultsWhenNull() {
LEDBarGraph graph = new LEDBarGraph();
graph.setBarColor(null);
Assert.assertEquals(BarColor.GREEN_YELLOW_RED, graph.getBarColor());
}
private static LEDBarGraph bar(Segments segments) {
LEDBarGraph graph = new LEDBarGraph();
graph.setSegments(segments);