<template>
|
<div>
|
<div id="gid_tc" style="float:left;">
|
<div id="gid"></div>
|
<ul
|
class="el-dropdown-menu el-popper"
|
id="my_custom_menu"
|
style="display: none;"
|
>
|
<li class="el-dropdown-menu__item" @click="btnOpenNode">
|
<svg class="ctwh_icon" aria-hidden="true">
|
<use xlink:href="#icon-zk-all"></use>
|
</svg>
|
<span class="pl-15">展开</span>
|
</li>
|
<li class="el-dropdown-menu__item" @click="btnCollapseNode">
|
<svg class="ctwh_icon" aria-hidden="true">
|
<use xlink:href="#icon-shouqi"></use>
|
</svg>
|
<span class="pl-15">收起</span>
|
</li>
|
</ul>
|
<div
|
class="el-dropdown-menu el-popper"
|
id="richContainer"
|
style="display: none;width: 420px;height: 300px;position: absolute; left: 222px; top: 75px;"
|
>
|
<span
|
@click="close"
|
class="close-x"
|
style="
|
float: right;
|
padding: 4px 8px;
|
cursor: pointer;
|
color: rgb(236, 105, 65);font-size: 16px;margin: -20px -33px 0 0;background: #fff;border-radius: 50%;border: 1px solid #ddd;z-index: 999;font-family: '微软雅黑';"
|
>X</span
|
>
|
<div class="search_result_list_min">
|
<div
|
:key="'m_' + index"
|
v-for="(item, index) in nodeRecordList"
|
class="search_result_item_min"
|
>
|
<div>
|
<div class="datatitle">
|
<a href="javascript:;" @click="linkto(item)"
|
>{{ index + 1 }}.{{ item.条目名称 }}
|
</a>
|
</div>
|
<div class="datasource">
|
<span>{{ item.工具书名称 }}</span>
|
</div>
|
</div>
|
<span class="datacontent" @click="linkto(item)" v-html="item.快照">
|
{{ item.快照 }}
|
</span>
|
</div>
|
</div>
|
</div>
|
<div class="mengceng"></div>
|
</div>
|
<div class="svg-set-box clearfix">
|
<div class="ctwh-dibmr">
|
<span>显示范围:</span>
|
<a
|
:key="index"
|
v-for="(m, index) in pageSizeList"
|
@click="setMatchSize(m, this)"
|
href="javascript:void(0)"
|
:class="[m.isActive ? 'sd-active' : '', 'ss-d sd' + (index + 1)]"
|
>
|
</a>
|
</div>
|
<div class="ctwh-dibmr" style="float: right">
|
<ul class="toolbar">
|
<li>
|
<a href="javascript:;" @click="zoomin"
|
><span><i class="el-icon-zoom-in"></i>放大</span></a
|
>
|
</li>
|
<li>
|
<a href="javascript:;" @click="zoomout"
|
><span><i class="el-icon-zoom-out"></i>缩小</span></a
|
>
|
</li>
|
<li>
|
<a href="javascript:;" @click="refresh"
|
><span><i class="el-icon-refresh-right"></i>还原</span></a
|
>
|
</li>
|
<li>
|
<a
|
v-if="!isFullscreen"
|
id="fullscreenbtn"
|
href="javascript:;"
|
@click="showFull"
|
>
|
<span><i class="el-icon-full-screen"></i>全屏</span>
|
</a>
|
<a
|
v-else
|
id="fullscreenbtn"
|
href="javascript:;"
|
@click="exitfullscreen"
|
>
|
<span><i class="el-icon-full-screen"></i>退出全屏</span>
|
</a>
|
</li>
|
</ul>
|
</div>
|
</div>
|
</div>
|
</template>
|
<script>
|
import axios from "axios";
|
import * as d3 from "d3";
|
import $ from "jquery";
|
|
export default {
|
props: ["pid"],
|
data() {
|
return {
|
qaGraphNode: {},
|
qaGraphNodeText: {},
|
qaGraphLink: {},
|
qaGraphLinkText: {},
|
theme: 0,
|
loading: false,
|
width: 1000,
|
height: 800,
|
gcontainer: {},
|
svg: {},
|
zoom: null,
|
arrowMarker: {},
|
simulation: {},
|
isFullscreen: false,
|
graph: {
|
nodes: [],
|
links: []
|
},
|
colorList: [
|
"#ff8373",
|
"#f9c62c",
|
"#a5ca34",
|
"#6fce7a",
|
"#70d3bd",
|
"#ea91b0"
|
],
|
pageSizeList: [
|
{ size: 100, isActive: false },
|
{ size: 300, isActive: false },
|
{ size: 500, isActive: true },
|
{ size: 1000, isActive: false }
|
],
|
nodeRecordList: []
|
};
|
},
|
components: {},
|
mounted() {
|
this.initGraphContainer();
|
this.addMaker();
|
this.initGraph();
|
},
|
created() {},
|
watch: {},
|
methods: {
|
initGraphContainer() {
|
this.gcontainer = d3.select("#gid");
|
if (this.isFullscreen) {
|
this.width = window.screen.width;
|
this.height = window.screen.height;
|
} else {
|
this.width = $("#" + this.pid).width();
|
this.height = $("#" + this.pid).height();
|
}
|
this.svg = this.gcontainer.append("svg");
|
var sWidth = this.width;
|
var sHeight = this.height;
|
this.svg.attr("width", sWidth);
|
this.svg.attr("height", sHeight);
|
// this.svg.attr("viewBox", "0 0 " + sWidth / 2 + " " + sHeight / 2);
|
this.svg.attr("id", "svg_idx");
|
this.svg.attr("preserveAspectRatio", "xMidYMidmeet");
|
this.simulation = d3
|
.forceSimulation()
|
.force("charge", d3.forceManyBody().strength(-1500))
|
.force(
|
"link",
|
d3
|
.forceLink()
|
.distance(60)
|
.id(function(d) {
|
return d.uuid;
|
})
|
)
|
.force("collide", d3.forceCollide().strength(-30))
|
.force("center", d3.forceCenter(this.width / 2, this.height / 2));
|
this.qaGraphLink = this.svg.append("g").attr("class", "line");
|
this.qaGraphLinkText = this.svg.append("g").attr("class", "lineText");
|
this.qaGraphNode = this.svg.append("g").attr("class", "node");
|
this.qaGraphNodeText = this.svg.append("g").attr("class", "nodeText");
|
},
|
initGraph() {
|
var _this = this;
|
axios.get("/static/kgData.json", {}).then(function(response) {
|
var data = response.data;
|
_this.graph.nodes = data.node;
|
_this.graph.links = data.relationship;
|
_this.updateGraph();
|
});
|
},
|
addMaker() {
|
var arrowMarker = this.svg
|
.append("marker")
|
.attr("id", "arrow")
|
.attr("markerUnits", "strokeWidth")
|
.attr("markerWidth", "12") //
|
.attr("markerHeight", "12")
|
.attr("viewBox", "0 0 12 12")
|
.attr("refX", "30")
|
.attr("refY", "6")
|
.attr("orient", "auto");
|
var arrowPath = "M2,2 L10,6 L2,10 L6,6 L2,2"; // 定义箭头形状
|
arrowMarker
|
.append("path")
|
.attr("d", arrowPath)
|
.attr("fill", "#ccc");
|
},
|
drawnode(node) {
|
var _this = this;
|
var nodeEnter = node.enter().append("circle");
|
nodeEnter.on("click", function(d) {
|
console.log("触发单击:" + d);
|
|
// eslint-disable-next-line no-debugger
|
debugger;
|
_this.opennode();
|
console.log("ddd");
|
//
|
});
|
nodeEnter.on("dblclick", function(d) {
|
event.preventDefault();
|
console.log("触发双击:" + d);
|
});
|
nodeEnter.call(
|
d3
|
.drag()
|
.on("start", _this.dragstarted)
|
.on("drag", _this.dragged)
|
.on("end", _this.dragended)
|
);
|
return nodeEnter;
|
},
|
opennode() {
|
var _this = this;
|
var noddd = [
|
{
|
flag: "1",
|
code: "27301",
|
parentCode: "273",
|
grade: "2",
|
name: "儒家2",
|
uuid: "4617858011"
|
},
|
{
|
code: "2730107",
|
flag: "1",
|
parentCode: "27301",
|
grade: "3",
|
name: "故事轶闻2",
|
uuid: "2636501111"
|
}
|
];
|
var newships = [
|
{
|
sourceid: "46178580",
|
targetid: "2636501111",
|
name: "",
|
targetcode: "2730107",
|
uuid: "91804213",
|
sourcecode: "27301"
|
},
|
{
|
sourceid: "46178580",
|
targetid: "4617858011",
|
name: "",
|
targetcode: "273010723",
|
uuid: "91804389",
|
sourcecode: "2730107"
|
}
|
];
|
_this.graph.nodes = _this.graph.nodes.concat(noddd);
|
_this.graph.links = _this.graph.links.concat(newships);
|
_this.updateGraph();
|
},
|
drawNodeText(nodeText) {
|
var _this = this;
|
var nodeTextEnter = nodeText.enter().append("text");
|
nodeTextEnter.call(
|
d3
|
.drag()
|
.on("start", _this.dragstarted)
|
.on("drag", _this.dragged)
|
.on("end", _this.dragended)
|
);
|
return nodeTextEnter;
|
},
|
drawLink(link) {
|
var _this = this;
|
var linkEnter = link
|
.enter()
|
.append("line")
|
.attr("stroke-width", 1)
|
.attr("stroke", function() {
|
return _this.colorList[2];
|
})
|
.attr("marker-end", "url(#arrow)"); // 箭头
|
return linkEnter;
|
},
|
drawLinkText(linktext) {
|
var linkTextEnter = linktext
|
.enter()
|
.append("text")
|
.attr("class", "lineText")
|
.style("fill", "#875034")
|
.style("font-size", "16px")
|
.text(function(d) {
|
return d.lk.name;
|
});
|
return linkTextEnter;
|
},
|
updateGraph() {
|
var _this = this;
|
var lks = _this.graph.links;
|
var nodes = _this.graph.nodes;
|
nodes.forEach(function(n) {
|
if (n.center === 1 || n.center === "1") {
|
n.fx = _this.width / 2;
|
n.fy = _this.height / 2;
|
}
|
if (typeof n.fx === "undefined" || n.fx === "") {
|
n.fx = null;
|
}
|
if (typeof n.fy === "undefined" || n.fy === "") {
|
n.fy = null;
|
}
|
});
|
var links = [];
|
// eslint-disable-next-line no-debugger
|
debugger;
|
lks.forEach(function(m) {
|
var sourceNode = nodes.filter(function(n) {
|
return n.uuid === m.sourceid;
|
})[0];
|
if (typeof sourceNode === "undefined") return;
|
var targetNode = nodes.filter(function(n) {
|
return n.uuid === m.targetid;
|
})[0];
|
if (typeof targetNode === "undefined") return;
|
links.push({ source: sourceNode.uuid, target: targetNode.uuid, lk: m });
|
});
|
// 更新节点
|
//_this.qaGraphNode = _this.drawnode(nodes);
|
var node = _this.qaGraphNode.selectAll("circle").data(nodes, function(d) {
|
return d.uuid;
|
});
|
node.exit().remove();
|
var nodeEnter = _this.drawnode(node);
|
node = nodeEnter.merge(node).text(function(d) {
|
return d.name;
|
});
|
node.attr("r", 25);
|
node.attr("fill", "red");
|
node
|
.append("title") // 为每个节点设置title
|
.text(function(d) {
|
return d.name;
|
});
|
// 更新节点文字
|
//_this.qaGraphNodeText = _this.drawNodeText(nodes);
|
var nodeText = _this.qaGraphNodeText
|
.selectAll("text")
|
.data(nodes, function(d) {
|
return d.uuid;
|
});
|
nodeText.exit().remove();
|
var nodeTextEnter = _this.drawNodeText(nodeText);
|
nodeText = nodeTextEnter.merge(nodeText).text(function(d) {
|
return d.name;
|
});
|
nodeText
|
.style("fill", function() {
|
if (_this.theme === 0) {
|
return "#333";
|
} else {
|
return "#fff";
|
}
|
})
|
.attr("class", "nodeText")
|
.attr("dy", "3.6em")
|
.attr("font-family", "宋体")
|
.attr("font-size", 16)
|
.attr("text-anchor", "middle")
|
.text(function(d) {
|
return d.name;
|
});
|
nodeText
|
.append("title") // 为每个节点设置title
|
.text(function(d) {
|
if (typeof d.name !== "undefined") {
|
return d.name;
|
}
|
return "";
|
});
|
// 更新连线 links
|
// _this.qaGraphLink = _this.drawLink(links);
|
var link = _this.qaGraphLink.selectAll("line").data(links, function(d) {
|
return d.uuid;
|
});
|
link.exit().remove();
|
var linkEnter = _this.drawLink(link);
|
link = linkEnter.merge(link);
|
// 更新连线文字
|
//_this.qaGraphLinkText = _this.drawLinkText(links);
|
var linktext = _this.qaGraphLinkText
|
.selectAll("text")
|
.data(links, function(d) {
|
return d.uuid;
|
});
|
linktext.exit().remove();
|
var linkTextEnter = _this.drawLinkText(linktext);
|
linktext = linkTextEnter.merge(linktext).text(function(d) {
|
return d.lk.name;
|
});
|
_this.simulation
|
.nodes(nodes)
|
.alphaTarget(0)
|
.alphaDecay(0.05)
|
.on("tick", ticked);
|
function ticked() {
|
// 更新连线坐标
|
link
|
.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;
|
});
|
// 刷新连接线上的文字位置
|
linktext
|
.attr("x", function(d) {
|
if (
|
typeof d.source.x === "undefined" ||
|
typeof d.target.x === "undefined"
|
)
|
return 0;
|
var x = (parseFloat(d.source.x) + parseFloat(d.target.x)) / 2;
|
return x;
|
})
|
.attr("y", function(d) {
|
if (
|
typeof d.source.y === "undefined" ||
|
typeof d.target.y === "undefined"
|
)
|
return 0;
|
var y = (parseFloat(d.source.y) + parseFloat(d.target.y)) / 2;
|
return y;
|
});
|
// 更新节点坐标
|
node
|
.attr("cx", function(d) {
|
return d.x;
|
})
|
.attr("cy", function(d) {
|
return d.y;
|
});
|
// 更新文字坐标
|
nodeText
|
.attr("x", function(d) {
|
return d.x;
|
})
|
.attr("y", function(d) {
|
return d.y;
|
});
|
}
|
|
_this.simulation.force("link").links(links);
|
_this.simulation.force(
|
"center",
|
d3.forceCenter(_this.width / 2, _this.height / 2)
|
);
|
_this.simulation.alpha(1).restart();
|
// 鼠标滚轮缩放
|
_this.zoom = d3
|
.zoom()
|
.scaleExtent([0.1, 4])
|
.on("zoom", _this.zoomed);
|
_this.svg.call(_this.zoom);
|
_this.svg.on("dblclick.zoom", null); // 静止双击缩放
|
},
|
dragstarted(d) {
|
if (!d3.event.active) this.simulation.alphaTarget(0.3).restart();
|
d.fx = d.x;
|
d.fy = d.y;
|
},
|
dragged(d) {
|
d.fx = d3.event.x;
|
d.fy = d3.event.y;
|
},
|
dragended(d) {
|
if (!d3.event.active) this.simulation.alphaTarget(0);
|
d.fx = d3.event.x;
|
d.fy = d3.event.y;
|
},
|
zoomed() {
|
this.svg.selectAll("g").attr("transform", d3.event.transform);
|
},
|
zoomClick(direction) {
|
var self = this;
|
var factor = 0.2;
|
var targetZoom = 1;
|
var extent = self.zoom.scaleExtent();
|
targetZoom = 1 + factor * direction;
|
if (targetZoom < extent[0] || targetZoom > extent[1]) {
|
return false;
|
}
|
self.zoom.scaleBy(self.svg, targetZoom); // 执行该方法后 会触发zoom事件
|
},
|
zoomin() {
|
this.zoomClick(1);
|
},
|
zoomout() {
|
this.zoomClick(-1);
|
},
|
refresh() {
|
this.svg.call(this.zoom.transform, d3.zoomIdentity);
|
},
|
showFull() {
|
this.isFullscreen = !this.isFullscreen;
|
var full = document.getElementById("kg_container");
|
this.fullscreen(full);
|
},
|
fullscreen(element) {
|
if (element.requestFullscreen) {
|
element.requestFullscreen();
|
} else if (element.mozRequestFullScreen) {
|
element.mozRequestFullScreen();
|
} else if (element.webkitRequestFullscreen) {
|
element.webkitRequestFullscreen();
|
} else if (element.msRequestFullscreen) {
|
element.msRequestFullscreen();
|
}
|
},
|
exitfullscreen() {
|
this.isFullscreen = !this.isFullscreen;
|
if (document.exitFullscreen) {
|
document.exitFullscreen();
|
} else if (document.mozCancelFullScreen) {
|
document.mozCancelFullScreen();
|
} else if (document.webkitExitFullscreen) {
|
document.webkitExitFullscreen();
|
}
|
},
|
btnCollapseNode() {},
|
btnOpenNode() {},
|
close() {}
|
}
|
};
|
</script>
|
<style>
|
.svg-set-box {
|
height: 46px;
|
line-height: 46px;
|
padding-left: 15px;
|
color: #7f7f7f;
|
/* background: #f7f7f7; */
|
position: absolute;
|
bottom: 0;
|
}
|
.ctwh-dibmr {
|
display: inline-block;
|
}
|
.ss-d {
|
display: inline-block;
|
vertical-align: middle;
|
margin-right: 10px;
|
border-radius: 50%;
|
background: #dedede;
|
}
|
.sd1 {
|
width: 30px;
|
height: 30px;
|
}
|
.sd2 {
|
width: 26px;
|
height: 26px;
|
}
|
.sd3 {
|
width: 20px;
|
height: 20px;
|
}
|
.sd4 {
|
width: 16px;
|
height: 16px;
|
}
|
.sd-active {
|
background: #08aefc !important;
|
}
|
.toolbar {
|
margin-left: 150px;
|
margin-right: 15px;
|
line-height: 18px;
|
}
|
ul,
|
li {
|
list-style: none;
|
}
|
.toolbar li {
|
float: left;
|
width: 60px;
|
}
|
</style>
|