package com.tellhow.svg;

import java.io.File;
import java.io.FileOutputStream;

/**
 *
 * @author 风絮NO.1
 *
 */
public class CakySvgWithLabel {
 //定义不同的颜色
 static String[] colors ={"#f2e692", "#aa1111",
         "#799AE1", "#3e941b",
         "#66cc00", "#297110",
         "#d6a97b", "#82522b",
         "#aaaaff", "#1111aa",
         "#ff2222", "#ffaaaa"};
 
 static String initialize(double [] percents,String[]names){
  StringBuffer sfile = new StringBuffer();
  sfile.append("<?xml version='1.0' encoding='UTF-8'?>");
  sfile.append("\n");
  sfile.append("<svg xmlns:svg='http://www.w3.org/2000/svg'");
  sfile.append("\n");
        sfile.append("xmlns='http://www.w3.org/2000/svg'");
        sfile.append("\n");
        sfile.append("xmlns:xlink='http://www.w3.org/1999/xlink'");
        sfile.append("\n");
        sfile.append("xml:space='default'");
        sfile.append("\n");
        sfile.append("version='1.1'  width='100%' height='100%' viewBox='0 0 2024 570'>");
        sfile.append("\n");
        sfile.append("<defs></defs>");
        sfile.append("\n");
        sfile.append("<g stroke-width='1' stroke='#FFFFFF' transform='matrix(1,0,0,1,16.384,-9.83)' xmlns='http://www.w3.org/2000/svg'>");
        sfile.append("\n");
        //循环创造path标签.
        String path =creatPath(502, 300, 300, percents,names);//中心点式503,300.
        sfile.append(path);
        sfile.append("</g>");
        sfile.append("\n");
        sfile.append("</svg>");
  return sfile.toString();
 }
 /**
  *
  * @param x0 中心点横坐标
  * @param y0 中心点纵坐标
  * @param r  半径
  * @param percents  百分比数组
  * @param names 显示颜色代表的名称
  * @return
  */
    public static String creatPath(double x0,double y0,double r,double[]percents,String[]names){
     StringBuffer sfile =new StringBuffer();
     double x1=0; //新扇形的x坐标
     double y1=0; //新扇形的y坐标
     double middleX=0;  //文本显示的坐标,包括竖线显示的坐标
     double middleY=0;
     double radian =0; //弧度
     double textRadian=0; //文本显示位置度弧度
     double k=0;
     int N=10;
     for(int i=0;i<percents.length;i++){
      
      if(i==0){
         radian =getRadian(percents[0]);
         textRadian=radian/2;
         x1 = (x0+getCos(radian)*r);
         y1 = (y0-getSin(radian)*r);
         middleX=(x0+getCos(textRadian)*r);
         middleY=(y0-getSin(textRadian)*r);
          double percent = Math.round(percents[0]*100)/100.0;//获得精确到两位小数点的坐标.
          k=Math.abs((middleY-y0)/(middleX-x0));//获得扇形终点的坐标,与中心点连成的直线的斜率.(取正值)
          double sita= Math.atan(k);//求斜角
          double lineLen=50;
            double textLen=70;
            if(radian<6){
           lineLen=90;
           textLen=110;//控制指示线的长度,与文字的位置
            }
         if(percents[i]!=0){//当一个类型为0时,饼图展示
          if((textRadian<(Math.PI/2))){
             sfile.append("<line x1='"+middleX+"' y1='"+middleY+"' x2='"+(middleX+Math.cos(sita)*lineLen)+"' y2='"+(middleY-(Math.sin(sita)*lineLen))+"' stroke='#000000'/>");
             sfile.append("\n");
              sfile.append("<text x='"+(middleX+Math.cos(sita)*textLen)+"' y='"+(middleY-(Math.sin(sita)*textLen))+"' space='preserve' font-family='Tahoma' font-size='21' fill='red' stroke='red' baseline-shift='baseline' >"+percent+"%</text>");
           }else if ((textRadian>(Math.PI/2)&&textRadian<Math.PI)){
             sfile.append("<line x1='"+middleX+"' y1='"+middleY+"' x2='"+(middleX-Math.cos(sita)*lineLen)+"' y2='"+(middleY-(Math.sin(sita)*lineLen))+"' stroke='#000000'/>");
             sfile.append("\n");
             sfile.append("<text x='"+(middleX-Math.cos(sita)*textLen)+"' y='"+(middleY-(Math.sin(sita)*textLen))+"' space='preserve' font-family='Tahoma' font-size='21' fill='red' stroke='red' baseline-shift='baseline' >"+percent+"%</text>");
           }else if ((textRadian>(Math.PI)&&textRadian<(Math.PI*3/2))){
             sfile.append("<line x1='"+middleX+"' y1='"+middleY+"' x2='"+(middleX-Math.cos(sita)*lineLen)+"' y2='"+(middleY+(Math.sin(sita)*lineLen))+"' stroke='#000000'/>");
             sfile.append("\n");
             sfile.append("<text x='"+(middleX-Math.cos(sita)*textLen)+"' y='"+(middleY+(Math.sin(sita)*textLen))+"' space='preserve' font-family='Tahoma' font-size='21' fill='red' stroke='red' baseline-shift='baseline' >"+percent+"%</text>");
           }else if((textRadian>(Math.PI*3/2)&&textRadian<(Math.PI*2))){
             sfile.append("<line x1='"+middleX+"' y1='"+middleY+"' x2='"+(middleX+Math.cos(sita)*lineLen)+"' y2='"+(middleY+Math.sin(sita)*lineLen)+"' stroke='#000000'/>");
             sfile.append("\n");
             sfile.append("<text x='"+(middleX+Math.cos(sita)*textLen)+"' y='"+(middleY+(Math.sin(sita)*textLen))+"' space='preserve' font-family='Tahoma' font-size='21' fill='red' stroke='red' baseline-shift='baseline' >"+percent+"%</text>");
           }
          sfile.append("\n");
          if(getRadian(percents[0])>Math.PI){
            sfile.append("<path d='M "+x0+" "+y0+" L "+(x0+r)+" "+r+" A "+r+" "+r+" 0 1 0 "+x1+" "+y1+" L "+x0+" "+y0+" z' fill='"+colors[0]+"'/>");
            }else{
            sfile.append("<path d='M "+x0+" "+y0+" L "+(x0+r)+" "+r+" A "+r+" "+r+" 0 0 0 "+x1+" "+y1+" L "+x0+" "+y0+" z' fill='"+colors[0]+"'/>");
            }
          sfile.append("\n");
          }
         
          sfile.append("<rect x='"+(x0+2*r)+"' y='"+(y0-r/2.0+N)+"' width='60' height='30' fill='"+colors[i]+"' stroke='#FFFFFF' stroke-dasharray='1,1' />");
          sfile.append("\n");
          sfile.append("<text x='"+(x0+2*r+80)+"' y='"+(y0-r/2.0+N+25)+"' space='preserve' font-family='宋体' font-size='28' fill='"+colors[0]+"' stroke='#000000' stroke-dasharray='1,1' baseline-shift='baseline'>"+names[0]+"</text>");
          sfile.append("\n");
         
      }else{
       textRadian = radian+(getRadian(percents[i])/2);//获取指示线与X轴的弧度.
       radian =radian+getRadian(percents[i]);//第i个扇形前面的弧度的总和
       middleX=(x0+getCos(textRadian)*r);
           middleY=(y0-getSin(textRadian)*r);
           double percent = Math.round(percents[i]*100)/100.0;
           k=Math.abs((middleY-y0)/(middleX-x0));
           double lineLen=50;
           double textLen=70;
           if(radian<6){
            lineLen=90;
            textLen=110;
           }
           double sita= Math.atan(k);
         if(percents[i]!=0){//当一个类型为0时,饼图展示
           if((textRadian<(Math.PI/2))){
             sfile.append("<line x1='"+middleX+"' y1='"+middleY+"' x2='"+(middleX+Math.cos(sita)*lineLen)+"' y2='"+(middleY-(Math.sin(sita)*lineLen))+"' stroke='#000000'/>");
             sfile.append("\n");
              sfile.append("<text x='"+(middleX+Math.cos(sita)*textLen)+"' y='"+(middleY-(Math.sin(sita)*textLen))+"' space='preserve' font-family='Tahoma' font-size='21' fill='red' stroke='red' baseline-shift='baseline' >"+percent+"%</text>");
           }else if ((textRadian>(Math.PI/2)&&textRadian<Math.PI)){
             sfile.append("<line x1='"+middleX+"' y1='"+middleY+"' x2='"+(middleX-Math.cos(sita)*lineLen)+"' y2='"+(middleY-(Math.sin(sita)*lineLen))+"' stroke='#000000'/>");
             sfile.append("\n");
             sfile.append("<text x='"+(middleX-Math.cos(sita)*textLen)+"' y='"+(middleY-(Math.sin(sita)*textLen))+"' space='preserve' font-family='Tahoma' font-size='21' fill='red' stroke='red' baseline-shift='baseline' >"+percent+"%</text>");
           }else if ((textRadian>(Math.PI)&&textRadian<(Math.PI*3/2))){
             sfile.append("<line x1='"+middleX+"' y1='"+middleY+"' x2='"+(middleX-Math.cos(sita)*lineLen)+"' y2='"+(middleY+(Math.sin(sita)*lineLen))+"' stroke='#000000'/>");
             sfile.append("\n");
             sfile.append("<text x='"+(middleX-Math.cos(sita)*textLen)+"' y='"+(middleY+(Math.sin(sita)*textLen))+"' space='preserve' font-family='Tahoma' font-size='21' fill='red' stroke='red' baseline-shift='baseline' >"+percent+"%</text>");
           }else if((textRadian>(Math.PI*3/2)&&textRadian<(Math.PI*2))){
             sfile.append("<line x1='"+middleX+"' y1='"+middleY+"' x2='"+(middleX+Math.cos(sita)*lineLen)+"' y2='"+(middleY+Math.sin(sita)*lineLen)+"' stroke='#000000'/>");
             sfile.append("\n");
             sfile.append("<text x='"+(middleX+Math.cos(sita)*textLen)+"' y='"+(middleY+(Math.sin(sita)*textLen))+"' space='preserve' font-family='Tahoma' font-size='21' fill='red' stroke='red' baseline-shift='baseline' >"+percent+"%</text>");
           }
       sfile.append("\n");
       // 参数 1 表示 画大于180的弧, 0 表示画小于180的弧 (这个地方比较重要)
       if(getRadian(percents[i])>Math.PI){
          sfile.append("<path d='M "+x0+" "+y0+" L "+x1+" "+y1+" A "+r+" "+r+" 0 1 0 "+(x1=x0+getCos(radian)*r)+" "+(y1=y0-getSin(radian)*r)+" L "+x0+" "+y0+" z' fill='"+colors[i]+"'/>");
       }else{
              sfile.append("<path d='M "+x0+" "+y0+" L "+x1+" "+y1+" A "+r+" "+r+" 0 0 0 "+(x1=x0+getCos(radian)*r)+" "+(y1=y0-getSin(radian)*r)+" L "+x0+" "+y0+" z' fill='"+colors[i]+"'/>");
       }
       sfile.append("\n");
      }
       N+=50;
          sfile.append("<rect x='"+(x0+2*r)+"' y='"+(y0-r/2.0+N)+"' width='60' height='30' fill='"+colors[i]+"' stroke='#FFFFFF' stroke-dasharray='1,1' />");
          sfile.append("\n");
          sfile.append("<text x='"+(x0+2*r+80)+"' y='"+(y0-r/2.0+N+25)+"' space='preserve' font-family='宋体' font-size='28' fill='"+colors[0]+"' stroke='#000000' stroke-dasharray='1,1' baseline-shift='baseline'>"+names[i]+"</text>");
          sfile.append("\n");
      }
      
     }
     return sfile.toString();
    }
    //返回弧度
    public static double getRadian(double fenshu){
     return (fenshu*Math.PI)/50;
    }
    //返回正弦
 public static double getSin(double radian){
   return Math.sin(radian);
 }
 //返回余弦
 public static double getCos(double radian){
  return Math.cos(radian);
 }
 public static void main(String[] args) {
  int[] data= {3,64,0,284,10};
  String[] names={"主变:"+data[0]+"个","断路器:"+data[1]+"个","线路:"+data[2]+"个","刀闸:"+data[3]+"个","母线:"+data[4]+"个"};
  create(data,names);
 }
 
