JAVA生成SVG图表实例之柱状图

类别:Java 点击:0 评论:0 推荐:

做系统的时候都要配合报表展示一些图表,例如柱状图、饼图还有曲线图,以前是用VML做成通用的,数值的计算和VML在页面上的显示,全部是用javascript做的,可是VML中的文字定位不是特别舒服,javascript计算数字也不是很精确。最近学了几天SVG,觉得不错,所以就想用JAVA生成SVG文件,然后显示,网上没有类似的文章,所以我就把自己的第一个作品放出来,希望大家能够提点向我提电意见,改进。我以后会陆续放做好的饼图、曲线图。我相信这是国内第一个类似的程序,希望能够起到抛砖引玉的作用。

这个程序能够生成单柱柱状图,也能生成多柱柱状图。我的注释写得相当的详细,相信大家都能看的懂。我没有使用APACHE的Batik来生成SVG文件,而是先组成字符串然后生成SVG文件。以下是源码,我做的时候是按照12组数据设计的,当数据少的话,柱子会很宽,我正在改进。

package com.hhh.Paint;

import java.io.File;
import java.io.FileOutputStream;
import java.math.BigDecimal;

/**
 * 该类是使用SVG画动态柱状图,只需调用本类的静态方法createSVG(String fileRealPath,String[]
 * pData,String[] pDataName)即可,我没有使用APACHE提供的SVG类库来生成SVG文件,只是将所有SVG描述用字符串返回
 *
 * @author 顾国勇
 * @version 1.0
 */
public class PaintHistogram {

 /**
  * 正值所用的12种颜色
  */
 public static String[][] color = { { "#ff2222", "#ffaaaa", "#aa1111" },
   { "#d0b83a", "#f2e692", "#9f8703" },
   { "#ffdf00", "#fef195", "#ce9a31" },
   { "#22FF22", "#aaffaa", "green" },
   { "#ff9e00", "#ffbe08", "#bd7500" },
   { "#799AE1", "#9aabEe", "#5778a1" },
   { "#99c741", "#aef292", "#3e941b" },
   { "#d0b83a", "#f2e692", "#9f8703" },
   { "#319a00", "#66cc00", "#297110" },
   { "#c27f34", "#d6a97b", "#82522b" },
   { "#2222ff", "#aaaaff", "#1111aa" },
   { "#ff2222", "#ffaaaa", "#aa1111" } }; //,{"#99c741","#aef292","#3e941b"}

 /**
  * 负值所用的颜色
  */
 public static String[][] colorNeg = { { "black", "#4F4F4F", "#757575" },
   { "#1A0B0F", "#4F4F4F", "#757575" } };

 /**
  * 存放转换成double型的数据,用于单例柱形
  */
 public static double[] data;

 /**
  * 存放转换成double型的数据,用于多例柱形
  */
 public static double[][] data1;

 /**
  * 数据总数,默认值为0
  */
 public static int dataNum = 0;

 /**
  * 默认柱状图X轴的起始X值
  */
 public static double HistogramXSx = 50.0;

 /**
  * 默认柱状图X轴的Y值
  */
 public static double HistogramXy = 440.0;

 /**
  * 将元数据从String转换成double,用于单例柱形
  *
  * @param data
  *            字符串数组形式的元数据
  * @return 转换好的数据
  */
 static double[] convertDataToDouble(String[] data) {
  double[] dData = new double[data.length];
  dataNum = 0;
  for (int i = 0; i < data.length; i++) {
   if (data[i] != null && !data[i].equalsIgnoreCase("")
     && !data[i].equalsIgnoreCase(" ")) {
    dData[i] = Double.valueOf(data[i]).doubleValue();
    dataNum += 1;
   } else {
    dData[i] = new Double(0.0).doubleValue();
    dataNum += 1;
   }
  }
  return dData;
 }

 /**
  * 将元数据从String转换成double,用于多例柱形
  *
  * @param data
  *            字符串数组形式的元数据
  * @return 转换好的数据
  */
 static double[][] convertDataToDouble(String[][] data) {
  double[][] dData = new double[data.length][data[0].length];
  dataNum = 0;
  for (int i = 0; i < data.length; i++) {
   for (int j = 0; j < data[i].length; j++) {
    if (data[i][j] != null && !data[i][j].equalsIgnoreCase("")
      && !data[i][j].equalsIgnoreCase(" ")) {
     dData[i][j] = Double.parseDouble(data[i][j]);//Double.valueOf(data[i][j]).doubleValue();
     dataNum += 1;
    } else {
     dData[i][j] = new Double(0.0).doubleValue();
     dataNum += 1;
    }
   }
  }
  return dData;
 }

