skip to main content
Programmer's documentation > Developing with the JViews Charts SDK > Decorations > Writing a new decoration
 
Writing a new decoration
The complete source code can be found in <installdir>/jviews-charts/samples/stock/src/stock/Stripes.java.
The draw method is automatically called by an IlvChart to draw the decoration (provided that the decoration has been added to a chart). Depending on its drawing order property, a decoration is drawn either before or after the graphical representation of the chart.
Write a decoration that displays stripes regularly spaced, and aligned on the graduations of an associated scale. The scale type determines the stripes direction (horizontal stripes for an ordinate scale and vertical stripes for an abscissa scale). The stripes width should be equal to the stripes spacing and equal to the width of one major scale graduation. Furthermore, the stripes should be painted using a customizable fill style and the result should be independent of the chart projector.
1. Extend the IlvChartDecoration class.
 
public class Stripes extends IlvChartDecoration
{
  ...
}
2. Define two data members: a reference on the associated scale and a rendering style.
 
private IlvStyle fillStyle;
IlvScale scale;
3. Initialize the scale at initialization time and pass it as a parameter to the constructor.
 
public Stripes(IlvScale scale, Paint fillPaint)
{
    this.scale = scale;
    setFillPaint(fillPaint);
}
The scale associated with the decoration should not change over the life of the instance.
4. Provide set and get accessors on the fill rendering style in addition to the constructor initialization. You want to allow the rendering style to be changed at any time.
 
public void setFillPaint(Paint paint)
{
    fillStyle = getFillStyle().setFillPaint(paint);
}
 
public final Paint getFillPaint()
{
    return getFillStyle().getFillPaint();
}
Define the private getFillStyle() method:
 
private IlvStyle getFillStyle()
{
    if (fillStyle == null)
        fillStyle = new IlvStyle(Color.lightGray);
    return fillStyle;
}
NOTE The IlvStyle class is an immutable class. Changing an attribute of an IlvStyle instance actually creates a copy of this instance with the specified attribute. This choice has been made to prevent unexpected side-effects when changing attributes of a shared IlvStyle instance.
Now everything is ready to draw the decoration.
The stripes should be aligned on the scale graduations, have a width equal to one major step of the scale graduation, and spaced from the same value. From these properties, you see that the position on the scale of a stripe depends on the position of the previous one, and that can be expressed as an interval between two values.
5. To compute the data interval covered by a stripe, use the following method to return the interval next to the IlvDataInterval specified as a parameter:
 
protected IlvDataInterval nextStripe(IlvDataInterval itv)
{
    IlvStepsDefinition def = scale.getStepsDefinition();
    if (itv == null) {
        itv = getAxis().getVisibleRange();
        double v = def.previousStep(itv.getMin());
        itv.setMin(def.incrementStep(v));
        itv.setMax(def.incrementStep(itv.getMin()));
    } else {
        itv.setMax(def.incrementStep(def.incrementStep(itv.getMax())));
        itv.setMin(def.incrementStep(def.incrementStep(itv.getMin())));
    }
    return itv;
}
Scale graduations are computed by a dedicated object, instance of the IlvStepsDefinition class. Since we need to compute the stripe position according to these graduations, we first get the steps definition of the scale, and then we compute the interval corresponding to the next stripe depending on the previous interval:
*if it is the first stripe, the interval will cover an area equal to [visibleMin+delta, visibleMin+2*delta], where delta is one major step.
*if the stripe comes after a previous stripe, it should cover the area between [previousMin+2*delta, previousMax+2*delta], where delta is one major step.
Now that we know the data interval corresponding to a given stripe, we can write the draw method. Remember, we want to be independent of the chart projector: our decoration should be used either with a Cartesian projector or a polar projector. Since we do not want to write projector-dependent code, we use the getShape method that returns a shape (in the screen coordinate system) corresponding to a specified data window. This shape contains all the data points of the data window projected by the current chart projector.
6. Draw the decoration.
The implementation of the draw method is as follows:
 
public void draw(Graphics g)
{
    IlvChart chart = getChart();
    if (chart == null)
        return;
 
    IlvDataInterval itv = nextStripe(null);
    IlvDataWindow w = null;
    if (getAxis().getType() == IlvAxis.X_AXIS) {
        w = new IlvDataWindow(itv, chart.getYAxis(0).getVisibleRange());
    } else {
        w = new IlvDataWindow(chart.getXAxis().getVisibleRange(), itv);
    }
 
    IlvChartProjector prj = getChart().getProjector();
    IlvCoordinateSystem coordSys = getChart().getCoordinateSystem(0);
    Rectangle plotRect = getChart().getChartArea().getPlotRect();
 
    IlvStyle style = getFillStyle();
    while (itv.getMin() < getAxis().getVisibleMax()) {
        style.fill(g, prj.getShape(w, plotRect, coordSys));
        if (getAxis().getType() == IlvAxis.X_AXIS)
            w.xRange = nextStripe(itv);
        else
            w.yRange = nextStripe(itv);
    }
}
Depending on the scale type (x- or y-scale), we initialize the data window corresponding to a stripe with the visible range of the corresponding axis and iterate on the stripes until the maximum visible range of the associated axis is reached.

Copyright © 2018, Rogue Wave Software, Inc. All Rights Reserved.