Example usage for java.awt.geom Rectangle2D getMinX

List of usage examples for java.awt.geom Rectangle2D getMinX

Introduction

In this page you can find the example usage for java.awt.geom Rectangle2D getMinX.

Prototype

public double getMinX() 

Source Link

Document

Returns the smallest X coordinate of the framing rectangle of the Shape in double precision.

Usage

From source file:org.trade.ui.chart.renderer.VolumeBarRenderer.java

/**
 * Draws the visual representation of a single data item.
 * /*from  www.  ja  va2s. co  m*/
 * @param g2
 *            the graphics device.
 * @param state
 *            the renderer state.
 * @param dataArea
 *            the area within which the plot is being drawn.
 * @param info
 *            collects information about the drawing.
 * @param plot
 *            the plot (can be used to obtain standard color information
 *            etc).
 * @param domainAxis
 *            the domain axis.
 * @param rangeAxis
 *            the range axis.
 * @param dataset
 *            the dataset.
 * @param series
 *            the series index (zero-based).
 * @param item
 *            the item index (zero-based).
 * @param crosshairState
 *            crosshair information for the plot (<code>null</code>
 *            permitted).
 * @param pass
 *            the pass index.
 * @see org.jfree.chart.renderer.xy.XYItemRenderer#drawItem(Graphics2D,
 *      XYItemRendererState, Rectangle2D, PlotRenderingInfo, XYPlot,
 *      ValueAxis, ValueAxis, XYDataset, int, int, CrosshairState, int)
 */
public void drawItem(Graphics2D g2, XYItemRendererState state, Rectangle2D dataArea, PlotRenderingInfo info,
        XYPlot plot, ValueAxis domainAxis, ValueAxis rangeAxis, XYDataset dataset, int series, int item,
        CrosshairState crosshairState, int pass) {

    if (!getItemVisible(series, item)) {
        return;
    }

    VolumeDataset volumeDataset = (VolumeDataset) dataset;
    VolumeItem volumeItem = (VolumeItem) volumeDataset.getSeries(series).getDataItem(item);

    if (volumeItem.isSide()) {
        this.color = Color.GREEN;
    } else {
        this.color = Color.RED;
    }

    double value0;
    double value1;
    if (this.getUseYInterval()) {
        value0 = volumeDataset.getStartYValue(series, item);
        value1 = volumeDataset.getEndYValue(series, item);
    } else {
        value0 = this.getBase();
        value1 = volumeDataset.getYValue(series, item);
    }
    if (Double.isNaN(value0) || Double.isNaN(value1)) {
        return;
    }
    if (value0 <= value1) {
        if (!rangeAxis.getRange().intersects(value0, value1)) {
            return;
        }
    } else {
        if (!rangeAxis.getRange().intersects(value1, value0)) {
            return;
        }
    }

    double translatedValue0 = rangeAxis.valueToJava2D(value0, dataArea, plot.getRangeAxisEdge());
    double translatedValue1 = rangeAxis.valueToJava2D(value1, dataArea, plot.getRangeAxisEdge());
    double bottom = Math.min(translatedValue0, translatedValue1);
    double top = Math.max(translatedValue0, translatedValue1);

    double startX = volumeItem.getPeriod().getFirstMillisecond();
    if (Double.isNaN(startX)) {
        return;
    }
    double endX = volumeItem.getPeriod().getLastMillisecond();
    if (Double.isNaN(endX)) {
        return;
    }

    if (startX <= endX) {
        if (!domainAxis.getRange().intersects(startX, endX)) {
            return;
        }
    } else {
        if (!domainAxis.getRange().intersects(endX, startX)) {
            return;
        }
    }

    // is there an alignment adjustment to be made?
    if (this.getBarAlignmentFactor() >= 0.0 && this.getBarAlignmentFactor() <= 1.0) {
        double x = volumeDataset.getXValue(series, item);
        double interval = endX - startX;
        startX = x - interval * this.getBarAlignmentFactor();
        endX = startX + interval;
    }

    RectangleEdge location = plot.getDomainAxisEdge();
    double translatedStartX = domainAxis.valueToJava2D(startX, dataArea, location);
    double translatedEndX = domainAxis.valueToJava2D(endX, dataArea, location);

    double translatedWidth = Math.max(1, Math.abs(translatedEndX - translatedStartX));

    RectangleEdge domainEdge = plot.getDomainAxisEdge();
    double xx = domainAxis.valueToJava2D(startX, dataArea, domainEdge);

    if (getMargin() > 0.0) {
        double cut = translatedWidth * getMargin();
        translatedWidth = translatedWidth - cut;
    }

    Rectangle2D bar = null;
    PlotOrientation orientation = plot.getOrientation();
    if (orientation == PlotOrientation.HORIZONTAL) {
        // clip left and right bounds to data area
        bottom = Math.max(bottom, dataArea.getMinX());
        top = Math.min(top, dataArea.getMaxX());
        bar = new Rectangle2D.Double(bottom, xx, top - bottom, translatedWidth);
    } else if (orientation == PlotOrientation.VERTICAL) {
        // clip top and bottom bounds to data area
        bottom = Math.max(bottom, dataArea.getMinY());
        top = Math.min(top, dataArea.getMaxY());
        bar = new Rectangle2D.Double(xx - (translatedWidth / 2), bottom, translatedWidth, top - bottom);
    }

    boolean positive = (value1 > 0.0);
    boolean inverted = rangeAxis.isInverted();
    RectangleEdge barBase;
    if (orientation == PlotOrientation.HORIZONTAL) {
        if (positive && inverted || !positive && !inverted) {
            barBase = RectangleEdge.RIGHT;
        } else {
            barBase = RectangleEdge.LEFT;
        }
    } else {
        if (positive && !inverted || !positive && inverted) {
            barBase = RectangleEdge.BOTTOM;
        } else {
            barBase = RectangleEdge.TOP;
        }
    }
    if (getShadowsVisible()) {
        this.getBarPainter().paintBarShadow(g2, this, series, item, bar, barBase, !this.getUseYInterval());
    }
    this.getBarPainter().paintBar(g2, this, series, item, bar, barBase);

    if (isItemLabelVisible(series, item)) {
        XYItemLabelGenerator generator = getItemLabelGenerator(series, item);
        drawItemLabel(g2, dataset, series, item, plot, generator, bar, value1 < 0.0);
    }

    // update the cross hair point
    double x1 = dataset.getXValue(series, item);
    double y1 = dataset.getYValue(series, item);
    double transX1 = domainAxis.valueToJava2D(x1, dataArea, location);
    double transY1 = rangeAxis.valueToJava2D(y1, dataArea, plot.getRangeAxisEdge());
    int domainAxisIndex = plot.getDomainAxisIndex(domainAxis);
    int rangeAxisIndex = plot.getRangeAxisIndex(rangeAxis);
    updateCrosshairValues(crosshairState, x1, y1, domainAxisIndex, rangeAxisIndex, transX1, transY1,
            plot.getOrientation());

    EntityCollection entities = state.getEntityCollection();
    // add an entity for the item...
    if (entities != null) {
        String tip = null;
        XYToolTipGenerator generator = getToolTipGenerator(series, item);
        if (generator != null) {
            tip = generator.generateToolTip(dataset, series, item);
        }
        XYItemEntity entity = new XYItemEntity(bar, dataset, series, item, tip, null);

        entities.add(entity);
    }
}

From source file:edu.dlnu.liuwenpeng.render.NewXYBarRenderer.java

/**    
* Draws the visual representation of a single data item.    
*    // w w w .ja v a  2s  .  c o  m
* @param g2  the graphics device.    
* @param state  the renderer state.    
* @param dataArea  the area within which the plot is being drawn.    
* @param info  collects information about the drawing.    
* @param plot  the plot (can be used to obtain standard color     
*              information etc).    
* @param domainAxis  the domain axis.    
* @param rangeAxis  the range axis.    
* @param dataset  the dataset.    
* @param series  the series index (zero-based).    
* @param item  the item index (zero-based).    
* @param crosshairState  crosshair information for the plot     
*                        (<code>null</code> permitted).    
* @param pass  the pass index.    
*/
public void drawItem(Graphics2D g2, XYItemRendererState state, Rectangle2D dataArea, PlotRenderingInfo info,
        XYPlot plot, ValueAxis domainAxis, ValueAxis rangeAxis, XYDataset dataset, int series, int item,
        CrosshairState crosshairState, int pass) {

    if (!getItemVisible(series, item)) {
        return;
    }
    IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset;

    double value0;
    double value1;
    if (this.useYInterval) {
        value0 = intervalDataset.getStartYValue(series, item);
        value1 = intervalDataset.getEndYValue(series, item);
    } else {
        value0 = this.base;
        value1 = intervalDataset.getYValue(series, item);
    }
    if (Double.isNaN(value0) || Double.isNaN(value1)) {
        return;
    }
    if (value0 <= value1) {
        if (!rangeAxis.getRange().intersects(value0, value1)) {
            return;
        }
    } else {
        if (!rangeAxis.getRange().intersects(value1, value0)) {
            return;
        }
    }

    double translatedValue0 = rangeAxis.valueToJava2D(value0, dataArea, plot.getRangeAxisEdge());
    double translatedValue1 = rangeAxis.valueToJava2D(value1, dataArea, plot.getRangeAxisEdge());
    double bottom = Math.min(translatedValue0, translatedValue1);
    double top = Math.max(translatedValue0, translatedValue1);

    double startX = intervalDataset.getStartXValue(series, item);
    if (Double.isNaN(startX)) {
        return;
    }
    double endX = intervalDataset.getEndXValue(series, item);
    if (Double.isNaN(endX)) {
        return;
    }
    if (startX <= endX) {
        if (!domainAxis.getRange().intersects(startX, endX)) {
            return;
        }
    } else {
        if (!domainAxis.getRange().intersects(endX, startX)) {
            return;
        }
    }

    RectangleEdge location = plot.getDomainAxisEdge();
    double translatedStartX = domainAxis.valueToJava2D(startX, dataArea, location);
    double translatedEndX = domainAxis.valueToJava2D(endX, dataArea, location);

    double translatedWidth = Math.max(1, Math.abs(translatedEndX - translatedStartX));

    double left = Math.min(translatedStartX, translatedEndX);
    if (getMargin() > 0.0) {
        double cut = translatedWidth * getMargin();
        translatedWidth = translatedWidth - cut;
        left = left + cut / 2;
    }

    Rectangle2D bar = null;
    PlotOrientation orientation = plot.getOrientation();
    if (orientation == PlotOrientation.HORIZONTAL) {
        // clip left and right bounds to data area    
        bottom = Math.max(bottom, dataArea.getMinX());
        top = Math.min(top, dataArea.getMaxX());
        bar = new Rectangle2D.Double(bottom, left, top - bottom, translatedWidth);
    } else if (orientation == PlotOrientation.VERTICAL) {
        // clip top and bottom bounds to data area    
        bottom = Math.max(bottom, dataArea.getMinY());
        top = Math.min(top, dataArea.getMaxY());
        bar = new Rectangle2D.Double(left, bottom, translatedWidth, top - bottom);
    }

    /* Paint itemPaint = getItemPaint(series, item);    
     if (getGradientPaintTransformer()     
           != null && itemPaint instanceof GradientPaint) {    
       GradientPaint gp = (GradientPaint) itemPaint;    
       itemPaint = getGradientPaintTransformer().transform(gp, bar);    
     }    
             
    g2.setPaint(itemPaint);  
    */
    if (dataset.getYValue(series, item) >= 0) {
        g2.setPaint(Color.red);
    } else {
        g2.setPaint(Color.green);
    }
    g2.fill(bar);
    if (isDrawBarOutline() && Math.abs(translatedEndX - translatedStartX) > 3) {
        Stroke stroke = getItemOutlineStroke(series, item);
        Paint paint = getItemOutlinePaint(series, item);

        if (stroke != null && paint != null) {
            g2.setStroke(stroke);
            g2.setPaint(paint);
            g2.draw(bar);
        }
    }

    if (isItemLabelVisible(series, item)) {
        XYItemLabelGenerator generator = getItemLabelGenerator(series, item);
        drawItemLabel(g2, dataset, series, item, plot, generator, bar, value1 < 0.0);
    }

    // update the crosshair point    
    double x1 = (startX + endX) / 2.0;
    double y1 = dataset.getYValue(series, item);
    double transX1 = domainAxis.valueToJava2D(x1, dataArea, location);
    double transY1 = rangeAxis.valueToJava2D(y1, dataArea, plot.getRangeAxisEdge());
    int domainAxisIndex = plot.getDomainAxisIndex(domainAxis);
    int rangeAxisIndex = plot.getRangeAxisIndex(rangeAxis);
    updateCrosshairValues(crosshairState, x1, y1, domainAxisIndex, rangeAxisIndex, transX1, transY1,
            plot.getOrientation());

    EntityCollection entities = state.getEntityCollection();
    if (entities != null) {
        addEntity(entities, bar, dataset, series, item, 0.0, 0.0);
    }

}

From source file:com.rapidminer.gui.plotter.charts.AbstractChartPanel.java

/**
 * Handles a 'mouse dragged' event./*from www.ja v a  2 s .  c  om*/
 * 
 * @param e
 *            the mouse event.
 */

@Override
public void mouseDragged(MouseEvent e) {

    // if the popup menu has already been triggered, then ignore dragging...
    if (this.popup != null && this.popup.isShowing()) {
        return;
    }

    // handle panning if we have a start point
    if (this.panLast != null) {
        double dx = e.getX() - this.panLast.getX();
        double dy = e.getY() - this.panLast.getY();
        if (dx == 0.0 && dy == 0.0) {
            return;
        }
        double wPercent = -dx / this.panW;
        double hPercent = dy / this.panH;
        boolean old = this.chart.getPlot().isNotify();
        this.chart.getPlot().setNotify(false);
        Pannable p = (Pannable) this.chart.getPlot();
        if (p.getOrientation() == PlotOrientation.VERTICAL) {
            panAxes(wPercent, hPercent, e);
        } else {
            panAxes(hPercent, wPercent, e);
        }
        this.panLast = e.getPoint();
        this.chart.getPlot().setNotify(old);
        return;
    }

    // if no initial zoom point was set, ignore dragging...
    if (this.zoomPoint == null) {
        return;
    }

    boolean hZoom = false;
    boolean vZoom = false;
    if (this.orientation == PlotOrientation.HORIZONTAL) {
        hZoom = this.rangeZoomable;
        vZoom = this.domainZoomable;
    } else {
        hZoom = this.domainZoomable;
        vZoom = this.rangeZoomable;
    }
    Rectangle2D scaledDataArea = getScreenDataArea((int) this.zoomPoint.getX(), (int) this.zoomPoint.getY());
    if (hZoom && vZoom) {
        // selected rectangle shouldn't extend outside the data area...
        double xmax = Math.min(e.getX(), scaledDataArea.getMaxX());
        double ymax = Math.min(e.getY(), scaledDataArea.getMaxY());
        this.selectionRectangle = new Rectangle2D.Double(this.zoomPoint.getX(), this.zoomPoint.getY(),
                xmax - this.zoomPoint.getX(), ymax - this.zoomPoint.getY());
    } else if (hZoom) {
        double xmax = Math.min(e.getX(), scaledDataArea.getMaxX());
        this.selectionRectangle = new Rectangle2D.Double(this.zoomPoint.getX(), scaledDataArea.getMinY(),
                xmax - this.zoomPoint.getX(), scaledDataArea.getHeight());
    } else if (vZoom) {
        double ymax = Math.min(e.getY(), scaledDataArea.getMaxY());
        this.selectionRectangle = new Rectangle2D.Double(scaledDataArea.getMinX(), this.zoomPoint.getY(),
                scaledDataArea.getWidth(), ymax - this.zoomPoint.getY());
    }

    // Draw the new zoom rectangle...
    repaint();

}

From source file:edu.dlnu.liuwenpeng.render.XYBarRenderer.java

/**
 * Draws the visual representation of a single data item.
 *
 * @param g2  the graphics device./*www  . j  a  v  a2s .  co m*/
 * @param state  the renderer state.
 * @param dataArea  the area within which the plot is being drawn.
 * @param info  collects information about the drawing.
 * @param plot  the plot (can be used to obtain standard color 
 *              information etc).
 * @param domainAxis  the domain axis.
 * @param rangeAxis  the range axis.
 * @param dataset  the dataset.
 * @param series  the series index (zero-based).
 * @param item  the item index (zero-based).
 * @param crosshairState  crosshair information for the plot 
 *                        (<code>null</code> permitted).
 * @param pass  the pass index.
 */
public void drawItem(Graphics2D g2, XYItemRendererState state, Rectangle2D dataArea, PlotRenderingInfo info,
        XYPlot plot, ValueAxis domainAxis, ValueAxis rangeAxis, XYDataset dataset, int series, int item,
        CrosshairState crosshairState, int pass) {

    if (!getItemVisible(series, item)) {
        return;
    }
    IntervalXYDataset intervalDataset = (IntervalXYDataset) dataset;

    double value0;
    double value1;
    if (this.useYInterval) {
        value0 = intervalDataset.getStartYValue(series, item);
        value1 = intervalDataset.getEndYValue(series, item);
    } else {
        value0 = this.base;
        value1 = intervalDataset.getYValue(series, item);
    }
    if (Double.isNaN(value0) || Double.isNaN(value1)) {
        return;
    }
    if (value0 <= value1) {
        if (!rangeAxis.getRange().intersects(value0, value1)) {
            return;
        }
    } else {
        if (!rangeAxis.getRange().intersects(value1, value0)) {
            return;
        }
    }

    double translatedValue0 = rangeAxis.valueToJava2D(value0, dataArea, plot.getRangeAxisEdge());
    double translatedValue1 = rangeAxis.valueToJava2D(value1, dataArea, plot.getRangeAxisEdge());
    double bottom = Math.min(translatedValue0, translatedValue1);
    double top = Math.max(translatedValue0, translatedValue1);

    double startX = intervalDataset.getStartXValue(series, item);
    if (Double.isNaN(startX)) {
        return;
    }
    double endX = intervalDataset.getEndXValue(series, item);
    if (Double.isNaN(endX)) {
        return;
    }
    if (startX <= endX) {
        if (!domainAxis.getRange().intersects(startX, endX)) {
            return;
        }
    } else {
        if (!domainAxis.getRange().intersects(endX, startX)) {
            return;
        }
    }

    RectangleEdge location = plot.getDomainAxisEdge();
    double translatedStartX1 = domainAxis.valueToJava2D(startX, dataArea, location);
    double translatedEndX1 = domainAxis.valueToJava2D(endX, dataArea, location);

    double translatedWidth = Math.max(1, Math.abs(translatedEndX1 - translatedStartX1));

    double translatedStartX = translatedStartX1 - translatedWidth / 2;

    double translatedEndX = translatedEndX1 - translatedWidth / 2;
    double left = Math.min(translatedStartX, translatedEndX);
    if (getMargin() > 0.0) {
        double cut = translatedWidth * getMargin();
        translatedWidth = translatedWidth - cut;
        left = left + cut / 2;
    }

    Rectangle2D bar = null;
    PlotOrientation orientation = plot.getOrientation();
    if (orientation == PlotOrientation.HORIZONTAL) {
        // clip left and right bounds to data area
        bottom = Math.max(bottom, dataArea.getMinX());
        top = Math.min(top, dataArea.getMaxX());
        bar = new Rectangle2D.Double(bottom, left, top - bottom, translatedWidth);
    } else if (orientation == PlotOrientation.VERTICAL) {
        // clip top and bottom bounds to data area
        bottom = Math.max(bottom, dataArea.getMinY());
        top = Math.min(top, dataArea.getMaxY());
        bar = new Rectangle2D.Double(left, bottom, translatedWidth, top - bottom);
    }

    Paint itemPaint = getItemPaint(series, item);
    if (getGradientPaintTransformer() != null && itemPaint instanceof GradientPaint) {
        GradientPaint gp = (GradientPaint) itemPaint;
        itemPaint = getGradientPaintTransformer().transform(gp, bar);
    }
    g2.setPaint(itemPaint);
    g2.fill(bar);
    if (isDrawBarOutline() && Math.abs(translatedEndX - translatedStartX) > 3) {
        Stroke stroke = getItemOutlineStroke(series, item);
        Paint paint = getItemOutlinePaint(series, item);
        if (stroke != null && paint != null) {
            g2.setStroke(stroke);
            g2.setPaint(paint);
            g2.draw(bar);
        }
    }

    if (isItemLabelVisible(series, item)) {
        XYItemLabelGenerator generator = getItemLabelGenerator(series, item);
        drawItemLabel(g2, dataset, series, item, plot, generator, bar, value1 < 0.0);
    }

    // update the crosshair point
    double x1 = (startX + endX) / 2.0;
    double y1 = dataset.getYValue(series, item);
    double transX1 = domainAxis.valueToJava2D(x1, dataArea, location);
    double transY1 = rangeAxis.valueToJava2D(y1, dataArea, plot.getRangeAxisEdge());
    int domainAxisIndex = plot.getDomainAxisIndex(domainAxis);
    int rangeAxisIndex = plot.getRangeAxisIndex(rangeAxis);
    updateCrosshairValues(crosshairState, x1, y1, domainAxisIndex, rangeAxisIndex, transX1, transY1,
            plot.getOrientation());

    EntityCollection entities = state.getEntityCollection();
    if (entities != null) {
        addEntity(entities, bar, dataset, series, item, 0.0, 0.0);
    }

}

From source file:ucar.unidata.idv.control.chart.MyXYPlot.java

/**
 * Utility method for drawing a horizontal line across the data area of the
 * plot./*from w ww . j  a  va  2s  .com*/
 *
 * @param g2  the graphics device.
 * @param dataArea  the data area.
 * @param value  the coordinate, where to draw the line.
 * @param stroke  the stroke to use.
 * @param paint  the paint to use.
 */
protected void drawHorizontalLine(Graphics2D g2, Rectangle2D dataArea, double value, Stroke stroke,
        Paint paint) {

    ValueAxis axis = getRangeAxis();
    if (getOrientation() == PlotOrientation.HORIZONTAL) {
        axis = getDomainAxis();
    }
    if (axis.getRange().contains(value)) {
        double yy = axis.valueToJava2D(value, dataArea, RectangleEdge.LEFT);
        Line2D line = new Line2D.Double(dataArea.getMinX(), yy, dataArea.getMaxX(), yy);
        g2.setStroke(stroke);
        g2.setPaint(paint);
        g2.draw(line);
    }

}

From source file:gda.plots.SimplePlot.java

/**
 * Recalculates the rectangle which should be magnified.
 * //ww w.ja va 2 s  . c  o  m
 * @param e
 *            the MouseEvent which triggered the recalculation
 */
private void recalculateMagnifyRectangle(MouseEvent e) {
    if (magnifyWidth == 0 || magnifyHeight == 0)
        return;

    Rectangle2D scaledDataArea = getScreenDataArea();

    double widthToUse;
    double heightToUse;
    double xToUse;
    double yToUse;

    // If magnifyWidth is positive then e.getX() is
    // the end of the rectangle so the start is (e.getX() - magnifyWidth ).
    // If magnifyWidth is negative then e.getX() is the start of a
    // rectangle with the opposite sign width. Similarly for y.

    if (magnifyWidth > 0) {
        xToUse = e.getX() - magnifyWidth;
        widthToUse = magnifyWidth;
    } else {
        xToUse = e.getX();
        widthToUse = -1.0 * magnifyWidth;
    }

    if (magnifyHeight > 0) {
        yToUse = e.getY() - magnifyHeight;
        heightToUse = magnifyHeight;
    } else {
        yToUse = e.getY();
        heightToUse = -1.0 * magnifyHeight;
    }

    // xToUse and yToUse now specify the top left of the rectangle. In order
    // to keep the magnified rectangle inside the data area the start point
    // must be inside a rectangle which is the scaledDataArea reduced in
    // width
    // and height by the width and height of the magnifyRectangle.

    Point2D revisedStartPoint = ShapeUtilities.getPointInRectangle(xToUse, yToUse,
            new Rectangle2D.Double(scaledDataArea.getMinX(), scaledDataArea.getMinY(),
                    scaledDataArea.getWidth() - magnifyWidth, scaledDataArea.getHeight() - magnifyHeight));
    magnifyRectangle = new Rectangle2D.Double(revisedStartPoint.getX(), revisedStartPoint.getY(), widthToUse,
            heightToUse);
}

From source file:extern.NpairsBoxAndWhiskerRenderer.java

/**
 * Draws the visual representation of a single data item when the plot has
 * a horizontal orientation.//  ww  w .j  av a 2 s .  c  o m
 *
 * @param g2  the graphics device.
 * @param state  the renderer state.
 * @param dataArea  the area within which the plot is being drawn.
 * @param plot  the plot (can be used to obtain standard color
 *              information etc).
 * @param domainAxis  the domain axis.
 * @param rangeAxis  the range axis.
 * @param dataset  the dataset (must be an instance of
 *                 {@link BoxAndWhiskerCategoryDataset}).
 * @param row  the row index (zero-based).
 * @param column  the column index (zero-based).
 */