 /**
  * @param fileRealPath
  *            指定的SVG文件的全路径,用于单例柱形
  * @param pData
  *            元数据数组
  * @param pDataName
  *            元数据数组名称
  */
 public static void createSVG(String fileRealPath, String[] pData,
   String[] pDataName) throws Exception {
  String sFile = paint(pData, pDataName);
  try {
   byte[] byteFil = sFile.getBytes("UTF-8");
   File svgFile = new File(fileRealPath);
   if (svgFile.exists()) {
    svgFile.delete();
   }
   FileOutputStream fos = new FileOutputStream(svgFile);
   fos.write(byteFil);
   fos.close();
  } catch (Exception ex) {
   System.out.print(ex.getMessage());
  }

 }

 /**
  * @param fileRealPath
  *            指定的SVG文件的全路径,用于多例柱形
  * @param pData
  *            元数据数组
  * @param pDataName
  *            元数据数组名称
  */
 public static void createSVG(String fileRealPath, String[][] pData,
   String[] pDataName) {
  try {
   String sFile = paint(pData, pDataName);

   byte[] byteFil = sFile.getBytes("UTF-8");
   File svgFile = new File(fileRealPath);
   if (svgFile.exists()) {
    svgFile.delete();
   }
   FileOutputStream fos = new FileOutputStream(svgFile);
   fos.write(byteFil);
   fos.close();
  } catch (Exception ex) {
   System.out.print("createSVG:" + ex.getMessage());
  }

 }

 /**
  * 根据原始数据过滤出最大最小值,已经考虑了数据正负的各种情况(全是正数,全是负数,有正有负),如果元数据中最大值或最小值的绝对值是小于1的,那最后返回的相应值的绝对值是1;
  * 如果最大或最小的绝对值小于100,那最后返回的相应值的绝对值是10的倍数;如果最大或最小的绝对值大于100,那最后返回的相应值的绝对值是50的倍数
  *
  * @param data
  *            <B>原始数据 </B>
  * @return <B>包含绝对值最大的值 </B>
  */
 static double getValueMax(double[] pData) {
  //存放所有数据值
  double max = pData[0];
  double min = pData[0];

  for (int i = 0; i < pData.length; i++) {
   if (pData[i] > max)
    max = pData[i];
   if (pData[i] < min)
    min = pData[i];
  }

  //全是负的
  if (max <= 0 && min < 0) {
   min = Math.floor(min);
   double tMin = Math.abs(min);
   max = 0;
   if (tMin <= 1)
    min = -1;
   else {
    min = -(tMin < 100 ? Math.ceil(tMin / 10) * 10 : Math
      .ceil(tMin / 50) * 50);
   }
  }
  //有正有负
  if (min < 0 && max > 0) {
   max = Math.ceil(max);
   if (max <= 1)
    max = 1;
   else {
    max = max < 100 ? Math.ceil(max / 10) * 10 : Math
      .ceil(max / 50) * 50;
   }

   min = Math.abs(Math.floor(min));
   if (min <= 1)
    min = -1;
   else {
    min = -(min < 100 ? Math.ceil(min / 10) * 10 : Math
      .ceil(min / 50) * 50);
   }
  }
  //全是正的
  if (min >= 0 && max >= 0) {
   if (max == 0.0) {
    max = min = 0.0;
   } else {
    if (max <= 1)
     max = 1;
    else {
     max = max < 100 ? Math.ceil(max / 10) * 10 : Math
       .ceil(max / 50) * 50;
    }
   }
  }

  double absMax = Math.abs(max) > Math.abs(min) ? Math.abs(max) : Math
    .abs(min);
  return absMax;
 }

