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

com.day.cq.graphics.chart.Axis 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.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

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

/**
 * @author tripod
 */
public final class Axis {

    public static final int TYPE_NORMAL = 0;
    public static final int TYPE_INVERT = 1;
    public static final int TYPE_LOG = 2;
    public static final int TYPE_LOGINV = 3;
    public static final int TYPE_CATEG = 4;
    public static final int TYPE_CATEGINV = 5;

    public static final int NO_AXIS = '0';
    public static final int X_AXIS = 'x';
    public static final int Y_AXIS = 'y';
    public static final int U_AXIS = 'u';
    public static final int V_AXIS = 'v';

    public static final int LABEL_ABOVE = 0x00; /* for label type */
    public static final int LABEL_BELOW = 0x01;
    public static final int LABEL_RIGHT = 0x00;
    public static final int LABEL_LEFT = 0x10;
    public static final int LABEL_CENTER = 0x20;

    public static final int LABEL_TYPE_NUMBER = 0; /* uses labelformat with sprintf  */
    public static final int LABEL_TYPE_DATE = 1; /* uses labelformat with strftime */

    public static final int TITLE_POS_NONE = 0;
    public static final int TITLE_POS_ABOVE = 1;
    public static final int TITLE_POS_BELOW = 2;
    public static final int TITLE_POS_BOTH = 3;

    int width;
    int height;
    LineStyle style;

    // main ticks
    int tickfrom;
    int tickto;
    int tickdistance; // pixels
    int numticks;
    LineStyle tickstyle;

    // sub ticks
    int subtickfrom;
    int subtickto;
    // Color subtickColor;
    int subtickspertick;
    LineStyle subtickstyle;

    // labeling
    Font labelfont;
    Color labelcolor;
    int labeldx;
    int labeldy;
    int labelalign;
    int labelcs;
    int labelwidth;
    private String labelformat; // format string for sprintf
    private String sublabelformat; // format string for sprintf
    int labeltype;

    // range
    private double rangemin;
    private double rangemax;
    private double rangestep;
    private double rangescale;
    private double rangeoffset;
    private boolean rangeminset;
    private boolean rangemaxset;
    private boolean rangestepset;
    private boolean rangescaleset;
    private boolean rangeoffsetset;

    int rangetype; // see above ??

    // title
    int titlepos;
    double inflate = 1;

    // internal hack :-)
    int[] tickpos = new int[256];
    double[] ticksample = new double[256];

    // the axisdrawer 'method'
    private AxisDrawer axisDrawer;
    private int axisType;

    private Axis(Graph graph, int axisType) {
        setType(axisType);
    }

    public static Axis getInstance(Graph graph, int type)
            throws IllegalArgumentException {
        return new Axis(graph, type);
    }

    public static Axis getInstance(Graph graph) {
        return new Axis(graph, NO_AXIS);
    }

    public Layer draw(Graph graph, boolean doDraw) {
        return (axisDrawer != null) ? axisDrawer.draw(graph, doDraw) : null;
    }

    private static interface AxisDrawer {
        public Layer draw(Graph graph, boolean doDraw);
    }

    private final class XAxis implements AxisDrawer {