public void drawHorizontalItem(Graphics2D g2, CategoryItemRendererState state, Rectangle2D dataArea,
        CategoryPlot plot, CategoryAxis domainAxis, ValueAxis rangeAxis, CategoryDataset dataset, int row,
        int column) {

    BoxAndWhiskerCategoryDataset bawDataset = (BoxAndWhiskerCategoryDataset) dataset;

    double categoryEnd = domainAxis.getCategoryEnd(column, getColumnCount(), dataArea,
            plot.getDomainAxisEdge());
    double categoryStart = domainAxis.getCategoryStart(column, getColumnCount(), dataArea,
            plot.getDomainAxisEdge());
    double categoryWidth = Math.abs(categoryEnd - categoryStart);

    double yy = categoryStart;
    int seriesCount = getRowCount();
    int categoryCount = getColumnCount();

    double widthWeWannaUse = Math.min(state.getBarWidth(), dataArea.getWidth() / 10);

    if (seriesCount > 1) {
        double seriesGap = dataArea.getHeight() * getItemMargin() / (categoryCount * (seriesCount - 1));
        //            double usedWidth = (state.getBarWidth() * seriesCount)
        //                               + (seriesGap * (seriesCount - 1));
        double usedWidth = (widthWeWannaUse * seriesCount) + (seriesGap * (seriesCount - 1));
        // offset the start of the boxes if the total width used is smaller
        // than the category width
        double offset = (categoryWidth - usedWidth) / 2;
        //            yy = yy + offset + (row * (state.getBarWidth() + seriesGap));
        yy = yy + offset + (row * (widthWeWannaUse + seriesGap));
    } else {
        // offset the start of the box if the box width is smaller than
        // the category width
        //            double offset = (categoryWidth - state.getBarWidth()) / 2;
        double offset = (categoryWidth - widthWeWannaUse) / 2;
        yy = yy + offset;
    }

    g2.setPaint(getItemPaint(row, column));
    Stroke s = getItemStroke(row, column);
    g2.setStroke(s);

    RectangleEdge location = plot.getRangeAxisEdge();

    Number xQ1 = bawDataset.getQ1Value(row, column);
    Number xQ3 = bawDataset.getQ3Value(row, column);
    Number xMax = bawDataset.getMaxRegularValue(row, column);
    Number xMin = bawDataset.getMinRegularValue(row, column);

    Shape box = null;
    if (xQ1 != null && xQ3 != null && xMax != null && xMin != null) {

        double xxQ1 = rangeAxis.valueToJava2D(xQ1.doubleValue(), dataArea, location);
        double xxQ3 = rangeAxis.valueToJava2D(xQ3.doubleValue(), dataArea, location);
        double xxMax = rangeAxis.valueToJava2D(xMax.doubleValue(), dataArea, location);
        double xxMin = rangeAxis.valueToJava2D(xMin.doubleValue(), dataArea, location);
        //            double yymid = yy + state.getBarWidth() / 2.0;
        double yymid = yy + widthWeWannaUse / 2.0;

        // draw the upper shadow...
        g2.draw(new Line2D.Double(xxMax, yymid, xxQ3, yymid));
        //            g2.draw(new Line2D.Double(xxMax, yy, xxMax,
        //                    yy + state.getBarWidth()));
        g2.draw(new Line2D.Double(xxMax, yy, xxMax, yy + widthWeWannaUse));

        // draw the lower shadow...
        g2.draw(new Line2D.Double(xxMin, yymid, xxQ1, yymid));
        //            g2.draw(new Line2D.Double(xxMin, yy, xxMin,
        //                    yy + state.getBarWidth()));
        g2.draw(new Line2D.Double(xxMin, yy, xxMin, yy + widthWeWannaUse));

        // draw the box...
        //            box = new Rectangle2D.Double(Math.min(xxQ1, xxQ3), yy,
        //                    Math.abs(xxQ1 - xxQ3), state.getBarWidth());
        box = new Rectangle2D.Double(Math.min(xxQ1, xxQ3), yy, Math.abs(xxQ1 - xxQ3), widthWeWannaUse);
        if (this.fillBox) {
            g2.fill(box);
        }
        g2.setStroke(getItemOutlineStroke(row, column));
        g2.setPaint(getItemOutlinePaint(row, column));
        g2.draw(box);
    }

    g2.setPaint(this.artifactPaint);
    double aRadius = 0; // average radius

    // draw mean - SPECIAL AIMS REQUIREMENT...
    Number xMean = bawDataset.getMeanValue(row, column);
    if (xMean != null) {
        double xxMean = rangeAxis.valueToJava2D(xMean.doubleValue(), dataArea, location);
        //            aRadius = state.getBarWidth() / 4;
        aRadius = widthWeWannaUse / 4;
        // here we check that the average marker will in fact be visible
        // before drawing it...
        if ((xxMean > (dataArea.getMinX() - aRadius)) && (xxMean < (dataArea.getMaxX() + aRadius))) {
            Ellipse2D.Double avgEllipse = new Ellipse2D.Double(xxMean - aRadius, yy + aRadius, aRadius * 2,
                    aRadius * 2);
            g2.fill(avgEllipse);
            g2.draw(avgEllipse);
        }
    }

    // draw median...
    Number xMedian = bawDataset.getMedianValue(row, column);
    if (xMedian != null) {
        double xxMedian = rangeAxis.valueToJava2D(xMedian.doubleValue(), dataArea, location);
        //            g2.draw(new Line2D.Double(xxMedian, yy, xxMedian,
        //                    yy + state.getBarWidth()));
        g2.draw(new Line2D.Double(xxMedian, yy, xxMedian, yy + widthWeWannaUse));
    }

    // collect entity and tool tip information...
    if (state.getInfo() != null && box != null) {
        EntityCollection entities = state.getEntityCollection();
        if (entities != null) {
            addItemEntity(entities, dataset, row, column, box);
        }
    }

}

From source file:edu.dlnu.liuwenpeng.render.CandlestickRenderer.java

