天天看點

知識圖譜可視化 - demo例子集

知識圖譜可視化

将結構化資料通過關系預處理程式處理為圖資料庫可以查詢的資料,示例是将其中一部分(人物關系資料)可視化表示。使用前請先使用idea中maven install打包工程,然後使用啟動腳本啟動即可。強烈建議使用IDEA開發~

代碼位址如下:

http://www.demodashi.com/demo/13181.html

人物關系知識圖譜

一、背景

将結構化資料通過關系預處理程式處理為圖資料庫可以查詢的資料,示例是将其中一部分(人物關系資料)可視化表示。

二、用到的技術

技術點:圖資料庫Neo4j,d3.js,java,css,spring boot

開發工具:IDEA專業版(可找學生賬号注冊免費使用一年,社群版不支援WEB開發)

三、項目結構以及代碼實作過程

實作思路這樣:

1,先定義基礎的展示頁面index.html

2、完成畫圖js(graph.js)

3,提供一個基礎的拿資料接口加載測試繪圖資料和繪圖需要的資料(例如節點選中之後的小圖示加載)

4、頁面從資料接口請求資料之後,調用繪圖JS在頁面完成畫圖操作(請求資料的接口可以很友善的改為從圖資料庫拿取資料進行展示)

主要檔案目錄說明:

1、data目錄

bg.jpg可視化背景圖檔資料

CircularPartition.json節點圓形分區圖工具欄需要加載的資料

test.json可視化需要展示的資料格式

2、images

此目錄存儲節點屬性圖檔資料

3、js

d3.js version-3.2.8

4、src

JS以及其它HTML等源碼

5、index.html

知識圖譜可視化入口檔案

6、拿資料接口

通過資料Type id加載圓形分區圖資料和測試知識圖譜構圖資料(type等于1加載圓形分區資料,type是等于2加載測試知識圖譜展示資料)

GET:http://localhost:7476/knowledge-graph/hello/dataSource/type/{id}

做圖過程(graph.js):

// 定義畫布 (radius是滑鼠點選生成圓形分區圖的半徑)
var width = 1345, height = 750, color = d3.scale.category20();
var svg = d3.select("body")
    .append("svg")
    .attr("id", "svgGraph")
    .attr("width", width)
    .attr("height", height)
    .append("g")
    .attr("id", "svgOne")
    .call(d3.behavior.zoom() // 自動建立事件偵聽器
        .scaleExtent([0.1, 10]) // 縮放允許的級數
        .on("zoom", zoom)
    )
    .on("dblclick.zoom", null); // remove輕按兩下縮放
           
// 實時擷取SVG畫布坐标
function printPosition() {
    var position = d3.mouse(svg.node());
    return position;
}
           
// 縮放函數
function zoom() {
    // translate變換矢量(使用二進制組辨別)scale目前尺度的數字
    svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); // 畫布縮放與移動
    // svg.attr("transform", "scale(" + d3.event.scale + ")"); // 畫布縮放
}
           
// 設定連線箭頭屬性
function setMarkers() {
    svg.append("g")
        .attr("id", "lineAndText")
        .selectAll("marker")
        .data(edges)
        .enter()
        .append("marker")
        .attr("id", function (d) {
            return d.id;
        })
        .attr("viewBox", "0 -5 10 10") // 坐标系的區域
        .attr("class", "arrow")
        .attr("refX", 27) // refX,refY在viewBox内的基準點,繪制時此點在直線端點上(要注意大小寫)
        .attr("refY", 0)
        .attr("markerWidth", 10) // 辨別的大小
        .attr("markerHeight", 18) // 辨別的大小
        .attr("markerUnits", "userSpaceOnUse") // 辨別大小的基準,有兩個值:strokeWidth(線的寬度)和userSpaceOnUse(圖形最前端的大小)
        .attr("orient", "auto") // 繪制方向,可設定為:auto(自動确認方向)和 角度值
        .append("path")
        .attr("d", "M0,-5L10,0L0,5")
        .attr("fill", "#ccc");
}
           
// 添加連線
function add_edges() {
    setMarkers(); // 設定連線箭頭屬性
    var svg_edges = svg.select("#lineAndText")
        .selectAll("line")
        .data(edges)
        .enter()
        .append("line")
        .attr("id", function (d) {
            return d.id;
        })
        .style("stroke", "#ccc")
        .style("stroke_width", 1)
        .attr("marker-end", function (d) {
            return "url(#" + d.id + ")";
        })
        .attr("stroke", "#999")
        .on("mouseover", function (d) { // 滑鼠選中時觸發
            mouseSelectLine(d);
            addToolTip(d); //添加提示框的div
        })
        .on("mouseout", function () {
            d3.select("#relation").remove();
            d3.select("#tooltip").remove();
        });
    return svg_edges;
}
           
// 求直線與圓的交點
// 函數參數說明:cx:圓X軸坐标 cy:圓y軸坐标  r:圓半徑 stx:起點直線的X軸坐标 sty:起點直線的軸坐标 edx:終點直線的X軸坐标 edy:終點直線的Y軸坐标
// 傳回值:交點坐标(x,y)
function getPoint(cx, cy, r, stx, sty, edx, edy) {
    // 求直線
    var k = (edy - sty) / (edx - stx);
    var b = edy - k * edx;
    //列方程
    var x1, y1, x2, y2;
    var c = cx * cx + (b - cy) * (b - cy) - r * r;
    var a = (1 + k * k);
    var b1 = (2 * cx - 2 * k * (b - cy));

    var tmp = Math.sqrt(b1 * b1 - 4 * a * c);
    x1 = (b1 + tmp) / (2 * a);
    y1 = k * x1 + b;
    x2 = (b1 - tmp) / (2 * a);
    y2 = k * x2 + b;

    // 過濾距離最近的坐标
    var p = {};

    function lineIf(lx, ly, lxx, lyy) {
        var d = Math.sqrt((lx - lxx) * (lx - lxx) + (ly - lyy) * (ly - lyy));
        return d;
    }

    if (cx != stx) { // stx, sty
        var d1 = lineIf(x1, y1, stx, sty);
        var d2 = lineIf(x2, y2, stx, sty);
        if (d1 < d2) {
            p.x = x1;
            p.y = y1;
        } else {
            p.x = x2;
            p.y = y2;
        }
    } else { // edx, edy
        var d1 = lineIf(x1, y1, edx, edy);
        var d2 = lineIf(x2, y2, edx, edy);
        if (d1 < d2) {
            p.x = x1;
            p.y = y1;
        } else {
            p.x = x2;
            p.y = y2;
        }
    }
    return p;
}
           
// 滑鼠選中關系添加顯示效果
function mouseSelectLine(d) {
    var p1 = getPoint(d.source.x, d.source.y, 20, d.source.x, d.source.y, d.target.x, d.target.y);
    var p2 = getPoint(d.target.x, d.target.y, 20, d.source.x, d.source.y, d.target.x, d.target.y);
    var json = [p1, p2];
    //構造預設線性生成器
    var line = d3.svg.line()
        .x(function (d) { //指定x存取器為:取每個資料元素的x屬性的值
            return d.x;
        })
        .y(function (d) { //指定y存取器為:取每個資料元素的y屬性的值
            return d.y;
        });
    svg.append(\'path\')
        .attr({
            "d": function () { //生成路徑資料
                return line(json);
            },
            "id": "relation"
        })
        .style({
            "stroke": "#87CEFA",  //path顔色
            "stroke-width": 6 //path粗細
        });
}
           
// 添加節點
function add_nodes() {
    var svg_nodes = svg.append("g")
        .attr("id", "circleAndText")
        .selectAll("circle")
        .data(nodes)
        .enter()
        .append("g")
        .call(force.drag().on("dragstart", function (d) {
                d3.select("#eee").remove(); // 删除節點扇形
                d3.select("#sel").remove(); // 删除節點選中
                d3.event.sourceEvent.stopPropagation(); // 畫布拖動與節點拖動分離
                d3.select(this).attr("r", 20 * 2);
            })
                .on("dragend", function (d) {
                    d3.select("#eee").remove(); // 删除節點扇形
                    d3.select("#sel").remove(); // 删除節點選中
                    d.fixed = true; // 拖動結束後節點固定
                    d3.select(this).attr("r", 20);
                })
        )
        .on("click", function (d) { // 滑鼠點選時觸發
            // 在目前節點處畫三頁扇形
            d3.select("#eee").remove();
            drawCirclePartition(d);
        })
        .on("mouseover", function (d) { // 光标放在某元素上s
            mouseSelect(d); // 滑鼠選中效果
            addToolTip(d); //添加提示框的div
        })
        .on("mouseout", function (d) {
            d3.select("#sel").remove(); // 删除節點選中
            d3.select("#tooltip").remove();
            d3.select("#tooltipCir").remove();
        });
    svg_nodes.append("circle")
        .attr("id", function (d) {
            return d.index;
        })
        .attr("r", 20)
        .attr("fill", function (d, i) {
            return color(i);
        });
    svg_nodes.append("image")
        .attr("class", "circle")
        .attr("xlink:href", function (d) {
            var img = d.image;
            if (img != undefined) {
                return "http://222.216.195.154:7476/knowledge-graph/path/images/" + d.image
            } else {
                return null;
            }
        })
        .attr("x", "-20px")
        .attr("y", "-20px")
        .attr("width", "40px")
        .attr("height", "40px");
    svg_nodes.append("svg:text")
        .style("fill", "#ccc")
        .attr("dx", 20)
        .attr("dy", 8)
        .text(function (d) {
            return d.name
        });
    return svg_nodes;
}
           
//添加提示框的div
function addToolTip(d) {
    var htmlStr;
    if (d.source && d.target && d.type) {
        htmlStr = "name:" + d.type + "<br/>";
    } else {
        htmlStr = "id:" + d.id + "<br/>" + "name:" + d.name + "<br/>";
    }
    var position = printPosition(d);
    var tooltip = d3.select("body").append("div")
        .attr("class", "tooltip") //用于css設定類樣式
        .attr("opacity", 0.0)
        .attr("id", "tooltip");
    htmlStr = htmlStr + "locx:" + position[0] + "<br/>" + "locy:" + position[1] + "<br/>";
    if (d.image != undefined) {
        htmlStr = htmlStr + "<img src=\"http://222.216.195.154:7476/knowledge-graph/path/images/" + d.image + "\" height=\"100\" width=\"100\" />";
    }
    tooltip.html(htmlStr)
        .style("left", (d3.event.pageX) + "px")
        .style("top", (d3.event.pageY + 20) + "px")
        .style("opacity", 0.75);
}
function addToolTipCir(d) {
    var htmlStr;
    if (d.name == "☿") {
        htmlStr = "notes:解鎖目前節點<br/>";
    }
    if (d.name == "✂") {
        htmlStr = "notes:裁剪目前節點與關系<br/>";
    }
    if (d.name == "✠") {
        htmlStr = "notes:拓展目前節點與關系<br/>";
    }
    if (d.name == "◎") {
        htmlStr = "notes:釋放所有鎖定的節點<br/>";
    }
    if (d.name == "오") {
        htmlStr = "notes:鎖定所有節點<br/>";
    }
    var tooltip = d3.select("body").append("div")
        .attr("class", "tooltip") //用于css設定類樣式
        .attr("opacity", 0.0)
        .attr("id", "tooltipCir");
    tooltip.html(htmlStr)
        .style("left", (d3.event.pageX) + "px")
        .style("top", (d3.event.pageY + 20) + "px")
        .style("opacity", 0.75);
}
           
// 生成圓弧需要的角度資料
var arcDataTemp = [{startAngle: 0, endAngle: 2 * Math.PI}];
var arc_temp = d3.svg.arc().outerRadius(26).innerRadius(20);
           
// 滑鼠選中節點添加顯示效果
var svg_selectNode;

function mouseSelect(d) {
    svg_selectNode = svg.append("g")
        .attr("id", "sel")
        .attr("transform", "translate(" + d.x + "," + d.y + ")")
        .selectAll("path.arc")
        .data(arcDataTemp)
        .enter()
        .append("path")
        .attr("fill", "#87CEFA")
        .attr("d", function (d, i) {
            return arc_temp(d, i);
        });
}
           
// 全局停止力作用之間的影響
function stopForce() {
    for (var i = 0; i < nodes.length; i++) {
        var obj = nodes[i];
        obj.fixed = true;
    }
}
           
// 全局開始力作用之間的影響
function startForce() {
    for (var i = 0; i < nodes.length; i++) {
        var obj = nodes[i];
        obj.fixed = false;
    }
    force.resume();
}
           
var nodesMark = [], edgesMark = [], indexNodeMark = []; // 緩存中所有已加載的資料标記
// 節點添加圓形分區(添加三頁扇形)
function drawCirclePartition(d) {
    // 圓形分區布局(資料轉換)
    var radius = 40;
    var partition = d3.layout.partition()
        .sort(null)
        .size([2 * Math.PI, radius * radius]) // 第一個值域時2 PI,第二個值時圓半徑的平方
        .value(function (d) {
            return 1;
        });

    // 繪制圓形分區圖
    // 如果以圓形的形式來轉換資料那麼d.x和d.y分别代表圓弧的繞圓心
    // 方向的起始位置和由圓心向外的起始位置d.dx和d.dy分别代表各自的寬度
    var arc = d3.svg.arc()
        .startAngle(function (d) {
            return d.x;
        })
        .endAngle(function (d) {
            return d.x + d.dx;
        })
        .innerRadius(function (d) {
            return 26;
        })
        .outerRadius(function (d) {
            return 80;
        });
    var circlePart = partition.nodes(dataCirclePartition);

    // "☿" 釋放固定的節點
    function releaseNode() {
        d.fixed = false;
        // force.start(); // 開啟或恢複結點間的位置影響
        force.resume();
    }

    // "✂" 删除目前節點以及目前節點到其它節點之間的關系
    function removeNode() {
        var newNodes = [];
        for (var i = 0; i < nodes.length; i++) {
            var obj = nodes[i];
            if (obj.id != d.id) {
                newNodes.push(obj);
            }
        }
        var newedges = [];
        for (var i = 0; i < edges.length; i++) {
            var obj = edges[i];
            if ((d.index != obj.source.index) && (d.index != obj.target.index)) {
                newedges.push(obj);
            }
        }
        nodes = newNodes;
        edges = newedges;

        var nIndex = function (d) {
            return d.index;
        };
        var lIndex = function (d) {
            return d.id;
        };
        // 通過添加\'g\'元素分組删除
        svg.select("#circleAndText").selectAll("circle")
            .data(nodes, nIndex)
            .exit()
            .remove();
        svg.select("#circleAndText").selectAll("image")
            .data(nodes, nIndex)
            .exit()
            .remove();
        svg.select("#circleAndText").selectAll("text")
            .data(nodes, nIndex)
            .exit()
            .remove();
        svg.select("#lineAndText").selectAll("line")
            .data(edges, lIndex)
            .exit()
            .remove();
        svg.select("#lineAndText").selectAll("text")
            .data(edges, lIndex)
            .exit()
            .remove();
    }
           
// 擴充目前節點,距離為1
    // 1.從rawData(rawNodes/rawEdges)中找出目前節點需要擴充的節點與關系資料
    // 2.拿出需要擴充的資料到node/edges中去除已經綁定圖形元素的資料
    // 3.将過濾出的未綁定圖形元素需要擴充的資料重新調用構圖方法進行構圖
    // 添加從伺服器實時加載資料的功能:基本思想與1~3類似
    function extendNode() {
        var index = d.index;
        var arrEdges = [], arrIndex = [], arrNodes = [];
        for (var i = 0; i < rawEdges.length; i++) {
            if ((index == rawEdges[i].source.index) || (index == rawEdges[i].target.index)) {
                arrEdges.push(rawEdges[i]);
                if (index != rawEdges[i].source.index) {
                    arrIndex.push(rawEdges[i].source.index);
                } else if (index != rawEdges[i].target.index) {
                    arrIndex.push(rawEdges[i].target.index);
                }
            }
            edgesMark.push(rawEdges[i].id);
        }
        for (var i = 0; i < rawNodes.length; i++) {
            for (var j = 0; j < arrIndex.length; j++) {
                var obj = arrIndex[j];
                if (rawNodes[i].index == obj) {
                    arrNodes.push(rawNodes[i]);
                }
            }
            nodesMark.push(rawNodes[i].id);
            indexNodeMark.push(rawNodes[i].index);
        }
        // nodes.push(arrNodes);
        // edges.push(arrEdges);
        var nodesRemoveIndex = [];
        for (var i = 0; i < arrNodes.length; i++) {
            var obj = arrNodes[i];
            for (var j = 0; j < nodes.length; j++) {
                var obj2 = nodes[j];
                if (obj.index == obj2.index) {
                    nodesRemoveIndex.push(i);
                }
            }
        }
        var edgesRemoveIndex = [];
        for (var i = 0; i < arrEdges.length; i++) {
            var obj = arrEdges[i];
            for (var j = 0; j < edges.length; j++) {
                var obj2 = edges[j];
                if (obj.id == obj2.id) {
                    edgesRemoveIndex.push(obj.id);
                }
            }
        }
        var coverNodes = [];
        for (var i = 0; i < arrNodes.length; i++) {
            var obj = arrNodes[i];
            if (!isInArray(nodesRemoveIndex, i)) {
                nodes.push(obj);
                coverNodes.push(obj);
            }
        }
        var coverEdges = [];
        for (var i = 0; i < arrEdges.length; i++) {
            var obj = arrEdges[i];
            if (!isInArray(edgesRemoveIndex, obj.id)) {
                edges.push(obj);
                coverEdges.push(obj);
            }
        }
        // console.log("找出需要擴充的資料");
        // console.log(arrEdges);
        // console.log(arrNodes);

        // console.log("添加到原始需要綁定圖形元素的資料集集合/與rawNodes,rawEdges伺服器加載的原始資料保持區分");
        // console.log(nodes);
        // console.log(edges);

        // 添加從伺服器請求擴充資料
        // var url = "http://222.216.195.154:7476/knowledge-graph/hello/dataSource/node/extend/" + d.id + "";
        // d3.json(url, function (error, json) { // 伺服器加載知識圖譜資料
        //     if (error) {
        //         return console.warn(error);
        //     }
        //     console.log("從伺服器請求的擴充資料:");
        //     var serverNodes = json.nodes;
        //     var serverEdges = json.links;
        //     console.log(serverNodes);
        //     console.log(serverEdges);
        //     console.log(nodesMark);
        //     console.log(edgesMark);
        //     // 重新設定INDEX
        //     var maxIndex = Math.max.apply(null, indexNodeMark);
        //     console.log("MAX:" + maxIndex);
        //
        //     for (var i = 0; i < serverNodes.length; i++) {
        //         if (!isInArray(nodesMark, serverNodes[i].id)) {
        //             serverNodes[i].index = maxIndex + 1
        //             maxIndex = maxIndex + 1;
        //             nodes.concat(serverNodes[i]);
        //             console.log(serverNodes[i]);
        //         }
        //     }
        //     for (var i = 0; i < serverEdges.length; i++) {
        //         if (!isInArray(edgesMark, serverEdges[i].id)) {
        //             edges.concat(serverEdges);
        //             console.log(serverEdges[i]);
        //         }
        //     }
        //     console.log("伺服器加載并且合并之後的資料:");
        //     console.log(nodes);
        //     console.log(edges);
        //     d3.select("#svgGraph").select("#svgOne").selectAll("*").remove(); // 清空SVG中的内容
        //     buildGraph();
        // });

        d3.select("#svgGraph").select("#svgOne").selectAll("*").remove(); // 清空SVG中的内容
        buildGraph();
    }

    var arcs = svg.append("g")
        .attr("id", "eee")
        .attr("transform", "translate(" + d.x + "," + d.y + ")")
        .selectAll("g")
        .data(circlePart)
        .enter()
        .append("g")
        .on("click", function (d) { // 圓形分區綁定Click事件
            if (d.name == "☿") {
                releaseNode();
            }
            if (d.name == "✂") {
                removeNode();
            }
            if (d.name == "✠") {
                extendNode();
            }
            if (d.name == "◎") {
                startForce();
            }
            if (d.name == "오") {
                stopForce();
            }
            d3.select("#eee").remove();
            d3.select("#tooltipCir").remove();
        });
    arcs.append("path")
        .attr("display", function (d) {
            return d.depth ? null : "none"; // hide inner ring
        })
        .attr("d", arc)
        .style("stroke", "#fff")
        .style("fill", "#A9A9A9")
        .on("mouseover", function (d) {
            d3.select(this).style("fill", "#747680");
            addToolTipCir(d); //添加提示框的div
        })
        .on("mouseout", function () {
            d3.select("#tooltipCir").remove();
            d3.select(this).transition()
                .duration(200)
                .style("fill", "#ccc")
            var array = printPosition();
            var distance = Math.sqrt(Math.pow((d.x - array[0]), 2) + Math.pow((d.y - array[1]), 2));
            if (distance > 80) {
                d3.select("#eee").remove(); // 删除節點扇形
            }
        });
    arcs.append("text")
        .style("font-size", "16px")
        .style("font-family", "simsun")
        .style("fill", "white")
        .attr("text-anchor", "middle")
        .attr("transform", function (d, i) {
            // 平移和旋轉
            var r = 0;
            if ((d.x + d.dx / 2) / Math.PI * 180 < 180) // 0-180度以内的
                r = 180 * ((d.x + d.dx / 2 - Math.PI / 2) / Math.PI);
            else // 180-360度
                r = 180 * ((d.x + d.dx / 2 + Math.PI / 2) / Math.PI);
            return "translate(" + arc.centroid(d) + ")" + "rotate(" + r + ")";
        })
        .text(function (d) {
            return d.name;
        });
    return arcs;
}
           
// 添加描述關系文字
function add_text_edges() {
    var svg_text_edges = svg.select("#lineAndText")
        .selectAll("line.text")
        .data(edges)
        .enter()
        .append("text")
        .attr("id", function (d) {
            return d.id;
        })
        .style("fill", "#ccc")
        .attr("x", function (d) {
            return (d.source.x + d.target.x) / 2
        })
        .attr("y", function (d) {
            return (d.source.y + d.target.y) / 2
        })
        .text(function (d) {
            return d.type;
        })
        .on("mouseover", function (d) { // 滑鼠選中時觸發
            mouseSelectLine(d);
            addToolTip(d); //添加提示框的div
        })
        .on("mouseout", function () {
            d3.select("#relation").remove();
            d3.select("#tooltip").remove();
        })
        .on("click", function () {

        });
    return svg_text_edges;
}
           
// 對于每一個時間間隔進行更新
function refresh() {
    force.on("tick", function () { // 對于每一個時間間隔
        // 更新連線坐标·
        svg_edges.attr("x1", function (d) {
            return d.source.x;
        })
            .attr("y1", function (d) {
                return d.source.y;
            })
            .attr("x2", function (d) {
                return d.target.x;
            })
            .attr("y2", function (d) {
                return d.target.y;
            });
        // 更新節點以及文字坐标
        svg_nodes.attr("transform", function (d) {
            return "translate(" + d.x + "," + d.y + ")";
        });
        // 更新關系文字坐标
        svg_text_edges.attr("x", function (d) {
            return (d.source.x + d.target.x) / 2
        })
            .attr("y", function (d) {
                return (d.source.y + d.target.y) / 2
            });
    });
}
           
var force, nodes = [], edges = [], rawNodes, rawEdges, mapNodes = new Map(); // 建構知識圖譜需要操作的資料 (rawNodes, rawEdges将加載的原始構圖資料緩存一份)
// 知識圖譜可視化建構
function graph(data) {

    // 先清空布局中的圖形元素
    // d3.select("#svgGraph").select("#svgOne").selectAll("*").remove();
    // var serverD = data.nodes;
    // var serverE = data.links;

    // 去除NODES中重複的節點,如果有節點重複即将EDGES中的資料重新設定source值和target值
    // serverD,serverE,nodes,edges

    // var filterServerD = [];
    // for (var i = 0; i < serverD.length; i++) {
    //     if (!isInArray(nodesIndexId, serverD[i].id)) {
    //         filterServerD.push(serverD[i]);
    //     }
    // }
    // 去重之後重新調整filterServerD的NODE index值

    // mapNodes.forEach(function (value, key) {
    //     console.log(value);
    //     console.log(key);
    //    if (isInArray(nodesIndexId,key)){
    //
    //    }
    // });
    // recordNodesIndex(serverD);
    // console.log(nodesIndexValue);

    // 多數組連接配接
    // nodes = nodes.concat(data.nodes);
    // edges = edges.concat(data.links);
    // console.log(nodes);
    // console.log(edges);
    // rawNodes = nodes;
    // rawEdges = edges;
    // // 定義力布局(資料轉換)
    // force = d3.layout.force()
    //     .nodes(nodes) // 指定節點數組
    //     .links(edges) // 指定連線數組
    //     .size([width, height]) // 指定範圍
    //     .linkDistance(150) // 指定連線長度
    //     // .gravity(0.02) // 設定引力避免躍出布局
    //     .friction(0.9) // 設定摩擦力速度衰減
    //     .charge(-400); // 互相之間的作用力
    // force.start(); // 開始作用
    // buildGraph();
}
           
var svg_edges, svg_nodes, svg_text_edges; // 需要動态更新的函數(dynamic update function)
// Strat build Knowledge Graph/Vault

function buildGraph() {
    console.log("開始建構可視化知識圖譜:");
    console.log(nodes);
    console.log(edges);
    svg_edges = add_edges(); // 添加連線與箭頭
    svg_nodes = add_nodes(); // 添加節點與文字
    svg_text_edges = add_text_edges(); // 添加描述關系的文字
    refresh();  // 對于每一個時間間隔進行更新
    force.resume(); // 必須添加否則圖形元素更新不及時
}
           
// 伺服器加載資料
var dataCirclePartition;

function load() {
    d3.json("http://222.216.195.154:7476/knowledge-graph/hello/dataSource/type/1", function (error, root) { // 伺服器加載節點圓形分區資料
        if (error) {
            return console.warn(error);
        }
        dataCirclePartition = root;
    });
    d3.json("http://222.216.195.154:7476/knowledge-graph/hello/dataSource/type/2", function (error, json) { // 伺服器加載知識圖譜資料
        if (error) {
            return console.warn(error);
        }
        console.log("初始加載:");
        console.log(json.nodes);
        console.log(json.links);
        graph(json);
    });
    // d3.json("http://222.216.195.154:7476/knowledge-graph/hello/dataSource/node/extend/99817", function (error, json) { // 伺服器加載知識圖譜資料
    //     if (error) {
    //         return console.warn(error);
    //     }
    //     console.log("初始加載:");
    //     console.log(json);
    //     graph(json);
    // });
}

// 初始化圖資料庫配置資訊
startNeo4j();

// 執行知識圖譜資料可視化
load();

// 傳入NODE ID與NODE INDEX,節點的INDEX與構圖時資料加載的順序密切相關
function loadById(id, maxNodeIndex, nodesIdList) {
    // var para = ["id:" + id, "maxNodeIndex:" + maxNodeIndex, "nodesIdList:" + nodesIdList];
    var para = {"id": id, "maxNodeIndex": maxNodeIndex, "nodesIdList": nodesIdList};
    console.log(para);
    d3.json("http://222.216.195.154:7476/knowledge-graph/hello/dataSource/node/idIndex/" + para, function (error, data) { // 伺服器加載知識圖譜資料
        if (error) {
            return console.warn(error);
        }
        console.log("動态ID加載的資料:");
        console.log(nodesMark);
        console.log(edgesMark);
        console.log(nodes);
        console.log(edges);
        console.log(data);
        graph(data);
    });
}

function loadZdrSearch(json) {
    d3.json("http://222.216.195.154:7476/knowledge-graph/hello/dataSource/type/1", function (error, root) { // 伺服器加載節點圓形分區資料
        if (error) {
            return console.warn(error);
        }
        dataCirclePartition = root;
    });

    graph(json);

}

// 執行知識圖譜資料可視化
// loadById(id);

           

啟動入口類KnowledgeGraphApplication之後,

調用接口:http://localhost:7476/knowledge-graph/hello/index

此接口調用控制類加載index.html,HTML中調用了js檔案加載展示資料,詳細的實作過程請看完整的代碼注釋。

代碼目錄結構說明一:
知識圖譜可視化 - demo例子集
代碼目錄結構說明二:
知識圖譜可視化 - demo例子集

四、可視化效果(所有可視化效果均帶有力布局效果)

1.節點與關系均帶有選中效果,節點關系裁剪與擴充

☿ 解鎖目前節點

✂ 剪切目前節點于關系

✠ 擴充目前節點與關系

오 固定所有節點

◎ 解鎖所有節點

實體擴充功能:
知識圖譜可視化 - demo例子集
節點效果:
知識圖譜可視化 - demo例子集

2.完整示例

完整效果顯示示例一:
知識圖譜可視化 - demo例子集
完整效果顯示示例二:
知識圖譜可視化 - demo例子集
知識圖譜可視化

代碼位址如下:

http://www.demodashi.com/demo/13181.html

注:本文著作權歸作者,由demo大師代發,拒絕轉載,轉載需要作者授權