 /**
  * 类初始化,主要是声明了文件开头和滤镜,对于画正负Y轴都通用
  *
  * @return SVG文件头
  */
 static String initialize() {
  //文件头声明
  StringBuffer sFile = new StringBuffer();
  sFile.append("<?xml version='1.0' encoding='UTF-8'?>");
  sFile.append("\n");
  sFile
    .append("<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN' 'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'>");
  sFile.append("\n");
  sFile
    .append("<svg width='700' height='500' viewBox='0 0 700 500' xmlns='http://www.w3.org/2000/svg'>");
  sFile.append("\n");
  sFile.append("<desc>Histogram</desc>");
  sFile.append("\n");
  sFile
    .append("<rect x='0' y='0' width='700' height='500' fill='none' stroke='blue' stroke-width='1'/>");
  sFile.append("\n");
  //定义滤镜和箭头
  sFile.append("<defs>");
  sFile.append("\n");
  sFile
    .append("  <marker id='Triangle' viewBox='0 0 10 10' refX='0' refY='5' markerUnits='strokeWidth' markerWidth='4' markerHeight='10' orient='auto'>");
  sFile.append("\n");
  sFile.append("   <path d='M 0 0 L 10 5 L 0 10 z'/>");
  sFile.append("\n");
  sFile.append("  </marker>");
  sFile.append("\n");
  sFile.append("  <linearGradient id='linear1'>");
  sFile.append("\n");
  sFile.append("     <stop offset='0%' stop-color='red'/>");
  sFile.append("\n");
  sFile.append("       <stop offset='30%' stop-color='white'/>");
  sFile.append("\n");
  sFile.append("       <stop offset='100%' stop-color='blue'/>");
  sFile.append("\n");
  sFile.append("    </linearGradient>");
  sFile.append("\n");
  sFile
    .append("    <filter id='MyFilter' filterUnits='userSpaceOnUse' x='0' y='0' width='100%' height='100%'>");
  sFile.append("\n");
  sFile
    .append("   <feGaussianBlur in='SourceAlpha' stdDeviation='3' result='blur'/>");
  sFile.append("\n");
  sFile
    .append("   <feOffset in='blur' dx='4' dy='4' result='offsetBlur'/>");
  sFile.append("\n");
  sFile.append("\n");
  sFile
    .append("   <feSpecularLighting in='blur' surfaceScale='.5' specularConstant='2.5' specularExponent='128' lighting-color='#bbbbbb'  result='specOut'>");
  sFile.append("\n");
  sFile.append("    <fePointLight x='-600' y='-100' z='2200'/>");
  sFile.append("\n");
  sFile.append("   </feSpecularLighting>");
  sFile.append("\n");
  sFile
    .append("   <feComposite in='specOut' in2='SourceAlpha' operator='in' result='specOut'/>");
  sFile.append("\n");
  sFile
    .append("   <feComposite in='SourceGraphic' in2='specOut' operator='arithmetic' k1='0' k2='1' k3='1' k4='0' result='litPaint'/>");
  sFile.append("\n");
  sFile.append("   <feMerge>");
  sFile.append("\n");
  sFile.append("      <feMergeNode in='offsetBlur'/>");
  sFile.append("\n");
  sFile.append("        <feMergeNode in='litPaint'/>");
  sFile.append("\n");
  sFile.append("   </feMerge>");
  sFile.append("\n");
  sFile.append("  </filter>");
  sFile.append("\n");
  sFile.append("<script type=\"text/javascript\">");
  sFile.append("\n");
  sFile.append("<![CDATA[");
  sFile.append("\n");
  sFile.append("       function showValue(value) {");
  sFile.append("\n");
  sFile.append("        alert(value);");
  sFile.append("\n");
  sFile.append("       }");
  sFile.append("\n");
  sFile.append("]]>");
  sFile.append("\n");
  sFile.append("</script>");
  sFile.append("\n");
  sFile.append("</defs>");
  sFile.append("\n");
  //X轴
  sFile
    .append("<line x1='50' y1='440' x2='660' y2='440' stroke-width='2' stroke-opacity='.4' fill='blue' stroke='#333300' />");
  sFile.append("\n");
  //Y轴
  sFile
    .append("<line x1='50' y1='440' x2='50' y2='40' stroke-width='2' stroke-opacity='.4' fill='blue' stroke='#333300' />");
  sFile.append("\n");
  sFile
    .append("<line x1='60' y1='30' x2='60' y2='430' stroke-width='0.5'  stroke='#333300'/>");
  /* Y轴刻度线 */
  for (int i = 0; i < 11; i++) {
   double tempY1 = 40 + i * 40.0; //每根Y轴刻度线的起始位置
   sFile.append("<line  x1='50' y1='" + tempY1 + "' x2='60' y2='"
     + (tempY1 - 10) + "' stroke-width='1'  stroke='#333300'/>");
   sFile.append("<line x1='60' y1='" + (tempY1 - 10)
     + "' x2='670' y2='" + (tempY1 - 10)
     + "' stroke='#333300'/>");
   sFile.append("\n");
   //            sFile.append("<polygon points='50," + tempY1 + " 660," + tempY1
   //                    + " 670," + (tempY1 - 10) + " 60," + (tempY1 - 10)
   //                    + " ' ");
   //            sFile
   //            .append("
   // style='fill:rgb(37,170,219);stroke:rgb(37,170,219);stroke-width:1;fill-opacity:0.3;stroke-opacity:0;opacity:0.8'/>");
   //            sFile.append("\n");
  }

  return sFile.toString();

 }

 /**
  * @param args
  */
 public static void main(String[] args) {
  try {
   String[][] data = { { "54", "44", "122" }, { "", "12", "-468" },
     { "78", "520", "10" } };
   String[] data1 = { "54", "4424.225", "12200" ,"-4658" };

   String[] dataName = { "营业所一", "二二二二", "III" };
   PaintHistogram.createSVG("d:\\t1.svg", data, dataName);
   PaintHistogram.createSVG("d:\\t2.svg", data1, dataName);

  } catch (Exception ex) {
   System.out.print(ex.getMessage());
  }
 }

 /**
  * 画出柱状及刻度等,适用于X轴每格都只显示一个柱型
  *
  * @param pData
  *            元数据
  * @param pDataName
  *            元数据的名称
  */
 static String paint(String[] pData, String[] pDataName) throws Exception {
  StringBuffer sFile = new StringBuffer();
  data = convertDataToDouble(pData);

  double valueMM = getValueMax(data); //取得最大值
  sFile.append(initialize());
  //X Y步长
  double yStep = 400.0 / valueMM;
  double xStep = (new BigDecimal(600 / pDataName.length).setScale(3,
    BigDecimal.ROUND_HALF_UP)).doubleValue();

  double colWidth = xStep / 2; //柱型的宽度

  double colWidthPre = xStep / 4; //每个单元格起始与柱型的距离

  double colWidthNext = xStep / 4; //每个单元格结束与柱型的距离
  /* x轴刻度线 */
  for (int i = 0; i < pDataName.length; i++) {

   double tempX1 = i == 0 ? HistogramXSx + i * xStep : HistogramXSx
     + i * xStep + 10; //每根X轴刻度线的起始位置

   //double tempX2 = tempX1 + colWidthPre; //每根柱状的起始位置
   sFile.append("<line x1='" + tempX1 + "' y1='" + HistogramXy
     + "' x2='" + (tempX1 + 10.0) + "' y2='"
     + (HistogramXy - 10)
     + "' stroke-width='1'  stroke='#333300'/>");
   sFile.append("\n");
  }

  /* 画Y轴刻度值 */
  int maxValue = (int) valueMM;
  int valueX; //Y轴刻度值起始的X坐标
  String fontsize = "";
  if (maxValue > 10000) {
   valueX = 5;
   fontsize = "11px";
  } else {
   valueX = 15;
   fontsize = "13px";
  }
  for (int i = 0; i < 10; i++) {
   sFile.append("<text x='" + valueX + "' y='" + (45 + i * 40)
     + "' fill='black' font-family='Verdana' font-size='"
     + fontsize + "'>");
   sFile.append("\n");
   sFile.append((maxValue / 10) * (10 - i));
   sFile.append("\n");
   sFile.append("</text>");
   sFile.append("\n");
  }

  /* 画矩形 */
  sFile.append("<g style='filter:url(#MyFilter)'>");
  sFile.append("\n");
  for (int i = 0; i < pDataName.length; i++) {

   double tempX1 = i == 0 ? HistogramXSx + i * xStep : HistogramXSx
     + i * xStep + 10; //每根X轴刻度线的起始位置

   double tempX2 = tempX1 + colWidthPre; //每根柱状的起始位置
   double colHeight = Math.ceil(Math.abs(data[i]) * yStep);
   double tempY = 440 - colHeight;

   String[] colorHistogram; //三个柱面的颜色
   if (data[i] < 0) {
    colorHistogram = colorNeg[0];
    sFile.append(paintHistogram(colWidth, colHeight, tempX2, tempY,
      colorHistogram, data[i]));
   } else if (data[i] > 0) {
    int n = i % color.length;
    colorHistogram = color[n];
    sFile.append(paintHistogram(colWidth, colHeight, tempX2, tempY,
      colorHistogram, data[i]));
   }

   /* 添加X轴字段说明 字无法在一行内显示的话,需要换行 */
   int n = (int) xStep / 13;//每行显示几个字符
   int m = pDataName[i].length() % n == 0 ? pDataName[i].length() / n
     : (int) (pDataName[i].length() / n + 1);//总共显示几行
   int l = 0;//记录总共处理了多少字符
   if (m > 1) {
    sFile
      .append("<text fill='blue' font-size='15px' font-family='STFangsong'>");
    for (int j = 0; j < m; j++) {
     for (int z = 0; z < n; z++) {
      l = j * n + z;
      if (l == pDataName[i].length()) {
       break;
      }
      sFile.append("<tspan x='" + (tempX1 + z * 15) + "' y='"
        + (460 + j * 20) + "' >");
      sFile.append(pDataName[i].substring(l, l + 1));
      sFile.append("</tspan>");
     }
     if (l == pDataName[i].length()) {
      break;
     }
    }
    sFile.append("</text>");
    sFile.append("\n");
   } else {
    sFile
      .append("<text x='"
        + (5 + tempX1)
        + "' y='460' fill='blue' font-size='15px' font-family='STFangsong'>"
        + pDataName[i] + "</text>");
    sFile.append("\n");
   }
  }
  sFile.append("</g>");
  sFile.append("\n");
  sFile.append("</svg>");
  return sFile.toString();

 }

 /**
  * 画出柱状及刻度等,适用于X轴每格都显示多个柱型
  *
  * @param pData
  *            具体的元数据
  * @param pDataName
  *            元数据的名称
  */
 static String paint(String[][] pData, String[] pDataName) {
  StringBuffer sFile = new StringBuffer();
  data1 = convertDataToDouble(pData);
  //取得最大值

  double[] tempValue = new double[dataNum];
  for (int i = 0; i < data1.length; i++) {
   for (int j = 0; j < data1[i].length; j++) {
    tempValue[i * data1[i].length + j] = data1[i][j];
   }
  }
  double valueMM = getValueMax(tempValue);
  sFile.append(initialize());
  double yStep = 400.0 / valueMM;
  double xStep = (new BigDecimal(600 / pDataName.length).setScale(3,
    BigDecimal.ROUND_HALF_UP)).doubleValue();

  double colWidthSum = xStep / 2; //多个柱型的宽度之和
  double colWidthPre = xStep / 4; //每个单元格起始与柱形的距离
  double colWidthNext = xStep / 4; //每个单元格结束与柱形的距离
  double colWidth = colWidthSum / data1[0].length; //单个柱形的宽度

  /* x轴刻度线 */
  for (int i = 0; i < pDataName.length; i++) {
   double tempX1 = i == 0 ? HistogramXSx + i * xStep : HistogramXSx
     + i * xStep + 10; //每根X轴刻度线的起始位置
   //double tempX2 = tempX1 + colWidthPre; //每根柱形的起始位置
   sFile.append("<line x1='" + tempX1 + "' y1='" + HistogramXy
     + "' x2='" + (tempX1 + 10.0) + "' y2='"
     + (HistogramXy - 10)
     + "' stroke-width='1'  stroke='#333300'/>");
   sFile.append("\n");
  }

  /* 画Y轴刻度值 */
  int maxValue = (int) valueMM;
  int valueX;//Y轴刻度值起始的X坐标
  String fontsize = "";
  if (maxValue > 10000) {
   valueX = 5;
   fontsize = "11px";
  } else {
   valueX = 15;
   fontsize = "13px";
  }
  for (int i = 0; i < 10; i++) {
   sFile.append("<text x='" + valueX + "' y='" + (45 + i * 40)
     + "' fill='black' font-family='Verdana' font-size='"
     + fontsize + "'>");
   sFile.append("\n");
   sFile.append((maxValue / 10) * (10 - i));
   sFile.append("\n");
   sFile.append("</text>");
   sFile.append("\n");
  }

  /* 画矩形 */
  sFile.append("<g style='filter:url(#MyFilter)'>");
  sFile.append("\n");
  for (int i = 0; i < pDataName.length; i++) {
   //每根X轴刻度线的起始位置
   double tempX1 = i == 0 ? HistogramXSx + i * xStep : HistogramXSx
     + i * xStep + 10;
   for (int j = 0; j < data1[i].length; j++) {
    double tempX2 = tempX1 + colWidthPre + j * colWidth; //每根柱形的起始位置
    double colHeight = Math.ceil(Math.abs(data1[i][j]) * yStep);
    double tempY = 440 - colHeight;
    String[] colorHistogram; //三个柱面的颜色
    if (data1[i][j] < 0) {
     colorHistogram = colorNeg[0];
     sFile.append(paintHistogram(colWidth, colHeight, tempX2,
       tempY, colorHistogram, data1[i][j]));
    } else if (data1[i][j] > 0) {
     int n = j % color.length;
     colorHistogram = color[n];
     sFile.append(paintHistogram(colWidth, colHeight, tempX2,
       tempY, colorHistogram, data1[i][j]));
    }

   }

   /* 添加X轴字段说明 字无法在一行内显示的话,需要换行 */
   int n = (int) xStep / 13;//每行显示几个字符
   int m = pDataName[i].length() % n == 0 ? pDataName[i].length() / n
     : (int) (pDataName[i].length() / n + 1);//总共显示几行
   int l = 0;//记录总共处理了多少字符
   if (m > 1) {
    sFile
      .append("<text fill='blue' font-size='15px' font-family='STFangsong'>");
    for (int j = 0; j < m; j++) {
     for (int z = 0; z < n; z++) {
      l = j * n + z;
      if (l == pDataName[i].length()) {
       break;
      }
      sFile.append("<tspan x='" + (tempX1 + z * 15) + "' y='"
        + (460 + j * 20) + "' >");
      sFile.append(pDataName[i].substring(l, l + 1));
      sFile.append("</tspan>");
     }
     if (l == pDataName[i].length()) {
      break;
     }
    }
    sFile.append("</text>");
    sFile.append("\n");
   } else {
    sFile
      .append("<text x='"
        + (5 + tempX1)
        + "' y='460' fill='blue' font-size='15px' font-family='STFangsong'>"
        + pDataName[i] + "</text>");
    sFile.append("\n");
   }

  }
  sFile.append("</g>");
  sFile.append("\n");
  sFile.append("</svg>");
  return sFile.toString();

 }

 /**
  * 画单一柱形
  *
  * @param colWidth
  *            柱形宽度
  * @param colHeight
  *            柱形高度
  * @param x
  *            柱形X值
  * @param y
  *            柱形Y值
  * @param color
  *            柱形三个面的颜色
  * @param dataValue
  *            柱形代表的值
  * @return SVG字符串
  */
 static String paintHistogram(double colWidth, double colHeight, double x,
   double y, String[] color, double dataValue) {
  StringBuffer sFile = new StringBuffer();
  double dOffset = (colWidth / 3) > 10.0 ? 10.0 : (colWidth / 3);//斜面的偏移量
  sFile.append("<rect width='" + colWidth + "' height='" + colHeight
    + "' x='" + x + "' y='" + y + "' fill='" + color[0]
    + "' onclick='showValue(" + dataValue + ")'/>");
  sFile.append("\n");
  sFile.append("<polygon points='" + x + "," + y + " " + (x + dOffset)
    + "," + (y - dOffset) + " " + (x + dOffset + colWidth) + ","
    + (y - dOffset) + " " + (x + colWidth) + "," + y
    + "' style='fill:" + color[1] + ";stroke:" + color[1]
    + ";stroke-width:1;' onclick='showValue(" + dataValue + ")'/>");
  sFile.append("\n");
  sFile.append("<polygon points='" + (x + dOffset + colWidth) + ","
    + (y - dOffset) + " " + (x + colWidth) + "," + y + " "
    + (x + colWidth) + "," + 440 + " " + (x + dOffset + colWidth)
    + "," + (y - dOffset + colHeight) + "' style='fill:" + color[2]
    + ";stroke:" + color[2]
    + ";stroke-width:1;' onclick='showValue(" + dataValue + ")'/>");
  return sFile.toString();
 }
}

 

本文地址:http://com.8s8s.com/it/it15730.htm