/**    
* Draws the visual representation of a single data item.    
*    /*from w ww . j  av  a 2s .  c om*/
* @param g2  the graphics device.    
* @param state  the renderer state.    
* @param dataArea  the area within which the plot is being drawn.    
* @param info  collects info about the drawing.    
* @param plot  the plot (can be used to obtain standard color    
*              information etc).    
* @param domainAxis  the domain axis.    
* @param rangeAxis  the range axis.    
* @param dataset  the dataset.    
* @param series  the series index (zero-based).    
* @param item  the item index (zero-based).    
* @param crosshairState  crosshair information for the plot    
*                        (<code>null</code> permitted).    
* @param pass  the pass index.    
*/
public void drawItem(Graphics2D g2, XYItemRendererState state, Rectangle2D dataArea, PlotRenderingInfo info,
        XYPlot plot, ValueAxis domainAxis, ValueAxis rangeAxis, XYDataset dataset, int series, int item,
        CrosshairState crosshairState, int pass) {

    boolean horiz;
    PlotOrientation orientation = plot.getOrientation();
    if (orientation == PlotOrientation.HORIZONTAL) {
        horiz = true;
    } else if (orientation == PlotOrientation.VERTICAL) {
        horiz = false;
    } else {
        return;
    }

    // setup for collecting optional entity info...    
    EntityCollection entities = null;
    if (info != null) {
        entities = info.getOwner().getEntityCollection();
    }

    OHLCDataset highLowData = (OHLCDataset) dataset;

    double x = highLowData.getXValue(series, item);
    double yHigh = highLowData.getHighValue(series, item);
    double yLow = highLowData.getLowValue(series, item);
    double yOpen = highLowData.getOpenValue(series, item);
    double yClose = highLowData.getCloseValue(series, item);

    RectangleEdge domainEdge = plot.getDomainAxisEdge();
    double xx = domainAxis.valueToJava2D(x, dataArea, domainEdge);

    RectangleEdge edge = plot.getRangeAxisEdge();
    double yyHigh = rangeAxis.valueToJava2D(yHigh, dataArea, edge);
    double yyLow = rangeAxis.valueToJava2D(yLow, dataArea, edge);
    double yyOpen = rangeAxis.valueToJava2D(yOpen, dataArea, edge);
    double yyClose = rangeAxis.valueToJava2D(yClose, dataArea, edge);

    double volumeWidth;
    double stickWidth;
    if (this.candleWidth > 0) {
        // These are deliberately not bounded to minimums/maxCandleWidth to    
        //  retain old behaviour.    
        volumeWidth = this.candleWidth;
        stickWidth = this.candleWidth;
    } else {
        double xxWidth = 0;
        int itemCount;
        switch (this.autoWidthMethod) {

        case WIDTHMETHOD_AVERAGE:
            itemCount = highLowData.getItemCount(series);
            if (horiz) {
                xxWidth = dataArea.getHeight() / itemCount;
            } else {
                xxWidth = dataArea.getWidth() / itemCount;
            }
            break;

        case WIDTHMETHOD_SMALLEST:
            // Note: It would be nice to pre-calculate this per series    
            itemCount = highLowData.getItemCount(series);
            double lastPos = -1;
            xxWidth = dataArea.getWidth();
            for (int i = 0; i < itemCount; i++) {
                double pos = domainAxis.valueToJava2D(highLowData.getXValue(series, i), dataArea, domainEdge);
                if (lastPos != -1) {
                    xxWidth = Math.min(xxWidth, Math.abs(pos - lastPos));
                }
                lastPos = pos;
            }
            break;

        case WIDTHMETHOD_INTERVALDATA:
            IntervalXYDataset intervalXYData = (IntervalXYDataset) dataset;
            double startPos = domainAxis.valueToJava2D(intervalXYData.getStartXValue(series, item), dataArea,
                    plot.getDomainAxisEdge());
            double endPos = domainAxis.valueToJava2D(intervalXYData.getEndXValue(series, item), dataArea,
                    plot.getDomainAxisEdge());
            xxWidth = Math.abs(endPos - startPos);
            break;

        }
        xxWidth -= 2 * this.autoWidthGap;
        xxWidth *= this.autoWidthFactor;
        xxWidth = Math.min(xxWidth, this.maxCandleWidth);
        volumeWidth = Math.max(Math.min(1, this.maxCandleWidth), xxWidth);
        stickWidth = Math.max(Math.min(3, this.maxCandleWidth), xxWidth);
    }

    Paint p = getItemPaint(series, item);
    Paint outlinePaint = null;
    if (this.useOutlinePaint) {
        outlinePaint = getItemOutlinePaint(series, item);
    }
    Stroke s = getItemStroke(series, item);

    g2.setStroke(s);

    if (this.drawVolume) {
        int volume = (int) highLowData.getVolumeValue(series, item);
        double volumeHeight = volume / this.maxVolume;

        double min, max;
        if (horiz) {
            min = dataArea.getMinX();
            max = dataArea.getMaxX();
        } else {
            min = dataArea.getMinY();
            max = dataArea.getMaxY();
        }

        double zzVolume = volumeHeight * (max - min);

        g2.setPaint(getVolumePaint());
        Composite originalComposite = g2.getComposite();
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));

        if (horiz) {
            g2.fill(new Rectangle2D.Double(min, xx - volumeWidth / 2, zzVolume, volumeWidth));
        } else {
            g2.fill(new Rectangle2D.Double(xx - volumeWidth / 2, max - zzVolume, volumeWidth, zzVolume));
        }

        g2.setComposite(originalComposite);
    }

    if (this.useOutlinePaint) {
        g2.setPaint(outlinePaint);
    } else {
        g2.setPaint(p);
    }

    double yyMaxOpenClose = Math.max(yyOpen, yyClose);
    double yyMinOpenClose = Math.min(yyOpen, yyClose);
    double maxOpenClose = Math.max(yOpen, yClose);
    double minOpenClose = Math.min(yOpen, yClose);

    // draw the upper shadow    
    if (yHigh > maxOpenClose) {
        if (yClose > yOpen) {
            g2.setPaint(Color.green);
        } else {
            g2.setPaint(Color.red);

        }
        if (horiz) {
            g2.draw(new Line2D.Double(yyHigh, xx, yyMaxOpenClose, xx));
        } else {
            g2.draw(new Line2D.Double(xx, yyHigh, xx, yyMaxOpenClose));
        }
    }

    // draw the lower shadow    
    if (yLow < minOpenClose) {
        if (yClose > yOpen) {
            g2.setPaint(Color.green);
        } else {
            g2.setPaint(Color.red);

        }
        if (horiz) {
            g2.draw(new Line2D.Double(yyLow, xx, yyMinOpenClose, xx));
        } else {
            g2.draw(new Line2D.Double(xx, yyLow, xx, yyMinOpenClose));
        }
    }

    // draw the body    
    Rectangle2D body = null;
    Rectangle2D hotspot = null;
    double length = Math.abs(yyHigh - yyLow);
    double base = Math.min(yyHigh, yyLow);
    if (horiz) {
        body = new Rectangle2D.Double(yyMinOpenClose, xx - stickWidth / 2, yyMaxOpenClose - yyMinOpenClose,
                stickWidth);

        hotspot = new Rectangle2D.Double(base, xx - stickWidth / 2, length, stickWidth);
    } else {
        body = new Rectangle2D.Double(xx - stickWidth / 2, yyMinOpenClose, stickWidth,
                yyMaxOpenClose - yyMinOpenClose);
        hotspot = new Rectangle2D.Double(xx - stickWidth / 2, base, stickWidth, length);

    }
    if (yClose > yOpen) {
        if (this.upPaint != null) {
            g2.setPaint(this.upPaint);
        } else {
            g2.setPaint(p);
        }
        g2.fill(body);
    } else {
        if (this.downPaint != null) {
            g2.setPaint(this.downPaint);
        } else {
            g2.setPaint(p);
        }
        g2.fill(body);
    }
    if (this.useOutlinePaint) {
        g2.setPaint(outlinePaint);

    } else {
        if (yClose > yOpen) {
            g2.setPaint(Color.green);

        } else {
            g2.setPaint(p);
        }
    }
    g2.draw(body);

    // add an entity for the item...    
    if (entities != null) {
        addEntity(entities, hotspot, dataset, series, item, 0.0, 0.0);
    }

}

From source file:ucar.unidata.idv.control.chart.MyXYPlot.java

/**
 * A utility method for drawing the axes.
 *
 * @param g2  the graphics device (<code>null</code> not permitted).
 * @param plotArea  the plot area (<code>null</code> not permitted).
 * @param dataArea  the data area (<code>null</code> not permitted).
 * @param plotState  collects information about the plot (<code>null</code>
 *                   permitted)./*  w  w w . j a  va2s  .c o m*/
 *
 * @return A map containing the state for each axis drawn.
 */
protected Map drawAxes(Graphics2D g2, Rectangle2D plotArea, Rectangle2D dataArea, PlotRenderingInfo plotState) {

    AxisCollection axisCollection = new AxisCollection();

    // add domain axes to lists...
    for (int index = 0; index < this.domainAxes.size(); index++) {
        ValueAxis axis = (ValueAxis) this.domainAxes.get(index);
        if (axis != null) {
            axisCollection.add(axis, getDomainAxisEdge(index));
        }
    }

    // add range axes to lists...
    for (int index = 0; index < this.rangeAxes.size(); index++) {
        ValueAxis yAxis = (ValueAxis) this.rangeAxes.get(index);
        if (yAxis != null) {
            axisCollection.add(yAxis, getRangeAxisEdge(index));
        }
    }

    Map axisStateMap = new HashMap();

    // draw the top axes
    double cursor = dataArea.getMinY() - this.axisOffset.calculateTopOutset(dataArea.getHeight());
    Iterator iterator = axisCollection.getAxesAtTop().iterator();
    while (iterator.hasNext()) {
        ValueAxis axis = (ValueAxis) iterator.next();
        AxisState info = axis.draw(g2, cursor, plotArea, dataArea, RectangleEdge.TOP, plotState);
        cursor = info.getCursor();
        axisStateMap.put(axis, info);
    }

    // draw the bottom axes
    cursor = dataArea.getMaxY() + this.axisOffset.calculateBottomOutset(dataArea.getHeight());
    iterator = axisCollection.getAxesAtBottom().iterator();
    while (iterator.hasNext()) {
        ValueAxis axis = (ValueAxis) iterator.next();
        AxisState info = axis.draw(g2, cursor, plotArea, dataArea, RectangleEdge.BOTTOM, plotState);
        cursor = info.getCursor();
        axisStateMap.put(axis, info);
    }

    // draw the left axes
    cursor = dataArea.getMinX() - this.axisOffset.calculateLeftOutset(dataArea.getWidth());
    iterator = axisCollection.getAxesAtLeft().iterator();
    while (iterator.hasNext()) {
        ValueAxis axis = (ValueAxis) iterator.next();
        AxisState info = axis.draw(g2, cursor, plotArea, dataArea, RectangleEdge.LEFT, plotState);
        cursor = info.getCursor();
        axisStateMap.put(axis, info);
    }

    // draw the right axes
    cursor = dataArea.getMaxX() + this.axisOffset.calculateRightOutset(dataArea.getWidth());
    iterator = axisCollection.getAxesAtRight().iterator();
    while (iterator.hasNext()) {
        ValueAxis axis = (ValueAxis) iterator.next();
        AxisState info = axis.draw(g2, cursor, plotArea, dataArea, RectangleEdge.RIGHT, plotState);
        cursor = info.getCursor();
        axisStateMap.put(axis, info);
    }

    return axisStateMap;
}

From source file:de.laures.cewolf.jfree.ThermometerPlot.java

/**
 * Draws the plot on a Java 2D graphics device (such as the screen or a printer).
 *
 * @param g2  the graphics device./* ww  w . j a va 2 s .c  o m*/
 * @param area  the area within which the plot should be drawn.
 * @param anchor  the anchor point (<code>null</code> permitted).
 * @param parentState  the state from the parent plot, if there is one.
 * @param info  collects info about the drawing.
 */
