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

📄 trendchart.java

📁 This code is trend chart for realtime monitor
💻 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 + -