/** * Returns the preferred width of the title. This will only be called when the title * is being drawn at the left or right of a chart. * * @param g2 the graphics device. * @param height the height. * * @return The preferred width of the title. */ public float getPreferredWidth(Graphics2D g2, float height) { float result = 0.0f; if (this.text != null && !this.text.equals("")) { g2.setFont(this.font); TextBlock title = TextUtilities.createTextBlock( this.text, this.font, this.paint, height, new G2TextMeasurer(g2) ); Size2D d = title.calculateDimensions(g2); result = (float) getSpacer().getAdjustedWidth(d.getHeight()); // use height here because the title // is displayed rotated } if (LOGGER.isDebugEnabled()) { LOGGER.debug("Title preferred width = " + result); } return result; }
/** * Returns the preferred height of the title. * * @param g2 the graphics device. * @param width the width. * * @return The preferred height of the title. */ public float getPreferredHeight(Graphics2D g2, float width) { float result = 0.0f; if (this.text != null && !this.text.equals("")) { g2.setFont(this.font); float textWidth = (float) getSpacer().trimWidth(width); TextBlock title = TextUtilities.createTextBlock( this.text, this.font, this.paint, textWidth, new G2TextMeasurer(g2) ); Size2D d = title.calculateDimensions(g2); result = (float) getSpacer().getAdjustedHeight(d.getHeight()); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("Title preferred height = " + result); } return result; }
/** * Arranges the contents of the block, within the given constraints, and * returns the block size. * * @param g2 the graphics device. * @param constraint the constraint (<code>null</code> not permitted). * * @return The block size (in Java2D units, never <code>null</code>). */ public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) { Size2D result = new Size2D(); fetchLegendItems(); if (this.items.isEmpty()) { return result; } BlockContainer container = this.wrapper; if (container == null) { container = this.items; } RectangleConstraint c = toContentConstraint(constraint); Size2D size = container.arrange(g2, c); result.height = calculateTotalHeight(size.height); result.width = calculateTotalWidth(size.width); return result; }
protected Size2D arrangeRR(BlockContainer container, Graphics2D g2, RectangleConstraint constraint) { // first arrange without constraints, and see if this fits within // the required ranges... Size2D s1 = arrangeNN(container, g2); if (constraint.getHeightRange().contains(s1.height)) { return s1; // TODO: we didn't check the width yet } else { RectangleConstraint c = constraint.toFixedHeight( constraint.getHeightRange().getUpperBound() ); return arrangeRF(container, g2, c); } }
/** * Arranges the blocks with the overall width and height to fit within * specified ranges. * * @param container the container. * @param g2 the graphics device. * @param constraint the constraint. * * @return The size after the arrangement. */ protected Size2D arrangeRR(BlockContainer container, Graphics2D g2, RectangleConstraint constraint) { // first arrange without constraints, and see if this fits within // the required ranges... Size2D s1 = arrangeNN(container, g2); if (constraint.getWidthRange().contains(s1.width)) { return s1; // TODO: we didn't check the height yet } else { RectangleConstraint c = constraint.toFixedWidth( constraint.getWidthRange().getUpperBound()); return arrangeFR(container, g2, c); } }
/** * Arranges the container with a fixed overall width and height. * * @param container the container. * @param g2 the graphics device. * @param constraint the constraint. * * @return The size following the arrangement. */ protected Size2D arrangeFF(BlockContainer container, Graphics2D g2, RectangleConstraint constraint) { double width = constraint.getWidth() / this.columns; double height = constraint.getHeight() / this.rows; List blocks = container.getBlocks(); for (int c = 0; c < this.columns; c++) { for (int r = 0; r < this.rows; r++) { int index = r * this.columns + c; if (index == blocks.size()) { break; } Block b = (Block) blocks.get(index); b.setBounds(new Rectangle2D.Double( c * width, r * height, width, height )); } } return new Size2D(this.columns * width, this.rows * height); }
/** * Arrange with a fixed width and a height within a given range. * * @param container the container. * @param constraint the constraint. * @param g2 the graphics device. * * @return The size of the arrangement. */ protected Size2D arrangeFR(BlockContainer container, Graphics2D g2, RectangleConstraint constraint) { RectangleConstraint c1 = constraint.toUnconstrainedHeight(); Size2D size1 = arrange(container, g2, c1); if (constraint.getHeightRange().contains(size1.getHeight())) { return size1; } else { double h = constraint.getHeightRange().constrain(size1.getHeight()); RectangleConstraint c2 = constraint.toFixedHeight(h); return arrange(container, g2, c2); } }
/** * Arrange with a fixed width and a height within a given range. * * @param container the container. * @param g2 the graphics device. * @param constraint the constraint. * * @return The size of the arrangement. */ protected Size2D arrangeFN(BlockContainer container, Graphics2D g2, RectangleConstraint constraint) { double width = constraint.getWidth() / this.columns; RectangleConstraint constraint2 = constraint.toFixedWidth(width); List blocks = container.getBlocks(); double maxH = 0.0; for (int r = 0; r < this.rows; r++) { for (int c = 0; c < this.columns; c++) { int index = r * this.columns + c; if (index == blocks.size()) { break; } Block b = (Block) blocks.get(index); Size2D s = b.arrange(g2, constraint2); maxH = Math.max(maxH, s.getHeight()); } } RectangleConstraint constraint3 = constraint.toFixedHeight( maxH * this.rows ); return arrange(container, g2, constraint3); }
/** * Arranges the blocks with the overall width and height to fit within * specified ranges. * * @param container the container. * @param constraint the constraint. * @param g2 the graphics device. * * @return The size after the arrangement. */ protected Size2D arrangeRR(BlockContainer container, Graphics2D g2, RectangleConstraint constraint) { // first arrange without constraints, and see if this fits within // the required ranges... Size2D s1 = arrangeNN(container, g2); if (constraint.getWidthRange().contains(s1.width)) { return s1; // TODO: we didn't check the height yet } else { RectangleConstraint c = constraint.toFixedWidth( constraint.getWidthRange().getUpperBound() ); return arrangeFR(container, g2, c); } }
/** * Arranges the block with a range constraint on the width, and no * constraint on the height. * * @param container the container. * @param constraint the constraint. * @param g2 the graphics device. * * @return The size following the arrangement. */ protected Size2D arrangeRN(BlockContainer container, Graphics2D g2, RectangleConstraint constraint) { // first arrange without constraints, then see if the width fits // within the required range...if not, call arrangeFN() at max width Size2D s1 = arrangeNN(container, g2); if (constraint.getWidthRange().contains(s1.width)) { return s1; } else { RectangleConstraint c = constraint.toFixedWidth( constraint.getWidthRange().getUpperBound() ); return arrangeFN(container, g2, c); } }
/** * A utility method for determining the width of a text block. * * @param block the text block. * @param position the position. * @param g2 the graphics device. * * @return The width. */ protected double calculateTextBlockWidth(TextBlock block, CategoryLabelPosition position, Graphics2D g2) { RectangleInsets insets = getTickLabelInsets(); Size2D size = block.calculateDimensions(g2); Rectangle2D box = new Rectangle2D.Double(0.0, 0.0, size.getWidth(), size.getHeight()); Shape rotatedBox = ShapeUtilities.rotateShape(box, position.getAngle(), 0.0f, 0.0f); double w = rotatedBox.getBounds2D().getWidth() + insets.getTop() + insets.getBottom(); return w; }
/** * A utility method for determining the height of a text block. * * @param block the text block. * @param position the label position. * @param g2 the graphics device. * * @return The height. */ protected double calculateTextBlockHeight(TextBlock block, CategoryLabelPosition position, Graphics2D g2) { RectangleInsets insets = getTickLabelInsets(); Size2D size = block.calculateDimensions(g2); Rectangle2D box = new Rectangle2D.Double(0.0, 0.0, size.getWidth(), size.getHeight()); Shape rotatedBox = ShapeUtilities.rotateShape(box, position.getAngle(), 0.0f, 0.0f); double h = rotatedBox.getBounds2D().getHeight() + insets.getTop() + insets.getBottom(); return h; }
/** * Some checks for the arrange method. */ @Test public void testArrangeNN() { BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB); Graphics2D g2 = image.createGraphics(); ImageTitle t = new ImageTitle(JFreeChart.INFO.getLogo()); Size2D s = t.arrange(g2); assertEquals(102.0, s.getWidth(), EPSILON); assertEquals(102.0, s.getHeight(), EPSILON); t.setPadding(1.0, 2.0, 3.0, 4.0); s = t.arrange(g2); assertEquals(106.0, s.getWidth(), EPSILON); assertEquals(104.0, s.getHeight(), EPSILON); t.setMargin(5.0, 6.0, 7.0, 8.0); s = t.arrange(g2); assertEquals(120.0, s.getWidth(), EPSILON); assertEquals(116.0, s.getHeight(), EPSILON); }
/** * Arranges the contents of the block, within the given constraints, and * returns the block size. * * @param g2 the graphics device. * @param constraint the constraint (<code>null</code> not permitted). * * @return The block size (in Java2D units, never <code>null</code>). */ @Override public Size2D arrange(Graphics2D g2, RectangleConstraint constraint) { Size2D result = new Size2D(); fetchLegendItems(); if (this.items.isEmpty()) { return result; } BlockContainer container = this.wrapper; if (container == null) { container = this.items; } RectangleConstraint c = toContentConstraint(constraint); Size2D size = container.arrange(g2, c); result.height = calculateTotalHeight(size.height); result.width = calculateTotalWidth(size.width); return result; }
/** * Returns the content size for the title. * * @param g2 the graphics device. * @param widthRange the width range. * @param heightRange the height range. * * @return The content size. */ @Override protected Size2D arrangeRR(Graphics2D g2, Range widthRange, Range heightRange) { g2.setFont(getFont()); FontMetrics fm = g2.getFontMetrics(getFont()); Rectangle2D bounds = TextUtilities.getTextBounds(getText(), g2, fm); if (bounds.getWidth() <= widthRange.getUpperBound() && bounds.getHeight() <= heightRange.getUpperBound()) { return new Size2D(bounds.getWidth(), bounds.getHeight()); } else { return new Size2D(0.0, 0.0); } }
/** * Arranges a container with range constraints for both the horizontal * and vertical. * * @param container the container. * @param g2 the graphics device. * @param constraint the constraint. * * @return The size of the container. */ protected Size2D arrangeRR(BlockContainer container, Graphics2D g2, RectangleConstraint constraint) { // first arrange without constraints, and see if this fits within // the required ranges... Size2D s1 = arrangeNN(container, g2); if (constraint.getHeightRange().contains(s1.height)) { return s1; // TODO: we didn't check the width yet } else { RectangleConstraint c = constraint.toFixedHeight( constraint.getHeightRange().getUpperBound() ); return arrangeRF(container, g2, c); } }
/** * Arrange with a fixed width and a height within a given range. * * @param container the container. * @param g2 the graphics device. * @param constraint the constraint. * * @return The size of the arrangement. */ protected Size2D arrangeFN(BlockContainer container, Graphics2D g2, RectangleConstraint constraint) { double width = constraint.getWidth() / this.columns; RectangleConstraint bc = constraint.toFixedWidth(width); List blocks = container.getBlocks(); double maxH = 0.0; for (int r = 0; r < this.rows; r++) { for (int c = 0; c < this.columns; c++) { int index = r * this.columns + c; if (index >= blocks.size()) { break; } Block b = (Block) blocks.get(index); if (b != null) { Size2D s = b.arrange(g2, bc); maxH = Math.max(maxH, s.getHeight()); } } } RectangleConstraint cc = constraint.toFixedHeight(maxH * this.rows); return arrange(container, g2, cc); }
/** * Arrange with a fixed height and no constraint for the width. * * @param container the container. * @param g2 the graphics device. * @param constraint the constraint. * * @return The size of the arrangement. */ protected Size2D arrangeNF(BlockContainer container, Graphics2D g2, RectangleConstraint constraint) { double height = constraint.getHeight() / this.rows; RectangleConstraint bc = constraint.toFixedHeight(height); List blocks = container.getBlocks(); double maxW = 0.0; for (int r = 0; r < this.rows; r++) { for (int c = 0; c < this.columns; c++) { int index = r * this.columns + c; if (index >= blocks.size()) { break; } Block b = (Block) blocks.get(index); if (b != null) { Size2D s = b.arrange(g2, bc); maxW = Math.max(maxW, s.getWidth()); } } } RectangleConstraint cc = constraint.toFixedWidth(maxW * this.columns); return arrange(container, g2, cc); }
/** * Arranges the container with a fixed overall width and height. * * @param container the container (<code>null</code> not permitted). * @param g2 the graphics device. * @param constraint the constraint (<code>null</code> not permitted). * * @return The size following the arrangement. */ protected Size2D arrangeFF(BlockContainer container, Graphics2D g2, RectangleConstraint constraint) { double width = constraint.getWidth() / this.columns; double height = constraint.getHeight() / this.rows; List blocks = container.getBlocks(); for (int c = 0; c < this.columns; c++) { for (int r = 0; r < this.rows; r++) { int index = r * this.columns + c; if (index >= blocks.size()) { break; } Block b = (Block) blocks.get(index); if (b != null) { b.setBounds(new Rectangle2D.Double(c * width, r * height, width, height)); } } } return new Size2D(this.columns * width, this.rows * height); }
/** * Arrange with a fixed width and no height constraint. * * @param container the container. * @param constraint the constraint. * @param g2 the graphics device. * * @return The size of the arrangement. */ protected Size2D arrangeRN(BlockContainer container, Graphics2D g2, RectangleConstraint constraint) { RectangleConstraint c1 = constraint.toUnconstrainedWidth(); Size2D size1 = arrange(container, g2, c1); if (constraint.getWidthRange().contains(size1.getWidth())) { return size1; } else { double w = constraint.getWidthRange().constrain(size1.getWidth()); RectangleConstraint c2 = constraint.toFixedWidth(w); return arrange(container, g2, c2); } }
/** * Arrange with a fixed height and no width constraint. * * @param container the container. * @param constraint the constraint. * @param g2 the graphics device. * * @return The size of the arrangement. */ protected Size2D arrangeNR(BlockContainer container, Graphics2D g2, RectangleConstraint constraint) { RectangleConstraint c1 = constraint.toUnconstrainedHeight(); Size2D size1 = arrange(container, g2, c1); if (constraint.getHeightRange().contains(size1.getHeight())) { return size1; } else { double h = constraint.getHeightRange().constrain(size1.getHeight()); RectangleConstraint c2 = constraint.toFixedHeight(h); return arrange(container, g2, c2); } }
/** * This test is for a particular bug that arose just prior to the release * of JFreeChart 1.0.10. A BorderArrangement with LEFT, CENTRE and RIGHT * blocks that is too wide, by default, for the available space, wasn't * shrinking the centre block as expected. */ @Test public void testBugX() { RectangleConstraint constraint = new RectangleConstraint( new Range(0.0, 200.0), new Range(0.0, 100.0)); BlockContainer container = new BlockContainer(new BorderArrangement()); BufferedImage image = new BufferedImage(200, 100, BufferedImage.TYPE_INT_RGB); Graphics2D g2 = image.createGraphics(); container.add(new EmptyBlock(10.0, 6.0), RectangleEdge.LEFT); container.add(new EmptyBlock(20.0, 6.0), RectangleEdge.RIGHT); container.add(new EmptyBlock(30.0, 6.0)); Size2D size = container.arrange(g2, constraint); assertEquals(60.0, size.width, EPSILON); assertEquals(6.0, size.height, EPSILON); container.clear(); container.add(new EmptyBlock(10.0, 6.0), RectangleEdge.LEFT); container.add(new EmptyBlock(20.0, 6.0), RectangleEdge.RIGHT); container.add(new EmptyBlock(300.0, 6.0)); size = container.arrange(g2, constraint); assertEquals(200.0, size.width, EPSILON); assertEquals(6.0, size.height, EPSILON); }
/** * Arrange with a fixed height and a width within a given range. * * @param container the container. * @param constraint the constraint. * @param g2 the graphics device. * * @return The size of the arrangement. */ protected Size2D arrangeRF(BlockContainer container, Graphics2D g2, RectangleConstraint constraint) { RectangleConstraint c1 = constraint.toUnconstrainedWidth(); Size2D size1 = arrange(container, g2, c1); if (constraint.getWidthRange().contains(size1.getWidth())) { return size1; } else { double w = constraint.getWidthRange().constrain(size1.getWidth()); RectangleConstraint c2 = constraint.toFixedWidth(w); return arrange(container, g2, c2); } }
/** * Returns the bounds of the text block. * * @param g2 the graphics device (<code>null</code> not permitted). * @param anchorX the x-coordinate for the anchor point. * @param anchorY the y-coordinate for the anchor point. * @param anchor the text block anchor (<code>null</code> not permitted). * @param rotateX the x-coordinate for the rotation point. * @param rotateY the y-coordinate for the rotation point. * @param angle the rotation angle. * * @return The bounds. */ public Shape calculateBounds(final Graphics2D g2, final float anchorX, final float anchorY, final TextBlockAnchor anchor, final float rotateX, final float rotateY, final double angle) { final Size2D d = calculateDimensions(g2); final float[] offsets = calculateOffsets( anchor, d.getWidth(), d.getHeight() ); final Rectangle2D bounds = new Rectangle2D.Double( anchorX + offsets[0], anchorY + offsets[1], d.getWidth(), d.getHeight() ); final Shape rotatedBounds = ShapeUtilities.rotateShape( bounds, angle, rotateX, rotateY ); return rotatedBounds; }
/** * Draws the text line. * * @param g2 the graphics device. * @param anchorX the x-coordinate for the anchor point. * @param anchorY the y-coordinate for the anchor point. * @param anchor the point on the text line that is aligned to the anchor * point. * @param rotateX the x-coordinate for the rotation point. * @param rotateY the y-coordinate for the rotation point. * @param angle the rotation angle (in radians). */ public void draw(Graphics2D g2, float anchorX, float anchorY, TextAnchor anchor, float rotateX, float rotateY, double angle) { Size2D dim = calculateDimensions(g2); float xAdj = 0.0f; if (anchor.isHorizontalCenter()) { xAdj = (float) -dim.getWidth() / 2.0f; } else if (anchor.isRight()) { xAdj = (float) -dim.getWidth(); } float x = anchorX + xAdj; final float yOffset = calculateBaselineOffset(g2, anchor); final Iterator iterator = this.fragments.iterator(); while (iterator.hasNext()) { final TextFragment fragment = (TextFragment) iterator.next(); final Size2D d = fragment.calculateDimensions(g2); fragment.draw(g2, x, anchorY + yOffset, TextAnchor.BASELINE_LEFT, rotateX, rotateY, angle); x = x + (float) d.getWidth(); } }
/** * A utility method for determining the width of a text block. * * @param block the text block. * @param position the position. * @param g2 the graphics device. * * @return the width. */ protected double calculateTextBlockWidth(TextBlock block, CategoryLabelPosition position, Graphics2D g2) { Insets insets = getTickLabelInsets(); Size2D size = block.calculateDimensions(g2); Rectangle2D box = new Rectangle2D.Double(0.0, 0.0, size.getWidth(), size.getHeight()); Shape rotatedBox = ShapeUtils.rotateShape(box, position.getAngle(), 0.0f, 0.0f); double w = rotatedBox.getBounds2D().getWidth() + insets.top + insets.bottom; return w; }
/** * A utility method for determining the height of a text block. * * @param block the text block. * @param position the label position. * @param g2 the graphics device. * * @return the height. */ protected double calculateTextBlockHeight(TextBlock block, CategoryLabelPosition position, Graphics2D g2) { Insets insets = getTickLabelInsets(); Size2D size = block.calculateDimensions(g2); Rectangle2D box = new Rectangle2D.Double(0.0, 0.0, size.getWidth(), size.getHeight()); Shape rotatedBox = ShapeUtils.rotateShape(box, position.getAngle(), 0.0f, 0.0f); double h = rotatedBox.getBounds2D().getHeight() + insets.top + insets.bottom; return h; }
/** * Test arrangement with no constraints. */ public void testNN() { BlockContainer c = createTestContainer1(); Size2D s = c.arrange(null, RectangleConstraint.NONE); assertEquals(90.0, s.width, EPSILON); assertEquals(33.0, s.height, EPSILON); }