图谱导航Graphviz文件生成,转dot类

这个Java类用于生成Graphviz的dot文件,实现图谱导航。它处理资产关系,创建有向或无向图,并使用颜色映射。类中包含用于生成头、组节点、关系和文件的函数,支持输出SVG和PNG格式。
package com.*.util.generator;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.jsoup.helper.StringUtil;

import com.*.common.model.AtlasNavigationVO;
import com.*.common.model.RelationShipVO;

// TODO 资产类型可变的时候,考虑类型的处理
// TODO Graphviz并发问题
/**
 * 图谱导航Graphviz文件生成,转dot类
 *
 * @since Test
 * @author brian
 *
 */
public class GraphvizDotGenerator {

	// 本地dot.exe路径
	private static String graphviz2xdot = "e:/graphviz/bin/dot.exe";
	//gv文件路径
	private String gvout;
	//生成的图形文件路径
	private String gvdotout;
	//输出文件格式
	private String outformat;
	//有向图,还是无向图
	private boolean undirected;
	//要进行绘图的关系
	private Map<String,List<AtlasNavigationVO>> relationsmap;
	private BufferedWriter bw;


	private static final String[] colorTable = new String[]{
		"antiquewhite","aqua","aquamarine",
		"bisque","blanchedalmond","blue",
		"blueviolet","brown","burlywood","cadetblue","chartreuse",
		"chocolate","coral","cornflowerblue","crimson",
		"cyan","darkcyan","darkgoldenrod","darkgray",
		"darkgreen","darkgrey","darkkhaki","darkmagenta","darkolivegreen",
		"darkorange","darkorchid","darkred","darksalmon","darkseagreen",
		"darkslategray","darkslategrey","darkturquoise","darkviolet",
		"deeppink","deepskyblue","dimgray","dimgrey","dodgerblue",
		"firebrick","forestgreen","fuchsia",
		"gold","goldenrod","gray","grey",
		"green","greenyellow","hotpink","indianred",
		"indigo","khaki","lavender","lavenderblush",
		"lawngreen","lemonchiffon","lightblue","lightcoral",
		"lightgoldenrodyellow","lightgray","lightgreen","lightgrey","lightpink",
		"lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey",
		"lightsteelblue","lime","limegreen",
		"magenta","maroon","mediumaquamarine","mediumorchid",
		"mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise",
		"mediumvioletred","moccasin",
		"navajowhite","olive","olivedrab",
		"orange","orangered","orchid","palegoldenrod","palegreen",
		"paleturquoise","palevioletred","peachpuff","peru",
		"pink","plum","powderblue","purple","red",
		"rosybrown","royalblue","saddlebrown","salmon","sandybrown",
		"seagreen","sienna","silver","skyblue",
		"slateblue","slategray","slategrey","springgreen",
		"steelblue","tan","teal","thistle","tomato",
		"turquoise","violet","wheat",
		"yellow","yellowgreen"

	};

	private static final int colorNumber = colorTable.length;

	private Random colorRnd = new Random();

	//分类节点颜色表
	private static Map<String,String> nodeColors = new HashMap<String, String>();
	private static Map<String,String> edgeColors = new HashMap<String,String>();

	public GraphvizDotGenerator(String gvout, String gvdotout, String outformat, Map<String,List<AtlasNavigationVO>> assets) throws Exception{
		this.gvout = gvout;
		this.gvdotout = gvdotout;
		this.outformat = outformat;
		this.relationsmap = assets;
		FileOutputStream fos = new FileOutputStream(gvout);
	    OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
		//fw = new FileWriter(gvout,"UTF-8");
		bw = new BufferedWriter(osw);
	}

	public void generate() throws Exception{
		generateHeader();
		generateGroupNodes();
		generateVirtualGroupRelations();
		generateRelations();
		generateFoot();
		generateDotFile();
	}

	protected void generateGroupRelation() throws Exception{
		Set keys = relationsmap.keySet();
		Object[] keyarray = keys.toArray();
		generateClusterStart(null);
		for (int i = 0; i < keyarray.length; i++) {
			generateCategoryNode((String)keyarray[i]);
		}
		for (int i = 1; i < keyarray.length; i++) {
			String pre = (String)keyarray[i - 1];
			String cur = (String)keyarray[i];
			String relstr = String.format("%s%s%s [style=invis]\n", pre, getDirection(), cur);
			bw.write(relstr);
		}
		generateClusterEnd();
	}
	/**
	 * 生成基本信息,头部文字
	 * @throws Exception
	 */
	protected void generateHeader() throws Exception {
		String 	digraph = "digraph atlas {\n";
		String header="rankdir=LR;\nlabeljust=l\n";
		String graph = "graph [ranksep=1.0 splines=true overlap=false charset=\"UTF-8\"]\n";
		String edge = "edge [dir=none labeldistance=3]\n";
		String node = "node [shape=ellipse style=filled fontname=SimSun width=0.5 label=\"\"]\n";
		bw.write(digraph);
		bw.write(header);
		bw.write(graph);
		bw.write(edge);
		bw.write(node);
		generateGroupRelation();
		node = "node [shape=rectangle style=\"rounded,filled\" fontname=SimSun width=0.5 label=\"\",href=\"javascript:parent.click_node('\\N')\"]\n";
		bw.write(node);
	}