 private static void create(int[] data,String[] names) {
    try {
   createSVG("d:/a.svg",getPercent(data),names);
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 private static double[] getPercent(int data[]){
  double sum=0;
  double percents[] = new double[data.length];
  for(int i=0;i<data.length;i++){
    sum+=data[i];
  }
  for(int i=0;i<data.length;i++){
   percents[i] =(data[i]/sum)*100;
  }
  return percents;
 }
 
 public static void createSVG(String fileRealPath, double[] percents,String[] names) throws Exception {
  String sFile = initialize(percents,names);
  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());
  }
 }
}

java生成饼图svg的更多相关文章

  1. java生成饼图

    pom.xml文件导入依赖包 <!-- https://mvnrepository.com/artifact/org.jfree/jfreechart --> <dependency ...

  2. Java生成和操作Excel文件(转载)

    Java生成和操作Excel文件   JAVA EXCEL API:是一开放源码项目,通过它Java开发人员可以读取Excel文件的内容.创建新的Excel文件.更新已经存在的Excel文件.使用该A ...

  3. 利用JAVA生成二维码

    本文章整理于慕课网的学习视频<JAVA生成二维码>,如果想看视频内容请移步慕课网. 维基百科上对于二维码的解释. 二维条码是指在一维条码的基础上扩展出另一维具有可读性的条码,使用黑白矩形图 ...

  4. Java生成验证码原理(jsp)

     验证码的作用: 验证码是Completely Automated Public Turing test to tell Computers and Humans Apart(全自动区分计算机和人类的 ...

  5. JAVA生成条形码

    1.下载生成条形码所需要的jar包barcode4j.jar: 2.java生成条形码代码 import java.awt.image.BufferedImage;import java.io.Fil ...

  6. Java生成CSV文件实例详解

    本文实例主要讲述了Java生成CSV文件的方法,具体实现步骤如下: 1.新建CSVUtils.java文件: package com.saicfc.pmpf.internal.manage.utils ...

  7. java 生成8位数字作为UID

    java 生成8位数字作为UUID: /*** * 生成uid 8位数字 */public static String generateUID(){ Random random = new Rando ...

  8. java生成随机序列号

    1.java生成随机序列号 String deleteUuid = UUID.randomUUID().toString(); 引用Jar包 //java-uuid-generator-3.1.3.j ...

  9. java生成简单Excel工作薄

    前言: 代码都是建立在实际需求上的,上周做完一个调外部电影券接口的项目,这周产品又要excel表格,大致内容为:券所属影院.图片URL.等信息制作为excel表格,把每次同步过来的数据给他分析. jx ...

随机推荐

  1. module+standard library.py

    #导入模块 import sys sys.path sys.path.append('D:\program files\Python34\PyWorks') #hello.py文件路径 #不用appe ...

  2. PYTHON路线图

    路线图: 第一部分:Python语言基础 第二部分:数据库开发 第三部分:web前端 第四部分:Python web开发 第五部分:Python web项目 第六部分:Linux 第七部分:NoSQL ...

  3. CMake学习记录--list(列表操作命令)

    CMake是一个跨平台的工程管理工具,能方便的把工程转换为vs各个版本.Borland Makefiles.MSSYS Makefiles.NMake Makefiles等工程,对于经常在不同IDE下 ...

  4. Intelidea右键新建选项没有Java class选项

    Intelidea创建好项目之后,右键新建Java class的时候发现没有改选项,只有以下几个选项 把sec目录设为源码目录,首先打开Project Structure

  5. apache日志信息详解

     一.访问日志的格式 Apache内建了记录服务器活动的功能,这就是它的日志功能.下文详细介绍Apache的访问日志.错误日志.以及如何分析日志数据,如何定制Apache日志,如何从日志数据生成统计报 ...

  6. E20180410-hm

    preface  n. 序言,引语; 开端,前奏; [宗] (弥撒的) 序诵,序祷;        vi. 作序; 作为…的序言,作为…的开端; 给…作序; 开始,导致; continue vi. 持 ...

  7. python list生成表达式

    列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式.运用列表生成式,可以写出非常简洁的代码. >>> list(ra ...

  8. loj #6302. 「CodePlus 2018 3 月赛」寻找车位【线段树+单调队列】

    考虑静态怎么做:枚举右边界,然后枚举上边界,对应的下边界一定单调不降,单调栈维护每一列从当前枚举的右边界向左最长空位的长度,这样是O(nm)的 注意到n>=m,所以m<=2000,可以枚举 ...

  9. bzoj 3667: Rabin-Miller算法【Miller-Rabin】

    Miller-Rabin模板 #include<iostream> #include<cstdio> #include<algorithm> using names ...

  10. JVM的参数详解

    今天就整理下JVM的参数!相对而已JVM有很多参数,但对于一般开发人员执行知道和堆栈大小,GC.远程调试的参数即可. JVM Parameters 首先需要说明的是JVM的参数形式: -X 开头的参数 ...