如何根据数组中的数据来确认Y轴坐标刻度值是一个比较头痛的事,我在这段代码中尽管可以正常确认Y轴坐标,但是显示出来的刻度依旧不理想。这个算法也是照抄了super的算法,不知道有没有更好的算法。

package 
   SvgGraph;

 
  import 
   java.io.File;
 
  import 
   java.io.FileOutputStream;
 
  import 
   java.io.FileWriter;
 
  import 
   java.io.OutputStreamWriter;
 
  import 
   java.math.BigDecimal;
 
  import 
   org.dom4j.CDATA;
 
  import 
   org.dom4j.Document;
 
  import 
   org.dom4j.DocumentHelper;
 
  import 
   org.dom4j.Element;
 
  import 
   org.dom4j.io.OutputFormat;
 
  import 
   org.dom4j.io.XMLWriter;
 
  /**/ 
  /*
 * BackgroundMap.java
 *
 * Created on 2007年8月9日, 上午10:13
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */ 
  

 
  /** */ 
  /**
 *
 * @author 周慧明
 * 用来生成svg背景用的图形,包括标题、坐标网格和标签
 */ 
  
 
  public 
    
  class 
   BackgroundMap  
  ... 
  {
    private int canvasWidth = 600;  // 画布宽度
    private int canvasHeight = 360; // 画布高度
    private int mapWidth = 480;        // 绘图区宽度
    private int mapHeight = 300;    // 绘图区高度
    private int zeroX = 30;    // 原点x坐标
    private int zeroY = 40;    // 原点y坐标
//    private double yMinValue;  // y轴最小值
//    private double yMaxValue;  // y轴最大值
//    private String xBegin;    // x轴起始值
//    private String xEnd;    // x轴结束值
//    private int xNum;    // x轴刻度总数
//    private String xTitle;  // x轴单位
//    private String yTitle;  // y轴单位
//    private int xStep;    // x轴步进长度(像素)
    private int yStep = 30;    // y轴步进长度(像素)
    private static int dataNum = 0;  // 数据总数,默认值为0
    
    private String[] lineColors = ...{"#00008B", "#8A2BE2", "#FFEBCD", "#A52A2A", "#DEB887",
        "#5F9EA0", "#7FFF00", "#D2691E", "#FF7F50", "#6495ED"};
    
    /** *//** Creates a new instance of BackgroundMap */
    public BackgroundMap() ...{
    }
    
    /** *//**
     * 建立一个SVG文件,文件名由输入参数决定
     * @param filename {String} 需要建立的文件名
     * @param titleName {String} 标题名
     * @param pData {String[]} 要绘制的数据源
     * @param pDataName {String[]} x轴标识
     * @return 返回操作结果,0表示失败,1表示成功
     **/
    public int createSvgFile(String filename,String titleName,
        String[] pData, String[] pDataName)...{
    /** *//** 返回操作结果,0表示失败,1表示成功*/
    int returnValue = 0;
    /** *//** 建立document对象*/
    Document document = DocumentHelper.createDocument();
    /** *//** 设置文件编码集*/
    document.setXMLEncoding("UTF-8");
    /** *//** !DOCTYPE声明*/
    document.addDocType("svg","-//W3C//DTD SVG 1.0//EN","http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");
    
    /** *//** 建立SVG文档的根svg*/
    Element svgRoot = CreateSvgRoot(document);
    /** *//** 绘制标题*/
    WriteTitle(svgRoot,titleName);
    /** *//** 绘背景*/
    WriteBackGround(svgRoot);
    /** *//** 绘制数据*/
    WriteDataLine(svgRoot,pData,pDataName);
    
    /** *//** 将数据写入SVG文件 */
    if(WriteDataToFile(document,filename))
        return 1;
    else
        return 0;
    }
 
    /** *//**
     * 建立一个SVG文件,文件名由输入参数决定
     * @param filename {String} 需要建立的文件名
     * @param titleName {String} 标题名
     * @param pData {String[][]} 要绘制的数据源
     * @param pDataName {String[]} x轴标识
     * @return 返回操作结果,0表示失败,1表示成功
     **/
    public int createSvgFile(String filename,String titleName,
        String[][] pData, String[] pDataName)...{
    /** *//** 返回操作结果,0表示失败,1表示成功*/
    int returnValue = 0;
    /** *//** 建立document对象*/
    Document document = DocumentHelper.createDocument();
    /** *//** 设置文件编码集*/
    document.setXMLEncoding("UTF-8");
    /** *//** !DOCTYPE声明*/
    document.addDocType("svg","-//W3C//DTD SVG 1.0//EN","http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");
    
    /** *//** 建立SVG文档的根svg*/
    Element svgRoot = CreateSvgRoot(document);
    /** *//** 绘制标题*/
    WriteTitle(svgRoot,titleName);
    /** *//** 绘背景*/
    WriteBackGround(svgRoot);
    /** *//** 绘制数据*/
    WriteDataLine(svgRoot,pData,pDataName);
    
    /** *//** 将数据写入SVG文件 */
    if(WriteDataToFile(document,filename))
        return 1;
    else
        return 0;
    }

    
    /** *//**
     * 创建SVG文件根节点
     * @param document {Document} 文档节点
     * @return SVG根节点
     **/
    private Element CreateSvgRoot(Document document)...{
    /** *//** 建立SVG文档的根svg*/
    Element svgRoot = document.addElement("svg","http://www.w3.org/2000/svg");
    svgRoot.addAttribute("width",Integer.toString(canvasWidth));
    svgRoot.addAttribute("height",Integer.toString(canvasHeight));
    svgRoot.addAttribute("font-family","SimSun");
    
    return svgRoot;
    }
    
    private boolean WriteDataToFile(Document document,String filename)...{
    try...{
        /** *//** 将document中的内容写入文件中*/
        OutputFormat format = OutputFormat.createPrettyPrint();
        //format.setEncoding("UTF-8");
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filename),"UTF-8");
        XMLWriter writer= new XMLWriter(osw,format);
        //XMLWriter writer = new XMLWriter(new FileWriter(new File(filename)),format);
        writer.write(document);
        writer.close();
        /** *//** 执行成功,返回1*/
        return true;
    }catch(Exception ex)...{
        System.out.println("写SVG文件时出错!");
        ex.printStackTrace();
        return false;
    }
    }
    
    /** *//**
     * 绘制SVG的背景及坐标网格
     * @param svgRoot {Element} SVG根节点
     **/
    private void WriteBackGround(Element svgRoot)...{
    /** *//**画布景*/
    Element canvRec = svgRoot.addElement("rect");
    canvRec.addAttribute("x","0");
    canvRec.addAttribute("y","0");
    canvRec.addAttribute("width",Integer.toString(canvasWidth));
    canvRec.addAttribute("height",Integer.toString(canvasHeight));
    canvRec.addAttribute("fill","none");
    canvRec.addAttribute("stroke","blue");
    canvRec.addAttribute("stroke-width","1");
    /** *//**X轴*/
    Element axesX = svgRoot.addElement("line");
    axesX.addAttribute("x1",Integer.toString(zeroX));
    axesX.addAttribute("y1",Integer.toString(zeroY + mapHeight));
    axesX.addAttribute("x2",Integer.toString(zeroX + mapWidth));
    axesX.addAttribute("y2",Integer.toString(zeroY + mapHeight));
    axesX.addAttribute("stroke-width","2");
    axesX.addAttribute("stroke-opacity",".4");
    axesX.addAttribute("fill","blue");
    axesX.addAttribute("stroke","#333300");
    /** *//**Y轴*/
    Element axesY = svgRoot.addElement("line");
    axesY.addAttribute("x1",Integer.toString(zeroX));
    axesY.addAttribute("y1",Integer.toString(zeroY + mapHeight));
    axesY.addAttribute("x2",Integer.toString(zeroX));
    axesY.addAttribute("y2",Integer.toString(zeroY));
    axesY.addAttribute("stroke-width","2");
    axesY.addAttribute("stroke-opacity",".4");
    axesY.addAttribute("fill","blue");
    axesY.addAttribute("stroke","#333300");
    /** *//**Y轴刻度*/
    for(int i=0; i<mapHeight/yStep; i++)...{
        int tempY = zeroY + i * yStep;
        Element scoreY = svgRoot.addElement("line");
        scoreY.addAttribute("x1",Integer.toString(zeroX));
        scoreY.addAttribute("y1",Integer.toString(tempY));
        scoreY.addAttribute("x2",Integer.toString(zeroX + mapWidth));
        scoreY.addAttribute("y2",Integer.toString(tempY));
        scoreY.addAttribute("stroke-width","1");
        scoreY.addAttribute("stroke-dasharray","3 2");
        scoreY.addAttribute("stroke","#333300");
    }
    }
    
    /** *//**
     * 书写标题
     * @param svgRoot {Element} SVG根节点
     * @param titleName {String} 标题名
     **/
    private void WriteTitle(Element svgRoot,String titleName)...{
    int wordNum = titleName.length();   // 标题字符个数
    int font_size;        // 字体大小
    int titleLength;    // 标题字符串栅格长度
    int x,y;        // 标题起始位置
    
    if(wordNum <= 40)...{
        font_size=15;
    }else...{
        font_size=canvasWidth/wordNum;
    }
    titleLength = font_size * wordNum;
    x = (canvasWidth-titleLength)/2;
    y = (zeroY-font_size);
    
    /** *//** 绘标题元素*/
    Element title = svgRoot.addElement("text");
    title.addAttribute("x", Integer.toString(x));
    title.addAttribute("y", Integer.toString(y));
    title.addAttribute("fill", "black");
    title.addAttribute("font-size", Integer.toString(font_size));
    title.setText(titleName);
    }
    
    /** *//**
     * 绘制折线,x轴刻度,x轴刻度名称,y轴刻度值
     * @param svgRoot {Element} SVG根节点
     * @param pData {String[]} 要绘制折线的数据
     * @param pDataName {String[]} x轴刻度名称
     **/
    private void WriteDataLine(Element svgRoot,String[] pData, String[] pDataName)...{
    /**//* 绘制x轴信息*/
    double[] xAxis = WriteXData(svgRoot, pDataName);
    /**//* 获取double型数据 */
    double[] data = convertDataToDouble(pData);
    /**//* y轴刻度值*/
    WriteYData(svgRoot, data);
    /** *//** 绘制数据折线*/
    WriteLine(svgRoot, data, xAxis,lineColors[0]);
    }

    /** *//**
     * 绘制折线,x轴刻度,x轴刻度名称,y轴刻度值
     * @param svgRoot {Element} SVG根节点
     * @param pData {String[][]} 要绘制折线的数据
     * @param pDataName {String[]} x轴刻度名称
     **/
    private void WriteDataLine(Element svgRoot,String[][] pData, String[] pDataName)...{
    /**//* 绘制x轴信息*/
    double[] xAxis = WriteXData(svgRoot, pDataName);
    /**//* 获取double型数据 */
    double[][] data = convertDataToDouble(pData);
    double[] tempValue = ChangePlanarQueue(data);
    /**//* y轴刻度值*/
    WriteYData(svgRoot, tempValue);
    /** *//** 绘制数据折线*/
    WriteLine(svgRoot, data, xAxis);
    }
    
    /** *//**
     * 将二维数组转换为一维数组
     **/
    private double[] ChangePlanarQueue(double[][] data)...{
    double[] tempValue = new double[dataNum];
    for (int i = 0; i < data.length; i++) ...{
        for (int j = 0; j < data[i].length; j++) ...{
        tempValue[i * data[i].length + j] = data[i][j];
        }
    }
    return tempValue;
    }

    
    /** *//** 
     * 绘制x轴刻度线和x轴标识
     * @param svgRoot {Element} SVG根节点
     * @param pDataName {String[]} x轴刻度名称
     * @return double[] x刻度的x轴坐标
     **/
    private double[] WriteXData(Element svgRoot, String[] pDataName)...{
    double xStep = (new BigDecimal(mapWidth / (pDataName.length-1)).setScale(3, BigDecimal.ROUND_HALF_UP)).doubleValue();
    double[] xAxis = new double[pDataName.length];    // 保存每个x轴刻度值的数组
    xAxis[0] = zeroX;   // x轴第一个刻度为y轴
    //System.out.println("length:"+pDataName.length);
    /** *//** x轴刻度线 */
    for (int i = 1; i < pDataName.length; i++) ...{
        // i=0时的y线不用绘制
        //double tempX1 = i == 0 ? zeroX + i * xStep : zeroX + i * xStep + 10; //每根X轴刻度线的起始位置
        double tempX1 = zeroX + i*xStep;
        //System.out.println(i+":"+tempX1);
        xAxis[i] = tempX1;    // 保存每个x轴刻度值
        Element line = svgRoot.addElement("line");
        line.addAttribute("x1",Double.toString(tempX1));
        line.addAttribute("y1",Integer.toString(zeroY + mapHeight));
        line.addAttribute("x2",Double.toString(tempX1));
        line.addAttribute("y2",Integer.toString(zeroY));
        line.addAttribute("stroke-width","1");
        line.addAttribute("stroke-dasharray","3 2");
        line.addAttribute("stroke","#333300");
    }
    /** *//** 添加X轴字段说明 字无法在一行内显示的话,需要换行 */
    for(int i=0; i<pDataName.length; i++)...{
        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;    //记录总共处理了多少字符
        int font_size = 13;    // 字体大小
        
        if(m>1)...{
        Element xName = svgRoot.addElement("text");
        xName.addAttribute("fill","blue");
        xName.addAttribute("font-size",Integer.toString(font_size));
        xName.addAttribute("font-family","SimSun");
        for(int j=0; j<m; j++)...{
            for(int z=0; z<n; z++)...{
            l = j * n + z;
            if(l == pDataName[i].length())...{
                break;
            }
            Element tspan = xName.addElement("tspan");
            tspan.addAttribute("x",Double.toString(xAxis[i]));
            tspan.addAttribute("y",Integer.toString(zeroY + mapHeight + font_size + j*(font_size+3)));
            tspan.setText(pDataName[i].substring(l,l+1));
            }
            if(l == pDataName[i].length())...{
            break;
            }
        }
        }else...{
        double textOffset = pDataName[i].length() * font_size / 2;
        Element xName = svgRoot.addElement("text");
        xName.addAttribute("x",Double.toString(xAxis[i]-textOffset));
        xName.addAttribute("y",Integer.toString(zeroY + mapHeight + font_size));
        xName.addAttribute("fill","blue");
        xName.addAttribute("font-size",Integer.toHexString(font_size));
        xName.addAttribute("font-family","SimSun");
        xName.setText(pDataName[i]);
        }
    }
    
    return xAxis;
    }
    
    /** *//**
     * 绘制y轴刻度值
     * @param svgRoot {Element} SVG根节点
     * @param data {double} 要绘制折线的数据
     * @return double[] y轴最大最小值
     **/
    private void WriteYData(Element svgRoot, double[] data)...{
    double[] extr = GetExtremum(data);
    int maxValue = (int)(extr[0]-extr[1]);
    int valueX; //Y轴刻度值起始的X坐标
    int font_size;
    if (maxValue > 10000) ...{
        valueX = 5;
        font_size = 9;
    } else ...{
        valueX = 10;
        font_size = 11;
    }
    for(int i=0; i<11; i++)...{
        Element yName = svgRoot.addElement("text");
        yName.addAttribute("x",Integer.toString(valueX));
        yName.addAttribute("y",Integer.toString(zeroY + i * yStep));
        yName.addAttribute("fill","black");
        yName.addAttribute("font-family","SimSun");
        yName.addAttribute("font-size",Integer.toString(font_size));
        yName.setText(Integer.toString((maxValue / 10) * (10 - i) + (int)extr[1]));
    }
    }
    
    /** *//**
     * 绘制数据折线
     * @param svgRoot {Element} SVG根节点
     * @param data {double[]} 需要绘制的数据
     * @param xAxis {double[]} x轴刻度坐标值
     **/
    private void WriteLine(Element svgRoot, double[] data, double[] xAxis, String lineColor)...{
    String strPoints = "";
    double[] extr = GetExtremum(data);  // 获取data的最大最小值
    int yValueStep = (int)(extr[0]-extr[1]);
    for(int i=0; i<xAxis.length; i ++)...{
        double valueSpan = data[i] - extr[1];
        double ySpan = valueSpan / yValueStep * mapHeight;
        strPoints += xAxis[i] +","+ (zeroY + mapHeight - ySpan) + " ";
    }
    
    Element dataLine = svgRoot.addElement("polyline");
    dataLine.addAttribute("stroke-width","2");
    dataLine.addAttribute("stroke",lineColor);
    dataLine.addAttribute("fill","none");
    dataLine.addAttribute("points", strPoints.trim());
    }

    /** *//**
     * 绘制数据折线
     * @param svgRoot {Element} SVG根节点
     * @param data {double[][]} 需要绘制的数据
     * @param xAxis {double[]} x轴刻度坐标值
     **/
    private void WriteLine(Element svgRoot, double[][] data, double[] xAxis)...{
    String strPoints = "";
    double[] tempValue = ChangePlanarQueue(data);
    double[] extr = GetExtremum(tempValue);  // 获取data的最大最小值
    int yValueStep = (int)(extr[0]-extr[1]);
    Element dataLine;
    for(int i=0; i<data.length; i++)...{
        strPoints = "";
        for(int j=0; j<data[i].length; j++)...{
        double valueSpan = data[i][j] - extr[1];
        double ySpan = valueSpan / yValueStep * mapHeight;
        strPoints += xAxis[j] +","+ (zeroY + mapHeight - ySpan) + " ";
        }
        dataLine = svgRoot.addElement("polyline");
        dataLine.addAttribute("stroke-width","2");
        dataLine.addAttribute("stroke",lineColors[i%lineColors.length]);
        dataLine.addAttribute("fill","none");
        dataLine.addAttribute("points", strPoints.trim());
    }
    }

    
    /** *//**
     * 将元数据从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();
        } 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 {double[]} pData 原始数据
     * @return {double[]} 最大值和最小值
     * 0位保存最大值
     * 1位保存最小值
     **/
    static double[] GetExtremum(double[] pData) ...{
    double max = pData[0];
    double min = pData[0];
    double[] mum = new double[2];
    
    /** *//** 获取数组中最大最小值 */
    for (int i = 0; i < pData.length; i++) ...{
        if (pData[i] > max)
        max = pData[i];
        if (pData[i] < min)
        min = pData[i];
    }
    
    /** *//** 将最大最小值整数化 */
    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.floor(min);
    if (Math.abs(min) <= 1 && max <= 1)
        min = -1;
    else ...{
        min = min < 100 ? Math.ceil(min / 10) * 10 : Math.ceil(min / 50) * 50;
    }

    mum[0] = max;
    mum[1] = min;
    return mum;
    }
    
    
    public static void main(String[] args) ...{
    System.out.println("createSvgFile");
    
    String filename = "d:/test/1.svg";
    String filename2 = "d:/test/2.svg";
    BackgroundMap instance = new BackgroundMap();
    
    int expResult = 1;
    String[][] data = ...{ ...{ "54", "44", "122" }, ...{ "10", "12", "-468" },
        ...{ "78", "520", "10" } };
    String[] data1 = ...{ "54", "4424.225", "12200", "-4658" };
    String[] dataName = ...{ "营业所一", "二二二二", "III" ,"adf"};
    int result = instance.createSvgFile(filename,"测试实例",data1, dataName);
    String[] dataName1 = ...{ "营业所一", "二二二二", "III"};
    int result1 = instance.createSvgFile(filename2,"测试实例",data, dataName1);
    }
}

java 绘制走势图 java绘制曲线图_import