        public Layer draw(Graph graph, boolean doDraw) {
            int x, w, h, tw, stw, spt, tc, ypos, flags, num;
            double pos, scale;
            tw = tickto - tickfrom;
            stw = subtickto - subtickfrom;
            spt = subtickspertick;

            w = width;
            h = height;

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

            // no axis crossing so far ??
            // X axis
            scale = getRangescale();
            ypos = (subtickto > tickto) ? subtickto : tickto;

            // ignore rangetype so far
            if (doDraw) {
                l.setLineStyle(style);
                l.drawLine(0, ypos, w - 1, ypos);
            }
            tc = spt;
            pos = getRangemin();
            num = 0;

            while (num <= numticks) {
                // tick ?
                x = (int) ((pos + getRangeoffset()) * scale);
                if (tc == spt) {
                    if (tw != 0 && doDraw) {
                        l.setLineStyle(tickstyle);
                        l.drawLine(x, ypos - tickfrom, x, ypos - tickto);
                    }
                    tickpos[num] = x;

                    // draw text
                    if (labelfont != null && doDraw) {
                        int rl = x + labeldx;
                        int rt = ypos - tickfrom - labeldy;
                        String tmp = String.format(labelformat, new Double(pos));
                        flags = Font.TTANTIALIASED;
                        if (labelalign == LABEL_CENTER) {
                            flags |= Font.ALIGN_CENTER;
                            rl -= labelwidth / 2;
                        }
                        labelfont.drawText(l, rl, rt, labelwidth, 0, tmp,
                                labelcolor, null, flags, labelcs, 0);
                    }
                    tc = 0;
                    num++;
                } else {
                    // subtick
                    if (stw != 0 && doDraw) {
                        l.setLineStyle(subtickstyle);
                        l.drawLine(x, ypos - subtickfrom, x, ypos - subtickto);
                    }
                    tc++;
                }
                pos += getRangestep() / (spt + 1);
            }
            if (doDraw) {
                l.setX(1);
                l.setY(-ypos - 1); // ??
            }
            return l;
        }

    }

    private final class YAxis implements AxisDrawer {
        public Layer draw(Graph graph, boolean doDraw) {
            int y, w, h, tw, stw, spt, tc, xpos, flags, num;
            double pos, scale;

            tw = tickto - tickfrom;
            stw = subtickto - subtickfrom;
            spt = subtickspertick;

            w = width;
            h = height;

            Layer l = graph.createLayer(doDraw, w, h);
            // Graphics2D ig = null;

            // no axis crossing so far ??
            scale = getRangescale();
            xpos = w - 1 - (subtickto > tickto ? subtickto : tickto);

            // ignore rangetype so far - missing style
            if (doDraw) {
                l.setLineStyle(style);
                l.drawLine(xpos, 0, xpos, h - 1);
            }

            tc = spt;
            pos = getRangemin();
            num = 0;

            while (num <= numticks) { // first one counts, too
                // tick ??
                y = h - 1 - (int) ((pos + getRangeoffset()) * scale);
                if (tc == spt) {
                    //tick

                    tickpos[num] = y;
                    ticksample[num] = pos;

                    // draw text
                    if (labelfont != null && doDraw) {
                        int lw, ly, lh;
                        if (labelalign == LABEL_ABOVE) {
                            flags = Font.ALIGN_BOTTOM | Font.ALIGN_RIGHT | Font.TTANTIALIASED;
                            ly = y + labeldy;
                            lh = 0; // dont care
                        } else if (labelalign == LABEL_CENTER) {
                            flags = Font.ALIGN_BASE | Font.ALIGN_RIGHT | Font.TTANTIALIASED;
                            ly = y + labeldy;
                            lh = 0;
                        } else { // below
                            flags = Font.ALIGN_TOP | Font.ALIGN_RIGHT | Font.TTANTIALIASED;
                            ly = y + labeldy;
                            lh = 0; // dont care
                        }
                        //lw = xpos + labeldx;
                        //hack to align Y label on the right
                        lw = -labeldx;
                        String str = String.format(labelformat, new Double(pos));
                        labelfont.drawText(l, 0, ly, lw, lh, str,
                                labelcolor, null, flags, labelcs, 0);
                    }


                    if (tw != 0 && doDraw) {
                        l.setLineStyle(tickstyle);
                        l.drawLine(xpos + tickfrom, y, xpos + tickto, y);
                    }

                    tc = 0;
                    num++;
                } else {
                    // subtick
                    if (stw != 0 && doDraw) {
                        l.setLineStyle(subtickstyle);
                        l.drawLine(xpos + subtickfrom, y, xpos + subtickto, y);
                    }
                    tc++;
                }
                pos += getRangestep() / (spt + 1);
            }

            if (doDraw) {
                l.setX(-xpos);
                l.setY(-h);
            }
            return l;
        }
    }

    private final class VAxis implements AxisDrawer {
        public Layer draw(Graph graph, boolean doDraw) {
            int y, w, h, tw, stw, spt, tc, xpos, flags;
            double pos, scale;
            String str;

            tw = tickto - tickfrom;
            stw = subtickto - subtickfrom;
            spt = subtickspertick;

            w = width;
            h = height;

            Layer l = graph.createLayer(doDraw, w, h);
            // Graphics2D ig = null;

            // no axis crossing so far ??
            int labelnum = 0;
            if (doDraw) {
                if (getRangescale() == 0) {
                    setRangescale(scale = h / (1 + getRangemax() - getRangemin()));
                } else {
                    scale = getRangescale();
                }
                xpos = w - 1 - (subtickto > tickto ? subtickto : tickto);

                // ignore rangetype so far

                if (doDraw) {
                    int y1 = 0, y2 = h - 1;
                    if ((graph.getYAxis().titlepos & TITLE_POS_ABOVE) == TITLE_POS_ABOVE)
                        y1 += (int) scale;
                    if ((graph.getYAxis().titlepos & TITLE_POS_BELOW) == TITLE_POS_BELOW)
                        y2 -= (int) scale;
                    l.setLineStyle(style);
                    l.drawLine(xpos, y1, xpos, y2);
                }

                // draw axis
                tc = spt;
                labelnum = (int) (pos = getRangemin());
                while (labelnum <= getRangemax()) {
                    y = (int) ((pos + getRangeoffset()) * scale);
                    if (tc == spt) {
                        // tick
                        if (labelnum >= 0) tickpos[labelnum] = y;
                        // draw text
                        if (labelfont != null) {
                            // default align is above/right
                            int vflags = Font.ALIGN_BOTTOM;
                            int hflags = Font.ALIGN_RIGHT;
                            int ll = 0, lr = xpos + labeldx, lt = 0, lb = y + labeldy;
                            if ((labelalign & LABEL_BELOW) != 0) {
                                vflags = Font.ALIGN_TOP;
                                lt = y + labeldy;
                                lb = 0;
                            } else if ((labelalign & LABEL_CENTER) != 0) {
                                vflags = Font.ALIGN_BASE;
                                lt = y + labeldy;
                                lb = 0;
                            }
                            if ((labelalign & LABEL_LEFT) != 0) {
                                hflags = Font.ALIGN_LEFT;
                                ll = xpos + labeldx;
                                lr = ll;
                            }
                            flags = vflags | hflags | Font.TTANTIALIASED;

                            if ((labelnum == getRangemin() && (graph.getYAxis().titlepos & TITLE_POS_ABOVE) != 0)
                                    || (labelnum == getRangemax() && (graph.getYAxis().titlepos & TITLE_POS_BELOW) != 0)) {
                                str = graph.getData().labels[0] != null ? graph.getData().labels[0] : "none";
                            } else {
                                str = String.format(labelformat, graph.getData().datarows[labelnum].label);
                            }
                            str = str.trim();
                            if (doDraw) {
                                labelfont.drawText(l, ll, lt, lr - ll, lt - lb, str,
                                        labelcolor, null, flags, labelcs, 0);
                            }
                        }

                        if (tw != 0 && doDraw && (!(labelnum == getRangemin() && (graph.getYAxis().titlepos & TITLE_POS_ABOVE) != 0))) {
                            l.setLineStyle(tickstyle);
                            l.drawLine(xpos + tickfrom, y, xpos + tickto, y);
                        }

                        labelnum++;
                        tc = 0;
                    } else {
                        // subtick
                        if (stw != 0 && doDraw) {
                            l.setLineStyle(subtickstyle);
                            l.drawLine(xpos + subtickfrom, y, xpos + subtickto, y);
                            tc++;
                        }
                    }

                    pos += getRangestep() / (spt + 1);
                }

                if (doDraw) {
                    l.setX(-xpos);
                    l.setY(-h);
                    if ((graph.getYAxis().titlepos & TITLE_POS_BELOW) != 0) {
                        l.setY(l.getY() + (int) scale - 1);
                    }
                }

            }
            return l;
        }
    }

