📄 trendchart.java
字号:
/**
*
* $Id: TrendChart.java,v 1.2 2006/08/14 10:03:16 liulidong Exp $
*
*/
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.Vector;
public class TrendChart
extends java.awt.Canvas //Panel
{
/** interface bandwidth 在使用前在外部已经被赋初始值100*/
private int iBandWidth;
/** y轴的最大值also is bandwidth, default value 100M*/
private int iMaxY = 100;
/** color of the chart's background */
Color m_clrBkgnd = SystemColor.control;
/** color of the chart's grid */
Color m_clrGrid = SystemColor.controlShadow;
/** color of the dataset to be hilighted */
Color m_clrHighlight = SystemColor.controlText;
/** font to use for axis-Y labels */
//Font m_font = new Font("Dialog", Font.PLAIN, 11);
/** # of horizontals in the grid */
int m_iHors = 10;
/** # of verticals in the grid */
int m_iVers = 16;
/** # of reading point per tick of
* 一个x刻度被分成4等份
* axis-X */
int m_iReadingsPerTick = 4;
/** # of data channels - can be set through API */
int m_iMaxChannels = 2;
/** channel to be highlighted,
should be 0 <= m_iHighlightChannel < m_iMaxChannels or -1 for none */
int m_iHighlightChannel = -1;
/**
* m_iMaxReadings 应该是当前范围最多能够容纳的点
*/
int m_iMaxReadings = (m_iVers * m_iReadingsPerTick) + 1;
//String m_counters[] = null;
/** array of colors used to plot data in the corresponding channel */
Color m_colors[/*m_iMaxChannels*/] = null;
int m_scale[/*m_iMaxChannels*/] = null; // (if > 0 then *) (if < 0 then /)
int m_iReading = 0;
int m_data[/*m_iMaxChannels*/][/*m_iMaxReadings*/] = null;
int m_xPoints[/*m_iMaxChannels*/][/*m_iMaxReadings*/];
int m_yPoints[/*m_iMaxChannels*/][/*m_iMaxReadings*/];
// Listeners.
// private Vector m_actionListeners = new Vector();
public TrendChart()
{
setColors(null, null, null);
// font to use for axis-Y labels
setFont(new Font("Dialog", Font.PLAIN, 11));
// enableEvents(java.awt.AWTEvent.MOUSE_EVENT_MASK);
}
public void setColors(Color clrBkgnd, Color clrGrid, Color clrHighlight)
{
if(clrBkgnd != null)
m_clrBkgnd = clrBkgnd;
if(clrGrid != null)
m_clrGrid = clrGrid;
if(clrHighlight != null)
m_clrHighlight = clrHighlight;
setBackground(m_clrBkgnd);
}
/**
* 在动态调用绘图之前,因为这些值在html tag中动态设置的,
* 在绘制折线图的之前已经调用了this method
* 通过iMaxChannels可以初步设定各个属性所需要的大小
* m_iMaxReadings的值是固定的,为什么要用一个2纬数组呢
* @param iMaxChannels
*/
public void setMaxChannels(int iMaxChannels)
{
m_iMaxChannels = iMaxChannels;
m_scale = new int[m_iMaxChannels];
m_colors = new Color[m_iMaxChannels];
m_xPoints = new int[m_iMaxChannels][m_iMaxReadings];
m_yPoints = new int[m_iMaxChannels][m_iMaxReadings];
m_data = new int[m_iMaxChannels][m_iMaxReadings];
}
public int getMaxChannels()
{
return m_iMaxChannels;
}
/**
* 由此可见一个channel 的属性包括iScale,color
* @param iChannel
* @param cntr //这个参数没有用到阿
* @param iScale
* @param clr
*/
public void setChannel(int iChannel, int iScale, Color clr)
{
if(iScale == 0)
iScale = 1;
m_scale[iChannel] = iScale;
if(clr == null)
{
// pick color automagically
if(m_iDefaultColor > defaultColors.length)
clr = m_clrGrid;
else
{
int iRGB = Integer.parseInt(defaultColors[m_iDefaultColor++], 16);
clr = new Color(iRGB);
}
}
m_colors[iChannel] = clr;
}
/**
* 根据给定的channel号,得到channel的颜色
* @param iChannel
* @return
*/
public Color getChannelColor(int iChannel)
{
return m_colors[iChannel];
}
/**
* 看来scale 也是某个Channel的属性,但是scale 到底是channel
* 的什么属性呢
* @param iChannel
* @return
*/
public int getChannelScale(int iChannel)
{
return m_scale[iChannel];
}
/**
* 因为是多个channel,把这多个channel的scale放在一个数组中
* 看来scale的设置 对整个图形的外观有影响,因此可以通过改变m_scale[i]
* 的值 看的到的图形有什么变化
* @param iChannel
* @param iScale
*/
public void setChannelScale(int iChannel, int iScale)
{
m_scale[iChannel] = iScale;
paint(getGraphics());
}
/**
* 设置最大带宽
*/
public void setBandWidth(int bandWidth){
this.iBandWidth = bandWidth;
}
/**
* highlight this channel.
* if iChannel < 0, highlight will be removed
* hightlight显示的效果是什么?
* 在我们的程序中没有用到highlight功能
* 在原来的程序中,有一个功能是根据选择的图例,highlight某个channel
*/
public void highlight(int iChannel)
{
m_iHighlightChannel = iChannel;
paint(getGraphics());
}
/**
* 假如新的数据,并刷新图形
* @param tuple
*/
public void addReading(int tuple[])
{
int iWrite = m_iReading % m_iMaxReadings;
int iMaxChannels = m_iMaxChannels;
if(iMaxChannels > tuple.length)
iMaxChannels = tuple.length;
/**
* 把每条线的数据依次给不同的数组 ,然后所有折线一起绘制
*/
for(int iChannel = 0; iChannel < iMaxChannels; iChannel++)
{
m_data[iChannel][iWrite] = tuple[iChannel];//看示意图
}
/**
* 每调用this method一次,m_iReading值增加一
* m_data2维数组的变化
*/
m_iReading++;
paint(getGraphics());
}
/**
* override update to *not* erase the background
* before painting
* 这些是继承的方法
*/
public void update(Graphics g)
{
paint(g);
}
/** offscreen drawing support */
Image m_imageOffscr;
/**
* null out the offscreen buffer as part of invalidation
* 该函数标志当前的component为无效
* This component and all parents
* above it are marked as needing to be laid out.
*/
public void invalidate()
{
super.invalidate();
if(m_imageOffscr != null) {
m_imageOffscr.flush();
m_imageOffscr = null;
}
}
/**
* 覆盖该方法,绘制组件
*/
public synchronized void paint(Graphics g)
{
Dimension dim = getSize();
if(m_imageOffscr == null)
{
m_imageOffscr = createImage(dim.width, dim.height);
}
// save m_imageOffscr locally and use this copy
// - invalidate can be called while we are painting!
Image imageOffscr = m_imageOffscr;
if(imageOffscr != null) {
Graphics og = imageOffscr.getGraphics();
paintInternal(og, dim);
g.drawImage(imageOffscr, 0, 0, null);
og.dispose();
}
}
private void paintInternal(Graphics g, Dimension dimChart)
{
// clear background
g.setColor(m_clrBkgnd);
g.fillRect(0, 0, dimChart.width, dimChart.height);
//g.setFont(m_font);
FontMetrics fm = g.getFontMetrics();
int iHeaderFooterHeight = fm.getAscent();
int iLegendYWidth = fm.stringWidth("10000M");
int iRightGapWidth = 2;//iHeaderFooterHeight;
int dy = (dimChart.height - iHeaderFooterHeight) / m_iHors;
int iDataHeight = m_iHors * dy;
int iDataTop = (dimChart.height - iDataHeight) / 2;
int iDataBot = iDataTop + iDataHeight;
//dx是x轴 每个单位刻度的长度
int dx = (dimChart.width - iLegendYWidth - iRightGapWidth) / m_iVers;
int iDataWidth = dx * m_iVers;
int iDataLeft = iLegendYWidth;
int iDataRight = iDataLeft + iDataWidth;
int iGridLeft = iDataLeft;
boolean bFirstPass = (m_iReading < m_iMaxReadings);
if(!bFirstPass)//如果读入的点数大于等于能容纳的点数
{
int i = m_iReading % m_iReadingsPerTick;
if(i != 0)
iGridLeft += dx - ((dx * i)/ m_iReadingsPerTick);
}
// draw the grid
g.setColor(m_clrGrid);
for(int y = iDataTop; y <= iDataBot; y += dy)
g.drawLine(iDataLeft, y, iDataRight, y);
for(int x = iGridLeft; x <= iDataRight; x += dx)
g.drawLine(x, iDataTop, x, iDataTop + iDataHeight);
//
// draw Y-axis legend (图例)
//y-axis
//
{
iMaxY = iBandWidth;
// if(m_iHighlightChannel >= 0)
// {
// int iScale = m_scale[m_iHighlightChannel];
// if(iScale > 0)
// iMaxY = iMaxY / iScale;
// else
// iMaxY = iMaxY * (- iScale);
// g.setColor(m_clrHighlight);
// }
String scale = "";
if(iMaxY >= 10000000) {
iMaxY /= 1000000;
scale = "M";
} else if(iMaxY >= 10000) {
iMaxY /= 1000;
scale = "K";
}
drawStringRightAligned(g, fm, iMaxY+scale+" ", iDataLeft, iDataTop + (iHeaderFooterHeight / 2));
drawStringRightAligned(g, fm, (iMaxY / 2)+scale+" ", iDataLeft, (iDataBot + iDataTop + iHeaderFooterHeight)/2);
drawStringRightAligned(g, fm, "0 ", iDataLeft, iDataBot + (iHeaderFooterHeight / 2));
}
/**绘制x轴图例*/
// g.drawRect(iGridLeft + dx/2,iDataBot + 1,dx,dy/2);
// g.setColor(Color.blue);
// g.fillRect(iGridLeft + dx/2,iDataBot + 1,dx,dy/2);
// g.setColor(Color.black);
// g.drawString("流入",iGridLeft + 2*dx,iDataBot + 10);
//
// output data
//
int iWrite = m_iReading % m_iMaxReadings;
dx = iDataWidth / (m_iMaxReadings - 1);
for(int iChannel = 0; iChannel < m_iMaxChannels; iChannel++)
{
g.setColor((iChannel == m_iHighlightChannel) ? m_clrHighlight : m_colors[iChannel]);
int iScale = m_scale[iChannel];
/**
* 在65个点范围内绘图,与在取到65个点之外绘图的算法是不一样的
*
*/
if(bFirstPass)
{
//
// output data between 0 and iWrite
//
for(int iReading = 0; iReading < iWrite; iReading++)
{
m_xPoints[iChannel][iReading] = iDataLeft +
((iReading * iDataWidth) / (m_iMaxReadings - 1));
// do map conversion from m_data[iChannel] to m_yPoints
int val = (iScale > 0)
? (m_data[iChannel][iReading] * iScale)
: (m_data[iChannel][iReading] / (-iScale));
if(val < 0)
val = 0;
else if(val > 100)
val = 100;
m_yPoints[iChannel][iReading] =
iDataTop + iDataHeight - (val * iDataHeight / 100);
}
g.drawPolyline(m_xPoints[iChannel], m_yPoints[iChannel], iWrite);
if(iChannel == m_iHighlightChannel)
{
for(int iReading = 0; iReading < iWrite; iReading++)
m_yPoints[iChannel][iReading]--;
g.drawPolyline(m_xPoints[iChannel], m_yPoints[iChannel], iWrite);
}
}
else
{
// output data between iWrite and m_iMaxReadings
int iX = 0;
for(;;iX++)
{
int iReading = iWrite + iX;
if(iReading >= m_iMaxReadings)
break;
m_xPoints[iChannel][iX] = iDataLeft +
((iX * iDataWidth) / (m_iMaxReadings - 1));
// do map conversion from m_data[iChannel] to m_yPoints
int val = (iScale > 0)
? (m_data[iChannel][iReading] * iScale)
: (m_data[iChannel][iReading] / (-iScale));
if(val < 0)
val = 0;
else if(val > 100)
val = 100;
m_yPoints[iChannel][iX] =
iDataTop + iDataHeight - ((val * iDataHeight) / 100);
}
// then betw 0 and iWrite
for(;;iX++)
{
int iReading = iX - (m_iMaxReadings - iWrite);
if(iReading >= iWrite)
break;
m_xPoints[iChannel][iX] = iDataLeft +
((iX * iDataWidth) / (m_iMaxReadings - 1));
// do map conversion from m_data[iChannel] to m_yPoints
int val = (iScale > 0)
? (m_data[iChannel][iReading] * iScale)
: (m_data[iChannel][iReading] / (-iScale));
if(val < 0)
val = 0;
else if(val > 100)
val = 100;
m_yPoints[iChannel][iX] =
iDataTop + iDataHeight - ((val * iDataHeight) / 100);
}
g.drawPolyline(m_xPoints[iChannel], m_yPoints[iChannel], m_iMaxReadings);
if(iChannel == m_iHighlightChannel)
{
for(int iReading = 0; iReading < m_iMaxReadings; iReading++)
m_yPoints[iChannel][iReading]--;
g.drawPolyline(m_xPoints[iChannel], m_yPoints[iChannel], m_iMaxReadings);
}
}
}
}
private void drawStringRightAligned(Graphics g, FontMetrics fm, String str, int x, int y)
{
int iWidth = fm.stringWidth(str);
g.drawString(str, x - iWidth, y);
}
/**
* Add a listener to recieve action events when user double clicks the charts
*
* @param actionListener An action listener object.
* @see #removeActionListener(ActionListener)
*/
// public void addActionListener(ActionListener actionListener)
// {
// m_actionListeners.addElement(actionListener);
// }
/**
* Remove the specified action listener.
* @see #addActionListener(ActionListener)
*/
// public void removeActionListener(ActionListener actionListener)
// {
// m_actionListeners.removeElement(actionListener);
// }
/**
*
*/
// void fireActionEvent()
// {
// ActionEvent ae = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, null);
// for(int i = 0; i < m_actionListeners.size(); i++)
// ((ActionListener)m_actionListeners.elementAt(i)).actionPerformed(ae);
// }
//
/**
* if the counter's color is not specified, we will choose from
* one of the following
*/
static private final String defaultColors[] = {
"FF0000", "00C000", "0000FF",
"FFFF00", "00FF00", "00FFFF",
"FF00FF", "00C000", "00C0C0",
"C00000", "00FF00", "0000C0"
};
/** index into defaultColors */
private int m_iDefaultColor = 0;
/** debugging utility */
/*void TRACE(String msg)
{
System.out.println("[" + Thread.currentThread().getName() + "] " +
getClass().getName() + "@" + hashCode()
+ ": " + msg);
}*/
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -