数据可视化:柱状图、二叉树、饼图、力导向、词云图的实现
1. js绘制SVG直方图
实现方法
获取屏幕分辨率&浏览器可用宽度
<p id="demo"></p>
<script>
var w=window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
var h=window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;
x=document.getElementById("demo");
x.innerHTML="浏览器的内部窗口宽度:" + w + ",高度:" + h + "。"
</script>
在JS中动态添加SVG的矩形
<script>
var hist=document.getElementById("histSvg");
//SVG添加文本
var svgText=document.createElement("text");
hist.appendChild(svgText);
svgText.outerHTML="<text x=0 y=20 style='font-family:微软雅黑;fill:rgb(0,0,255);font-size:20'> "+w+" </text>";
//SVG添加图形
var myRect=document.createElement("rect");
hist.appendChild(myRect);
myRect.outerHTML="<rect x=20 y=50 width=100 height=300 style='fill:blue'/>";
</script>
完整代码
<html>
<body>
<svg id="mysvg" width="2000" height="1200">
</svg>
<script charset=”utf-8″>
var svg=document.getElementById("mysvg"); //创建一个矢量图变量
var rec=new Array(34);
var captine_name=new Array(34);
var captinne_name=new Array(34);
var population_data=new Array(11169,10005.83,9559.13,8302,8029.3,
7519.52,6860.2,6254.8,5902,
5657,4885,4800.5,4622.1,4368.9,3911,3835.44,
3788.7,3702.35,3580,3048.43,2717.43,
2625.71,
2528.6,2444.67,2418.33,2369,
2170.7,1556.87,925.76,743,681.79,598.38,337.15,63.2);
var captine=new Array("广东","山东","河南","四川","江苏","河北","湖南","安徽",
"湖北","浙江","广西","云南","江西","辽宁","福建","陕西","黑龙江","山西","贵州",
"重庆","吉林","甘肃","内蒙古","新疆","上海","台湾","北京","天津","海南","香港",
"宁夏","青海","西藏","澳门");
for(var i=0;i<34;i++)
{
rec[i]=document.createElement("rect");
svg.appendChild(rec[i]);
var rec_height=population_data[i]/20;
var color_value=Math.random()*255;
rec[i].outerHTML="<rect x="+i*55+" y="+(600-rec_height)+" width=25 height="+rec_height+" fill=rgb(0,"+color_value+",0)>";
captine_name[i]=document.createElement("text");
svg.appendChild(captine_name[i]);
captine_name[i].outerHTML="<text x="+i*55+" y="+(600-rec_height)+" font-size:25 fill=rgb(0,0,255 >"+population_data[i]+"</text>";
captinne_name[i]=document.createElement("text");
svg.appendChild(captinne_name[i]);
captinne_name[i].outerHTML="<text x="+i*55+" y=610 font-size:25 fill=rgb(0,0,255)charset=”utf-8” >"+captine[i]+"</text>";
}
</script>
</body>
</html>
结果截屏
2.分形二叉树
实现方法
递归
<html>
<head>
<title>
标准分形二叉树
</title>
</head>
<body>
<line x1=0 y1=0 x2=800 y2=800></line>
<svg id="mySvg" width=800 height=600>
<!-- <line x1=0 y1=0 x2=800 y2=800 stroke='blue'/>
var lineY=document.createElement("line");
mysvg.appendChild(lineY);
lineY.outerHTML="<line x1="+w/2+" y1=0 x2="+w/2+" y2="+h+" stroke='blue'/>";
-->
</svg>
<script>
var w=window.innerWidth|| document.documentElement.clientWidth|| document.body.clientWidth;
var h=window.innerHeight|| document.documentElement.clientHeight|| document.body.clientHeight;
var mysvg=document.getElementById("mySvg");
w=w*0.9;
h=h*0.9;
var L=300; <!-- 线段长度-->
var rate=0.8; <!--衰减率-->
var a=-Math.PI/2; <!--0度-->
count=7; <!--迭代次数-->
var x0=w/3; <!--定义起点-->
var y0=h/1.2;
mysvg.setAttribute("width",w);
mysvg.setAttribute("heiht",h);
function show(x0,y0,L,rate,a,count)
{
var x1=x0;
var y1=y0;
var x2=x1+L*rate*Math.cos(a);
var y2=y1+L*rate*Math.sin(a);
var L=L*rate*(0.5+Math.random()/2);
var aL=a-Math.PI/4*(0.5+Math.random()/2);
var aR=a+Math.PI/4*(0.5+Math.random()/2);
var lineX=document.createElement("line");
mysvg.appendChild(lineX);
lineX.outerHTML="<line x1="+x1+" y1="+y1+" x2="+x2+" y2="+y2+" stroke='purple' stroke-width="+count+" />";
if(count>0)
{
show(x2,y2,L,rate,aL,count-1);
show(x2,y2,L,rate,aR,count-1);
}
}
show(x0,y0,L,rate,a,count);
</script>
</body>
</html>
3.文字二叉树
实现方法
<html>
<head>
<title>
wordtree
</title>
<style>
#header{
background-color:black;
color:white;
text-align:center;
padding:8px;
};
</style>
</head>
<meta charset="UTF-8">
<body >
<div id="header">
<h3>201811113022罗梦18计科-文字二叉树</h3>
<line x1=0 y1=0 x2=800 y2=800></line>
<svg id="mySvg" width=900 height=1000>
<!-- <line x1=0 y1=0 x2=800 y2=800 stroke='blue'/>
var lineY=document.createElement("line");
mysvg.appendChild(lineY);
lineY.outerHTML="<line x1="+w/2+" y1=0 x2="+w/2+" y2="+h+" stroke='blue'/>";
-->
</svg>
<script>
var w=window.innerWidth|| document.documentElement.clientWidth|| document.body.clientWidth;
var h=window.innerHeight|| document.documentElement.clientHeight|| document.body.clientHeight;
var mysvg=document.getElementById("mySvg");
w=w*0.9;
h=h*0.9;
var L=300; <!-- 线段长度-->
var rate=0.8; <!--衰减率-->
var a=-Math.PI/2; <!--0度-->
count=7; <!--迭代次数-->
var x0=w/2; <!--定义起点-->
var y0=h+40;
mysvg.setAttribute("width",w);
mysvg.setAttribute("heiht",h);
function show(x0,y0,L,rate,a,count)
{
var str="一直熬夜一直爽,天亮就送火葬场";
var strfontsize=count*2;
var L=strfontsize*str.length; //字符串长度+字体大小
//var L=50;
var x1=x0;
var y1=y0;
var x2=x1+L*Math.cos(a);
var y2=y1+L*Math.sin(a);
//var L=L*rate*(0.5+Math.random()/2);
var aL=a-Math.PI/4*(0.5+Math.random()/2);
var aR=a+Math.PI/4*(0.5+Math.random()/2);
var rec_h=Math.random()*255;
var rredcircle=document.createElement("circle");
mysvg.appendChild(rredcircle);
var redcircle=document.createElement("circle");
mysvg.appendChild(redcircle);
// var lineX=document.createElement("line");
// mysvg.appendChild(lineX);
// lineX.outerHTML="<line x1="+x1+" y1="+y1+" x2="+x2+" y2="+y2+" stroke='purple' stroke-width="+count+" />";
var words=document.createElement("text");
mysvg.appendChild(words);
//words.outerHTML="<text x="+x1+" y="+y1+" font-size='15' fill='green'>平</text>";
words.outerHTML="<text x="+x1+" y="+y1+" transform='rotate("+a*180/Math.PI+","+x1+","+y1+")' fill='white' font-size="+strfontsize+">一直熬夜一直爽,天亮就送火葬场</text>";
// words.outerHTML="<text x="+x1+" y="+y1+" transform='rotate("+a*180/Math.PI+","+x1+","+y1+")' fill='red'font-size="+strfontsize+">"+str+"</text>";
if(count<=1)
{
var randomR=Math.random();
// rredcircle.outerHTML="<circle cx="+x1+" cy="+y1+" r="+(8*randomR)+" fill='red'/>";
redcircle.outerHTML="<circle cx="+x1+" cy="+y1+" r="+(10*randomR)+" fill='red'/>";
}
if(count>0)
{
show(x2,y2,L,rate,aL,count-1);
show(x2,y2,L,rate,aR,count-1);
}
}
show(x0,y0,L,rate,a,count);
show(x0,y0,L,rate,a,count);
show(x0,y0,L,rate,a,count);
show(x0,y0,L,rate,a,count);
// show(x0,y0,L,rate,a,count);
</script>
</div>
</body>
</html>
4.D3概述&直方图
实现方法
1、在页面添加一个SVG绘图区和矩形框
<script>
var width=document.body.clientWidth;
var height=document.body.clientHeight;
var dataset=[189,300,60,200,120,150];
var svg=d3.select("body")
.append("svg")
.attr("width",width)
.attr("height",height);
var rect=svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("fill","green")
.attr("x",100)
.attr("y",50)
.attr("width",240)
.attr("height",300)
</script>
2-3矩形向上生长
<script>
var width=document.body.clientWidth;
var height=document.body.clientHeight;
var dataset=[189,300,60,200,120,150];
var svg=d3.select("body")
.append("svg")
.attr("width",width)
.attr("height",height);
var rect=svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("fill","green")
.attr("x",function(d,i){return i*250})
.attr("y",function(d,i){return 800-d})
.attr("width",240)
.attr("height",function(d,i){return d})
</script>
4矩形添加文本数值
var text=svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.attr("fill","red")
.attr("x",function(d,i){return i*250})
.attr("y",function(d,i){return 800-d})
.attr("dx",120)
.attr("dy","1em")
.text("Hi")
总代码
<html>
<head>
<meta charset="utf-8">
<title>D3直方图绘制</title>
</head>
<body>
<h1 align="center" >北京市4.2-4.15两周内天气最高温度变化情况统计图</h1>
<h2 align="right" >---数据来源:中国天气网</h1>
<h2 align="right" >计科--10鲁俊丽--22罗梦</h2>
<script src="https://d3js.org/d3.v4.js"></script>
<script>
var dataset = [18,18,18,16,19,18,21,23,20,22,23,24,17,19];
var width = 1000; //SVG绘制区域的宽度
var height = 600; //SVG绘制区域的高度
var svg = d3.select("body") //选择<body>
.append("svg") //在<body>中添加<svg>
.attr("width", width) //设定<svg>的宽度属性
.attr("height", height);//设定<svg>的高度属性
//x轴宽度
var xAxisWidth = 800;
//y轴宽度
var yAxisWidth = 400;
//x轴比例尺
var xScale = d3.scaleBand()
.domain(['4.2','4.3','4.4','4.5','4.6','4.7','4.8','4.9','4.10','4.11','4.12','4.13','4.14','4.15'])
.range([0,xAxisWidth]);
//y轴比例尺
var yScale = d3.scaleLinear()
.domain([0,d3.max(dataset)])
.range([0,yAxisWidth]);
//外边框
var padding = { top: 30 , right: 30, bottom: 180, left: 180 };
var text = svg.selectAll("text")
.data(dataset)
var rect = svg.selectAll("rect")
.data(dataset) //绑定数据
.enter() //获取enter部分
.append("rect") //添加rect元素,使其与绑定数组的长度一致
.attr("fill","steelblue") //设置颜色为steelblue
.attr("x", function(d,i){ //设置矩形的x坐标
return padding.left + xAxisWidth/14*i;
})
.attr("y", function(d){ //设置矩形的y坐标
return height- padding.bottom - yScale(d);
})
.attr("width",xScale.bandwidth()) //设置矩形的宽度
.attr("height",function(d){ //设置矩形的高度
return yScale(d);
});
//绑定数据
text
.enter() //获取enter部分
.append("text") //添加text元素,使其与绑定数组的长度一致
.attr("fill","white")
.attr("font-size","14px")
.attr("text-anchor","middle")
.attr("x", function(d,i){
return padding.left + xAxisWidth/14*i;
})
.attr("y", function(d){
return height- padding.bottom - yScale(d);
})
.attr("dx",xScale.bandwidth()/2)
.attr("dy","1em")
.text(function(d){
return d;
});
var xAxis = d3.axisBottom(xScale);
yScale.range([yAxisWidth,0]);
var yAxis = d3.axisLeft(yScale);
svg.append("g")
.attr("class","axis")
.attr("transform","translate(" + padding.left + "," + (height - padding.bottom) + ")")
.call(xAxis);
svg.append("g")
.attr("class","axis")
.attr("transform","translate(" + padding.left + "," + (height - padding.bottom - yAxisWidth) + ")")
.call(yAxis);
</script>
</body>
</html>
5.D3布局 饼图&环图&玫瑰图&交互
实现方法
<html>
<head>
<meta charset="utf-8">
<title>玫瑰图</title>
</head>
<body>
<h1 align="center" >第四十七次中国互联网网民学历构成调查图</h1>
<h2 align="right" >---数据来源:CNNIC中国互联网络发展状况统计调查</h1>
<script src="https://d3js.org/d3.v4.js" charset="utf-8"></script>
<script>
var w=window.innerWidth|| document.documentElement.clientWidth|| document.body.clientWidth;
var h=window.innerHeight|| document.documentElement.clientHeight|| document.body.clientHeight;
var width = w*0.98;
var height =h*0.72;
var padding = { top: 100 , right: 400, bottom: 380, left: 880 };
//x轴宽度
var xAxisWidth = 200;
//y轴宽
var yAxisWidth = 100;
var dataset = [["小学及以下",19.3],["初中",40.3],["高中/中专/技校",20.6],["大学专科",10.5],["大学本科及以上",9.3]];
//转化数据为适合生成饼图的对象数组
var pie = d3.pie()
.value(function(d){return d[1];});
innerRadius = 80;//圆环内半径
var arc=d3.arc()//设置弧度的内外半径,等待传入的数据生成弧度
.innerRadius(innerRadius)
.outerRadius(function (d) {
var value=d.value;
return value*3+ innerRadius+50;
});
var svg=d3.select("body")
.append("svg")
.attr("width",width)
.attr("height",height);
var color = d3.scaleOrdinal(d3.schemeCategory20);
//准备分组,把每个分组移到图表中心
var arcs=svg.selectAll("g")
.data(pie(dataset))
.enter()
.append("g")
//移到图表中心
.attr("transform", "translate(" + width / 3 + "," + ((height / 2)+25)+ ")");//translate(a,b)a表示横坐标起点,b表示纵坐标起点
//为组中每个元素绘制弧形路路径
arcs.append("path")//每个g元素都追加一个path元素用绑定到这个g的数据d生成路径信息
.attr("fill",function(d,i){//填充颜色
return color(i);
})
.attr("d",arc)//将角度转为弧度(d3使用弧度绘制
.on('mouseover',function(d,i){
d3.select(this)
.attr("fill", d3.rgb(color(i)).brighter());
svg.append("text")
.attr("id","info")
.attr("x",width/3)
.attr("y",height/2+25)
.attr("text-anchor","middle")
.attr("fill","steelblue")
.attr("font-size",20)
.text(d.data[0]);
svg.append("text")
.attr("id","value")
.attr("x",width/3)
.attr("y",height/2+50)
.attr("fill","steelblue")
.attr("text-anchor","middle")
.attr("font-size",20)
.text(d.value+"%");
})
.on('mouseout',function(d,i){
d3.select(this)
.attr("fill",color(i));
d3.select("#info")
.remove();
d3.select("#value")
.remove();
});
arcs.append("text")
.attr("transform",function(d){
var x = arc.centroid(d)[0];
var y = arc.centroid(d)[1];
return "translate(" + x + "," + y + ")";
})
.attr("text-anchor","middle")
//.attr("fill","steelblue")
.attr("font-size",function(d) {
return d.data[1]*0.8 + "px";
})
.text(function(d){
return (d.value+"%");
});
arcs.append("text")
.attr("font-size","14px")
.attr("text-anchor","start")
.attr("x", function(d){
return width-padding.right-240;
})
.attr("y", function(d,i){
return xAxisWidth/5*i-130;
})
.attr("text-anchor","middle")
//.attr("fill","steelblue")
.attr("font-size",function(d) {
return 14 + "px";
})
.text(function(d){
return (d.data[0]);
});
var widthH = 100; //SVG绘制区域的宽度
var heightH = 60; //SVG绘制区域的高度
var text1=["小学及以下","初中","高中/中专/技校","大学专科","大学本科及以上"];
var rect = svg.selectAll("rect")
.data(text1) //绑定数据
.enter() //获取enter部分
.append("rect") //添加rect元素,使其与绑定数组的长度一致
.attr("fill",function(d,i){//填充颜色
return color(i);
})
.attr("x", function(d,i){ //设置矩形的x坐标
return width-padding.right+100;
})
.attr("y", function(d,i){ //设置矩形的y坐标
//return height- padding.bottom;
return padding.top+xAxisWidth/5*i+50
})
.attr("height",40) //设置矩形的宽度
.attr("width",function(d){ //设置矩形的高度
//return yScale(d);
return 100;
});
</script>
<p align="right" >计科--10鲁俊丽--22罗梦</p>
</body>
</html>
7.JSP链接数据库并可视化
实现方法
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<h1 align="center" size=250%><font color=black > 中国互联网民职业结构调查</h1>
<h2 align="right">
来源:中国互联网发展状况统计调查2020.12
</h2>
</head>
<body charset="utf-8">
<p align="right"><img src="./images/cnniclogo.jpg"/></p>
<div id="wc"></div>
<%@ page contentType="text/html; charset=gb2312" %>
<%@ page language="java" %>
<%@ page import="com.mysql.jdbc.Driver" %>
<%@ page import="java.sql.*" %>
<%
//out.print("<center></center>");
//out.print("<left></left>");
//驱动程序名
String driverName="com.mysql.jdbc.Driver";
//数据库用户名
String userName="root";
//密码
String userPasswd="123456";
//数据库名
String dbName="2021occupationonile";
//表名
String tableName="occupation_online";
//联结字符串
String url="jdbc:mysql://localhost/"+dbName+"?user="+userName+"&password="+userPasswd;
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection connection=DriverManager.getConnection(url);
Statement statement = connection.createStatement();
float charcount[]=new float[14];
String occu[]=new String[14];
for(int i=1;i<15;i++){
String sql="SELECT * FROM "+tableName+" where id = '"+i+"'";
String str=" ";
float per=1;
ResultSet rs = statement.executeQuery(sql);
while(rs.next())
{
str=rs.getString(2);
per=rs.getFloat(3);
// out.print(per);
//out.print(str);
}
charcount[i-1]=per;
occu[i-1]=str;
rs.close();
}
statement.close();
connection.close();
%>
<script src="https://d3js.org/d3.v4.js" charset="utf-8"></script>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="d3.min.js"></script>
<script>
var w=window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
var h=window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;
w=w;
h=h*3.5;
var color=d3.scale.category20();
var color1=d3.scale.category20();
var dataset=new Array(14);
//var dataAlphabet=new Array(14);
var occupation=new Array(14);
<%
for (int i=0;i<14;i++){
%>
//dataset[i]=Math.floor(Math.random()*500);
dataset[<%=i%>]=<%=charcount[i]%>; //js的代码
//dataset[<%=i%>]={text:String.fromCharCode(<%=65+i%>),size:<%=charcount[i]%>};
//dataAlphabet[<%=i%>]=String.fromCharCode(<%=65+i%>);
occupation[<%=i%>]='<%=occu[i]%>';
<% }%>
var ww=w/dataset.length;
var svg=d3.select("body")
.append("svg")
.attr("width",w)
.attr("height",h);
var rect=svg.selectAll("rect")
.data(dataset)
.enter()
.append("rect")
.attr("x",function(d,i){return 120+i*w*0.85/dataset.length})
.attr("y",function(d){return 0.8*h-d*40})
.attr("width",ww*0.7)
.attr("height",function(d){return d*40})
.attr("fill",function(d,i){return color(i)});
var rect=svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
.attr("x",function(d,i){return 100+i*w*0.85/dataset.length})
.attr("y",function(d){return 0.8*h-40*d+8})
.text(function(d){return d+"%"})
.attr("dx",ww/2)
.attr("dy","-1em")
.attr("text-anchor","middle")
.attr("font-size",15)
.attr("fill",'black');
var rectA=svg.selectAll("text1")
.data(occupation)
.enter()
.append("text")
.attr("x",function(d,i){return 100+i*w*0.85/occupation.length})
.attr("y",function(d){return 0.8*h+23})
.attr("font-size",11)
.text(function(d){return d})
.attr("dx",ww/2)
.attr("dy","-1em")
.attr("text-anchor","middle")
.attr("font-size",7.4)
.attr("fill","black");
var dataset1=new Array(14);
var total=0;
<%
for (int i=0;i<14;i++){
%>
dataset1[<%=i%>]=['<%=occu[i]%>',<%=charcount[i]%>];
// total+=dataset1[<%=i%>][1];
<% }%>
//转化数据为适合生成饼图的对象数组
var pie = d3.pie()
.value(function(d){return d[1];});
innerRadius = 100;//圆环内半径
var arc=d3.arc()//设置弧度的内外半径,等待传入的数据生成弧度
.innerRadius(innerRadius)
.outerRadius(function (d) {
var value=10;
return value*d.data[1]+ 100+innerRadius;
});
//准备分组,把每个分组移到图表中心
var arcs=svg.selectAll("g")
.data(pie(dataset1))
.enter()
.append("g")
//移到图表中心
.attr("transform", "translate(" + w / 2 + "," + (h/5.5)+ ")");//translate(a,b)a表示横坐标起点,b表示纵坐标起点
//为组中每个元素绘制弧形路路径
arcs.append("path")//每个g元素都追加一个path元素用绑定到这个g的数据d生成路径信息
.attr("fill","steelblue")
.attr("d",arc)//将角度转为弧度(d3使用弧度绘制
.on('mouseover',function(d,i){
d3.select(this)
.attr("fill","green");
svg.append("text")
.attr("id","info")
.attr("x",w/2)
.attr("y",h/5.5)
.attr("text-anchor","middle")
.attr("font-size",24)
.text(i.data[0]);
/* .text(function(d) {
console.log(d);
console.log(dataset1[i]);
console.log(i);
//return dataset1[i][0];
return dataset1[i][0];;
});*/
console.log(d);
console.log(dataset1[i]);
console.log(i);
svg.append("text")
.attr("id","value")
.attr("x",w/2)
.attr("y",h/5.5+35)
.attr("text-anchor","middle")
.attr("font-size",24)
.text(i.data[1]+"%");
})
.on('mouseout',function(d,i){
d3.select(this)
.attr("fill","steelblue");
d3.select("#info")
.remove();
d3.select("#value")
.remove();
});
arcs.append("text")
.attr("transform",function(d){
var x = arc.centroid(d)[0];
var y = arc.centroid(d)[1];
return "translate(" + x + "," + y + ")";
})
.attr("text-anchor","middle")
.attr("font-size",function(d) {
return d.data[1] + "px";
})
.attr("fill","white")
.text(function(d){
return d.data[0]+d.data[1]+"%";
});
</script>
<!-- <p>截至2020年12月,在我国网民群体中,学生最多,占比为21.0%;其次是个体户/自由职业者,占比为16.9%;农林牧渔劳动人员占比为8.0%。</p>-->
</body>
8.力导向图
实现方法
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>赖成川《如梦之梦》人物关系图</title>
<style>
path{
fill: none;
stroke: #666;
stroke-width: 1.5px;
}
circle {
stroke: #333;
stroke-width: 1.5px;
}
text {
font: 10px sans-serif;
pointer-events: none;
}
.tooltip{
position: absolute;
width: 340px;
height: auto;
font-family: simsun;
font-size: 10px;
text-align: left;
color: black;
border-width: 1px solid black;
background-color: 7FFF00;
border-radius: 3px;
}
.tooltip:after{
content: '';
position: absolute;
bottom: 100%;
left: 20%;
margin-left: -3px;
width: 0;
height: 0;
border-bottom: 12px solid black;
border-right: 12px solid transparent;
border-left: 12px solid transparent;
}
</style>
</head>
<body style=" opacity:1">
<script src="https://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript">
var width=(window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth)*0.98;
var height=(window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight)*0.9;
var img_h=50;
var img_w=50;
var radius=10;
var svg=d3.select("body")
.append("svg")
.attr("width",width)
.attr("height",height);
var nodes=[
/*1*/ {name:"五号病人",image:"wuhao.jpg",intro:"妻子失踪,孩子得了怪病去世,自己从台湾去诺曼底寻找真相"},
/*2*/ {name:"妻子",image:"qizi.jpg",intro:"女同,孩子死后离开了五号"},
/*3*/ {name:"和平",image:"erzi.jpg",intro:"得了怪病死去"},
/*4*/ {name:"医生",image:"yisheng.jpg",intro:"作为新主任医生,第一天上班,负责的五个病人死了四个"},
/*5*/ {name:"顾香兰",image:"guxianglan.jpg",intro:"年轻时是妓女,被小开追求并陷入爱河,最后还是和法国伯爵去了诺曼底,老年又回了上海"},
/*6*/ {name:"伯爵",image:"bojue.jpg",intro:"为了顾香兰离婚并带她去了诺曼底,最后还是抛弃了顾香兰找了个黑人,最后染上疾病死去"},
/*7*/ {name:"皮耶",image:"all.jpg",intro:"疯狂爱着顾香兰"},
/*8*/ {name:"尚保德(老总管)",image:"guanjia.jpg",intro:"作为伯爵家的老总管,见证了顾香兰在诺曼底由富裕到贫穷的生活"},
/*9*/ {name:"艾玛(新夫人)",image:"all.jpg",intro:"为伯爵生了一男一女,阴差阳错下潦倒的顾香兰去家里当保姆"},
/*10*/ {name:"小女生",image:"all.jpg",intro:""},
/*11*/ {name:"小男生",image:"all.jpg",intro:""},
/*12*/ {name:"金姨",image:"all.jpg",intro:"天香楼的主人,捡到了顾香兰,是妓院的老板"},
/*13*/ {name:"十里红、翠琴等人",image:"all.jpg",intro:"天香楼的妓女"},
/*14*/ {name:"王德宝",image:"all.jpg",intro:"裁缝铺小开,有钱时追求顾香兰,开始的一个月被拒绝,最后抱得美人归,无奈家族企业破产,顾香兰和大老板走了,后面事业东山再起,在诺曼底偶遇顾香兰并将她带回了上海"},
/*15*/ {name:"路易",image:"all.jpg",intro:"顾香兰情人之一"},
/*16*/ {name:"萨林瓦多",image:"salinwaduo.jpg",intro:"顾香兰的画画老师,她发掘出顾香兰奔放的一面"},
/*17*/ {name:"江红",image:"jianghong.jpg",intro:"病弱的五号第一次到诺曼底时和她相爱,本人偷渡到法国时男朋友不幸死去,愧疚和无奈让她不敢和五号归国"},
/*18*/ {name:"吉普赛人",image:"jipusairen.jpg",intro:"精通巫术,算出了江红和五号的过去,并给予二人探寻人生因果的线索"},
/*18*/ {name:"伊莎贝尔",image:"all.jpg",intro:"被伯爵抛弃,育有一子"}];
var edges=[
{source:0,target:1,relation:"初恋"},
{source:0,target:3,relation:"讲故事"},
{source:0,target:4,relation:"听故事"},
{source:0,target:16,relation:"爱情/听故事、讲故事"},
{source:1,target:2,relation:"母亲"},
{source:1,target:0,relation:"初恋"},
{source:4,target:5,relation:"夫妻"},
{source:4,target:15,relation:"学生"},
{source:4,target:14,relation:"暧昧"},
{source:4,target:13,relation:"爱情"},
{source:4,target:12,relation:"姐妹"},
{source:4,target:11,relation:"员工"},
{source:4,target:9,relation:"说故事"},
{source:4,target:10,relation:"说故事"},
{source:5,target:18,relation:"抛弃"},
{source:5,target:6,relation:"兄弟"},
{source:5,target:8,relation:"夫妻"},
{source:6,target:4,relation:"疯狂爱慕"},
{source:7,target:5,relation:"员工"},
{source:8,target:5,relation:"夫妻"},
{source:13,target:4,relation:"爱情"},
{source:14,target:4,relation:"暧昧"},
{source:16,target:0,relation:"暧昧"},
{source:16,target:17,relation:"求助"},
{source:17,target:0,relation:"指引线索"}
];
var force=d3.layout.force()
.nodes(nodes)
.links(edges)
.size([width,height])
.linkDistance(150)
.charge(-1200)
.start();
//提示框部分
var tooltip=d3.selectAll("body")
.append("div")
.attr("class","tooltip")
.style("opacity",0.0);
//箭头绘制
var defs = svg.append("defs");
var radius=10;
var arrowMarker = defs.append("marker")
.attr("id","arrow")
.attr("markerUnits","strokeWidth")
.attr("markerWidth","4")
.attr("markerHeight","4")
.attr("viewBox","0 0 4 4")
.attr("refX",20+radius/8-2) //实际是radius/strokeWidth
.attr("refY",2)
.attr("orient","auto");
var arrow_path = "M0,1 L4,2 L0,3 L0,0";
arrowMarker.append("path")
.attr("d",arrow_path);
var color=d3.scale.category20();
var path = svg.selectAll("path")
.data(edges)
.enter()
.append("path")
.attr("id", function(d,i) {
return "edgepath" +i;
})
.attr("class","edges")
.attr("marker-end","url(#arrow)");
var pathtext = svg.selectAll('.pathText')
.data(edges)
.enter()
.append("text")
.attr("class","pathText")
.append('textPath')
.attr("text-anchor", "middle")//居中
.attr("startOffset","50%")
.attr('xlink:href', function(d,i) { return "#edgepath" + i; })
.text(function(d) { return d.relation; });
var img_h=50;
var img_w=50;
var radius=23;
var circles=svg.selectAll("forceCircle")
.data(nodes)
.enter()
.append("circle")
.attr("class","forceCircle")
.attr("r",radius)
.style("stroke","DarkGray")
.style("stroke-width","1.0px")
.attr("fill", function(d, i){
//创建圆形图片
var defs = svg.append("defs").attr("id", "imgdefs");
var catpattern = defs.append("pattern")
.attr("id", "catpattern" + i)
.attr("height", 1)
.attr("width", 1);
catpattern.append("image")
.attr("x", - (img_w / 2 - radius+5.8))
.attr("y", - (img_h / 2 - radius+3.5))
.attr("width", img_w+11)
.attr("height", img_h+6)
.attr("xlink:href","image/"+d.image);
return "url(#catpattern" + i + ")";
})
.on("mouseover",function(d,i){ //加入提示框
tooltip.html("角色简介:"+d.intro)
.style("left",(d3.event.pageX)+"px")
.style("top",(d3.event.pageY+20)+"px")
.style("opacity",1.0);
})
.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(force.drag);
var texts=svg.selectAll(".forceText")
.data(nodes)
.enter()
.append("text")
.attr("class","forceText")
.attr("x",function(d){return d.x;})
.attr("y",function(d){return d.y;})
.style("stroke", "#336666")
.attr("dx","-1.5em")
.attr("dy","3em")
.text(function(d){return d.name;});
force.on("tick",function(){
path.attr("d", function(d) {
var dx = d.target.x - d.source.x;//增量
var dy = d.target.y - d.source.y;
return "M" + d.source.x + ","+ d.source.y + "L" + d.target.x + "," + d.target.y;
});
circles.attr("cx",function(d){return d.x;});
circles.attr("cy",function(d){return d.y;});
texts.attr("x",function(d){return d.x;});
texts.attr("y",function(d){return d.y;});
});
</script>
</body>
</html>