    private class UAxis implements AxisDrawer {
        public Layer draw(Graph graph, boolean doDraw) {
            int x, w, h, tw, stw, spt, tc, ypos, flags;
            double pos, scale;
            tw = tickto - tickfrom;
            stw = subtickto - subtickfrom;
            spt = subtickspertick;

            w = width;
            h = height;
            int lastx = 0;

            Layer l = graph.createLayer(doDraw, w, h);
            // Graphics2D ig = null;

            // no axis crossing so far ??
            int labelnum = 0;
            if (getRangescale() == 0) {
                setRangescale(scale = w / (1.0 + getRangemax() - getRangemin()));
            } else {
                scale = getRangescale();
            }
            ypos = stw > tw ? stw / 2 : tw / 2;

            // ignore rangetype so far
            if (doDraw) {
                l.setLineStyle(style);
                l.drawLine(0, ypos, w - 1, ypos);
            }

            // draw axis
            tc = spt;
            labelnum = (int) (pos = getRangemin());
            while (labelnum <= getRangemax()) {
                // tick ??
                x = (int) ((pos + getRangeoffset()) * scale);
                if (tc == spt) {
                    if (tw != 0 && doDraw) {
                        l.setLineStyle(tickstyle);
                        l.drawLine(x, ypos - tickfrom, x, ypos - tickto);
                    }

                    // draw text
                    if (labelfont != null && x + labeldx >= lastx) {
                        int rl = x + labeldx;
                        int rt = ypos - tickfrom - labeldy;
                        String tmp = formatlabel(graph.getXAxis().labeltype,
                                graph.getXAxis().labelformat,
                                graph.getData().labels[labelnum]);
                        flags = Font.TTANTIALIASED;
                        if (labelalign == LABEL_CENTER) {
                            flags |= Font.ALIGN_CENTER;
                            rl -= labelwidth / 2;
                        }
                        if (doDraw) {
                            labelfont.drawText(l, rl, rt, labelwidth, 0, tmp,
                                    labelcolor, null, flags, labelcs, 0);
                            lastx = rl + labelwidth;
                        }
                    }
                    labelnum += (int) getRangestep();
                    tc = 0;

                } else {
                    // subtick
                    if (stw != 0 && doDraw) {
                        l.setLineStyle(subtickstyle);
                        l.drawLine(x, ypos - subtickfrom, x, ypos - subtickto);
                    }
                    tc++;
                }
                pos += getRangestep() / (spt + 1);
            }

            if (doDraw) {
                l.setX(0);
                l.setY(-ypos - 1); // ??
            }

            return l;
        }
    }

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

    /* package use */

    static String formatlabel(int type, String format, String label) {
        if (label == null) label = "";

        if (type == LABEL_TYPE_NUMBER) {
            return String.format(format, label);
        } else if (type == LABEL_TYPE_DATE) {
            try {
                SimpleDateFormat fmt = new SimpleDateFormat();
                Date date = fmt.parse(label);
                return String.format(format, date);
            } catch (ParseException pe) {
                // log
                return "";
            }
        } else {
            // log
            return "";
        }
    }

    //---------- getter and setter for data ------------------------------------

    public double getRangemin() {
        return rangemin;
    }

    public void setRangemin(double rangemin) {
        if (!rangeminset && rangemin != 0) {
            this.rangemin = rangemin;
            this.rangeminset = true;
        }
    }

    public double getRangemax() {
        return rangemax;
    }

    public void setRangemax(double rangemax) {
        if (!rangemaxset && rangemax != 0) {
            this.rangemax = rangemax;
            this.rangemaxset = true;
        }
    }

    public double getRangestep() {
        return rangestep;
    }

    public void setRangestep(double rangestep) {
        if (!rangestepset && rangestep != 0) {
            this.rangestep = rangestep;
            this.rangestepset = true;
        }
    }

    public double getRangescale() {
        return rangescale;
    }

    public void setRangescale(double rangescale) {
        if (!rangescaleset && rangescale != 0) {
            this.rangescale = rangescale;
            this.rangescaleset = true;
        }
    }

    public double getRangeoffset() {
        return rangeoffset;
    }

    public void setRangeoffset(double rangeoffset) {
        if (!rangeoffsetset && rangeoffset != 0) {
            this.rangeoffset = rangeoffset;
            this.rangeoffsetset = true;
        }
    }

    public String getLabelformat() {
        return labelformat;
    }

    public void setLabelformat(String labelformat) {
        if (labelformat != null && labelformat.length() != 0) {
            this.labelformat = labelformat;
        }
    }

    public String getSublabelformat() {
        return sublabelformat;
    }

    public void setSublabelformat(String sublabelformat) {
        if (sublabelformat != null && sublabelformat.length() != 0) {
            this.sublabelformat = sublabelformat;
        }
    }

    public void setType(int type) throws IllegalArgumentException {
        if (type == X_AXIS) {
            this.axisDrawer = new XAxis();
        } else if (type == Y_AXIS) {
            this.axisDrawer = new YAxis();
        } else if (type == U_AXIS) {
            this.axisDrawer = new UAxis();
        } else if (type == V_AXIS) {
            this.axisDrawer = new VAxis();
        } else if (type == NO_AXIS) {
            this.axisDrawer = null;
        } else {
            // log
            throw new IllegalArgumentException("Unknown type " + (char) type);
        }

        this.axisType = type;
    }

    public int getType() {
        return axisType;
    }

    //--------------------------------------------------------------------------

    public void setStyle(LineStyle style) {
        this.style = style;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public void setTickfrom(int tickfrom) {
        this.tickfrom = tickfrom;
    }

    public void setTickto(int tickto) {
        this.tickto = tickto;
    }

    public void setTickdistance(int tickdistance) {
        this.tickdistance = tickdistance;
    }

    public void setNumticks(int numticks) {
        this.numticks = numticks;
    }

    public void setTickstyle(LineStyle tickstyle) {
        this.tickstyle = tickstyle;
    }

    public void setSubtickfrom(int subtickfrom) {
        this.subtickfrom = subtickfrom;
    }

    public void setSubtickto(int subtickto) {
        this.subtickto = subtickto;
    }

    public void setSubtickspertick(int subtickspertick) {
        this.subtickspertick = subtickspertick;
    }

    public void setSubtickstyle(LineStyle subtickstyle) {
        this.subtickstyle = subtickstyle;
    }

    public void setLabelfont(Font labelfont) {
        this.labelfont = labelfont;
    }

    public void setLabelcolor(Color labelcolor) {
        this.labelcolor = labelcolor;
    }

    public void setLabeldx(int labeldx) {
        this.labeldx = labeldx;
    }

    public void setLabeldy(int labeldy) {
        this.labeldy = labeldy;
    }

    public void setLabelalign(int labelalign) {
        this.labelalign = labelalign;
    }

    public void setLabelcs(int labelcs) {
        this.labelcs = labelcs;
    }

    public void setLabelwidth(int labelwidth) {
        this.labelwidth = labelwidth;
    }

    public void setLabeltype(int labeltype) {
        this.labeltype = labeltype;
    }

    public void setRangetype(int rangetype) {
        this.rangetype = rangetype;
    }

    public void setTitlepos(int titlepos) {
        this.titlepos = titlepos;
    }

    public void setInflate(double inflate) {
        if (!Double.isNaN(inflate) && inflate != 0) {
            this.inflate = inflate;
        }
    }

    public double getTickSample(int i) {
        if (i >= 0 && i < numticks) {
            return ticksample[i];
        } else {
            return Double.NaN;
        }
    }

    public int getNumticks() {
        return numticks;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy