Use bounds

This commit is contained in:
Andrea Cavalli 2022-09-15 19:08:02 +02:00
parent 7802386392
commit e3f579f38c
5 changed files with 63 additions and 32 deletions

View File

@ -6,13 +6,13 @@ import java.awt.image.BufferedImage;
public class AWTBufferedGraphRenderer implements IGraphRenderer<BufferedImage> { public class AWTBufferedGraphRenderer implements IGraphRenderer<BufferedImage> {
@Override @Override
public BufferedImage renderGraph(Graph graph, RasterSize totalSize) { public BufferedImage renderGraph(Graph graph, GraphBounds bounds) {
BufferedImage image = new BufferedImage((int) totalSize.width(), BufferedImage image = new BufferedImage((int) bounds.maxX(),
(int) totalSize.height(), (int) bounds.maxY(),
BufferedImage.TYPE_INT_ARGB BufferedImage.TYPE_INT_ARGB
); );
Graphics2D graphics2D = image.createGraphics(); Graphics2D graphics2D = image.createGraphics();
AWTGraphRenderer.renderGraph(graphics2D, graph, totalSize); AWTGraphRenderer.renderGraph(graphics2D, graph, bounds);
return image; return image;
} }

View File

@ -95,8 +95,8 @@ 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", false, AxisMode.SHOW_WITH_VALUES, "%.2fs"::formatted), new GraphAxisStyle("X axis", true, AxisMode.SHOW_WITH_VALUES, "%.2fs"::formatted),
new GraphAxisStyle("Y axis", false, AxisMode.SHOW_WITH_VALUES, "%.2fm"::formatted), new GraphAxisStyle("Y axis", true, AxisMode.SHOW_WITH_VALUES, "%.2fm"::formatted),
GRAPH_COLOR, GRAPH_COLOR,
new GraphFonts(10f, 18f, 12f, 12f), new GraphFonts(10f, 18f, 12f, 12f),
2f, 2f,
@ -104,6 +104,6 @@ public class AWTGraphExample {
1 1
)); ));
var r = new AWTGraphRenderer(); var r = new AWTGraphRenderer();
r.renderGraph(g, new RasterSize(w, h)).drawTo(g2d); r.renderGraph(g, new GraphBounds(0, 0, w, h)).drawTo(g2d);
} }
} }

View File

@ -26,11 +26,12 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
private static final int MAX_LABELS = 1000; private static final int MAX_LABELS = 1000;
@Override @Override
public AWTDrawer renderGraph(Graph graph, RasterSize totalSize) { public AWTDrawer renderGraph(Graph graph, GraphBounds bounds) {
return graphics2D -> renderGraph(graphics2D, graph, totalSize); return graphics2D -> renderGraph(graphics2D, graph, bounds);
} }
public static void renderGraph(Graphics2D graphics2D, Graph graph, RasterSize totalSize) { public static void renderGraph(Graphics2D g2d, Graph graph, GraphBounds bounds) {
var graphics2D = (Graphics2D) g2d.create();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
@ -76,7 +77,7 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
var graphHeight var graphHeight
// Start with total height // Start with total height
= totalSize.height() = bounds.height()
// Remove the padding on top // Remove the padding on top
- topPadding - topPadding
// Remove the x value lines length // Remove the x value lines length
@ -90,16 +91,16 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
// Remove the padding on bottom // Remove the padding on bottom
- bottomPadding; - bottomPadding;
var xValueLineOffset = topPadding + graphHeight; var xValueLineOffset = bounds.minY() + topPadding + graphHeight;
var yLabels = getYLabels(graph, graphHeight, valuesFontMetrics, scaleY, y.mode()); var yLabels = getYLabels(graph, bounds.minY(), graphHeight, valuesFontMetrics, scaleY, y.mode());
RasterSize yLabelsAreaSize = computeYLabelsAreaSize(y.mode(), 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 = bounds.minX() + leftPadding + yAxisNameWidth + yValuesToYAxisNamePadding + yValuesWidth;
var graphWidth var graphWidth
// Start with total width // Start with total width
= totalSize.width() = bounds.width()
// Remove the padding on left // Remove the padding on left
- leftPadding - leftPadding
// Remove y-axis name "90deg height" // Remove y-axis name "90deg height"
@ -133,32 +134,39 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
} }
} }
var xLabels = getXLabels(graph, graphWidth, valuesFontMetrics, scaleX, x.mode()); var xLabels = getXLabels(graph, bounds.minX(), graphWidth, valuesFontMetrics, scaleX, x.mode());
RasterSize yAxisNameCenterOffset = new RasterSize(leftPadding + valuesFontMetrics.getHeight() / 2d, valuesFontMetrics.getHeight() RasterSize yAxisNameCenterOffset = new RasterSize(bounds.minX()
+ leftPadding
+ valuesFontMetrics.getHeight() / 2d, bounds.minY()
+ valuesFontMetrics.getHeight()
// Add half of graph height // Add half of graph height
+ graphHeight / 2 + topPadding); + graphHeight / 2 + topPadding);
RasterSize yValuesOffset = new RasterSize(leftPadding RasterSize yValuesOffset = new RasterSize(bounds.minX()
+ leftPadding
// Add y axis name "90deg height" // Add y axis name "90deg height"
+ yAxisNameWidth + yAxisNameWidth
// Add the space between the values and the axis name // Add the space between the values and the axis name
+ yValuesToYAxisNamePadding, topPadding); + yValuesToYAxisNamePadding, bounds.minY() + topPadding);
RasterSize graphOffset = new RasterSize(leftPadding RasterSize graphOffset = new RasterSize(bounds.minX()
+ leftPadding
+ yAxisNameWidth + yAxisNameWidth
+ yValuesToYAxisNamePadding + yValuesToYAxisNamePadding
+ yValuesWidth + yValuesWidth
+ yValueLineLength, topPadding); + yValueLineLength, bounds.minY() + topPadding);
RasterSize xValuesOffset = new RasterSize(graphOffset.width(), xValueLineOffset + xValueLineLength); RasterSize xValuesOffset = new RasterSize(graphOffset.width(), xValueLineOffset + xValueLineLength);
RasterSize xAxisNameCenterOffset = new RasterSize(leftPadding RasterSize xAxisNameCenterOffset = new RasterSize(bounds.minX()
+ leftPadding
+ yAxisNameWidth + yAxisNameWidth
+ yValuesToYAxisNamePadding + yValuesToYAxisNamePadding
+ yValuesWidth + yValuesWidth
+ yValueLineLength + yValueLineLength
// Add half of graph width // Add half of graph width
+ graphWidth / 2, topPadding + graphWidth / 2, bounds.minY()
+ topPadding
// Add graph height // Add graph height
+ graphHeight + graphHeight
// Add the x value lines length // Add the x value lines length
@ -179,7 +187,11 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
try { try {
graphics2D.setBackground(bgColor); graphics2D.setBackground(bgColor);
graphics2D.clearRect(0, 0, (int) totalSize.width(), (int) totalSize.height()); graphics2D.clearRect((int) Math.floor(bounds.minX()),
(int) Math.floor(bounds.minY()),
(int) Math.ceil(bounds.width()),
(int) Math.ceil(bounds.height())
);
if (graphHeight < 0) { if (graphHeight < 0) {
return; return;
@ -188,7 +200,7 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
return; return;
} }
renderGraphBorders(graphics2D, graph, graphOffset, graphSize, defaultStroke, totalSize); renderGraphBorders(graphics2D, graph, graphOffset, graphSize, defaultStroke, bounds);
if (y.showName()) { if (y.showName()) {
renderYAxisName(graphics2D, graph, yAxisNameCenterOffset, axisNameFont, axisNameFontMetrics); renderYAxisName(graphics2D, graph, yAxisNameCenterOffset, axisNameFont, axisNameFontMetrics);
} }
@ -710,12 +722,12 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
RasterSize graphOffset, RasterSize graphOffset,
RasterSize graphSize, RasterSize graphSize,
BasicStroke defaultStroke, BasicStroke defaultStroke,
RasterSize totalSize) { GraphBounds bounds) {
// Do not draw the border if the graph is fullscreen // Do not draw the border if the graph is fullscreen
if (graphOffset.width() <= 0 if (graphOffset.width() <= bounds.minX()
&& graphOffset.height() <= 0 && graphOffset.height() <= bounds.minY()
&& graphSize.width() >= totalSize.width() && graphSize.width() >= bounds.width()
&& graphSize.height() >= totalSize.height()) { && graphSize.height() >= bounds.height()) {
return; return;
} }
var fgColor = graph.style().colors().foreground().toColor(); var fgColor = graph.style().colors().foreground().toColor();
@ -750,6 +762,7 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
* @return rendered labels * @return rendered labels
*/ */
private static List<LabelWithOffset> getXLabels(Graph graph, private static List<LabelWithOffset> getXLabels(Graph graph,
double labelsAreaOffset,
double labelsAreaWidth, double labelsAreaWidth,
FontMetrics valuesFontMetrics, FontMetrics valuesFontMetrics,
NiceScale scaleX, NiceScale scaleX,
@ -767,7 +780,7 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
int i = 0; int i = 0;
double prevRasterLabelEndOffset = -Double.MAX_VALUE; double prevRasterLabelEndOffset = -Double.MAX_VALUE;
double currentRasterOffset = 0; double currentRasterOffset = labelsAreaOffset;
double currentValue = minX; double currentValue = minX;
while (currentValue <= maxX && i < MAX_LABELS && (scaleX.getTickSpacing() > 0)) { while (currentValue <= maxX && i < MAX_LABELS && (scaleX.getTickSpacing() > 0)) {
if (mode.showLabels()) { if (mode.showLabels()) {
@ -794,6 +807,7 @@ public class AWTGraphRenderer implements IGraphRenderer<AWTDrawer> {
* @return rendered labels * @return rendered labels
*/ */
private static List<LabelWithOffset> getYLabels(Graph graph, private static List<LabelWithOffset> getYLabels(Graph graph,
double labelsAreaOffset,
double labelsAreaHeight, double labelsAreaHeight,
FontMetrics valuesFontMetrics, FontMetrics valuesFontMetrics,
NiceScale scaleY, NiceScale scaleY,

View File

@ -6,6 +6,15 @@ public record GraphBounds(double minX, double minY, double maxX, double maxY) {
private static final GraphBounds EMPTY = new GraphBounds(0, 0, 0, 0); private static final GraphBounds EMPTY = new GraphBounds(0, 0, 0, 0);
public static GraphBounds fromRasterSize(RasterSize size) {
return fromRasterSize(RasterSize.EMPTY, size);
}
public static GraphBounds fromRasterSize(RasterSize offset, RasterSize size) {
return new GraphBounds(offset.width(), offset.height(),
offset.width() + size.width(), offset.height() + size.height());
}
public static GraphBounds fromSeriesData(List<SeriesData> seriesDataList, public static GraphBounds fromSeriesData(List<SeriesData> seriesDataList,
boolean includeOriginX, boolean includeOriginX,
boolean includeOriginY) { boolean includeOriginY) {
@ -91,4 +100,12 @@ public record GraphBounds(double minX, double minY, double maxX, double maxY) {
return adjustZero(new GraphBounds(minX, minY, maxX, maxY), showZeroX, showZeroY); return adjustZero(new GraphBounds(minX, minY, maxX, maxY), showZeroX, showZeroY);
} }
} }
public double height() {
return maxY - minY;
}
public double width() {
return maxX - minX;
}
} }

View File

@ -2,5 +2,5 @@ package it.cavallium.jlinegraph;
public interface IGraphRenderer<T> { public interface IGraphRenderer<T> {
T renderGraph(Graph graph, RasterSize size); T renderGraph(Graph graph, GraphBounds bounds);
} }