`

扩展jfreechart实现对于每一个bar颜色的控制

阅读更多

  在jfreechart中,对于显示bar的控制,是通过对于series设置实现的,从而,在同一个series中,所有的bar的颜色都是一致的。这在一些需要更细控制的环境中,会存在一些问题。

   为了实现在jfreechart中对于每一个bar的颜色显示控制,这里我选择XYBarchart作为例子,进行了相应的扩展。在jfreechart中,对于图形的控制,可以分为数据和绘制两个部分。在数据方面层次为:dataset->series->item;在绘制方面为:renderer->painter。基于这样的架构,这里扩展了XYInternalSeries、XYInternalDataItem、XYBarRenderer、XYBarPainter四个类,分别如下:

XYInternalSeries扩展类ExtendedXYInternalSeries,在其中定义了一个add方法,增加了一个Color的传入参数:

import java.awt.Color;

import org.jfree.data.xy.XYIntervalSeries;

public class ExtendedXYIntervalSeries extends XYIntervalSeries {

	public ExtendedXYIntervalSeries(Comparable key) {
		super(key);
		// TODO Auto-generated constructor stub
	}


	public void add(double x, double xLow, double xHigh, double y, double yLow,
			double yHigh,Color color) {
		// TODO Auto-generated method stub
		super.add(new ExtendedXYInternalDataItem(x,xLow,xHigh,y,yLow,yHigh,color), true);
	}


	/* (non-Javadoc)
	 * @see org.jfree.data.xy.XYIntervalSeries#add(double, double, double, double, double, double)
	 */
	@Override
	public void add(double x, double xLow, double xHigh, double y, double yLow,
			double yHigh) {
		// TODO Auto-generated method stub
		super.add(new ExtendedXYInternalDataItem(x,xLow,xHigh,y,yLow,yHigh), true);
	}
	
	

 XYInternalDataItem的扩展类ExtendedXyInternalDataItem,其中,增加了一个属性color,在jfreechart中,Item代表的是一个显示的单元,在BarChart中就是一个Bar,原来是没有color属性的,这里增加了这个属性,在后面的绘制时将被用到:

import java.awt.Color;

import org.jfree.data.xy.XYIntervalDataItem;

public class ExtendedXYInternalDataItem extends XYIntervalDataItem {

	private Color color = null;
	
	public ExtendedXYInternalDataItem(double x, double xLow, double xHigh, double y,
			double yLow, double yHigh,Color color) {
		super(x, xLow, xHigh, y, yLow, yHigh);
		// TODO Auto-generated constructor stub
		this.color = color;
	}

	/**
	 * @param x
	 * @param xLow
	 * @param xHigh
	 * @param y
	 * @param yLow
	 * @param yHigh
	 */
	public ExtendedXYInternalDataItem(double x, double xLow, double xHigh, double y,
			double yLow, double yHigh) {
		super(x, xLow, xHigh, y, yLow, yHigh);
		// TODO Auto-generated constructor stub
	}

	/**
	 * @return the color
	 */
	public Color getColor() {
		return color;
	}

	/**
	 * @param color the color to set
	 */
	public void setColor(Color color) {
		this.color = color;
	}

}

 

上面的扩展在数据方面,做好了准备,已经可以在每一个显示单元中设置一个颜色属性了,下面在绘制过程中,利用这个属性来控制bar的颜色。

  在ExtendedBarRenderer中,重载drawItem函数,当bar有颜色定义时,调用扩展的BarPainter:

import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;

import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.entity.EntityCollection;
import org.jfree.chart.labels.XYItemLabelGenerator;
import org.jfree.chart.plot.CrosshairState;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.chart.renderer.xy.XYItemRendererState;
import org.jfree.data.extend.xy.ExtendedXYInternalDataItem;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYIntervalSeriesCollection;
import org.jfree.ui.RectangleEdge;


public class ExtendedXYBarRenderer extends XYBarRenderer {

	/**
	 * 
	 */
	private static final long serialVersionUID = -2257416613878068969L;

	/* (non-Javadoc)
	 * @see org.jfree.chart.renderer.xy.XYBarRenderer#drawItem(java.awt.Graphics2D, org.jfree.chart.renderer.xy.XYItemRendererState, java.awt.geom.Rectangle2D, org.jfree.chart.plot.PlotRenderingInfo, org.jfree.chart.plot.XYPlot, org.jfree.chart.axis.ValueAxis, org.jfree.chart.axis.ValueAxis, org.jfree.data.xy.XYDataset, int, int, org.jfree.chart.plot.CrosshairState, int)
	 */
	@Override
	
	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) {
		// TODO Auto-generated method stub
        if (!getItemVisible(series, item)) {
            return;
        }
        XYIntervalSeriesCollection intervalDataset = (XYIntervalSeriesCollection) dataset;
        
        ExtendedXYInternalDataItem myXYItem = (ExtendedXYInternalDataItem) intervalDataset.getSeries(series).getDataItem(item);

        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;
            }
        }

        // is there an alignment adjustment to be made?
        if (this.barAlignmentFactor >= 0.0 && this.barAlignmentFactor <= 1.0) {
            double x = intervalDataset.getXValue(series, item);
            double interval = endX - startX;
            startX = x - interval * this.barAlignmentFactor;
            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));

        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);
        }

        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.barPainter.paintBarShadow(g2, this, series, item, bar, barBase,
                !this.useYInterval);
        }
        if(myXYItem.getColor() == null)
        {
            this.barPainter.paintBar(g2, this, series, item, bar, barBase);
       	
        }
        else
        {
        	((ExtendedXYBarPainter)this.barPainter).paintBar(g2, this, series, item, bar, barBase,myXYItem.getColor());
        }
        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);
        }
	}

	
}

 

在ExtendBarPainter中,实现对于每一个Bar的颜色设置:

import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Stroke;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RectangularShape;

import org.jfree.chart.renderer.xy.GradientXYBarPainter;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.ui.RectangleEdge;

public class ExtendedXYBarPainter extends GradientXYBarPainter {

	/**
	 * 
	 */
	private static final long serialVersionUID = -7874550052210278757L;
	XYBarRenderer myrenderer;
	private double g1;
	private double g2;
	private double g3;

	public void paintBar(Graphics2D g2, XYBarRenderer renderer, int row,
			int column, RectangularShape bar, RectangleEdge base, Color color) {
		// TODO Auto-generated method stub
        Paint itemPaint = renderer.getItemPaint(row, column);

        Color c0, c1;
        if (itemPaint instanceof Color) {
            c0 = color;
            c1 = c0.brighter();
        }
        else if (itemPaint instanceof GradientPaint) {
            GradientPaint gp = (GradientPaint) itemPaint;
            c0 = gp.getColor1();
            c1 = gp.getColor2();
        }
        else {
            c0 = Color.blue;
            c1 = Color.blue.brighter();
        }

        // as a special case, if the bar colour has alpha == 0, we draw
        // nothing.
        if (c0.getAlpha() == 0) {
            return;
        }

        if (base == RectangleEdge.TOP || base == RectangleEdge.BOTTOM) {
            Rectangle2D[] regions = splitVerticalBar(bar, this.g1, this.g2,
                    this.g3);
            GradientPaint gp = new GradientPaint((float) regions[0].getMinX(),
                    0.0f, c0, (float) regions[0].getMaxX(), 0.0f, Color.white);
            g2.setPaint(gp);
            g2.fill(regions[0]);

            gp = new GradientPaint((float) regions[1].getMinX(), 0.0f,
                    Color.white, (float) regions[1].getMaxX(), 0.0f, c0);
            g2.setPaint(gp);
            g2.fill(regions[1]);

            gp = new GradientPaint((float) regions[2].getMinX(), 0.0f, c0,
                    (float) regions[2].getMaxX(), 0.0f, c1);
            g2.setPaint(gp);
            g2.fill(regions[2]);

            gp = new GradientPaint((float) regions[3].getMinX(), 0.0f, c1,
                     (float) regions[3].getMaxX(), 0.0f, c0);
            g2.setPaint(gp);
            g2.fill(regions[3]);
            
         

            }
        else if (base == RectangleEdge.LEFT || base == RectangleEdge.RIGHT) {
            Rectangle2D[] regions = splitHorizontalBar(bar, this.g1, this.g2,
                    this.g3);
            GradientPaint gp = new GradientPaint(0.0f,
                    (float) regions[0].getMinY(), c0, 0.0f,
                    (float) regions[0].getMaxX(), Color.white);
            g2.setPaint(gp);
            g2.fill(regions[0]);

            gp = new GradientPaint(0.0f, (float) regions[1].getMinY(),
                    Color.white, 0.0f, (float) regions[1].getMaxY(), c0);
            g2.setPaint(gp);
            g2.fill(regions[1]);

            gp = new GradientPaint(0.0f, (float) regions[2].getMinY(), c0,
                    0.0f, (float) regions[2].getMaxY(), c1);
            g2.setPaint(gp);
            g2.fill(regions[2]);

            gp = new GradientPaint(0.0f, (float) regions[3].getMinY(), c1,
                     0.0f, (float) regions[3].getMaxY(), c0);
            g2.setPaint(gp);
            g2.fill(regions[3]);

        }

        // draw the outline...
        if (renderer.isDrawBarOutline()) {
            Stroke stroke = renderer.getItemOutlineStroke(row, column);
            Paint paint = renderer.getItemOutlinePaint(row, column);
            if (stroke != null && paint != null) {
                g2.setStroke(stroke);
                g2.setPaint(paint);
                g2.draw(bar);
            }
        }
	}

	private Rectangle2D[] splitVerticalBar(RectangularShape bar, double a,
			double b, double c) {
		Rectangle2D[] result = new Rectangle2D[4];
		double x0 = bar.getMinX();
		double x1 = Math.rint(x0 + (bar.getWidth() * a));
		double x2 = Math.rint(x0 + (bar.getWidth() * b));
		double x3 = Math.rint(x0 + (bar.getWidth() * c));
		result[0] = new Rectangle2D.Double(bar.getMinX(), bar.getMinY(), x1
				- x0, bar.getHeight());
		result[1] = new Rectangle2D.Double(x1, bar.getMinY(), x2 - x1, bar
				.getHeight());
		result[2] = new Rectangle2D.Double(x2, bar.getMinY(), x3 - x2, bar
				.getHeight());
		result[3] = new Rectangle2D.Double(x3, bar.getMinY(), bar.getMaxX()
				- x3, bar.getHeight());
		return result;
	}

	/**
	 * Splits a bar into subregions (elsewhere, these subregions will have
	 * different gradients applied to them).
	 * 
	 * @param bar
	 *            the bar shape.
	 * @param a
	 *            the first division.
	 * @param b
	 *            the second division.
	 * @param c
	 *            the third division.
	 * 
	 * @return An array containing four subregions.
	 */
	private Rectangle2D[] splitHorizontalBar(RectangularShape bar, double a,
			double b, double c) {
		Rectangle2D[] result = new Rectangle2D[4];
		double y0 = bar.getMinY();
		double y1 = Math.rint(y0 + (bar.getHeight() * a));
		double y2 = Math.rint(y0 + (bar.getHeight() * b));
		double y3 = Math.rint(y0 + (bar.getHeight() * c));
		result[0] = new Rectangle2D.Double(bar.getMinX(), bar.getMinY(), bar
				.getWidth(), y1 - y0);
		result[1] = new Rectangle2D.Double(bar.getMinX(), y1, bar.getWidth(),
				y2 - y1);
		result[2] = new Rectangle2D.Double(bar.getMinX(), y2, bar.getWidth(),
				y3 - y2);
		result[3] = new Rectangle2D.Double(bar.getMinX(), y3, bar.getWidth(),
				bar.getMaxY() - y3);
		return result;
	}

}

 最后利用XYBarChartDemo7,对于实现的的扩展测试如下:

import java.awt.Color;

import javax.swing.JPanel;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.SymbolAxis;
import org.jfree.chart.extend.ExtendedChartPanel;
import org.jfree.chart.extend.renderer.xy.ExtendedXYBarPainter;
import org.jfree.chart.extend.renderer.xy.ExtendedXYBarRenderer;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.extend.xy.ExtendedXYIntervalSeries;
import org.jfree.data.time.Day;
import org.jfree.data.time.RegularTimePeriod;
import org.jfree.data.xy.IntervalXYDataset;
import org.jfree.data.xy.XYIntervalSeries;
import org.jfree.data.xy.XYIntervalSeriesCollection;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;

@SuppressWarnings("serial")
public class XYBarChartDemo7 extends ApplicationFrame
{

    public XYBarChartDemo7(String s)
    {
        super(s);
        ChartPanel jpanel = (ChartPanel) createDemoPanel();
        
//        JScrollPane scroll = new JScrollPane(jpanel);
        
//        jpanel.setPreferredSize(new Dimension(2000, 1000));
        setContentPane(jpanel);

       jpanel.addChartMouseListener(new MyBarChartListener());
 
  
    }

    private static JFreeChart createChart(IntervalXYDataset intervalxydataset)
    {
        JFreeChart jfreechart = ChartFactory.createXYBarChart("XYBarChartDemo7", "Date", true, "Y", intervalxydataset, PlotOrientation.VERTICAL, true, true, false);
        jfreechart.setBackgroundPaint(Color.white);
        XYPlot xyplot = (XYPlot)jfreechart.getPlot();
        xyplot.setDomainAxis(new DateAxis("Date"));
        SymbolAxis symbolaxis = new SymbolAxis("Series", new String[] {
            "S1", "S2", "S3"
        });
        symbolaxis.setGridBandsVisible(false);
        xyplot.setRangeAxis(symbolaxis);
    
        xyplot.setBackgroundPaint(Color.lightGray);
        xyplot.setDomainGridlinePaint(Color.white);
        xyplot.setRangeGridlinePaint(Color.white);
      
        xyplot.setRenderer(new ExtendedXYBarRenderer());      
        XYBarRenderer xybarrenderer = (XYBarRenderer)xyplot.getRenderer();
        xybarrenderer.setUseYInterval(true);
        xybarrenderer.setShadowVisible(false);
        xybarrenderer.setBarPainter(new ExtendedXYBarPainter());
        

        return jfreechart;
    }

    private static IntervalXYDataset createDataset()
    {
        Day day = new Day(12, 6, 2007);
        Day day1 = new Day(13, 6, 2007);
        Day day2 = new Day(14, 6, 2007);
        Day day3 = new Day(15, 6, 2007);
        Day day4 = new Day(16, 6, 2007);
        Day day5 = new Day(17, 6, 2007);
        XYIntervalSeriesCollection xyintervalseriescollection = new XYIntervalSeriesCollection();
        ExtendedXYIntervalSeries xyintervalseries = new ExtendedXYIntervalSeries("S1");
        ExtendedXYIntervalSeries xyintervalseries1 = new ExtendedXYIntervalSeries("S2");
        ExtendedXYIntervalSeries xyintervalseries2 = new ExtendedXYIntervalSeries("S3");
        addItem(xyintervalseries, day, day1, 0);
        xyintervalseries.add(day.getFirstMillisecond(), day.getFirstMillisecond(), day3.getLastMillisecond(), 0, -0.45, -0.35,Color.green);
       
        addItem(xyintervalseries, day3, day3, 0);
        addItem(xyintervalseries1, day, day5, 1);
        addItem(xyintervalseries2, day2, day4, 2);
        xyintervalseriescollection.addSeries(xyintervalseries);
        xyintervalseriescollection.addSeries(xyintervalseries1);
        xyintervalseriescollection.addSeries(xyintervalseries2);
        return xyintervalseriescollection;
    }

    public static void addItem(XYIntervalSeries xyintervalseries, RegularTimePeriod regulartimeperiod, RegularTimePeriod regulartimeperiod1, int i)
    {
        xyintervalseries.add(regulartimeperiod.getFirstMillisecond(), regulartimeperiod.getFirstMillisecond(), regulartimeperiod1.getLastMillisecond(), i, (double)i - 0.10000000000000001D, (double)i + 0.45000000000000001D);
    }

    public static JPanel createDemoPanel()
    {
        return new ExtendedChartPanel(createChart(createDataset()));
    }

    public static void main(String args[])
    {
 /*   	
        JFreeChart chart = createChart(createDataset());
        Display display = new Display();
        Shell shell = new Shell(display);
        shell.setSize(600, 300);
        shell.setLayout(new FillLayout());
        shell.setText("Test for jfreechart running with SWT");
        ChartComposite frame = new ChartComposite(shell, SWT.NONE, chart,
                true);
//        frame.pack();
        frame.setHorizontalAxisTrace(true);
        frame.setVerticalAxisTrace(true);
        frame.addChartMouseListener(new MyBarChartListener());
       
        
        shell.open();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch())
                display.sleep();
        }
*/

        XYBarChartDemo7 xybarchartdemo7 = new XYBarChartDemo7("JFreeChart : XYBarChartDemo7.java");
  
        xybarchartdemo7.pack();
        RefineryUtilities.centerFrameOnScreen(xybarchartdemo7);
        xybarchartdemo7.setVisible(true);
  
    	}
}

 会看到,利用

     xyintervalseries.add(day.getFirstMillisecond(), day.getFirstMillisecond(), day3.getLastMillisecond(), 0, -0.45, -0.35,Color.green);
  

 设置的bar的颜色会按照不同的设置进行变化了。 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics