⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 simplechartengine.java

📁 非常接近C/S操作方式的Java Ajax框架-ZK 用ZK框架使你的B/S应用程序更漂亮更易操作。 官网:www.zkoss.org
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/* SimpleChartEngine.java

{{IS_NOTE
	Purpose:
		
	Description:
		
	History:
		Tue Aug 1 10:30:48     2006, Created by henrichen
}}IS_NOTE

Copyright (C) 2006 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
	This program is distributed under GPL Version 2.0 in the hope that
	it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.zul.impl;

import org.zkoss.zul.*;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.UiException;
import org.zkoss.image.AImage;
import org.zkoss.util.TimeZones;
import org.zkoss.lang.Strings;
import org.zkoss.lang.Objects;

import org.jfree.chart.*;
import org.jfree.chart.encoders.*;
import org.jfree.chart.plot.*;
import org.jfree.chart.entity.*;
import org.jfree.data.general.*;
import org.jfree.data.category.*;
import org.jfree.data.xy.*;
import org.jfree.data.time.RegularTimePeriod;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.util.TableOrder;

import java.util.List;
import java.util.Date;
import java.util.Map;
import java.util.HashMap;
import java.util.TimeZone;
import java.io.ByteArrayOutputStream;
import java.awt.image.BufferedImage;
import java.awt.Paint;
import java.awt.Color;
import java.util.Iterator;


/**
 * A Facade Chart engine implemented with JFreeChart.
 *
 * <p>This is the JFreeChart base chart engine implementation. All chart would 
 * support drilldown by providing Area hot spots. Each Area would callback to 
 * {@link org.zkoss.zul.event.ChartAreaListener} class that application developers
 * can do processing on each area.</p>
 *
 * @author henrichen
 */
public class SimpleChartEngine implements ChartEngine {
	//as long as the series name is not set
	private static final String DEFAULT_HI_LO_SERIES = "High Low Data";
	
	//caching chartImpl if type and 3d are the same 
	private boolean _threeD; 
	private String _type; 
	private ChartImpl _chartImpl; //chart implementaion
	
	/**
	 * create specific type of chart drawing engine. This implementation use 
	 * JFreeChart engine.
	 */
	private ChartImpl getChartImpl(Chart chart) {
		if (Objects.equals(chart.getType(), _type) && _threeD == chart.isThreeD()) {
			return _chartImpl;
		}

		if (Chart.PIE.equals(chart.getType())) 
			_chartImpl = chart.isThreeD() ? new Pie3d() : new Pie();

		else if (Chart.RING.equals(chart.getType()))
			_chartImpl = new Ring();
					
		else if (Chart.BAR.equals(chart.getType()))
			_chartImpl = chart.isThreeD() ? new Bar3d() : new Bar();
		
		else if (Chart.LINE.equals(chart.getType()))
			_chartImpl = chart.isThreeD() ? new Line3d() : new Line();
			
		else if (Chart.AREA.equals(chart.getType()))
			_chartImpl = new AreaImpl();
					
		else if (Chart.STACKED_BAR.equals(chart.getType()))
			_chartImpl = chart.isThreeD() ? new StackedBar3d() : new StackedBar();

		else if (Chart.STACKED_AREA.equals(chart.getType()))
			_chartImpl = new StackedArea();
					
		else if (Chart.WATERFALL.equals(chart.getType()))
			_chartImpl = new Waterfall();
					
		else if (Chart.POLAR.equals(chart.getType()))
			_chartImpl = new Polar();

		else if (Chart.SCATTER.equals(chart.getType()))
			_chartImpl = new Scatter();

		else if (Chart.TIME_SERIES.equals(chart.getType()))
			_chartImpl = new TimeSeries();

		else if (Chart.STEP_AREA.equals(chart.getType()))
			_chartImpl = new StepArea();

		else if (Chart.STEP.equals(chart.getType()))
			_chartImpl = new Step();
			
		else if (Chart.HISTOGRAM.equals(chart.getType()))			
			_chartImpl = new Histogram();

		else if (Chart.CANDLESTICK.equals(chart.getType()))			
			_chartImpl = new Candlestick();

		else if (Chart.HIGHLOW.equals(chart.getType()))			
			_chartImpl = new Highlow();

		else 
			throw new UiException("Unsupported chart type yet: "+chart.getType());

		_threeD = chart.isThreeD();
		_type = chart.getType();
		return _chartImpl;
	}

