Use bounds
This commit is contained in:
parent
7802386392
commit
e3f579f38c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user