public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor, PlotState parentState,
        PlotRenderingInfo info) {

    RoundRectangle2D outerStem = new RoundRectangle2D.Double();
    RoundRectangle2D innerStem = new RoundRectangle2D.Double();
    RoundRectangle2D mercuryStem = new RoundRectangle2D.Double();
    Ellipse2D outerBulb = new Ellipse2D.Double();
    Ellipse2D innerBulb = new Ellipse2D.Double();
    String temp = null;
    FontMetrics metrics = null;
    if (info != null) {
        info.setPlotArea(area);
    }

    // adjust for insets...
    RectangleInsets insets = getInsets();
    insets.trim(area);
    drawBackground(g2, area);

    // adjust for padding...
    Rectangle2D interior = (Rectangle2D) area.clone();
    this.padding.trim(interior);
    int midX = (int) (interior.getX() + (interior.getWidth() / 2));
    int midY = (int) (interior.getY() + (interior.getHeight() / 2));
    int stemTop = (int) (interior.getMinY() + getBulbRadius());
    int stemBottom = (int) (interior.getMaxY() - getBulbDiameter());
    Rectangle2D dataArea = new Rectangle2D.Double(midX - getColumnRadius(), stemTop, getColumnRadius(),
            stemBottom - stemTop);

    outerBulb.setFrame(midX - getBulbRadius(), stemBottom, getBulbDiameter(), getBulbDiameter());

    outerStem.setRoundRect(midX - getColumnRadius(), interior.getMinY(), getColumnDiameter(),
            stemBottom + getBulbDiameter() - stemTop, getColumnDiameter(), getColumnDiameter());

    Area outerThermometer = new Area(outerBulb);
    Area tempArea = new Area(outerStem);
    outerThermometer.add(tempArea);

    innerBulb.setFrame(midX - getBulbRadius() + getGap(), stemBottom + getGap(),
            getBulbDiameter() - getGap() * 2, getBulbDiameter() - getGap() * 2);

    innerStem.setRoundRect(midX - getColumnRadius() + getGap(), interior.getMinY() + getGap(),
            getColumnDiameter() - getGap() * 2, stemBottom + getBulbDiameter() - getGap() * 2 - stemTop,
            getColumnDiameter() - getGap() * 2, getColumnDiameter() - getGap() * 2);

    Area innerThermometer = new Area(innerBulb);
    tempArea = new Area(innerStem);
    innerThermometer.add(tempArea);

    if ((this.dataset != null) && (this.dataset.getValue() != null)) {
        double current = this.dataset.getValue().doubleValue();
        double ds = this.rangeAxis.valueToJava2D(current, dataArea, RectangleEdge.LEFT);

        int i = getColumnDiameter() - getGap() * 2; // already calculated
        int j = getColumnRadius() - getGap(); // already calculated
        int l = (i / 2);
        int k = (int) Math.round(ds);
        if (k < (getGap() + interior.getMinY())) {
            k = (int) (getGap() + interior.getMinY());
            l = getBulbRadius();
        }

        Area mercury = new Area(innerBulb);

        if (k < (stemBottom + getBulbRadius())) {
            mercuryStem.setRoundRect(midX - j, k, i, (stemBottom + getBulbRadius()) - k, l, l);
            tempArea = new Area(mercuryStem);
            mercury.add(tempArea);
        }

        g2.setPaint(getCurrentPaint());
        g2.fill(mercury);

        // draw range indicators...
        if (this.subrangeIndicatorsVisible) {
            g2.setStroke(this.subrangeIndicatorStroke);
            Range range = this.rangeAxis.getRange();

            // draw start of normal range
            double value = this.subrangeInfo[NORMAL][RANGE_LOW];
            if (range.contains(value)) {
                double x = midX + getColumnRadius() + 2;
                double y = this.rangeAxis.valueToJava2D(value, dataArea, RectangleEdge.LEFT);
                Line2D line = new Line2D.Double(x, y, x + 10, y);
                g2.setPaint(this.subrangePaint[NORMAL]);
                g2.draw(line);
            }

            // draw start of warning range
            value = this.subrangeInfo[WARNING][RANGE_LOW];
            if (range.contains(value)) {
                double x = midX + getColumnRadius() + 2;
                double y = this.rangeAxis.valueToJava2D(value, dataArea, RectangleEdge.LEFT);
                Line2D line = new Line2D.Double(x, y, x + 10, y);
                g2.setPaint(this.subrangePaint[WARNING]);
                g2.draw(line);
            }

            // draw start of critical range
            value = this.subrangeInfo[CRITICAL][RANGE_LOW];
            if (range.contains(value)) {
                double x = midX + getColumnRadius() + 2;
                double y = this.rangeAxis.valueToJava2D(value, dataArea, RectangleEdge.LEFT);
                Line2D line = new Line2D.Double(x, y, x + 10, y);
                g2.setPaint(this.subrangePaint[CRITICAL]);
                g2.draw(line);
            }
        }

        // draw the axis...
        if ((this.rangeAxis != null) && (this.axisLocation != NONE)) {
            int drawWidth = AXIS_GAP;
            Rectangle2D drawArea;
            double cursor = 0;

            switch (this.axisLocation) {
            case RIGHT:
                cursor = midX + getColumnRadius();
                drawArea = new Rectangle2D.Double(cursor, stemTop, drawWidth, (stemBottom - stemTop + 1));
                this.rangeAxis.draw(g2, cursor, area, drawArea, RectangleEdge.RIGHT, null);
                break;

            case LEFT:
            default:
                //cursor = midX - COLUMN_RADIUS - AXIS_GAP;
                cursor = midX - getColumnRadius();
                drawArea = new Rectangle2D.Double(cursor, stemTop, drawWidth, (stemBottom - stemTop + 1));
                this.rangeAxis.draw(g2, cursor, area, drawArea, RectangleEdge.LEFT, null);
                break;
            }

        }

        // draw text value on screen
        g2.setFont(this.valueFont);
        g2.setPaint(this.valuePaint);
        metrics = g2.getFontMetrics();
        switch (this.valueLocation) {
        case RIGHT:
            g2.drawString(this.valueFormat.format(current), midX + getColumnRadius() + getGap(), midY);
            break;
        case LEFT:
            String valueString = this.valueFormat.format(current);
            int stringWidth = metrics.stringWidth(valueString);
            g2.drawString(valueString, midX - getColumnRadius() - getGap() - stringWidth, midY);
            break;
        case BULB:
            temp = this.valueFormat.format(current);
            i = metrics.stringWidth(temp) / 2;
            g2.drawString(temp, midX - i, stemBottom + getBulbRadius() + getGap());
            break;
        default:
        }
        /***/
    }

    g2.setPaint(this.thermometerPaint);
    g2.setFont(this.valueFont);

    //  draw units indicator
    metrics = g2.getFontMetrics();
    int tickX1 = midX - getColumnRadius() - getGap() * 2 - metrics.stringWidth(UNITS[this.units]);
    if (tickX1 > area.getMinX()) {
        g2.drawString(UNITS[this.units], tickX1, (int) (area.getMinY() + 20));
    }

    // draw thermometer outline
    g2.setStroke(this.thermometerStroke);
    g2.draw(outerThermometer);
    g2.draw(innerThermometer);

    drawOutline(g2, area);
}