/*
* 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 3 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, see <http://www.gnu.org/licenses/>.
* (C)opyright 2002-2010 Dr. Lars H. Hahn
*/
package haushalt.auswertung.bloecke;
import haushalt.auswertung.FarbPaletten;
import haushalt.daten.EinzelKategorie;
import haushalt.daten.Euro;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.logging.Logger;
/**
* @author Dr. Lars H. Hahn
* @version 2.0/2008.02.13
* @since 2.0
*/
/*
* 2008.02.13 Ausgaben können wahlweise mit positiven oder negativen Werten
* angezeigt werden
* 2004.08.22 Erste Version
*/
public class EntwicklungBlock extends AbstractGraphikBlock {
private static final boolean DEBUG = false;
private static final Logger LOGGER = Logger.getLogger(EntwicklungBlock.class.getName());
private Euro grWert = new Euro();
private Euro klWert = new Euro();
private final EinzelKategorie[] kategorien;
private final String[] zeitraumNamen;
private final Euro[][] werte;
private final String farbschema;
private final Boolean negativeWerte;
public EntwicklungBlock(
final EinzelKategorie[] kategorien,
final String[] zeitraumNamen,
final Euro[][] werte,
final String farbschema,
final Boolean negativeWerte) {
this.kategorien = kategorien;
this.zeitraumNamen = zeitraumNamen;
this.werte = werte;
this.farbschema = farbschema;
this.negativeWerte = negativeWerte;
final int anzahlKategorien = kategorien.length;
final int anzahlZeitraeume = zeitraumNamen.length;
for (int k = 0; k < anzahlKategorien; k++) {
for (int z = 0; z < anzahlZeitraeume; z++) {
if (negativeWerte) {
if (this.grWert.compareTo(werte[z][k]) < 0) {
this.grWert = werte[z][k];
}
if (this.klWert.compareTo(werte[z][k]) > 0) {
this.klWert = werte[z][k];
}
} else {
if (this.grWert.compareTo(werte[z][k]) < 0) {
this.grWert = werte[z][k];
}
if (this.grWert.compareTo(werte[z][k].mal(-1.0D)) < 0) {
this.grWert = werte[z][k].mal(-1.0D);
}
}
}
}
if (DEBUG) {
LOGGER.info("EntwicklungBlock: MIN/MAX = " + this.klWert + "/" + this.grWert);
}
}
@Override
public int paint(final Graphics g, final int xStart, final int yStart, final int breite) {
g.setFont(getFont()); // WICHTIG: Font setzen vor der Definition der
// FontMetrics
final FontMetrics fontMetrics = g.getFontMetrics();
final int anzahlZeitraeume = this.zeitraumNamen.length;
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 spaltenBreite = (breite - breiteYAchse - 2 * rand) / (anzahlZeitraeume - 1);
// kompliziert, um den Rundungs-Fehler zu vermeiden
final int graphikBreite = spaltenBreite * (anzahlZeitraeume - 1);
final int hoehe = getHoehe(breite) - fontMetrics.getHeight();
// 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 Euro deltaWert = this.grWert.sub(this.klWert);
final double yFaktor = hoehe / deltaWert.toDouble();
final double yOffset = yStart + this.grWert.toDouble() * yFaktor;
// Werte für die Y-Achse berechnen und zeichnen
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.setColor(Color.gray);
g.drawLine(x, y, x + graphikBreite, y);
g.setColor(Color.black);
g.drawString("" + wert, x - fontMetrics.stringWidth("" + wert) - 5, y + fontMetrics.getDescent());
}
// Y-Null-Linie zeichnen
g.drawLine(xStart + rand + breiteYAchse, (int) yOffset, xStart + rand + breiteYAchse + graphikBreite, (int) yOffset);
// Werte für die X-Achse berechnen und zeichnen
for (int i = 0; i < anzahlZeitraeume; i++) {
final int y = yStart + getHoehe(breite);
final int x = xStart + rand + breiteYAchse + spaltenBreite * i;
g.setColor(Color.gray);
g.drawLine(x, yStart, x, yStart + hoehe);
g.setColor(Color.black);
g.drawString(this.zeitraumNamen[i], x - fontMetrics.stringWidth(this.zeitraumNamen[i]) / 2, y);
}
((Graphics2D) g).setStroke(new BasicStroke(2.0f));
for (int k = 0; k < this.kategorien.length; k++) {
g.setColor(FarbPaletten.getFarbe(k, this.farbschema));
final int[] x = new int[anzahlZeitraeume];
final int[] y = new int[anzahlZeitraeume];
for (int z = 0; z < anzahlZeitraeume; z++) {
x[z] = xStart + rand + breiteYAchse + spaltenBreite * z;
if (!this.negativeWerte && (this.werte[z][k].compareTo(Euro.NULL_EURO) < 0)) {
y[z] = (int) (yOffset - yFaktor * -this.werte[z][k].toDouble());
} else {
y[z] = (int) (yOffset - yFaktor * this.werte[z][k].toDouble());
}
g.fillOval(x[z] - 4, y[z] - 4, 8, 8);
}
g.drawPolyline(x, y, anzahlZeitraeume);
}
return getHoehe(breite);
}
@Override
protected int getHoehe(final int breite) {
// enspricht dem Standard-Bildschirmverhältnis 4:3
return (int) (breite * 0.75 + 0.5);
}
}