	/**
	 * 生成左边成组的节点
	 * 研发技术[ label = 研发技术]
	 * @throws Exception
	 */
	protected void generateCategoryNode(String category) throws Exception {
		String color = nextNodeColor(category);
		//nodeColors.put(category, color);
		String categorynode = String.format("%s[ color=%2$s label = \"%1$s\"]\n", category, color);
		bw.write(categorynode);
	}

	/**
	 * 生成右边结果的节点
	 * XML数据库技术[ label = a0]
	 * @throws Exception
	 */
	protected void generateAssetNode(String category, String assetid, String asset) throws Exception {
		String color = nodeColors.get(category);
		String label = asset;
		if(label.length() > 10){
			label = label.substring(0, 10);
		}
		String assetnode = String.format("%s[ label = \"%s\" color=%s]\n", assetid, label, color);
		bw.write(assetnode);
	}

	/**
	 * 生成每种类型的组节点,
	 * @throws Exception
	 */
	protected void generateGroupNodes() throws Exception {
		Integer i = 0;
		for (String key : relationsmap.keySet()) {
			i++;
			generateClusterStart(i.toString());
			//generateCategoryNode(key);在头部同一生成即可
		    List<AtlasNavigationVO> relations = relationsmap.get(key);
		    //生成虚拟联系,保证其在同一水平上
		    generateVirtualRelation(i.toString(), relations);
		    for(AtlasNavigationVO avo: relations){
		    	generateAssetNode(key, getAtlasId(avo), avo.getName());
		    }
		    generateClusterEnd();
		}

	}



	/**
	 * 生成一个关系,根据传入的两个asset进行关联
	 * 方正畅流45商业版->XML数据库技术 [color=brown]
	 * @throws Exception
	 */
	protected void generateRelation(String category, String startAsset, String endAsset) throws Exception {
		//String color = edgeColors.get(category);
		String color = nextEdgeColor(category);
		String relationnode = String.format("%s %s %s[ color = %s penwidth=1.5]\n", startAsset, getDirection(), endAsset, color);
		bw.write(relationnode);
	}

	/**
	 * 生成所有关系
	 * @throws Exception
	 */
	protected void generateRelations() throws Exception {
		//生成一固定字符串,用于布局时不调整rank
		bw.write("edge[constraint=false]\n");
		for (String key : relationsmap.keySet()) {
			//edgeColors.put(key, nextColor());
		    List<AtlasNavigationVO> relations = relationsmap.get(key);
		    for(AtlasNavigationVO avo: relations){
		    	List<RelationShipVO> relation = avo.getRelatedasset();
		    	if(relation != null){
		    		for(RelationShipVO rel: relation){
		    			generateRelation(key, getAtlasId(avo), getAtlasId(rel));
		    		}
		    	}
		    }
		}
	}

	/**
	 * 生成gv分块开始
	 * @param clusterName 子图名称
	 * @throws Exception
	 */
	protected void generateClusterStart(String clusterName) throws Exception {
		String cluster = "{\n";
		if(!StringUtil.isBlank(clusterName)){
			cluster = "subgraph cluster" + clusterName.trim() + cluster;
			cluster += "color=none\n";
		}
		bw.write(cluster);
		bw.write("rank=same\n");
	}

	/**
	 * 生成gv分块结束
	 * @throws Exception
	 */
	protected void generateClusterEnd() throws Exception {
		bw.write("}\n");
	}

	/*
	 * 生成组到每组第一个节点的虚拟联系
	 */
	private void generateVirtualGroupRelations() throws Exception {
		for (String key : relationsmap.keySet()) {
			List<AtlasNavigationVO> relations = relationsmap.get(key);
			String relation = String.format("%s%s%s[style=invis]\n", key, this.getDirection(), getAtlasId(relations.get(0)));
			bw.write(relation);
		}

	}
	/**
	 * 生成每组数据水平之间的虚拟联系
	 * @param weight 虚拟水平数据的重量,如1,2,3,
	 * @param relations 每组group的数据,比如解决方案所有节点
	 * @throws Exception
	 */
	private void generateVirtualRelation(String weight,
			List<AtlasNavigationVO> relations) throws Exception {
		StringBuilder relation = new StringBuilder();
		int relsize = relations.size();
		if(relsize >= 2){
			for (int i = 0; i < relsize - 1; i++) {
				relation.append(getAtlasId(relations.get(i)));
				relation.append(this.getDirection());
			}
			relation.append(getAtlasId(relations.get(relsize - 1)));
			relation.append("[style=invis weight=");
			relation.append(weight);
			relation.append("]\n");
			bw.write(relation.toString());
		}
	}

	protected String getAtlasId(String id){
		return "abc_" + id;
	}

	protected String getAtlasId(AtlasNavigationVO avo){
		return getAtlasId(avo.getId());
	}

	protected String getAtlasId(RelationShipVO rvo){
		return getAtlasId(rvo.getAssetId());
	}

	/**
	 * 生成结束
	 * @throws Exception
	 */
	protected void generateFoot() throws Exception {
		generateClusterEnd();
		bw.flush();
		bw.close();

	}

	protected String getDirection(){
		String direction = "->";
		if(!this.undirected){
			direction = "->";
		}
		return direction;
	}

	protected void generateDotFile() throws Exception {
		//生成svg用于页面显示,png用于下载
		Process proc = new ProcessBuilder(graphviz2xdot, gvout, "-T" + outformat, "-o", gvdotout).start();
		wait(proc);
	}


	private void wait(Process process) throws Exception{
       InputStream in=process.getInputStream();
		byte[] re=new byte[1024];
	    while (in.read(re)!= -1) {
	    	System.out.println(new String(re));
		}
		in.close();
		InputStream err=process.getErrorStream();
	    while (err.read(re)!= -1) {
	    	System.out.println(new String(re));
		}
	    err.close();
	}

	protected String nextNodeColor(String key){
		String cateColor = nodeColors.get(key);
		if (StringUtils.isBlank(cateColor)) {
			String color = colorTable[colorRnd.nextInt(colorNumber)];
			nodeColors.put(key, color);
			return color;
		}else {
			return cateColor;
		}
	}

	protected String nextEdgeColor(String key){
		String edgeColor = edgeColors.get(key);
		if (StringUtils.isBlank(edgeColor)) {
			String color = colorTable[colorRnd.nextInt(colorNumber)];
			edgeColors.put(key, color);
			return color;
		}else {
			return edgeColor;
		}
	}


	// 测试本地Graphviz转xdot
	public static void main(String[] args) throws Exception {
		Map<String,List<AtlasNavigationVO>> relationsmap = new HashMap<String,List<AtlasNavigationVO>>();
		new HashSet();
		new Random();
		List<AtlasNavigationVO> list1 = new ArrayList<AtlasNavigationVO>();
		AtlasNavigationVO avo1 = new AtlasNavigationVO();
		avo1.setName("p0");
		List<RelationShipVO> rlist1 = new ArrayList<RelationShipVO>();
		RelationShipVO ro1 = new RelationShipVO();
		ro1.setAssetName("s1");
		rlist1.add(ro1);
		avo1.setRelatedasset(rlist1);
		list1.add(avo1);
		relationsmap.put("产品", list1);

//		List<AtlasNavigationVO> list2 = new ArrayList<AtlasNavigationVO>();
//		AtlasNavigationVO avo2 = new AtlasNavigationVO();
//		avo2.setName("p1");
//		List<RelationShipVO> rlist2 = new ArrayList<RelationShipVO>();
//		RelationShipVO ro2 = new RelationShipVO();
//		ro2.setAssetName("s1");
//		rlist2.add(ro2);
//		avo2.setRelatedasset(rlist2);
//		list2.add(avo2);
//		relationsmap.put("产品", list2);
//
//		List<AtlasNavigationVO> list3 = new ArrayList<AtlasNavigationVO>();
//		AtlasNavigationVO avo3 = new AtlasNavigationVO();
//		avo3.setName("s1");
//		List<RelationShipVO> rlist3 = new ArrayList<RelationShipVO>();
//		RelationShipVO ro3 = new RelationShipVO();
//		ro3.setAssetName("p0");
//		rlist3.add(ro3);
//		avo3.setRelatedasset(rlist3);
//		list3.add(avo3);
//		relationsmap.put("解决方案", list3);
//

		GraphvizDotGenerator gdg = new GraphvizDotGenerator("d:/out.gv", "d:/out.dot", "svg", relationsmap);
		gdg.generate();

	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值