	//-- ChartEngine --//
	public byte[] drawChart(Object data) {
		Chart chart = (Chart) data;
		ChartImpl impl = getChartImpl(chart);

		JFreeChart jfchart = impl.createChart(chart);
		
		Plot plot = (Plot) jfchart.getPlot();
		float alpha = (float)(((float)chart.getFgAlpha()) / 255);
		plot.setForegroundAlpha(alpha);
		
		alpha = (float)(((float)chart.getBgAlpha()) / 255);
		plot.setBackgroundAlpha(alpha);

		int[] bgRGB = chart.getBgRGB();
		if (bgRGB != null) {
			plot.setBackgroundPaint(new Color(bgRGB[0], bgRGB[1], bgRGB[2], chart.getBgAlpha()));
		}

        int[] paneRGB = chart.getPaneRGB();
        if (paneRGB != null) {
            jfchart.setBackgroundPaint(new Color(paneRGB[0], paneRGB[1], paneRGB[2], chart.getPaneAlpha()));
        }

		//callbacks for each area
		ChartRenderingInfo jfinfo = new ChartRenderingInfo();
		BufferedImage bi = jfchart.createBufferedImage(chart.getIntWidth(), chart.getIntHeight(), BufferedImage.TRANSLUCENT, jfinfo);
		
		//remove old areas 	
		chart.getChildren().clear();
		
		int j = 0;
		String preUrl = null;
		for(Iterator it=jfinfo.getEntityCollection().getEntities().iterator();it.hasNext();) {
			ChartEntity ce = ( ChartEntity ) it.next();
			final String url = ce.getURLText();

			//workaround JFreeChart's bug (skip replicate areas)
			if (url != null) { 
				if (preUrl == null) {
					preUrl = url;
				} else if (url.equals(preUrl)) { //start replicate, skip
					break;
				}
			}
			
			Area area = new Area();
			area.setParent(chart);
		 	area.setCoords(ce.getShapeCoords());
		 	area.setShape(ce.getShapeType());
		    area.setId("area_"+chart.getId()+'_'+(j++));
		    if (chart.isShowTooltiptext() && ce.getToolTipText() != null) {
		    	area.setTooltiptext(ce.getToolTipText());
		    }
		    area.setAttribute("url", ce.getURLText());
		    impl.render(chart, area, ce);
			if (chart.getAreaListener() != null) {
				try {
					chart.getAreaListener().onRender(area, ce);
				} catch (Exception ex) {
					throw UiException.Aide.wrap(ex);
				}
			}
		}
		
		//clean up the "LEGEND_SEQ"
		//used for workaround LegendItemEntity.getSeries() always return 0
		//used for workaround TickLabelEntity no information
	    chart.removeAttribute("LEGEND_SEQ"); 
	    chart.removeAttribute("TICK_SEQ"); 

		try {		
			//encode into png image format byte array
			return EncoderUtil.encode(bi, ImageFormat.PNG, true);
		} catch(java.io.IOException ex) {
			throw UiException.Aide.wrap(ex);
		}
	}
	
	//-- utilities --//
	/**
	 * transfer a PieModel into JFreeChart PieDataset.
	 */
	private PieDataset PieModelToPieDataset(PieModel model) {
		DefaultPieDataset dataset = new DefaultPieDataset();
		for (final Iterator it = model.getCategories().iterator(); it.hasNext();) {
			Comparable category = (Comparable) it.next();
			Number value = model.getValue(category);
			dataset.setValue(category, value);
		}
		return dataset;
	}

	/**
	 * transfer a CategoryModel into JFreeChart PieDataset.
	 */
	private PieDataset CategoryModelToPieDataset(CategoryModel model) {
		DefaultPieDataset dataset = new DefaultPieDataset();
		Comparable defaultSeries = null;
		int max = 0;
		for (final Iterator it = model.getKeys().iterator(); it.hasNext();) {
			final List key = (List) it.next();
			Comparable series = (Comparable) key.get(0);
			if (defaultSeries == null) {
				defaultSeries = series;
				max = model.getCategories().size();
			}
			if (!Objects.equals(defaultSeries, series)) {
				continue;
			}
			Comparable category = (Comparable) key.get(1);
			Number value = (Number) model.getValue(series, category);
			dataset.setValue(category, value);

			if (--max == 0) break; //no more in this series
		}
		return dataset;
	}

	/**
	 * transfer a CategoryModel into JFreeChart CategoryDataset.
	 */
	private CategoryDataset CategoryModelToCategoryDataset(CategoryModel model) {
		DefaultCategoryDataset dataset = new DefaultCategoryDataset();
		for (final Iterator it = model.getKeys().iterator(); it.hasNext();) {
			final List key = (List) it.next();
			Comparable series = (Comparable) key.get(0);
			Comparable category = (Comparable) key.get(1);
			Number value = (Number) model.getValue(series, category);
			dataset.setValue(value, series, category);
		}
		return dataset;
	}

	/**
	 * transfer a XYModel into JFreeChart XYSeriesCollection.
	 */
	private XYDataset XYModelToXYDataset(XYModel model) {
		XYSeriesCollection dataset = new XYSeriesCollection();
		for (final Iterator it = model.getSeries().iterator(); it.hasNext();) {
			final Comparable series = (Comparable) it.next();
			XYSeries xyser = new XYSeries(series, model.isAutoSort());
			final int size = model.getDataCount(series);
			for(int j = 0; j < size; ++j) {
				xyser.add(model.getX(series, j), model.getY(series, j), false);
			}
			dataset.addSeries(xyser);
		}
		return dataset;
	}

