1. 程式人生 > >web思維導圖

web思維導圖

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"}
                ]