index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
*{
margin: 0;
padding: 0;
}
#keyword{
height: 90%;
width: 95%;
position: absolute;
top: 55px;
bottom: 0px;
z-index: 0;
overflow:hidden;
word-break:break-all;
}
#keyword2{
height: 90%;
width: 95%;
position: absolute;
top: 55px;
bottom: 0px;
z-index: 0;
overflow:hidden;
word-break:break-all;
}
.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}
#licensing {
fill: green;
}
.link.licensing {
stroke: green;
}
.link.resolved {
stroke-dasharray: 0,2 1;
}
circle {
stroke: #333;
stroke-width: 1.5px;
}
text {
font: 12px Microsoft YaHei;
pointer-events: none;
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
}
.linetext {
font: 12px Microsoft YaHei;
}
.mytooltip{
position: absolute;
height: auto;
font-family: "microsoft yahei", simhei;
font-size: 14px;
text-align: center;
border: 1px solid #999;
padding: 5px;
background-color: white;
border-radius: 5px;
opacity:0.0;
}
#gallery {
width: 200px;
height: 200px;
/*background: url('img/1.JPG') no-repeat center center;
background-size:100%;
font-size:30px;
color:#fff;*/
text-align:center;
/*line-height:200px;*/
}
</style>
<link rel="stylesheet" type="text/css" href="css/easyui.css">
<link rel="stylesheet" type="text/css" href="css/icon.css">
</head>
<body>
<div title="数据展示" >
<div id="keyword">
</div>
<div id="keyword2" style="top:80px;position: fixed;opacity: 0">
</div>
</div>
<img id="img_id" src="img/map.jpg" onmousemove="imgMouseMove(this,event)" onmouseover="imgMouseOver(this)"
onmouseleave="imgMouseOut(this)" onclick="imgClick(this,event)"
style="position: fixed;bottom: 5px;right: 5px;z-index: 100px;width: 136.6px;height: 76.8px"/>
<div class="mytooltip" id="imgtooltip"></div>
<script src="assets/plugins/jquery/jquery-3.3.1.min.js"></script>
<script src="assets/plugins/jquery.easyui.min.js"></script>
<script src="assets/plugins/d3/d3.v3.min.js"></script>
<script src="assets/plugins/html2canvas.js"></script>
<script src="assets/js/pages/index.js"></script>
</body>
</html>
index.js
var root = {};
var nodesbak = {};
var colorObj = {};
var imgtype = 0;
var maxValue = 0;//最大的那个系统
$(function (){
$.getJSON("assets/data/word.json", function (data){
root = deepClone(data,{});
//系统备份
root.nodes.concat().forEach(function(node,k) {
if(node.value > maxValue){
maxValue = node.value;
}
colorObj[node.id] = k;
nodesbak[node.id] = {name:node.id,group:node.group,x1:node.x,y1:node.y,type:node.id,value:node.value};
});
//表备份
root.nodes1.concat().forEach(function(node,k) {
nodesbak[node.id] = {name:node.id,group:node.group,x1:node.x,y1:node.y,pid:node.pid,type:node.pid};
});
//画系统布局图
draw(root.nodes,root.links,sys_transform,sys_scale,null);
//画表的矩形树图
drawTabImg();
//表矩形树图截图
doScreenShot();
})
$("#img_id").hide();
$("#sys_keyword").val("");
})
var links = [];//关联关系
var nodes = {};//节点数据
var initscale = 1;//保留一份最初始的缩放系数,用于放大时计算最近距离
var sys_scale = 1;//域、系统放大时的缩放倍数
var sys_transform = [0,0];//域、系统放大时的中心坐标
var tab_scale = 1;//表放大时的缩放倍数
var tab_transform = [0,0];//表放大时的中心坐标
var edges_line = null;//连接线
var circle = null;//节点
var edges_text = null;//连接线上的文字
var text = null;//节点文字
var svg = null;
var force = null;//力学图对象
var zoom = null;//缩放配置
var dx = 0;//x偏移量
var dy = 0;//y偏移量
var ds = 1;//放大缩小倍数
var m_down_x ;//拖拽前x
var m_down_y ;//拖拽前y
var m_move_x ;//拖拽后x
var m_move_y ;//拖拽后y
var isDown = false;//记录鼠标状态
var width = '100%',height = '100%';
var type = '1';//'1':域、系统;'2':表
//格式化数据
function formatData(paramNodes,paramLinks,pid){
var m = 0;
var copynodes = deepClone(nodesbak,{});
paramNodes.forEach(function(node,k) {
var x = copynodes[node.id].x1;
var y = copynodes[node.id].y1;
if(pid == null){
if(type == 1){
x = x*((screen.width -100)/1366);
y = y*((screen.height -280)/768);
}
if(type == 2){
x = x*10;
y = y*10;
}
if(x*ds+dx > 0 && x*ds+dx < screen.width
&& y*ds+dy > 0 && y*ds+dy < (screen.height -280) && m < 500/ds
){
nodes[node.id] = {name: node.id,group:node.group,x1:x,y1:y,type:(type ==1?node.id:node.pid)};
m++;
}
return;
}
if(pid != null && pid == node.pid){
x = x*10;
y = y*10;
if(x*ds+dx > 0 && x*ds+dx < screen.width
&& y*ds+dy > 0 && y*ds+dy < (screen.height -280) && m < 500/ds
){
nodes[node.id] = {name: node.id,group:node.group,x1:x,y1:y,type:(type ==1?node.id:node.pid)};
m++;
}
}
});
for(var i=0;i<paramLinks.length;i++){
if(nodes[paramLinks[i].source] != null && nodes[paramLinks[i].target] != null){
links.push({
source: paramLinks[i].source,
target: paramLinks[i].target,
rela: paramLinks[i].value
})
}
}
links.forEach(function(link) {
//利用source和target名称进行连线以及节点的确认
link.source = nodes[link.source];
link.target = nodes[link.target];
});
}
function zoomed(){//缩放函数
svg.selectAll("g").attr("transform",//svg下的g标签移动大小
"translate(" +d3.event.translate + ")scale(" +d3.event.scale + ")");
}
//绘制图像
function draw(paramNodes,paramLinks,paramTransform,paramScale,pid) {
tooltip ?tooltip.html(""):tooltip;
nodes = {};
links = [];
edges_line = null;//连接线
circle = null;//节点
edges_text = null;//连接线上的文字
text = null;//节点文字
formatData(paramNodes,paramLinks,pid);
force = d3.layout.force()//layout将json格式转化为力学图可用的格式
.nodes(d3.values(nodes))//设定节点数组
.links(links)//设定连线数组
.size([width, height])//大小
.linkDistance(120)//连接线长度
.charge(-600)//值为+,则相互吸引,绝对值越大吸引力越大。值为-,则相互排斥,绝对值越大排斥力越大
.on("tick", tick)//开始转换
.start();
zoom = d3.behavior.zoom()//缩放配置,
.scaleExtent([0.4, 10])//缩放比例
.on("zoom", zoomed);
svg = d3.select("#keyword").append("svg")//添加svg元素进行图形的绘制
.attr("width", width)
.attr("height", height)
.call(zoom)
.on("mousedown",function(event){
isDown = true;
//获取鼠标按下时坐标
m_down_x = d3.event.pageX;//拖拽前x
m_down_y = d3.event.pageY;//拖拽前y
})
.on("mousemove",function(){
//获取鼠标移动实时坐标
m_move_x = d3.event.pageX;
m_move_y = d3.event.pageY;
if(type == 2){//鼠标移动到某个区域后,显示那个区域的域或者系统
getSysByXy(m_move_x,m_move_y);
}
})
.on("mouseup",function(){
isDown = false;
var mx = m_move_x - m_down_x;
var my = m_move_y - m_down_y;
//获取鼠标偏移量
if(mx != 0 || my != 0){
//有偏移量的情况下,再去加载数据
svg.selectAll('g').remove();
d3.select("#keyword").selectAll("svg").remove();
if(type == 1){
draw(root.nodes,root.links,[dx,dy],ds,null);
} else if(type == 2){
var val = $("#sys_keyword").val() == ""?null:$("#sys_keyword").val();
draw(root.nodes1,root.links1,[dx,dy],ds,val);
}
}
});//使顶点可以被拖动;//使顶点可以被拖动;
//箭头
var marker=
svg.append("marker")
.attr("id", "resolved")
.attr("markerUnits","userSpaceOnUse")
.attr("viewBox", "0 -5 10 10")//坐标系的区域
.attr("refX",18)//箭头坐标
.attr("refY", -1)
.attr("markerWidth", 12)//标识的大小
.attr("markerHeight", 12)
.attr("orient", "auto")//绘制方向,可设定为:auto(自动确认方向)和 角度值
.attr("stroke-width",2)//箭头宽度
.append("path")
.attr("d", "M0,-5L10,0L0,5")//箭头的路径
.attr('fill','#000000');//箭头颜色
edges_line = setLine();//设置连接线
circle = setTabNode();//设置节点
//edges_text = setEdgesText();//设置连接线上的文字
text = setText();//设置节点文字
svg.selectAll("g").attr("transform",//svg下的g标签移动大小
"translate("+paramTransform.toString()+")scale("+paramScale+")");
zoom.translate(paramTransform);
zoom.scale(paramScale);
svg.selectAll("g").call(drag());//为svg下的所有g标签添加拖拽事件
svg.on("dblclick.zoom", null);//取消svg和圆圈的双击放大事件(d3中默认开启7个事件,关闭防止与上面的双击事件冲突)
circle.on("dblclick.zoom", null);
}
//设置连接线
function setLine(){
var edges_line = svg.append("g").selectAll(".edgepath")
.data(force.links())//连线数据
.enter()//当数组中的个数大于元素个数时,由d3创建空元素并与数组中超出的部分进行绑定。
//可以参考http://www.ourd3js.com/wordpress/797/ enter、exit、update的区别
.append("path")//添加path标签
.attr({
'd': function(d) {
return 'M '+d.source.x1+' '+d.source.y1+' L '+ d.target.x1 +' '+d.target.y1},//变量 d 是由D3.js提供的一个在匿名函数中的可用变量。这个变量是对当前要处理的元素的_data_属性的引用。
'class':'edgepath',//定义该path标签class为edgepath
'id':function(d,i) {return d.source.name+"_"+d.target.name;},
'rid':function(d,i) {return d.source.name;},
'sid':function(d,i) {return d.target.name;}
})// i也是d3.js提供的变量,表示当前处理的HTML元素在已选元素选集中的索引值
.attr("marker-end", "url(#resolved)")
.style("stroke","#B43232")//设置线条颜色
.style("stroke-width",0.5);//线条粗细
return edges_line;
}
function drag(){//拖拽函数
return force.drag()
.on("dragstart",function(d){
d3.event.sourceEvent.stopPropagation(); //取消默认事件
d.fixed = true; //拖拽开始后设定被拖拽对象为固定
});
}
//圆圈的提示文字 根据需要到数据库中进行读取数据
var tooltip = d3.select("body")
.append("div")//添加div并设置成透明
.attr("class","mytooltip")
.style("opacity",0.0);
var localColor = d3.scale.category20();
//设置域、系统图片
function setTabNode(){
var circle = svg.append("g")
.selectAll("circle")
.data(force.nodes())//表示使用force.nodes数据
.enter()
.append("circle")
.attr("class", "circle")
/*.attr("transform", function(node,i){
return "translate("+node.x1+","+node.y1+")";
})*/
.attr("cx", function(node,i){
return node.x1;
})
.attr("cy", function(node,i){
return node.y1;
})
.attr("id", function(node,i){
return node.name;
})
.attr("r",function(node,i){
if(node.group == 1 || node.group == 2){
if(nodesbak[node.name].value == maxValue){//最大
return 20;
}else if(nodesbak[node.name].value/(maxValue/20) < 3){//最小
return 3;
}else{
return nodesbak[node.name].value/(maxValue/20);
}
} else{
return 3;
}
})//设置圆圈半径
.style('fill',function (node,i) {
return localColor(colorObj[node.type]);
})
.on("click",function(node){
//单击时让连接线加粗
edges_line.style("stroke-width",function(line){
if(line.source.name==node.name || line.target.name==node.name){//当与连接点连接时变粗
return 2;
}else{
return 2.5;
}
});
circle.style('stroke-width',1);//所有的圆圈边框
d3.select(this).style('stroke-width',4);//被选中的圆圈边框
})
.on("dblclick",function(d){
//双击节点时节点恢复拖拽
d.fixed = false;
})
.on("mouseover",function(d){
set_tooltip(d.name);
})
.on("mousemove",function(d){
tooltip.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY + 20) + "px");
})
.on("mouseout",function(d){
tooltip.style("opacity",0.0);
})
.call(drag());//使顶点可以被拖动
return circle;
}
//设置圆圈上的文字
function setText(){
var text = svg.append("g").selectAll("text")
.data(force.nodes())
//返回缺失元素的占位对象(placeholder),指向绑定的数据中比选定元素集多出的一部分元素。
.enter()
.append("text")//添加text标签
.attr("dy", ".35em") //将文字下移
.attr("text-anchor", "middle")//在圆圈中加上数据
.style('fill',function (node,i) {
return localColor(colorObj[node.type]);
})
.style('cursor',"pointer")
.attr('id',function(d){return 'text_'+d.name;})
.attr("transform", function(node,i){
return "translate("+node.x1+","+node.y1+")";
})
.on("mouseover",function(d){
set_tooltip(d.name);
})
.on("mouseout",function(d){
tooltip.style("opacity",0.0);
})
.call(drag())
.attr('x',function(d){
//如果小于6个字符,不换行
if(d.name.length <= 6){
d3.select(this).append('tspan')
.attr('x',6)
.attr('y',35)
.text(function(){return d.name;});
} else if(d.name.length > 12){//大于12个字符时,将12个字后的内容显示为。。。
var top=d.name.substring(0,6);
var bot=d.name.substring(6,12)+"...";
d3.select(this).text(function(){return '';});
d3.select(this).append('tspan')//前n个字
.attr('x',0)
.attr('y',35)
.text(function(){return top;});
d3.select(this).append('tspan')//后n个字
.attr('x',0)
.attr('y',52)
.text(function(){return bot;});
} else {//6-12字符分两行显示
var top=d.name.substring(0,6);
var bot=d.name.substring(6,d.name.length);
d3.select(this).text(function(){return '';});
d3.select(this).append('tspan')
.attr('x',0)
.attr('y',35)
.text(function(){return top;});
d3.select(this).append('tspan')
.attr('x',0)
.attr('y',52)
.text(function(){return bot;});
}
});
return text;
}
//连线上的文字
function setEdgesText(){
var edges_text = svg.append("g").selectAll(".edgelabel")
.data(force.links())
.enter()
.append("text")//添加text标签
.attr({ 'class':'edgelabel',//定义该text标签class为edgelabel
'id':function(d,i){return 'edgepath_'+i;},
'dx':50,//在连线上的坐标
'dy':0
});
//设置线条上的文字路径
edges_text.append('textPath')
.attr('xlink:href',function(d,i) {return '#edgepath_'+i})
.style("pointer-events", "none")
.text(function(d){return d.rela;});
return edges_text;
}
function tick() {//刷新页面函数
}
//设置连线上的文字一直显示在中间
function getLineTextDx(d){
var copyNodes = deepClone(nodesbak,{});
var sourceId = d.source.name;
var targetId = d.target.name;
var sx = copyNodes[sourceId].x1;
var sy = copyNodes[sourceId].y1;
var tx = copyNodes[targetId].x1;
var ty = copyNodes[targetId].y1;
var distance = Math.sqrt(Math.pow(tx-sx,2)+Math.pow(ty-sy,2));
var textLength = d.rela.length;
var deviation = 8;
var dx = (tx + sx)/2;
return dx;
}
function set_tooltip(name){//设置提示内容
var r;
for(var i=0;i<links.length;i++){
if(name == links[i].source.name || name == links[i].target.name){
r=links[i].rela;
break;
}
}
tooltip.html(name)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY + 20) + "px")
.style("opacity",1.0);
}
function deepClone(obj1,obj2){
var obj2=obj2||{}; //最初的时候给它一个初始值=它自己或者是一个json
for(var name in obj1){
if(typeof obj1[name] === "object"){ //先判断一下obj[name]是不是一个对象
obj2[name]= (obj1[name].constructor===Array)?[]:{}; //我们让要复制的对象的name项=数组或者是json
deepClone(obj1[name],obj2[name]); //然后来无限调用函数自己 递归思想
}else{
obj2[name]=obj1[name]; //如果不是对象,直接等于即可,不会发生引用。
}
}
return obj2; //然后在把复制好的对象给return出去
}
//设置圆圈和文字的坐标
function transform1(d) {
return "translate(" + d.x + "," + d.y + ")";
}
//根据鼠标的点击位置获取当前所在的域或者系统
function getSysByXy(temp_x,temp_y) {
root.nodes.concat().forEach(function(node,k) {
var xmin = node.xmin*10*ds+dx;
var xmax = node.xmax*10*ds+dx;
var ymin = node.ymin*10*ds+dy;
var ymax = node.ymax*10*ds+dy;
if(temp_x > xmin && temp_x < xmax && temp_y > ymin && temp_y < ymax){
$("#d").val(node.id);
}
});
}
//鼠标移动
function imgMouseMove(obj,event){
//计算鼠标在图片上的坐标,以此算出在表页面中的坐标
var img_right = parseInt(obj.style.right);
var img_bottom = parseInt(obj.style.bottom);
//图片的起始坐标
var img_x = screen.width - img_right - 683;//549
var img_y = screen.height - 130 - img_bottom - 384;//307
//鼠标所在坐标
var client_x = event.clientX;
var client_y = event.clientY;
//鼠标对于图片的坐标
var x = client_x-img_x;
var y = client_y-img_y;
//根据鼠标移到图片上的坐标显示对应的域或者系统
getSysByImgXy(x*2,y*2,event);
}
//鼠标点击
function imgClick(obj,event){
//计算鼠标在图片上的坐标,以此算出在表页面中的坐标
var img_right = parseInt(obj.style.right);
var img_bottom = parseInt(obj.style.bottom);
//图片的起始坐标
var img_x = screen.width - img_right - 683;
var img_y = screen.height - 130 - img_bottom - 384;
//鼠标所在坐标
var client_x = event.clientX;
var client_y = event.clientY;
//鼠标对于图片的坐标
var x = client_x-img_x;
var y = client_y-img_y;
//将坐标放大到屏幕
var x1 = x*2*10;
var y1 = y*2*10;
//目标坐标(这里是将鼠标点击的区域放到屏幕的中心位置,所以屏幕的中心坐标作为目标坐标)
var x2 = screen.width/2;
var y2 = 950/2;
//偏移量
dx = x2-x1;
dy = y2-y1;
ds = 1;
svg.selectAll('g').remove();
d3.select("#keyword").selectAll("svg").remove();
draw(root.nodes1,root.links1,[dx,dy],ds,null);
}
//根据鼠标在图片上的位置显示当前所在的域或者系统
function getSysByImgXy(temp_x,temp_y,event) {
root.nodes.concat().forEach(function(node,k) {
var xmin = node.xmin;
var xmax = node.xmax;
var ymin = node.ymin;
var ymax = node.ymax;
if(temp_x > xmin && temp_x < xmax && temp_y > ymin && temp_y < ymax){
$("#imgtooltip").html(node.id)
.css("left", (event.clientX) + "px")
.css("top", (event.clientY + 20) + "px")
.css("opacity",1.0);
}
});
}
//鼠标进入
function imgMouseOver(obj){
$(obj).animate({width:683,height:384},500);
}
//鼠标移出
function imgMouseOut(obj){
$(obj).animate({width:136.6,height:76.8},500);
$("#imgtooltip").html("")
.css("opacity",0.0);
}
//截图
function doScreenShot(){
html2canvas(document.getElementById('svgtreemap'), {
allowTaint:false,
taintTest:false,
onrendered: function (canvas) {
var canvasData = canvas.toDataURL();
$("#img_id").attr("src",canvasData);
// $("#img_id").show();
$("#keyword2").remove();
},
// useCORS: true// 此代码针对跨域问题
});
}
//画表的矩形树图
function drawTabImg(){
//var color = d3.scale.category20b();
var obj = {name:"测试"};
var childrens = [];
var datas = root.nodes.concat();
for(var k = datas.length-1; k >= 0; k--){
childrens.push(datas[k]);
}
obj['children'] = childrens;
var treemap = d3.layout.treemap()
.size([1366,768])
.value(function(d){
return d.value;
});
var nodestreemap =treemap.nodes(obj);
var svgtreemap = d3.select("#keyword2").append("svg")//添加svg元素进行图形的绘制
.attr("id", "svgtreemap")
.attr("width", 1366)
.attr("height", 768);
var groups = svgtreemap.selectAll("g")
.data(nodestreemap.filter(function(d){return !d.children;}))
.enter()
.append("g");
var rects = groups.append("rect")
.attr("class","node")
.attr("x",function(d){return d.xmin;})
.attr("y",function (d){return d.ymin;})
.attr("width",function(d){return d.xmax - d.xmin;})
.attr("height",function(d){return d.ymax - d.ymin;})
.style("fill",function(d,k){return localColor(colorObj[d.id]);});
var texts = groups.append("text")
.attr("class","nodename")
.attr("x",function(d){return (d.xmax - ((d.xmax - d.xmin)/2 + 20));})
.attr("y",function (d){return (d.ymax - (d.ymax - d.ymin)/2);})
.attr("dx","0.5em")
.attr("dy","1.5em")
.text(function(d){return d.id});
}