New labels/axis settings
This commit is contained in:
parent
817a70a938
commit
bccf1f5823
2
pom.xml
2
pom.xml
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>it.cavallium</groupId>
|
<groupId>it.cavallium</groupId>
|
||||||
<artifactId>jlinegraph</artifactId>
|
<artifactId>jlinegraph</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.1-SNAPSHOT</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>17</maven.compiler.source>
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
@ -95,12 +95,13 @@ public class AWTGraphExample {
|
|||||||
new SeriesStyle(new Color(0.5f, 1f, 0.5f, 1f), 0, 1, 0.3, 1d),
|
new SeriesStyle(new Color(0.5f, 1f, 0.5f, 1f), 0, 1, 0.3, 1d),
|
||||||
new SeriesStyle(new Color(1f, 1f, 0.7f, 1f), 1.5, 2, 0, 1d)
|
new SeriesStyle(new Color(1f, 1f, 0.7f, 1f), 1.5, 2, 0, 1d)
|
||||||
),
|
),
|
||||||
new GraphAxisStyle("X axis", true, "%.2fs"::formatted),
|
new GraphAxisStyle("X axis", false, AxisMode.SHOW_WITH_VALUES, "%.2fs"::formatted),
|
||||||
new GraphAxisStyle("Y axis", true, "%.2fm"::formatted),
|
new GraphAxisStyle("Y axis", false, AxisMode.SHOW_WITH_VALUES, "%.2fm"::formatted),
|
||||||
GRAPH_COLOR,
|
GRAPH_COLOR,
|
||||||
new GraphFonts(10f, 18f, 12f, 12f),
|
new GraphFonts(10f, 18f, 12f, 12f),
|
||||||
2f,
|
2f,
|
||||||
true
|
true,
|
||||||
|
1
|
||||||
));
|
));
|
||||||
var r = new AWTGraphRenderer();
|
var r = new AWTGraphRenderer();
|
||||||
r.renderGraph(g, new RasterSize(w, h)).drawTo(g2d);
|
r.renderGraph(g, new RasterSize(w, h)).drawTo(g2d);
|
||||||
|
@ -48,25 +48,31 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
|
|||||||
var valuesFontMetrics = graphics2D.getFontMetrics(valuesFont);
|
var valuesFontMetrics = graphics2D.getFontMetrics(valuesFont);
|
||||||
var axisNameFontMetrics = graphics2D.getFontMetrics(axisNameFont);
|
var axisNameFontMetrics = graphics2D.getFontMetrics(axisNameFont);
|
||||||
|
|
||||||
|
var paddingMultiplier = graph.style().paddingMultiplier();
|
||||||
var graphBounds = graph.data().bounds();
|
var graphBounds = graph.data().bounds();
|
||||||
var x = graph.style().x();
|
var x = graph.style().x();
|
||||||
var y = graph.style().y();
|
var y = graph.style().y();
|
||||||
|
var padding = defaultFontMetrics.getHeight() * paddingMultiplier;
|
||||||
var scaleX = new NiceScale(graphBounds.minX(), graphBounds.maxX());
|
var scaleX = new NiceScale(graphBounds.minX(), graphBounds.maxX());
|
||||||
scaleX.setMaxTicks(20);
|
scaleX.setMaxTicks(20);
|
||||||
var scaleY = new NiceScale(graphBounds.minY(), graphBounds.maxY());
|
var scaleY = new NiceScale(graphBounds.minY(), graphBounds.maxY());
|
||||||
scaleY.setMaxTicks(20);
|
scaleY.setMaxTicks(20);
|
||||||
var topPadding = defaultFontMetrics.getHeight() + valuesFontMetrics.getHeight() / 2d;
|
var halfMaxXLabelWidth = x.mode().showLabels()
|
||||||
var leftPadding = defaultFontMetrics.getHeight();
|
? (valuesFontMetrics.stringWidth(y.valueFormat().apply(graphBounds.maxX())) / 2d) : 0;
|
||||||
var rightPadding = defaultFontMetrics.getHeight()
|
var halfMaxYLabelHeight = (y.mode().showLabels() ? valuesFontMetrics.getHeight() / 2d : 0);
|
||||||
+ valuesFontMetrics.stringWidth(y.valueFormat().apply(graphBounds.maxX())) / 2d;
|
var topPadding = padding + halfMaxYLabelHeight;
|
||||||
var bottomPadding = defaultFontMetrics.getHeight();
|
var leftPadding = padding
|
||||||
var xValueLineLength = valuesFontMetrics.getHeight();
|
+ ((y.mode() == AxisMode.HIDE && !y.showName()) ? halfMaxXLabelWidth : 0);
|
||||||
var yValueLineLength = valuesFontMetrics.getHeight();
|
var rightPadding = padding + (x.mode().showLabels() ? halfMaxXLabelWidth : 0);
|
||||||
var xValuesHeight = valuesFontMetrics.getHeight();
|
var bottomPadding = padding
|
||||||
var xValuesToXAxisNamePadding = (x.show() ? valuesFontMetrics.getHeight() : 0);
|
+ ((x.mode() == AxisMode.HIDE && !x.showName()) ? halfMaxYLabelHeight : 0);
|
||||||
var xAxisNameHeight = (x.show() ? axisNameFontMetrics.getHeight() : 0);
|
var xValueLineLength = x.mode().showRuler() ? valuesFontMetrics.getHeight() : 0;
|
||||||
var yAxisNameWidth = (y.show() ? axisNameFontMetrics.getHeight() : 0);
|
var yValueLineLength = y.mode().showRuler() ? valuesFontMetrics.getHeight() : 0;
|
||||||
var yValuesToYAxisNamePadding = (y.show() ? valuesFontMetrics.getHeight() : 0);
|
var xValuesHeight = x.mode().showLabels() ? valuesFontMetrics.getHeight() : 0;
|
||||||
|
var xValuesToXAxisNamePadding = (x.showName() ? valuesFontMetrics.getHeight() / 2 : 0);
|
||||||
|
var xAxisNameHeight = (x.showName() ? axisNameFontMetrics.getHeight() : 0);
|
||||||
|
var yAxisNameWidth = (y.showName() ? axisNameFontMetrics.getHeight() : 0);
|
||||||
|
var yValuesToYAxisNamePadding = (y.showName() ? valuesFontMetrics.getHeight() / 2 : 0);
|
||||||
|
|
||||||
var graphHeight
|
var graphHeight
|
||||||
// Start with total height
|
// Start with total height
|
||||||
@ -87,7 +93,7 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
|
|||||||
var xValueLineOffset = topPadding + graphHeight;
|
var xValueLineOffset = topPadding + graphHeight;
|
||||||
|
|
||||||
var yLabels = getYLabels(graph, graphHeight, valuesFontMetrics, scaleY);
|
var yLabels = getYLabels(graph, graphHeight, valuesFontMetrics, scaleY);
|
||||||
RasterSize yLabelsAreaSize = computeYLabelsAreaSize(graphHeight, valuesFontMetrics, yLabels);
|
RasterSize yLabelsAreaSize = computeYLabelsAreaSize(y.mode(), graphHeight, valuesFontMetrics, yLabels);
|
||||||
var yValuesWidth = yLabelsAreaSize.width();
|
var yValuesWidth = yLabelsAreaSize.width();
|
||||||
var yValueLineOffset = leftPadding + yAxisNameWidth + yValuesToYAxisNamePadding + yValuesWidth;
|
var yValueLineOffset = leftPadding + yAxisNameWidth + yValuesToYAxisNamePadding + yValuesWidth;
|
||||||
|
|
||||||
@ -129,9 +135,9 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
|
|||||||
|
|
||||||
var xLabels = getXLabels(graph, graphWidth, valuesFontMetrics, scaleX);
|
var xLabels = getXLabels(graph, graphWidth, valuesFontMetrics, scaleX);
|
||||||
|
|
||||||
RasterSize yAxisNameCenterOffset = new RasterSize(valuesFontMetrics.getHeight(), valuesFontMetrics.getHeight()
|
RasterSize yAxisNameCenterOffset = new RasterSize(leftPadding + valuesFontMetrics.getHeight() / 2d, valuesFontMetrics.getHeight()
|
||||||
// Add half of graph height
|
// Add half of graph height
|
||||||
+ graphHeight / 2);
|
+ graphHeight / 2 + topPadding);
|
||||||
|
|
||||||
RasterSize yValuesOffset = new RasterSize(leftPadding
|
RasterSize yValuesOffset = new RasterSize(leftPadding
|
||||||
// Add y axis name "90deg height"
|
// Add y axis name "90deg height"
|
||||||
@ -182,11 +188,11 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderGraphBorders(graphics2D, graph, graphOffset, graphSize, defaultStroke);
|
renderGraphBorders(graphics2D, graph, graphOffset, graphSize, defaultStroke, totalSize);
|
||||||
if (y.show()) {
|
if (y.showName()) {
|
||||||
renderYAxisName(graphics2D, graph, yAxisNameCenterOffset, axisNameFont, axisNameFontMetrics);
|
renderYAxisName(graphics2D, graph, yAxisNameCenterOffset, axisNameFont, axisNameFontMetrics);
|
||||||
}
|
}
|
||||||
if (x.show()) {
|
if (x.showName()) {
|
||||||
renderXAxisName(graphics2D, graph, xAxisNameCenterOffset, axisNameFont, axisNameFontMetrics);
|
renderXAxisName(graphics2D, graph, xAxisNameCenterOffset, axisNameFont, axisNameFontMetrics);
|
||||||
}
|
}
|
||||||
renderYAxisValueLabels(graphics2D,
|
renderYAxisValueLabels(graphics2D,
|
||||||
@ -198,7 +204,9 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
|
|||||||
yLabels,
|
yLabels,
|
||||||
yLabelsAreaSize,
|
yLabelsAreaSize,
|
||||||
yValuesOffset,
|
yValuesOffset,
|
||||||
defaultStroke
|
defaultStroke,
|
||||||
|
y.mode().showRuler(),
|
||||||
|
y.mode().showLabels()
|
||||||
);
|
);
|
||||||
renderXAxisValueLabels(graphics2D,
|
renderXAxisValueLabels(graphics2D,
|
||||||
graph,
|
graph,
|
||||||
@ -207,7 +215,9 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
|
|||||||
xValueLineOffset,
|
xValueLineOffset,
|
||||||
xValueLineLength,
|
xValueLineLength,
|
||||||
xLabels, xValuesOffset,
|
xLabels, xValuesOffset,
|
||||||
defaultStroke
|
defaultStroke,
|
||||||
|
x.mode().showRuler(),
|
||||||
|
x.mode().showLabels()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@ -615,25 +625,33 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
|
|||||||
List<LabelWithOffset> yLabels,
|
List<LabelWithOffset> yLabels,
|
||||||
RasterSize yLabelsAreaSize,
|
RasterSize yLabelsAreaSize,
|
||||||
RasterSize yValuesOffset,
|
RasterSize yValuesOffset,
|
||||||
BasicStroke defaultStroke) {
|
BasicStroke defaultStroke,
|
||||||
graphics2D.setFont(valuesFont);
|
boolean showRulerTicks,
|
||||||
graphics2D.setStroke(defaultStroke);
|
boolean showRulerLabels) {
|
||||||
graphics2D.setColor(graph.style().colors().foreground().toColor());
|
if ((yValueLineLength > 0 && showRulerTicks) || showRulerLabels) {
|
||||||
yLabels.forEach(label -> {
|
graphics2D.setFont(valuesFont);
|
||||||
var lineStartOffsetY = yValuesOffset.height() + label.rasterOffset();
|
graphics2D.setStroke(defaultStroke);
|
||||||
var currentLineOffsetX = label.formattedText().isBlank() ? yValueLineLength / 3d : 0;
|
graphics2D.setColor(graph.style().colors().foreground().toColor());
|
||||||
var currentLineLength = yValueLineLength + (label.formattedText().isBlank() ? -yValueLineLength / 3d : 0);
|
yLabels.forEach(label -> {
|
||||||
graphics2D.draw(new Line2D.Double(yValueLineOffset + currentLineOffsetX,
|
if (showRulerTicks) {
|
||||||
lineStartOffsetY,
|
var lineStartOffsetY = yValuesOffset.height() + label.rasterOffset();
|
||||||
yValueLineOffset + currentLineOffsetX + currentLineLength,
|
var currentLineOffsetX = label.formattedText().isBlank() ? yValueLineLength / 3d : 0;
|
||||||
lineStartOffsetY
|
var currentLineLength = yValueLineLength + (label.formattedText().isBlank() ? -yValueLineLength / 3d : 0);
|
||||||
));
|
graphics2D.draw(new Line2D.Double(yValueLineOffset + currentLineOffsetX,
|
||||||
graphics2D.fill(generateShapeFromText(graphics2D,
|
lineStartOffsetY,
|
||||||
label.formattedText(),
|
yValueLineOffset + currentLineOffsetX + currentLineLength,
|
||||||
yValuesOffset.width() + yLabelsAreaSize.width() - valuesFontMetrics.stringWidth(label.formattedText()),
|
lineStartOffsetY
|
||||||
yValuesOffset.height() + label.rasterOffset() + valuesFontMetrics.getHeight() / 2d - valuesFontMetrics.getDescent()
|
));
|
||||||
));
|
}
|
||||||
});
|
if (showRulerLabels) {
|
||||||
|
graphics2D.fill(generateShapeFromText(graphics2D,
|
||||||
|
label.formattedText(),
|
||||||
|
yValuesOffset.width() + yLabelsAreaSize.width() - valuesFontMetrics.stringWidth(label.formattedText()),
|
||||||
|
yValuesOffset.height() + label.rasterOffset() + valuesFontMetrics.getHeight() / 2d - valuesFontMetrics.getDescent()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void renderXAxisName(Graphics2D graphics2D,
|
private static void renderXAxisName(Graphics2D graphics2D,
|
||||||
@ -662,28 +680,44 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
|
|||||||
int xValueLineLength,
|
int xValueLineLength,
|
||||||
List<LabelWithOffset> xLabels,
|
List<LabelWithOffset> xLabels,
|
||||||
RasterSize xValuesOffset,
|
RasterSize xValuesOffset,
|
||||||
BasicStroke defaultStroke) {
|
BasicStroke defaultStroke,
|
||||||
graphics2D.setFont(valuesFont);
|
boolean showRulerTicks,
|
||||||
graphics2D.setStroke(defaultStroke);
|
boolean showRulerLabels) {
|
||||||
graphics2D.setColor(graph.style().colors().foreground().toColor());
|
if ((xValueLineLength > 0 && showRulerTicks) || showRulerLabels) {
|
||||||
xLabels.forEach(label -> {
|
graphics2D.setFont(valuesFont);
|
||||||
var lineStartOffsetX = xValuesOffset.width() + label.rasterOffset();
|
graphics2D.setStroke(defaultStroke);
|
||||||
var currentLineLength = label.formattedText().isBlank() ? xValueLineLength / 1.5d : xValueLineLength;
|
graphics2D.setColor(graph.style().colors().foreground().toColor());
|
||||||
//noinspection SuspiciousNameCombination
|
xLabels.forEach(label -> {
|
||||||
graphics2D.draw(new Line2D.Double(lineStartOffsetX, xValueLineOffset, lineStartOffsetX, xValueLineOffset + currentLineLength));
|
var lineStartOffsetX = xValuesOffset.width() + label.rasterOffset();
|
||||||
graphics2D.fill(generateShapeFromText(graphics2D,
|
if (showRulerTicks) {
|
||||||
label.formattedText(),
|
var currentLineLength = label.formattedText().isBlank() ? xValueLineLength / 1.5d : xValueLineLength;
|
||||||
xValuesOffset.width() + label.rasterOffset() - valuesFontMetrics.stringWidth(label.formattedText()) / 2d,
|
//noinspection SuspiciousNameCombination
|
||||||
xValuesOffset.height() + valuesFontMetrics.getHeight()
|
graphics2D.draw(new Line2D.Double(lineStartOffsetX, xValueLineOffset, lineStartOffsetX, xValueLineOffset + currentLineLength));
|
||||||
));
|
}
|
||||||
});
|
if (showRulerLabels) {
|
||||||
|
graphics2D.fill(generateShapeFromText(graphics2D,
|
||||||
|
label.formattedText(),
|
||||||
|
xValuesOffset.width() + label.rasterOffset() - valuesFontMetrics.stringWidth(label.formattedText()) / 2d,
|
||||||
|
xValuesOffset.height() + valuesFontMetrics.getHeight()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void renderGraphBorders(Graphics2D graphics2D,
|
private static void renderGraphBorders(Graphics2D graphics2D,
|
||||||
Graph graph,
|
Graph graph,
|
||||||
RasterSize graphOffset,
|
RasterSize graphOffset,
|
||||||
RasterSize graphSize,
|
RasterSize graphSize,
|
||||||
BasicStroke defaultStroke) {
|
BasicStroke defaultStroke,
|
||||||
|
RasterSize totalSize) {
|
||||||
|
// Do not draw the border if the graph is fullscreen
|
||||||
|
if (graphOffset.width() <= 0
|
||||||
|
&& graphOffset.height() <= 0
|
||||||
|
&& graphSize.width() >= totalSize.width()
|
||||||
|
&& graphSize.height() >= totalSize.height()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var fgColor = graph.style().colors().foreground().toColor();
|
var fgColor = graph.style().colors().foreground().toColor();
|
||||||
graphics2D.setColor(fgColor);
|
graphics2D.setColor(fgColor);
|
||||||
graphics2D.setStroke(defaultStroke);
|
graphics2D.setStroke(defaultStroke);
|
||||||
@ -694,7 +728,11 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RasterSize computeYLabelsAreaSize(double graphHeight, FontMetrics valuesFontMetrics, List<LabelWithOffset> yLabels) {
|
private static RasterSize computeYLabelsAreaSize(AxisMode axisMode, double graphHeight, FontMetrics valuesFontMetrics,
|
||||||
|
List<LabelWithOffset> yLabels) {
|
||||||
|
if (!axisMode.showLabels()) {
|
||||||
|
return RasterSize.EMPTY;
|
||||||
|
}
|
||||||
double maxLabelWidth = 0d;
|
double maxLabelWidth = 0d;
|
||||||
for (LabelWithOffset yLabel : yLabels) {
|
for (LabelWithOffset yLabel : yLabels) {
|
||||||
var currentMaxLabelWidth = valuesFontMetrics.stringWidth(yLabel.formattedText);
|
var currentMaxLabelWidth = valuesFontMetrics.stringWidth(yLabel.formattedText);
|
||||||
|
21
src/main/java/it/cavallium/jlinegraph/AxisMode.java
Normal file
21
src/main/java/it/cavallium/jlinegraph/AxisMode.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package it.cavallium.jlinegraph;
|
||||||
|
|
||||||
|
public enum AxisMode {
|
||||||
|
SHOW_WITH_VALUES,
|
||||||
|
SHOW_RULER_ONLY,
|
||||||
|
HIDE;
|
||||||
|
|
||||||
|
public boolean showLabels() {
|
||||||
|
return switch (this) {
|
||||||
|
case SHOW_WITH_VALUES -> true;
|
||||||
|
default -> false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean showRuler() {
|
||||||
|
return switch (this) {
|
||||||
|
case SHOW_WITH_VALUES, SHOW_RULER_ONLY -> true;
|
||||||
|
default -> false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -2,4 +2,4 @@ package it.cavallium.jlinegraph;
|
|||||||
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public record GraphAxisStyle(String title, boolean show, Function<Number, String> valueFormat) {}
|
public record GraphAxisStyle(String title, boolean showName, AxisMode mode, Function<Number, String> valueFormat) {}
|
||||||
|
@ -3,4 +3,4 @@ package it.cavallium.jlinegraph;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public record GraphStyle(List<SeriesStyle> seriesStyles, GraphAxisStyle x, GraphAxisStyle y, GraphColors colors,
|
public record GraphStyle(List<SeriesStyle> seriesStyles, GraphAxisStyle x, GraphAxisStyle y, GraphColors colors,
|
||||||
GraphFonts fonts, double strokeWidth, boolean showLegend) {}
|
GraphFonts fonts, double strokeWidth, boolean showLegend, double paddingMultiplier) {}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
package it.cavallium.jlinegraph;
|
package it.cavallium.jlinegraph;
|
||||||
|
|
||||||
public record RasterSize(double width, double height) {}
|
public record RasterSize(double width, double height) {
|
||||||
|
public static final RasterSize EMPTY = new RasterSize(0, 0);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user