📄 chart.java
字号:
package net.sf.dz.util.chart;import java.awt.BasicStroke;import java.awt.Color;import java.awt.Dimension;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.GridBagConstraints;import java.awt.GridBagLayout;import java.awt.Font;import java.awt.Insets;import java.awt.Paint;import java.awt.Stroke;import java.awt.geom.Line2D;import java.awt.geom.Rectangle2D;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import javax.swing.BorderFactory;import javax.swing.JPanel;import javax.swing.border.BevelBorder;import net.sf.dz.controller.DataSet;/** * Chart, revisited. * * @author Copyright © <a href="mailto:vt@freehold.crocodile.org">Vadim Tkachenko</a> 2001-2002 * @version $Id: Chart.java,v 1.19 2004/01/23 07:33:05 vtt Exp $ */public class Chart extends JPanel { /** * The legend font size. * * VT: FIXME: This better be configurable, and retrieved from the actual font. */ public static final int FONT_SIZE = 10; /** * The legend font. */ public static final Font smallFont = new Font("Courier", Font.PLAIN, FONT_SIZE); /** * The chart legend. */ private List legend; /** * The chart data. */ private Map name2data = new HashMap(); /** * The chart colors. */ private Map name2color = new HashMap(); /** * Chart length, in milliseconds. * * Default is 30 minutes. */ private long chartLength; /** * Dead timeout, in milliseconds. * * It is possible that the data readings don't come for a long time, in * this case the chart becomes funny - there will be interruptions at * the right, but when the data becomes available quite a bit longer, * there'll be a change in appearance - what should have been a * horizontal line with a step, will become a slightly sloped line. In * order to avoid this, the gaps longer than the dead timeout will be * painted differently. * * <p> * * Default is 10 seconds. */ private long deadTimeout = 1000 * 10; /** * Horizontal grid spacing. * * Vertical grid lines will be painted every <code>timeSpacing</code> * milliseconds. Default is 5 minutes. */ private long timeSpacing = 1000 * 60 * 5; /** * Vertical grid spacing. * * Horizontal grid lines will be painted every <code>valueSpacing</code> * units. Default is 1.0. */ private double valueSpacing = 1.0; /** * Grid color. * * Default is dark gray. */ private Color gridColor = Color.darkGray; /** * Background color. * * Default is black. */ private Color bgColor = Color.black; /** * Top limit. * * This limit is represented in the data coordinate space. */ private Double chartTop = null; /** * Bottom limit. * * This limit is represented in the data coordinate space. */ private Double chartBottom = null; /** * The chart itself. */ private TheChart theChart = new TheChart(); /** * The repaint thread. * * Keeps repainting the chart if there's no new data coming - otherwise * it will not change. */ private Thread up2date; /** * Last update time. * * Modified by {@link #record record()}. */ private long lastUpdate; public Chart() { // 30 minutes this(1000 * 60 * 30); } public Chart(long chartLength) { // VT: FIXME: Check the value this.chartLength = chartLength; GridBagLayout layout = new GridBagLayout(); GridBagConstraints cs = new GridBagConstraints(); setLayout(layout); cs.fill = GridBagConstraints.BOTH; cs.weightx = 1; cs.weighty = 1; layout.setConstraints(theChart, cs); add(theChart); startRepainter(); } /** * Create the repainter thread. */ private Thread createRepainter() { Runnable repainter = new Runnable() { public void run() { long timeout = deadTimeout/2; while ( true ) { try { Thread.sleep(timeout); } catch ( InterruptedException iex ) { // Somebody wants us to stop? if ( up2date == null ) { return; } } long now = System.currentTimeMillis(); if ( now - lastUpdate > deadTimeout ) { invalidate(); repaint(); } timeout = deadTimeout - (now - lastUpdate); if ( timeout <= 0 ) { // This is not so uncommon 'cause we don't exactly // do rocket science here timeout = deadTimeout/2; } } } }; return new Thread(repainter); } /** * Start the repaint thread. */ private synchronized void startRepainter() { if ( up2date != null ) { stopRepainter(); } up2date = createRepainter(); up2date.start(); } /** * Stop the repaint thread. */ private synchronized void stopRepainter() { if ( up2date == null ) { return; } Thread t = up2date; up2date = null; t.interrupt(); } public void finalize() throws Throwable { stopRepainter(); } public void setVisible(boolean visible) { synchronized ( this ) { if ( visible ) { startRepainter(); } else { stopRepainter(); } } super.setVisible(visible); } public void removeNotify() { stopRepainter(); } public void setBackground(Color bgColor) { this.bgColor = bgColor; } public void setChartColors(Map colorMap) { if ( legend == null ) { throw new IllegalStateException("Can't set color map before legend"); } if ( colorMap == null ) { throw new IllegalArgumentException("Color map can't be null"); } for ( Iterator i = legend.iterator(); i.hasNext(); ) { Object key = i.next(); if ( colorMap.get(key) == null ) { throw new IllegalArgumentException("Missing color for '" + key + "'"); } } // We don't really care if there are extra colors this.name2color = colorMap; } public void setGridColor(Color gridColor) { this.gridColor = gridColor; } /** * Set the grid spacing. * * @param time Time spacing, in milliseconds. * * @param value Value spacing. */ public void setGridSpacing(long time, double value) { this.timeSpacing = time; this.valueSpacing = value; } /** * Set the legend for the chart. * * <p> * * This method has to be called before doing any rendering, because the * data to render will be {@link #record recorded} and extracted based * on the legend. * * <p> * * Moreover, this operation may be done just once - it will be simpler * to just discard the chart and create a new one than to reinitialize * everything. * * @param legend List of strings - names for the chart curves. This is * an ordered collection - the curves will be painted in the order the * names are specified, so make sure the order is the one you want. */ public synchronized void setLegend(List legend) { // Check if we already have a legend.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -