123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704 |
- <template>
- <div
- id="chartContent"
- style="position:relative;height:100%"
- :style="{ 'min-width': minWid + 'px', 'min-height': minHei + 'px' }"
- >
- <div
- style="display: flex;justify-content: flex-end;height: 30px; margin-top:10px"
- >
- <a-button @click="switchOPen" v-if="enable" style="display: none;"
- >{{ isShow ? '隐藏图标' : '显示图标' }}
- </a-button>
- <a-button
- type="primary"
- @click="exportChartData"
- style="margin-left: 10px;"
- v-if="showExportBtn"
- >导出数据到控制台
- </a-button>
- <a-button
- type="default"
- @click="resetChart"
- v-if="showReset"
- style="width: 150px;"
- >重置
- </a-button>
- </div>
- <div
- :id="domUuid"
- style="height: calc(100% - 40px);width: 100%"
- v-if="isShowChart"
- ></div>
- <div
- class="flex-center"
- :class="isRoad ? 'road_computed_blank' : 'relevance_blank'"
- style="height: 100%;width: 100%;"
- v-else
- ></div>
- <a-dropdown
- :visible="dropdown.show && isShowContextMenu === true"
- :getPopupContainer="getPopupContainer"
- :trigger="['click']"
- style="position: absolute;z-index: 1"
- :style="{ left: dropdown.x, top: dropdown.y }"
- >
- <a class="ant-dropdown-link" href="#" />
- <a-menu slot="overlay">
- <a-menu-item
- v-if="!contextMenu && clickTarget.type === 'node'"
- key="1"
- @click="handleRemoveEntCls"
- >隐藏选中
- </a-menu-item>
- <a-menu-item
- v-if="contextMenu && contextMenu.indexOf('delete') > -1"
- key="2"
- @click="contextMenuDelete"
- >排除
- </a-menu-item>
- <!--<a-menu-item v-if="clickTarget.type === 'node'" key="2" @click="movePosition">移动位置</a-menu-item>-->
- </a-menu>
- </a-dropdown>
- </div>
- </template>
- <script>
- import uuid from 'uuid'
- import { NetChart } from '@/plugins/knowledge/zoomChart'
- // const NetChart = window.NetChart
- // const NetChart = null;
- const colors = ['rgba(111,82,184,1)',
- 'rgba(255,214,24,1)',
- 'rgba(47,195,47,1)',
- 'rgba(86,185,247,1)',
- 'rgba(234,180,4,1)',
- 'rgba(222,103,44,1)',
- '#FEDD00',
- '#00843D',
- '#009A44',
- '#4A7729',
- '#78BE20',
- '#007A33',
- '#BFB800',
- '#64A70B',
- '#006341',
- '#FDDA24',
- '#009639',
- '#43B02A',
- '#00205B',
- '#00629B',
- '#64CCC9',
- '#0093B2',
- '#004F71',
- '#006BA6',
- '#003DA5',
- '#003B5C',
- '#008578',
- '#0033A0',
- '#002855',
- '#003087',
- '#00778B',
- '#0082BA',
- '#00A9CE',
- '#002D72',
- '#001871',
- '#672146',
- '#AD1AAC',
- '#A9431E',
- '#D57800',
- '#643335',
- '#FFCD00',
- '#3E2B2E',
- '#BE6A14',
- '#A50034',
- '#F9423A',
- '#C8102E',
- '#E4002B',
- '#C5003E',
- '#EF3340',
- '#CB333B',
- '#FC4C02',
- '#FE5000',
- '#FF671F',
- '#2C2A29',
- '#FFA300',
- '#FBD872',
- '#333F48',
- '#C99700',
- '#ABCAE9',
- '#F4364C',
- '#7A7D81',
- '#C5299B',
- '#DB3EB1',
- '#B9975B',
- ]
- let g_root,
- chart,
- node_colors = {},
- link_colors = {}
- let highLightCache = {}
- let isShow = true
- let _vue
- let isDivisionColor = false
- export default {
- props: {
- nodes: {
- type: Array,
- default: () => [],
- },
- links: {
- type: Array,
- default: () => [],
- },
- enable: {
- type: Boolean,
- default: false,
- },
- isDivisionColor: {
- type: Boolean,
- default: false,
- },
- isShowChart: {
- type: Boolean,
- default: false,
- },
- isShowContextMenu: {
- type: Boolean,
- default: false,
- },
- contextMenu: {
- type: Array,
- default: () => [],
- },
- isRoad: {
- type: Boolean,
- default: false,
- },
- isShowTree: {
- type: Boolean,
- default: false,
- },
- minWid: {
- type: Number,
- default: null,
- },
- minHei: {
- type: Number,
- default: null,
- },
- showExportBtn: {
- type: Boolean,
- default: false,
- },
- showRelKey: {
- // 默认关系之间的名称显示,默认显示true:relClsName [true:'relClsName', false:'relName']
- type: Boolean,
- default: true,
- },
- isEntChart: {
- type: Boolean,
- default: false,
- },
- },
- data() {
- _vue = this
- return {
- domUuid: uuid(),
- useNavigation: false,
- showReset: false,
- isShow,
- dropdown: {
- // 下拉菜单的样式配置
- show: false,
- x: null,
- y: null,
- },
- chartNodes: null,
- chartLinks: null,
- clickTarget: {},
- //moveid:'', // 要移动的id
- selectedEntClsIds: [], // 选中的实体类ids
- }
- },
- watch: {
- nodes: function() {
- this.chartNodes = this.nodes
- },
- links: function() {
- this.chartLinks = this.links
- },
- contextMenu: function() {
- console.log(this.contextMenu)
- },
- },
- methods: {
- getPopupContainer() {
- return document.getElementById('chartContent')
- },
- // 导出图表的数据(json格式)
- exportChartData() {
- const nodes = chart.nodes()
- const links = chart.links()
- const json = {
- nodes: [],
- links: [],
- }
- for (let i = 0; i < nodes.length; i++) {
- const node = nodes[i].data
- node.x = nodes[i].x
- node.y = nodes[i].y
- json.nodes.push(node)
- }
- for (let l = 0; l < links.length; l++) {
- json.links.push(links[l].data)
- }
- // 这里显示导出的数据,不要删
- console.log(JSON.stringify(json))
- },
- // 切换图标显示和隐藏
- switchOPen() {
- this.isShow = isShow = !isShow
- this.$emit('reloadChart', this.chartNodes, this.chartLinks)
- // this.$emit('reloadChart')
- },
- hidePopup() {
- this.dropdown.show = false
- },
- movePosition() {
- chart.reloadData({ nodes: [{ id: this.moveid, x: 300, y: 300 }] })
- // chart.replaceData({ nodes: [{id: this.moveid,x: 300, y: 300}] });
- },
- // 右键菜单删除
- contextMenuDelete() {
- this.dropdown.show = false
- this.$emit('delete', this.selectedEntClsIds)
- },
- // 批量隐藏 实体类
- handleRemoveEntCls() {
- this.dropdown.show = false
- chart.removeData({ nodes: this.selectedEntClsIds })
- this.selectedEntClsIds = [] // 清空上次删除的ids
- },
- /**
- * 高亮时图表的样式
- * */
- highLightStyle(start, end, nodes) {
- let nodeIds = []
- nodes.forEach((v) => {
- if (nodeIds.indexOf(v.endEntVOS.entID) === -1) {
- nodeIds.push(v.endEntVOS.entID)
- }
- if (nodeIds.indexOf(v.startEntVo.entID) === -1) {
- nodeIds.push(v.startEntVo.entID)
- }
- })
- highLightCache.nodeIds = nodeIds
- highLightCache.linkIds = computePath(nodes)
- chart.updateStyle()
- },
- /**
- * 取消高亮
- * */
- unhighLightStyle() {
- highLightCache = {}
- chart.updateStyle()
- },
- /**
- * 重绘
- * */
- reDraw(root, nodes, links) {
- g_root = root
- if (chart) {
- chart.replaceData({
- nodes: getNodes(nodes),
- links: getLinks(links),
- })
- } else {
- this.drawChart(root, nodes, links)
- }
- },
- addDraw(root, nodes, links) {
- if (chart) {
- chart.addData({
- nodes: getNodes(nodes),
- links: getLinks(links),
- })
- } else {
- this.drawChart(root, nodes, links)
- }
- },
- /*
- * 画zoomchart
- * */
- drawChart(root, nodes, links) {
- console.log(root, nodes, links)
- const vm = this
- g_root = root
- highLightCache = {}
- chart = new NetChart({
- container: document.getElementById(this.domUuid),
- area: {},
- legend: {
- enabled: true,
- margin: 20,
- },
- layout: this.isShowTree
- ? {
- mode: 'hierarchy',
- nodeSpacing: 45,
- rowSpacing: 80,
- }
- : {},
- navigation: this.useNavigation
- ? {
- mode: 'focusnodes',
- autoZoomOnFocus: true,
- // initialNodes: g_root,
- initialNodes: nodes[0].entClsID,
- focusNodeExpansionRadius: 1,
- numberOfFocusNodes: 2,
- focusNodeTailExpansionRadius: 0.5,
- }
- : {},
- style: {
- link: { fillColor: 'rgba(0,0,0,0.4)' },
- node: {
- lineWidth: 2,
- lineColor: '#09c',
- imageCropping: true,
- },
- nodeLabel: {
- // 节点label的显示样式
- padding: 0,
- borderRadius: 4,
- textStyle: { font: '16px Arial', fillColor: 'black' },
- backgroundStyle: { fillColor: 'rgba(255,255,255,0.7)' },
- }, // 节点label的显示样式,
- linkLabel: {
- // 线的label显示样式
- padding: 0,
- borderRadius: 20, //make as round as possible
- textStyle: { font: '20px Arial', fillColor: '#aaa' },
- backgroundStyle: {
- fillColor: 'rgba(255,255,255,0.6)',
- lineColor: 'rgba(0,0,0,0)',
- },
- rotateWithLink: true,
- scaleWithSize: true,
- }, // 线的label显示样式
- nodeStyleFunction: vm.nodeStyle, // 节点样式与配置的回调
- linkStyleFunction: linkStyle, // 关系样式与配置的回调
- },
- info: {
- enabled: true,
- nodeContentsFunction: function(data, item) {
- let html
- if (data.entName) {
- // 实体
- html =
- '<div class="chart_tooltip"><h3>实体名称:' +
- data.entName +
- '</h3>'
- } else if (data.entClsName) {
- // 实体类
- html =
- '<div class="chart_tooltip"><h3>实体类名称:' +
- data.entClsName +
- '</h3>'
- }
- if (
- data.entName === undefined &&
- data.entClsName === undefined
- )
- html = ''
- return html
- },
- linkContentsFunction: function(data, item) {
- let html =
- '<div class="chart_tooltip"><h3>关系名称:' +
- data.relClsName +
- '</h3>'
- if (data.relClsName === undefined) html = ''
- return html
- },
- },
- events: {
- onClick: function(event, args) {
- if (
- !event.ctrlKey &&
- !event.shiftKey &&
- args.clickNode &&
- vm.useNavigation
- ) {
- chart.addFocusNode(args.clickNode)
- }
- vm.dropdown.show = false
- vm.$emit('c_click', event, args)
- event.preventDefault()
- },
- onSelectionChange: function(event, args) {
- // 选中的实体类事件
- vm.selectedEntClsIds = [] // 清空上一次选中
- for (let i = 0; i < event.selection.length; i++) {
- const item = {}
- item.id = event.selection[i].id
- item.label = event.selection[i].label
- vm.selectedEntClsIds.push(item)
- }
- },
- onDoubleClick: function(event, args) {
- // 双击事件
- vm.dropdown.show = false
- if (args.clickNode) {
- vm.$emit('changeRoot', args.clickNode.data.id, 1)
- }
- event.preventDefault()
- },
- onRightClick: function(event, args) {
- // 右键
- // vm.moveid = event.clickNode.id
- vm.dropdown.show = true
- vm.dropdown.x = event.x + 20 + 'px'
- vm.dropdown.y = event.y + 50 + 'px'
- if (args.clickNode) {
- vm.clickTarget.type = 'node'
- // vm.clickTarget.data = args.clickNode.data
- this.selectedEntClsIds = [
- {
- id: event.clickNode.id,
- label: event.clickNode.label,
- },
- ]
- } else if (args.clickLink) {
- vm.clickTarget.type = 'link'
- } else {
- vm.hidePopup()
- }
- event.preventDefault()
- },
- },
- })
- document.oncontextmenu = function() {
- return false
- }
- this.reDraw(root, nodes, links)
- },
- // 重定义变量
- reloadData(obj) {
- this.useNavigation = obj.useNavigation
- this.showReset = obj.showReset
- },
- resetChart() {
- this.$emit('resetChart')
- },
- /**
- * 销毁chart实例
- * */
- destroyChart() {
- chart = undefined
- },
- nodeStyle(node) {
- // 定义节点的样式
- const vm = this
- let data = node.data.data ? node.data.data : node.data
- if (vm.isEntChart) {
- node.label = data.label
- let r = 90
- let g = 150
- let b = 220
- r -= (data.relNum - 1) * 5
- g -= (data.relNum - 1) * 5
- b -= (data.relNum - 1) * 5
- node.fillColor = 'rgba(' + r + ',' + g + ',' + b + ',1)'
- node.radius = 50 + (data.relNum - 1) * 10
- } else {
- if (data.entClsIcon && isShow) {
- node.image = data.entClsIcon
- }
- if (data.entIcon && isShow) {
- node.image = data.entIcon
- }
- node.label = data.label
- if (data.id === g_root) {
- if (!node.data.backGroundColor) {
- node.fillColor = 'orange'
- } else {
- node.fillColor = data.backGroundColor
- }
- } else {
- let lineColor = node_colors[data.entClsID]
- if (lineColor === undefined) {
- lineColor = getColor()
- }
- node.lineColor = lineColor
- node.fillColor = 'white'
- if (isDivisionColor) {
- // 根据创建和修改的时间,标记颜色
- if (data.createTime && !data.updateTime) {
- node.lineColor = '#f5222d'
- } else if (data.createTime == data.updateTime) {
- node.lineColor = '#1890ff'
- } else if (data.createTime != data.updateTime) {
- node.lineColor = '#52c41a'
- }
- node.lineWidth = 3
- } else {
- if (!!node.data.backGroundColor) {
- node.fillColor = data.backGroundColor
- }
- }
- }
- }
- // 如果当前节点在高亮节点集合中
- if (
- highLightCache.nodeIds &&
- highLightCache.nodeIds.indexOf(data.id) > -1
- ) {
- node.fillColor = 'orange'
- }
- },
- },
- created() {
- window.isEntChart = this.isEntChart
- isDivisionColor = this.isDivisionColor
- },
- destroyed() {
- this.destroyChart()
- },
- }
- // 定义线的样式
- function linkStyle(link) {
- // debugger
- let data = link.data.data ? link.data.data : link.data
- // link.label = data.label ? data.label : data.relName
- getLinkClass(link)
- if (
- highLightCache.linkIds &&
- highLightCache.linkIds.indexOf(data.id) > -1
- ) {
- if (!link.data.backGroundColor) {
- link.fillColor = 'orange'
- } else {
- link.fillColor = data.backGroundColor
- }
- link.radius = 4
- link.label = ''
- }
- }
- // 格式化成zoomchart需要的nodes
- function getNodes(nodes) {
- if(nodes){
- nodes.forEach((node, index) => {
- if (node.entID) node.id = node.entID
- if (node.label === undefined) node.label = node.entName
- if (!node_colors[node.entClsID]) {
- node_colors[node.entClsID] = colors[index % nodes.length]
- }
- })
- return nodes
- } else {
- return []
- }
- }
- // 格式化成zoomchart需要的links
- function getLinks(links) {
- if(links){
- links.forEach((link, index) => {
- if (link.relID) link.id = link.relID
- if (link.from === undefined) link.from = link.startEntID
- if (link.to === undefined) link.to = link.endEntID
- if (!link_colors[link.relClsID]) {
- link_colors[link.relClsID] = colors[index % links.length]
- }
- })
- return links
- } else {
- return []
- }
- }
- // 生成随机颜色
- function getColor() {
- let r = Math.floor(Math.random() * 255)
- let g = Math.floor(Math.random() * 255)
- let b = Math.floor(Math.random() * 255)
- return 'rgba(' + r + ',' + g + ',' + b + ',0.8)'
- }
- // 根据关系的classType生成不同的线的样式
- function getLinkClass(link) {
- let data = link.data.data ? link.data.data : link.data
- if (data.classType === 'dashed') {
- link.toDecoration = 'arrow'
- link.lineDash = [10, 10, 2, 2]
- } else {
- link.toDecoration = 'arrow'
- link.items = [
- {
- text: _vue.showRelKey ? data.relClsName : data.relName,
- padding: 2,
- backgroundStyle: {
- fillColor: 'white',
- // lineColor: link_colors[data.relClsID]
- lineColor: 'black',
- },
- textStyle: {
- fillColor: 'black',
- },
- },
- ]
- }
- return link
- }
- function computePath(nodes) {
- let linkIds = []
- const currentLinks = chart.links()
- nodes.forEach((v) => {
- let startId = v.startEntVo.entID,
- endId = v.endEntVOS.entID
- currentLinks.forEach((_v) => {
- if (startId === _v.from.id && endId === _v.to.id) {
- linkIds.push(_v.id)
- }
- })
- })
- return linkIds
- }
- </script>
- <style>
- .DVSL-menu-container.DVSL-menu-workaround {
- display: none;
- }
- .flex-center {
- position: relative;
- }
- .road_computed_blank,
- .relevance_blank {
- width: auto;
- border-radius: 4px;
- background-size: cover;
- }
- .road_computed_blank {
- /* background-image: url('../../assets/banner (1).png'); */
- }
- .relevance_blank {
- background-size: 100% 100%;
- /* background-image: url('../../assets/banner (2).png'); */
- }
- </style>
|