/* * This file is part of jHaushalt. * jHaushalt is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * jHaushalt is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with jHaushalt; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * (C)opyright 2002-2010 Dr. Lars H. Hahn */ package haushalt.auswertung.bloecke; import haushalt.daten.Datum; import haushalt.daten.Euro; import java.awt.Color; import java.awt.FontMetrics; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.util.logging.Logger; /** * @author Dr. Lars H. Hahn * @version 2.5.3/2008.04.03 */ /* * 2008.04.03 BugFix: Ausgabe des Wert "0 €" an der Nulllinie * 2008.03.05 BugFix: pos. Betrag immer oberhalb der X-Achse; * neg. Betrag immer oberhalb des kleinsten Wertes * 2004.08.22 Version 2.0 */ public class VermoegenBlock extends AbstractGraphikBlock { private static final boolean DEBUG = false; private static final Logger LOGGER = Logger.getLogger(VermoegenBlock.class.getName()); private final Datum[] zeitpunkte; private final Euro[] salden; private Color farbePos = Color.blue; private Color farbeNeg = Color.red; private final int anzahl; private Euro grWert = new Euro(); private Euro klWert = new Euro(); public VermoegenBlock(final Datum[] zeitpunkte, final Euro[] salden) { this.zeitpunkte = zeitpunkte; this.salden = salden; this.anzahl = zeitpunkte.length; for (int i = 0; i < salden.length; i++) { if (salden[i].compareTo(this.grWert) > 0) { this.grWert = salden[i]; } if (salden[i].compareTo(this.klWert) < 0) { this.klWert = salden[i]; } } if (DEBUG) { LOGGER.info("VermoegenBlock: MIN/MAX = " + this.klWert + "/" + this.grWert); } } @Override protected int getHoehe(final int breite) { return (int) (breite * 0.75 + 0.5); } @Override public int paint(final Graphics g, final int xStart, final int yStart, final int breite) { final Graphics2D g2 = (Graphics2D) g; g2.setFont(getFont()); // WICHTIG: Font setzen vor der Definition der // FontMetrics final FontMetrics fontMetrics = g2.getFontMetrics(); int breiteYAchse = fontMetrics.stringWidth("" + this.grWert) + 5; if ((fontMetrics.stringWidth("" + this.klWert) + 5) > breiteYAchse) { breiteYAchse = fontMetrics.stringWidth("" + this.klWert) + 5; } final int rand = getAbsRand(breite); final int hoehe = getHoehe(breite); final int textHoehe = fontMetrics.getHeight(); final int graphikBreite = breite - breiteYAchse - 2 * rand; final int intervallBreite = graphikBreite / this.anzahl; final int balkenBreite = intervallBreite * 6 / 8; final int xSaldoText = (intervallBreite - textHoehe / 2) * 4 / 8; final int xBalken = intervallBreite * 1 / 8; final Euro deltaWert = this.grWert.sub(this.klWert); if (deltaWert.equals(Euro.NULL_EURO)) { return 0; // keine Veränderungen im Vermögen -> keine Anzeige } // Mit der folgenden Formel wird ein Euro-Wert in eine Y-Koordinate // umgerechnet: // y = yStart + rand + (grWert - wert) * hoehe / (grWert - klWert) // = yOffset - yFaktor * wert final double yFaktor = (hoehe - 2 * textHoehe) / deltaWert.toDouble(); final double yOffset = yStart + this.grWert.toDouble() * yFaktor; // = // Nullline // Werte für die Y-Achse berechnen und zeichnen g.setColor(Color.gray); for (int i = 0; i <= 8; i++) { final Euro wert = deltaWert.mal(i / 8.0D).add(this.klWert); final int y = (int) (yOffset - yFaktor * wert.toDouble()); final int x = xStart + rand + breiteYAchse; g.drawLine(x, y, x + graphikBreite, y); g.drawString("" + wert, x - fontMetrics.stringWidth("" + wert) - 5, y + fontMetrics.getDescent()); } // Y-Null-Linie zeichnen g.setColor(Color.black); final int x0 = xStart + rand + breiteYAchse; g.drawLine(x0, (int) yOffset, xStart + rand + breiteYAchse + graphikBreite, (int) yOffset); g.drawString( "" + Euro.NULL_EURO, x0 - fontMetrics.stringWidth("" + Euro.NULL_EURO) - 5, (int) (yOffset + fontMetrics.getDescent())); final GradientPaint verlaufPos = new GradientPaint(0, (int) yOffset, this.farbePos, 0, (int) (yOffset - yFaktor * this.grWert.toDouble()), Color.lightGray); final GradientPaint verlaufNeg = new GradientPaint(0, (int) yOffset, this.farbeNeg, 0, (int) (yOffset - yFaktor * this.klWert.toDouble()), Color.lightGray); int x = xStart + breiteYAchse + rand; for (int i = 0; i < this.anzahl; i++) { final double y = yOffset - yFaktor * this.salden[i].toDouble(); g2.setPaint(verlaufPos); if (this.salden[i].compareTo(Euro.NULL_EURO) >= 0) { g2.setPaint(verlaufPos); g2.fill(new Rectangle2D.Double(x + xBalken, y, balkenBreite, yOffset - y)); } else { g2.setPaint(verlaufNeg); g2.fill(new Rectangle2D.Double(x + xBalken, yOffset, balkenBreite, y - yOffset)); } g2.setPaint(Color.black); g2.drawString("" + this.zeitpunkte[i], x + xBalken, hoehe + yStart - 5); final AffineTransform oldAt = g2.getTransform(); final int textBreite = fontMetrics.stringWidth("" + this.salden[i]); if (this.salden[i].compareTo(Euro.NULL_EURO) >= 0) { // -- Positiver Wert // ----------------------------------------------------------------- if (textBreite + 10 <= yFaktor * this.salden[i].toDouble()) { // Prima! Der Balken ist hoch genug für den Text g2.rotate(Math.toRadians(90), x + xSaldoText, y + 5); g2.drawString("" + this.salden[i], x + xSaldoText, (int) (y + 5)); } else { // Pech! Der Text ragt über den Balken hinaus, ist aber // sichtbar g2.rotate(Math.toRadians(90), x + xSaldoText, yOffset - textBreite - 5); g2.drawString("" + this.salden[i], x + xSaldoText, (int) (yOffset - textBreite - 5)); } } else { // -- Negativer Wert // ----------------------------------------------------------------- if (textBreite + 10 <= yFaktor * -this.salden[i].toDouble()) { // Prima! Der Balken ist hoch genug für den Text g2.rotate(Math.toRadians(90), x + xSaldoText, y - textBreite - 5); g2.drawString("" + this.salden[i], x + xSaldoText, (int) y - textBreite - 5); } else { // Pech! Der Text ragt über den Balken hinaus, ist aber // sichtbar g2.rotate(Math.toRadians(90), x + xSaldoText, yOffset + 5); g2.drawString("" + this.salden[i], x + xSaldoText, (int) (yOffset + 5)); } } g2.setTransform(oldAt); x += intervallBreite; } return hoehe; } public void setFarbePos(final Color farbe) { this.farbePos = farbe; } public void setFarbeNeg(final Color farbe) { this.farbeNeg = farbe; } }