index.html内容:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Web思维导图</title>
<link rel="stylesheet" href="css/prism.css">
<link rel="stylesheet" href="css/common.css">
</head>
<body>
<h3>
Web思维导图,梳理Hacker知识点为例:
</h3>
<div id="drawing" class="drawing">
</div>
<div class="modal" id="modal">
<div class="modal-bg">
<div class="modal-content">
<div class="modal-cell">
<pre class="modal-code">
<code class="language-html"></code>
</pre>
</div>
</div>
<div class="modal-close">
</div>
</div>
<div class="modal-mask"></div>
</div>
<iframe class="code_iframe" id="html_code" src="bs_introduction/code_container.html"></iframe>
<script src="js/d3_flex_tree.js"></script>
<script src="js/mind_mapping.js"></script>
<script src="js/prism.js"></script>
</body>
</html>
CSS文件夹
common.css:
body{
height: 100%;
margin: 0;
overflow: hidden;
}
.clear-fix:before,.clear-fix:after{
display: table;
content: '';
clear: both;
}
.code_iframe{
display: none;
}
.drawing{
visibility: hidden;
font-weight: bold;
border: 1px solid #ccc;
animation: drawingframe;
animation-duration: 1s;
animation-timing-function: linear;
animation-delay: 1s;
-webkit-animation: drawingframe 1s linear 1s;
}
@keyframes drawingframe
{
from {opacity: 0;}
to {opacity: 1;}
}
@-webkit-keyframes drawingframe
{
from {opacity: 0;}
to {opacity: 1;}
}
.node g{
cursor: pointer;
}
.node circle {
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node line{
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
.modal{
display: none;
position: fixed;
z-index: 9999;
top: 0;
bottom: 0;
left: 0;
right: 0;
text-align: left;
}
.modal-mask{
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: black;
opacity: 0.5;
}
.modal-bg{
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 9999;
}
.modal-content{
display: table;
position: relative;
height: 100%;
width: 100%;
}
.modal-cell{
display: table-cell;
vertical-align: middle;
text-align: center;
}
.modal-cell img{
max-height: 95%;
}
.modal-code{
display: none;
margin: 0 auto !important;
}
.modal-close{
display: inline-block;
position: absolute;
top: 20px;
right: 20px;
width: 48px;
height: 48px;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABYlBMVEUAAABUbnpUbnpUbnpUbnpUbnpMZG9MZG9MZG9MZG9MZG9UbnpUbnpUbnpUbnpUbnpUbnpUbnpMZG9MZG9MZG9MZG9MZG9MZG9MZG9UbnpUbnpUbnpUbnpUbnpUbnpUbnpUbnpMZG9MZG9MZG9MZG9MZG9MZG9MZG9MZG9UbnpUbnpUbnpUbnpUbnpUbnpMZG9MZG9MZG9MZG9MZG9MZG9UbnpUbnpUbnpUbnpUbnpUbnpUbnpMZG9MZG9MZG9MZG9MZG9MZG9MZG9UbnpUbnpUbnpUbnpMZG9MZG9MZG9MZG9UbnpUbnpUbnpMZG9MZG9MZG9UbnpMZG9UbnpWcHxKYm1MZG9UbnpUbnlMZG9MZG9UbnpTbHhNZXBMZG9UbnpUbnpUbnpUbnpTbHhNZXBMZG9MZG9MZG9MZG9UbnpUbnpUbnpUbnpUbnpMZG9MZG9MZG9MZG9MZG9TbHhNZXD///9kx6K7AAAAc3RSTlMAAAAAAAAAAAAAAAAAAAsGAAAAAAYLAAAAAAAao3gGAAAAAAZ4oxoAAACr//Z3BQV39v+rAAD///V3BQAABXf1//8A///1d3f1//8A/////wAAAHcFBXf1e3v1//r6/3f1////////9XcABXv6///6ewUAJoszcwAAAAFiS0dEdahqmPsAAAAHdElNRQfeDAoPOSkJx4hxAAABVUlEQVRIx2NgGAWDDDAyMbOwYgqzsXNwcmFTz83Dy8cvIIguLCQsIiomLoGpXpJHSlpGVk5eAVVYUUlZRVVNXVwDQ4Mmr7SWto6unjyKHUJK+gaGRsZqYiYYGkz5ZLTNzC0srayRdAjZ2NrZOzgaqYo6YWhg4ZfVMXd2cXWzQrhKUcnW3cPTy8FQRYQdQwOrt5yuhYuPr6sl3FVA99h5+Pl72hsoB7Bh+lpQXs/S1dfHBe4qsHs8/f087PSVhLCFq4K8lZurC9xVUPd4erjbKilijzlBaytLuKvg7rGztRFiwAGQXBUYRMA9aK4KDgkNI+AeVFeFR0RGEXIPiquiY2LjCLoH7qr4hMSk5JTUtPQMAu6B2pGZlZ2TW1ySl19QWETQfDI0kOokUj1NarCSGnGkJg1SEx+pyZvUDERyFiW5ECC5mCG5ICO5qCS5MCa9uB8FAwkA1tqHz8dmcxMAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTYtMDktMTdUMTU6MjE6MjUrMDg6MDBOsysLAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE0LTEyLTEwVDE1OjU3OjQxKzA4OjAwNdJKeAAAAE10RVh0c29mdHdhcmUASW1hZ2VNYWdpY2sgNy4wLjEtNiBRMTYgeDg2XzY0IDIwMTYtMDktMTcgaHR0cDovL3d3dy5pbWFnZW1hZ2ljay5vcmfd2aVOAAAAGHRFWHRUaHVtYjo6RG9jdW1lbnQ6OlBhZ2VzADGn/7svAAAAGHRFWHRUaHVtYjo6SW1hZ2U6OkhlaWdodAAxMjhDfEGAAAAAF3RFWHRUaHVtYjo6SW1hZ2U6OldpZHRoADEyONCNEd0AAAAZdEVYdFRodW1iOjpNaW1ldHlwZQBpbWFnZS9wbmc/slZOAAAAF3RFWHRUaHVtYjo6TVRpbWUAMTQxODE5ODI2MfKdw1kAAAAQdEVYdFRodW1iOjpTaXplADk0NEK36UZEAAAAX3RFWHRUaHVtYjo6VVJJAGZpbGU6Ly8vaG9tZS93d3dyb290L3NpdGUvd3d3LmVhc3lpY29uLm5ldC9jZG4taW1nLmVhc3lpY29uLmNuL3NyYy8xMTgxNy8xMTgxNzU3LnBuZ7UlySMAAAAASUVORK5CYII=");
}
tspan{
font-size: 14px;
}
text{
dominant-baseline: middle;
}
prism.css:
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection, pre[class*="language-"] ::selection,
code[class*="language-"]::selection, code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #a67f59;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
mind_mapping.js代码:
var engine,
duration = 750;
var margin = {
top: 20,
right: 120,
bottom: 20,
left: 120
},
width = 960 - margin.right - margin.left,
height = 800 - margin.top - margin.bottom;
d3.json('bs_introduction/bs_introduction.json', function (err, tree) {
engine = d3.layout.tree().setNodeSizes(true);
// sizing
engine.nodeSize(function (t) {
return [t.x_size, t.y_size];
});
// gap
engine.spacing(function (a, b) {
return a.parent == b.parent ?
5 : engine.rootXSize();
});
tree.x0 = height / 2;
tree.y0 = 0;
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
var $iframe_doc = document.getElementById('html_code').contentWindow.document;
var $modal = d3.select('#modal'),
$modal_cell = $modal.select('.modal-cell'),
$modal_pre = $modal.select('.modal-code'),
$modal_code = $modal_pre.select('code');
$modal.on("click.mask", function(){
if(d3.event.target.className !== 'modal-cell'){
return false;
}
$modal.style('display', 'none');
$modal.selectAll('img').style('display', 'none');
$modal_pre.style('display', 'none')
});
var client_width = document.documentElement.clientWidth,
client_height = document.documentElement.clientHeight;
var svg = d3.select("#drawing").append('svg').attr("width", client_width).attr("height", client_height);
var svg_g = svg.append("g");
svg.call(d3.behavior.zoom().scaleExtent([0.5,3]).on("zoom", redraw));
update(tree);
tree.children.forEach(collapse);
update(tree, function(){
setTimeout(function(){
d3.select("#drawing").style({'visibility': "visible"});
d3.selectAll(".node").each(function(d, i){
i > 0 && (d3.select(this).select(".vertical-line").style('display', 'block'));
});
},1000);
});
function update(source, callback){
var nodes = d3.layout.hierarchy()(tree);
var last_id = 0;
var node = svg_g.selectAll(".node")
.data(nodes, function (d) {
return d.id || (d.id = ++last_id);
});
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", function (d) {
var x_size = source.x_size ? source.x_size : 0;
return "translate(" + source.y0 + "," + (source.x0 - x_size / 2) + ")";
});
//.on("click", click);
var text_elements = nodeEnter.append("text")
.attr({
id: function (d) {
return d.id;
},
fill: 'black',
dy: "0.35em"
}).each(function(d){
parseText(this, d);
});
engine.nodeSize(function (d) {
var ele = document.getElementById(d.id),
ele_size = ele.getBBox();
return [ele_size["height"] + 30, ele_size["width"] + 14];
});
nodes = engine.nodes(tree);
function node_extents(n) {
return [n.x - n.x_size / 2, n.y,
n.x + n.x_size / 2, n.y + n.y_size];
}
var root_extents = node_extents(nodes[0]);
var xmin = root_extents[0],
ymin = root_extents[1],
xmax = root_extents[2],
ymax = root_extents[3],
area_sum = (xmax - xmin) * (ymax - ymin),
x_size_min = nodes[0].x_size,
y_size_min = nodes[0].y_size;
nodes.slice(1).forEach(function (n) {
var ne = node_extents(n);
xmin = Math.min(xmin, ne[0]);
ymin = Math.min(ymin, ne[1]);
xmax = Math.max(xmax, ne[2]);
ymax = Math.max(ymax, ne[3]);
area_sum += (ne[2] - ne[0]) * (ne[3] - ne[1]);
x_size_min = Math.min(x_size_min, n.x_size);
y_size_min = Math.min(y_size_min, n.y_size);
});
var scale = 1;
function svg_x(node_y) {
return (node_y - ymin) * scale;
}
function svg_y(node_x) {
return (node_x - xmin) * scale;
}
var nodebox_right_margin = Math.min(x_size_min * scale, 10),
nodebox_vertical_margin = Math.min(y_size_min * scale, 3);
function rand() {
return 80 + Math.floor(Math.random() * 100);
}
var filler = function () {
return "fill-opacity: 0; stroke:rgb(" + rand() + "," + rand() + "," + rand() + ")"
};
node.transition()
.duration(duration)
.attr("transform", function (d) {
if(d.parent && d.parent.y0 && d.parent.y_size){
d.y = d.parent.y0 + d.parent.y_size + 100;
} else {
d.y = d.depth * 180;
}
return "translate(" + svg_x(d.y) + "," + (svg_y(d.x)-(d.x_size * scale - nodebox_vertical_margin) / 2) + ")";
});
nodeEnter.append("rect")
.attr({
x: 0,
rx: 6,
ry: 6,
width: function (d) {
return d.y_size * scale - nodebox_right_margin;
},
height: function (d) {
return d.x_size * scale - nodebox_vertical_margin;
},
style: function(d){
return d.filler = filler();
}
})
.attr('next', function(d){
if(d.children || d._children){
var $g = d3.select(this.parentNode).append('g').attr({
transform: 'translate(' + (d.y_size - 6) + ',' + (d.x_size/2 - 5) + ')'
}).on("click", click);
$g.append('circle').attr({
r: '7',
cx: 3.5,
cy: 3.5,
style: 'stroke:' + d.filler
});
$g.append('line').attr({
x1: 0,
y1: 3.5,
x2: 7,
y2: 3.5,
style: 'stroke:' + d.filler
});
var $vertical_line = $g.append('line').attr({
x1: 3.5,
y1: 0,
x2: 3.5,
y2: 7,
style: 'stroke:' + d.filler
}).classed('vertical-line', true);
if(d._children){
$vertical_line.style('display', 'block');
} else {
$vertical_line.style('display', 'none');
}
return true
}
return false
});
node.exit().transition()
.duration(duration)
.attr("transform", function (d) {
return "translate(" + (source.y) + "," + (svg_y(source.x)-(source.x_size * scale - nodebox_vertical_margin)/2) + ")";
})
.remove();
var diagonal = d3.svg.diagonal()
.source(function (d, i) {
var s = d.source;
return {
x: s.x,
y: s.y + s.y_size - nodebox_right_margin / scale
};
})
.projection(function (d) {
return [svg_x(d.y), svg_y(d.x)];
})
;
var enter_diagonal = d3.svg.diagonal()
.source(function (d, i) {
var s = d.source;
return {
x: s.x,
y: s.y + s.y_size - nodebox_right_margin / scale
};
})
.projection(function (d) {
return [d.y, d.x];
});
var links = engine.links(nodes);
var link = svg_g.selectAll("path.link")
.data(links, function (d) {
return d.target.id;
});
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", function (d) {
var o = {
x: source.x0,
y: source.y0,
y_size: source.y_size
};
return enter_diagonal({
source: o,
target: o
});
});
link.transition()
.duration(duration)
.attr("d", diagonal);
link.exit().transition()
.duration(duration)
.attr("d", function (d) {
var o = {
x: source.x,
y: source.y,
y_size: source.y_size
};
return diagonal({
source: o,
target: o
});
})
.remove();
nodes.forEach(function (d) {
d.x0 = svg_y(d.x);
d.y0 = svg_x(d.y);
});
callback && callback();
}
function redraw() {
svg_g.attr("transform",
"translate(" + d3.event.translate + ")"
+ " scale(" + d3.event.scale + ")");
}
function click(d) {
if (d.children) {
d3.select(this).select('.vertical-line').style('display', 'block');
d._children = d.children;
d.children = null;
} else {
d3.select(this).select('.vertical-line').style('display', 'none');
d.children = d._children;
d._children = null;
}
update(d);
}
function parseText(text_tag, d){
var $text = d3.select(text_tag),
content = d.content;
if(typeof content === 'string'){
if(/^(\.\/)?img\//.test(content)){
var img_id = content.replace(/[\/\.]/g, '');
if($modal_cell.select('#' + img_id)[0][0] === null){
$modal_cell.append('img').attr('id', img_id).attr('src', content).attr('style', 'display:none');
}
$text.append('tspan').attr({x: '2', dy: '1.5em', path: content}).text('点击查看图片');
d3.select(text_tag.parentNode).attr('img_id', img_id).on("click.show", function(){
$modal.select('#' + d3.select(this).attr('img_id')).attr("style", "display:inline-block");
$modal.attr("style", "display: block");
});
} else {
var len = 0, split_str = '', reg = /[^\x00-\xff]/;
var split_arr = content.split(''),
split_arr_len = split_arr.length - 1;
split_arr.forEach(function(val, i){
if(reg.test(val)){
len += 2;
} else {
len += 1;
}
split_str += val;
if(len >= 30 || i >= split_arr_len){
$text.append('tspan').attr({x: '2', dy: '1.5em'}).text(split_str);
len = 0;
split_str = '';
}
});
}
} else {
if(content.type === 'html_code'){
$modal_code.attr('class', 'language-html');
} else if(content.type === 'js_code'){
$modal_code.attr('class', 'language-javascript');
}
$text.append('tspan').attr({x: '2', dy: '1.5em'}).text('点击查看代码');
d3.select(text_tag.parentNode).attr('code_id', content.id).on("click.show", function(){
var code = $iframe_doc.getElementById(d3.select(this).attr('code_id')).innerHTML;
$modal_code.text(code);
$modal_pre.style('display', 'inline-block');
Prism.highlightAll();
$modal.style('display', 'block');
});
}
}
});
bs_introduction.json
{
"content":"如何学习黑客",
"children":
[
{
"content":"预备知识" ,
"children":
[
{"content":"HTML & CSS" },
{"content":"JavaScript" },
{"content":"Linux" },
{"content":"SQL" }
]
},
{
"content":"安装" ,
"children":
[
{
"content":"记事本软件",
"children":
[
{"content":"VIM"},
{"content":"EditPlus"},
{"content":"Sublime Text"}
]
},
{
"content":"服务器软件",
"children":
[
{"content":"Apache Http Server"},
{"content":"Tomcat"},
{"content":"IIS"}
]
},
{"content":"下载NMAP"},
{"content":"下载WIRESHARK"}
]
},
{
"content":"入门",
"children":
[
{
"content":"入侵",
"children":
[
{"content":"select"},
{"content":"selectAll"}
]
},
{
"content":"sql注入",
"children":
[
{"content":"shell"},
{"content":"data"}
]
},
{"content":"跨站脚本"},
{
"content":"简单图形",
"children":
[
{"content":"柱形图"},
{"content":"折线图"},
{"content":"散点图"}
]
},
{"content":"比例尺"},
{"content":"生成器"},
{"content":"过渡"}
]
},
{
"content":"进阶" ,
"children":
[
{
"content":"社会工程学的应用",
"children":
[
{"content":"饼状图"},
{"content":"树状图"},
{"content":"矩阵树图"}
]
},
{"content":"缓冲区溢出攻击"}
]
}
]
}