	/**
	 * transfer a XYModel into JFreeChart DefaultTableXYDataset.
	 */
	private TableXYDataset XYModelToTableXYDataset(XYModel model) {
		DefaultTableXYDataset dataset = new DefaultTableXYDataset();
		for (final Iterator it = model.getSeries().iterator(); it.hasNext();) {
			final Comparable series = (Comparable) it.next();
			XYSeries xyser = new XYSeries(series, false, false);
			final int size = model.getDataCount(series);
			for(int j = 0; j < size; ++j) {
				xyser.add(model.getX(series, j), model.getY(series, j), false);
			}
			dataset.addSeries(xyser);
		}
		return dataset;
	}

	/**
	 * transfer a XYModel into JFreeChart TimeSeriesCollection.
	 */
	private XYDataset XYModelToTimeDataset(XYModel model, Chart chart) {
		TimeZone tz = chart.getTimeZone();
		if (tz == null) tz = TimeZones.getCurrent();
		String p = chart.getPeriod();
		if (p == null) p = Chart.MILLISECOND;
		Class pclass = (Class) _periodMap.get(p);
		if (pclass == null) {
			throw new UiException("Unsupported period for Time Series chart: "+p);
		}
		TimeSeriesCollection dataset = new TimeSeriesCollection(tz);
		
		for (final Iterator it = model.getSeries().iterator(); it.hasNext();) {
			final Comparable series = (Comparable) it.next();
			final org.jfree.data.time.TimeSeries tser = 
						new org.jfree.data.time.TimeSeries((String)series, pclass);
			final int size = model.getDataCount(series);
			for(int j = 0; j < size; ++j) {
				final RegularTimePeriod period = RegularTimePeriod.createInstance(
					pclass, new Date(model.getX(series, j).longValue()), tz);
				tser.addOrUpdate(period, model.getY(series, j));
			}
			dataset.addSeries(tser);
		}
		return dataset;
	}

	private static Map _periodMap = new HashMap(10);	
	static {
		_periodMap.put(Chart.MILLISECOND, org.jfree.data.time.Millisecond.class);
		_periodMap.put(Chart.SECOND, org.jfree.data.time.Second.class);
		_periodMap.put(Chart.MINUTE, org.jfree.data.time.Minute.class);
		_periodMap.put(Chart.HOUR, org.jfree.data.time.Hour.class);
		_periodMap.put(Chart.DAY, org.jfree.data.time.Day.class);
		_periodMap.put(Chart.WEEK, org.jfree.data.time.Week.class);
		_periodMap.put(Chart.MONTH, org.jfree.data.time.Month.class);
		_periodMap.put(Chart.QUARTER, org.jfree.data.time.Quarter.class);
		_periodMap.put(Chart.YEAR, org.jfree.data.time.Year.class);
	}

	/**
	 * transfer a HiLoModel into JFreeChart DefaultOHLCDataset
	 */
	private OHLCDataset HiLoModelToOHLCDataset(HiLoModel model) {
		final int size = model.getDataCount();
		final OHLCDataItem[] items = new OHLCDataItem[size];
		
		for(int j = 0; j < size; ++j) {
			Date date = model.getDate(j);
			Number open = model.getOpen(j);
			Number high = model.getHigh(j);
			Number low = model.getLow(j);
			Number close = model.getClose(j);
			Number volume = model.getVolume(j);
			
			OHLCDataItem item = new OHLCDataItem(date, 
				doubleValue(open), doubleValue(high), 
				doubleValue(low), doubleValue(close), 
				doubleValue(volume));
			items[j] = item;
		}
		
		Comparable series = model.getSeries();
		if (series == null) {
			series = DEFAULT_HI_LO_SERIES;
		}
		return new DefaultOHLCDataset(series, items);
	}
	
	private double doubleValue(Number n) {
		return n == null ? 0.0 : n.doubleValue();
	}

	/**
	 * decode LegendItemEntity into key-value pair of Area's componentScope.
	 * @param area the Area where the final attribute is set
	 * @param info the LegendItemEntity to be decoded.
	 */
	private void decodeLegendInfo(Area area, LegendItemEntity info, Chart chart) {
		if (info == null) {
			return;
		}
		final ChartModel model = chart.getModel(); 
		final int seq = ((Integer)chart.getAttribute("LEGEND_SEQ")).intValue();
		
		if (model instanceof PieModel) {
			Comparable category = ((PieModel)model).getCategory(seq);
			area.setAttribute("category", category);
			area.setAttribute("value", ((PieModel)model).getValue(category));
		    if (chart.isShowTooltiptext() && info.getToolTipText() == null) {
		    	area.setTooltiptext(category.toString());
		    }
		} else if (model instanceof CategoryModel) {
			Comparable series = ((CategoryModel)model).getSeries(seq);
			area.setAttribute("series", series);
		    if (chart.isShowTooltiptext() && info.getToolTipText() == null) {
		    	area.setTooltiptext(series.toString());
		    }
		} else if (model instanceof XYModel) {
			Comparable series = ((XYModel)model).getSeries(seq);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -