All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.day.cq.graphics.chart.BarChart Maven / Gradle / Ivy

There is a newer version: 6.5.21
Show newest version
/*
 * Copyright 1997-2004 Day Management AG
 * Barfuesserplatz 6, 4001 Basel, Switzerland
 * All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * Day Management AG, ("Confidential Information"). You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Day.
 */
package com.day.cq.graphics.chart;

import java.awt.Color;
import java.awt.Rectangle;

import com.day.cq.graphics.Graph;
import com.day.image.Font;
import com.day.image.Layer;

/**
 * @author fmeschbe
 */
public class BarChart extends Chart {

    public static final int BARS_TILE = 0;
    public static final int BARS_CASCADE = 1;
    public static final int BARS_HORIZONTAL = 2;
    public static final int BARS_CANDLE = 3;

    int style = 0;
    int barwidth = 0;
    int barspacing = 0;
    int numlines = 0;

    public static String getName() {
        return "bar";
    }

    public Layer draw(Graph graph, boolean doDraw) {

        // init infos
        int numtitles = 0;

        // get axis and force creation if not existing yet
        Axis yAxis = graph.getYAxis();
        Axis xAxis = graph.getXAxis();

        if ((yAxis.titlepos & Axis.TITLE_POS_ABOVE) != 0)
            numtitles++;
        if ((yAxis.titlepos & Axis.TITLE_POS_BELOW) != 0)
            numtitles++;

        if (style == BARS_HORIZONTAL) {
            yAxis.setType(Axis.V_AXIS);
            if (yAxis.height == 0) {
                yAxis.setRangescale(0);
                yAxis.height = yAxis.tickdistance
                        * (graph.getData().numrows + numtitles);
            } else if (yAxis.tickdistance == 0) {
                yAxis.setRangescale(0);
                yAxis.tickdistance = yAxis.height
                        / (graph.getData().numrows + numtitles);
            } else {
                yAxis.setRangescale(yAxis.tickdistance);
            }

            if ((yAxis.titlepos & Axis.TITLE_POS_ABOVE) != 0) {
                yAxis.setRangemin(-1);
                yAxis.setRangeoffset(1);
            } else {
                yAxis.setRangemin(0);
                yAxis.setRangeoffset(0);
            }

            yAxis.numticks = graph.getData().numrows;
            yAxis.setRangemax(yAxis.getRangemin() + numtitles
                    + graph.getData().numrows - 1);
            yAxis.setRangestep(1);
            yAxis.setLabelformat("%s");
        } else {
            yAxis.setType(Axis.Y_AXIS);
            getBarMetrics(graph, graph.getMetrics(), yAxis);

            // little hack if label is to be displayed above
            yAxis.height = graph.getMetrics().height + 1;
            yAxis.numticks = graph.getMetrics().numlines;
            if (yAxis.labelalign == Axis.LABEL_ABOVE) {
                yAxis.height += yAxis.tickdistance;
                yAxis.numticks++;
            }
            yAxis.setRangemin(graph.getMetrics().bottomvalue);
            yAxis.setRangemax(graph.getMetrics().topvalue);
            yAxis.setRangestep(graph.getMetrics().distance);
            if (yAxis.getRangescale() == 0) {
                yAxis.setRangescale(graph.getMetrics().height
                        / (yAxis.getRangemax() - yAxis.getRangemin()));
                yAxis.numticks = (int) ((yAxis.getRangemax() - yAxis
                        .getRangemin()) / yAxis.getRangestep());
            }
            yAxis.setRangeoffset(-yAxis.getRangemin());
            yAxis.setLabelformat("%." + graph.getMetrics().coma + "f");
        }

        if (xAxis.rangetype == Axis.TYPE_CATEG
                || xAxis.rangetype == Axis.TYPE_CATEGINV) {

            int numticks = graph.getData().numcols;

            if (xAxis.width == 0) {
                xAxis.width = xAxis.tickdistance - numticks;
                xAxis.setRangescale(0);
            } else if (xAxis.tickdistance == 0) {
                xAxis.tickdistance = xAxis.width / numticks;
                xAxis.setRangescale(0);
            } else {
                xAxis.setRangescale(xAxis.tickdistance);
            }

            xAxis.setType(Axis.U_AXIS);
            xAxis.setRangemin(0);
            xAxis.setRangemax(numticks - 1);
            xAxis.setRangestep(1);
            xAxis.setRangeoffset(0.5);
            xAxis.setLabelformat("%s");

        } else {

            xAxis.setType(Axis.X_AXIS);
            getBarMetrics(graph, graph.getMetrics(), xAxis);
            xAxis.numticks = graph.getMetrics().numlines - 1;
            if (xAxis.width == 0) {
                xAxis.width = graph.getMetrics().height;
                xAxis.setRangescale(graph.getMetrics().scaley);
            } else if (xAxis.tickdistance == 0) {
                xAxis.tickdistance = xAxis.width / xAxis.numticks;
                xAxis
                        .setRangescale(xAxis.width
                                / (graph.getMetrics().topvalue - graph
                                .getMetrics().minvalue));
            } else {
                xAxis.setRangescale(graph.getMetrics().scaley);
            }
            xAxis.setRangemin(graph.getMetrics().minvalue);
            xAxis.setRangemax(graph.getMetrics().maxvalue);
            xAxis.setRangestep(graph.getMetrics().distance);
            xAxis.setRangeoffset(0);
            xAxis.setLabelformat("%." + graph.getMetrics().coma + "f");
        }

        /* build it */
        Layer[] axisLayers = new Layer[2];
        axisLayers[0] = graph.getYAxis().draw(graph, doDraw);
        axisLayers[1] = graph.getXAxis().draw(graph, doDraw);

        Layer dataLayer = drawBars(graph, doDraw);
        dataLayer.merge(axisLayers);

        return doDraw ? dataLayer : null;
    }

    public void setStyle(int style) {
        if (this.style == 0)
            this.style = style;
    }

    public void setBarwidth(int barwidth) {
        if (this.barwidth == 0)
            this.barwidth = barwidth;
    }

    public void setBarspacing(int barspacing) {
        if (this.barspacing == 0)
            this.barspacing = barspacing;
    }

    public void setNumlines(int numlines) {
        if (this.numlines == 0)
            this.numlines = numlines;
    }

    // ---------- internal
    // ------------------------------------------------------

    private void getBarMetrics(Graph graph, Metrics mx, Axis ax) {
        Data data = graph.getData();

        // init locals
        int approx = this.numlines;
        double maxValue = 0;
        double minValue = 0;
        double topValue = 0;
        double botValue = 0;

        // get max value
        if (style == BARS_TILE) {
            for (int j = 0; j < data.numcols; j++) {
                double rest = 0;
                for (int i = 0; i < data.numrows; i++) {
                    rest += data.datarows[i].samples[j];
                }
                if (rest > maxValue)
                    maxValue = rest;
            }

        } else {
            // cascading or candle

            if (style == BARS_CANDLE) {
                minValue = Double.MAX_VALUE;
            }

            for (int j = 0; j < data.numcols; j++) {
                for (int i = 0; i < data.numrows; i++) {
                    double rest = data.datarows[i].samples[j];
                    if (rest < minValue)
                        minValue = rest;
                    if (rest > maxValue)
                        maxValue = rest;
                }
            }

        }

        maxValue *= ax.inflate;

        // get next 'nice' number, for the moment, we take a power of 10
        double delta = maxValue - minValue;

        if (delta == 0)
            delta = 1;

        double power = Math.log(delta) / Math.log(10);
        if (power == Math.floor(power))
            power -= 1.0;
        power = Math.floor(power);

        // try to improve resolution
        double distance = 0;
        double ac = 0;
        int first = 0;
        double[] factors = new double[]{0.1, 0.2, 0.25, 0.3, 0.5, 0.6, 1};
        do {
            for (int i = first; i < factors.length; i++) {

                distance = Math.pow(10, power) * (factors[i] + ac);

                topValue = Math.ceil(maxValue / distance) * distance;
                if (topValue == maxValue)
                    topValue += distance;
                botValue = Math.floor(minValue / distance) * distance;

                numlines = (int) ((topValue - botValue) / distance);

                if (numlines <= approx)
                    break;
            }

            ac += 1;
            first = 1;
        } while (numlines > approx);

        //re-compute tickdistance depending on new number of lines and graph height
        ax.tickdistance = graph.getExtent().height / numlines;

        int height = ax.tickdistance * numlines;
        double scale = height / (topValue - botValue);

        int coma = 0;
        double rest = distance - Math.rint(distance);
        while (rest > 0.00001 && rest < 1.0 && coma < 4) {
            coma++;
            rest = (rest * 10.0) - Math.rint(rest * 10.0);
        }

        mx.height = height;
        mx.coma = coma;
        mx.topvalue = topValue;
        mx.bottomvalue = botValue;
        mx.distance = distance;
        mx.scaley = scale;
        mx.shifty = -(int) (topValue * scale);
        mx.numlines = numlines;
        mx.maxvalue = maxValue;
        mx.minvalue = minValue;
    }

    private Layer drawBars(Graph graph, boolean doDraw) {

        // don't do anything if we don't draw ...
        if (!doDraw)
            return null;

        Axis xAxis = graph.getXAxis();
        Axis yAxis = graph.getYAxis();
        int w = xAxis.width;
        int h = yAxis.height;

        if ((yAxis.titlepos & Axis.TITLE_POS_BELOW) != 0)
            h -= yAxis.getRangescale();

        Layer l = graph.createLayer(true, w, h);

        if ((yAxis.titlepos & Axis.TITLE_POS_ABOVE) != 0) {
            // hack upper x-axis
            double scale = xAxis.getRangescale();
            int ypos = (xAxis.subtickto > xAxis.tickto) ? xAxis.subtickto
                    : xAxis.tickto;
            int x, flags;
            String tmp;

            // ignore range type so far
            double pos = xAxis.getRangemin();
            for (int num = 0; num <= xAxis.numticks; num++, pos += xAxis
                    .getRangestep()) {
                // tick ?
                x = (int) ((pos + xAxis.getRangeoffset()) * scale);
                // draw text
                if (xAxis.labelfont != null) {
                    int rl = x + xAxis.labeldx;
                    int rt = ypos - xAxis.tickfrom - xAxis.labeldy;
                    tmp = String.format(xAxis.getLabelformat(), String
                            .valueOf(pos));
                    flags = 0;
                    if (xAxis.labelalign == Axis.LABEL_CENTER) {
                        flags = Font.ALIGN_CENTER;
                        rl -= xAxis.labelwidth / 2;
                    }
                    xAxis.labelfont.drawText(l, rl, rt, xAxis.labelwidth, 0,
                            tmp, xAxis.labelcolor, null, flags, xAxis.labelcs,
                            0);
                }
                ;
            }
        }

        // first draw the grid
        graph.getGrid().draw(l, doDraw);

        if (xAxis.getType() == Axis.U_AXIS) {
            int bw = barwidth;
            for (int col = (int) xAxis.getRangemin(); col <= xAxis
                    .getRangemax(); col += xAxis.getRangestep()) {

                if (style == BARS_TILE) {

                    double realtop = 0.0;
                    int rt = h - 1;
                    int rb = 0;
                    int rl = (int) (((col + xAxis.getRangeoffset()) * xAxis
                            .getRangescale()) - bw / 2);
                    int rr = rl + bw;
                    for (int row = 0; row < graph.getData().numrows; row++) {
                        realtop += (graph.getData().datarows[row].samples[col]);
                        rb = rt;
                        rt = (h - 1)
                                - (int) (Math.round(realtop) * yAxis
                                .getRangescale());
                        l.setPaint(graph.getData().datarows[row].color);
                        l.fillRect(new Rectangle(rl, rt, rr - rl, rb - rt));
                    }

                } else if (style == BARS_CANDLE) {
                    // we abuse the bar-spacing for the 2nd barwidth
                    int bsp = barspacing;
                    for (int row = 0; row < graph.getData().numrows; row += 2) {
                        double d0 = graph.getData().datarows[row].samples[col]
                                + yAxis.getRangeoffset();
                        double d1 = graph.getData().datarows[row + 1].samples[col]
                                + yAxis.getRangeoffset();
                        Color color;
                        int rt, rl, rb, rr;

                        if (d0 > d1) {
                            rb = h - 1 - (int) (d1 * yAxis.getRangescale());
                            rt = h - 1 - (int) (d0 * yAxis.getRangescale());
                            color = graph.getData().datarows[row + 1].color;
                        } else {
                            rb = h - 1 - (int) (d0 * yAxis.getRangescale());
                            rt = h - 1 - (int) (d1 * yAxis.getRangescale());
                            color = graph.getData().datarows[row].color;
                        }

                        if (row % 4 != 0) {
                            // draw thick part
                            rl = (int) (((col + xAxis.getRangeoffset()) * xAxis
                                    .getRangescale()) - bw / 2);
                            rr = rl + bw + 1;
                        } else {
                            // draw thin part
                            rl = (int) (((col + xAxis.getRangeoffset()) * xAxis
                                    .getRangescale()) - bsp / 2);
                            rr = rl + bsp + 1;
                        }

                        l.setPaint(color);
                        l.fillRect(new Rectangle(rl, rt, rr - rl, rb - rt));
                    }

                } else {
                    // cascading
                    int zeroline = (int) (h - 1 - yAxis.getRangeoffset()
                            * yAxis.getRangescale());
                    int bsp = barspacing;
                    int rr = (int) (((col + xAxis.getRangeoffset()) * xAxis
                            .getRangescale()) - (bw * graph.getData().numrows + bsp
                            * (graph.getData().numrows - 1)) / 2)
                            - bsp;

                    for (int row = 0; row < graph.getData().numrows; row++) {
                        double d = graph.getData().datarows[row].samples[col];
                        int rl = rr + bsp;
                        rr = rl + bw;
                        int rb, rt;
                        if (d >= 0) {
                            rb = zeroline;
                            rt = zeroline - (int) (d * yAxis.getRangescale());
                        } else {
                            rt = zeroline;
                            rb = zeroline - (int) (d * yAxis.getRangescale());
                        }

                        l.setPaint(graph.getData().datarows[row].color);
                        l.fillRect(new Rectangle(rl, rt, rr - rl, rb - rt));
                    }
                }
            }
            l.setY(-h);
        } else {

            //
            // NOT SUPPORTED YET
            //

            if (style == BARS_HORIZONTAL) {

                int bw = barwidth;
                for (int col = 0; col < graph.getData().numrows; col++) {
                    int y = (int) (yAxis.tickpos[col] + yAxis.getRangescale() / 2);
                    int rt = y - bw / 2;
                    int rb = y + bw / 2;
                    int rl = 0;
                    double d = graph.getData().datarows[col].samples[0];
                    int rr = (int) (d * xAxis.getRangescale());
                    l.setPaint(graph.getData().datarows[0].color);
                    l.fillRect(new Rectangle(rl, rt, rr - rl, rb - rt));
                }
                l.setX(1);
                l.setY(-h - 1);
            }
        }

        return l;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy