import React, {Component} from 'react'
|
import PropTypes from 'prop-types'
|
import { is, fromJS } from 'immutable'
|
import { Modal, notification, Spin, Empty } from 'antd'
|
import G6 from '@antv/g6'
|
|
import Api from '@/api'
|
import Utils from '@/utils/utils.js'
|
import UtilsDM from '@/utils/utils-datamanage.js'
|
import MKEmitter from '@/utils/events.js'
|
import NormalHeader from '@/tabviews/custom/components/share/normalheader'
|
import './index.scss'
|
|
const { Util } = G6
|
|
const styles = {
|
blue: '#1890ff',
|
red: '#f5222d',
|
orange_red: '#fa541c',
|
orange: '#fa8c16',
|
orange_yellow: '#faad14',
|
yellow: '#fadb14',
|
yellow_green: '#a0d911',
|
green: '#52c41a',
|
cyan: '#13c2c2',
|
blue_purple: '#2f54eb',
|
purple: '#722ed1',
|
magenta: '#eb2f96',
|
grass_green: '#aeb303',
|
deep_red: '#c32539',
|
deep_blue: '#1d3661'
|
}
|
|
let systemColor = '#1890ff'
|
if (window.GLOB.style) {
|
let type = window.GLOB.style.replace(/bg_black_style_|bg_white_style_/, '')
|
systemColor = styles[type] || '#1890ff'
|
}
|
const COLORS = ['#5B8FF9', '#F6BD16', '#5AD8A6', '#945FB9', '#E86452', '#6DC8EC', '#FF99C3', '#1E9493', '#FF9845', '#5D7092']
|
|
// 思维导图
|
G6.registerNode(
|
'dice-mind-map-root', {
|
jsx: (cfg) => {
|
const width = Util.getTextSize(cfg.label, 16)[0] + 24
|
|
return `
|
<group>
|
<rect style={{width: ${width}, height: 42, stroke: ${systemColor}, radius: 4}} keyshape>
|
<text style={{ fontSize: 16, marginLeft: 6, marginTop: 12 }}>${cfg.label}</text>
|
</rect>
|
</group>
|
`
|
},
|
getAnchorPoints() {
|
return [
|
[0, 0.5],
|
[1, 0.5]
|
]
|
}
|
},
|
'single-node',
|
)
|
|
G6.registerNode(
|
'dice-mind-map-leaf', {
|
jsx: (cfg) => {
|
const width = Util.getTextSize(cfg.label, 12)[0] + 24
|
|
return `
|
<group>
|
<rect style={{width: ${width}, height: 26, fill: 'transparent', cursor: pointer }}>
|
<text style={{ fontSize: 12, fill: ${cfg.selected ? systemColor : '#000000'}, marginLeft: 12, marginTop: 6, cursor: pointer }}>${cfg.label}</text>
|
</rect>
|
<rect style={{ fill: ${cfg.color}, width: ${width}, height: 2, x: 0, y: 32, cursor: pointer }} />
|
</group>
|
`
|
},
|
getAnchorPoints() {
|
return [
|
[0, 0.965],
|
[1, 0.965]
|
]
|
}
|
},
|
'single-node',
|
)
|
|
G6.registerBehavior('scroll-canvas', {
|
getEvents: function getEvents() {
|
return {
|
wheel: 'onWheel'
|
}
|
},
|
onWheel: function onWheel(ev) {
|
const { graph } = this
|
if (!graph) {
|
return
|
}
|
if (ev.ctrlKey) {
|
const canvas = graph.get('canvas')
|
const point = canvas.getPointByClient(ev.clientX, ev.clientY)
|
let ratio = graph.getZoom()
|
if (ev.wheelDelta > 0) {
|
ratio += ratio * 0.05
|
} else {
|
ratio *= ratio * 0.05
|
}
|
graph.zoomTo(ratio, {
|
x: point.x,
|
y: point.y
|
})
|
} else {
|
const x = ev.deltaX || ev.movementX
|
const y = ev.deltaY || ev.movementY || (-ev.wheelDelta * 125) / 3
|
graph.translate(-x, -y)
|
}
|
ev.preventDefault()
|
}
|
})
|
|
// 缩进文件树
|
G6.registerNode('indentedRoot', {
|
draw(model, group) {
|
const keyShape = group.addShape('rect', {
|
attrs: {
|
x: -46,
|
y: -16,
|
width: 92,
|
height: 32,
|
fill: systemColor,
|
radius: 2,
|
stroke: '#5B8FF9',
|
lineWidth: 0
|
},
|
name: 'key-shape'
|
})
|
|
const text = group.addShape('text', {
|
attrs: {
|
text: model.label || 'root',
|
fill: "#fff",
|
fontSize: 12,
|
x: 0,
|
y: 0,
|
textAlign: 'center',
|
textBaseline: 'middle'
|
},
|
name: 'root-text-shape'
|
})
|
const textBBox = text.getBBox()
|
const width = textBBox.width + 24
|
const height = textBBox.height + 12
|
keyShape.attr({
|
x: -width / 2,
|
y: -height / 2,
|
width,
|
height
|
})
|
|
return keyShape
|
},
|
getAnchorPoints() {
|
return [
|
[0.5, 1]
|
]
|
},
|
update: undefined
|
})
|
|
G6.registerNode('indentedNode', {
|
addChildCount(group, tag, props) {
|
const { collapsed, branchColor, count } = props
|
let clickCircleY = 10
|
// 子类数量 icon,绘制圆点在节点正下方
|
if (tag) {
|
const childCountGroup = group.addGroup({
|
name: 'child-count-group'
|
})
|
childCountGroup.setMatrix([1, 0, 0, 0, 1, 0, 0, clickCircleY, 1])
|
const countBackWidth = collapsed ? 26 : 12
|
childCountGroup.addShape('rect', {
|
attrs: {
|
width: countBackWidth,
|
height: 12,
|
radius: 6,
|
stroke: branchColor,
|
lineWidth: 2,
|
fill: collapsed ? branchColor : '#fff',
|
x: -countBackWidth / 2,
|
y: -6,
|
cursor: 'pointer',
|
},
|
name: 'child-count-rect-shape'
|
})
|
const childCountText = childCountGroup.addShape('text', {
|
attrs: {
|
text: count,
|
fill: '#fff',
|
x: 0,
|
y: 0,
|
fontSize: 10,
|
textAlign: 'center',
|
textBaseline: 'middle',
|
cursor: 'pointer',
|
},
|
name: 'child-count-text-shape'
|
})
|
const childHoverIcon = childCountGroup.addShape('path', {
|
attrs: {
|
stroke: '#fff',
|
lineWidth: 1,
|
cursor: 'pointer',
|
path: [['M', -3, 2], ['L', 0, -2], ['L', 3, 2]]
|
},
|
name: 'child-count-expand-icon',
|
capture: false
|
})
|
childHoverIcon.hide()
|
|
// 连接 count 的线段
|
const countLink = group.addShape('path', {
|
attrs: {
|
path: [['M', 0, 0], ['L', 0, 11]],
|
stroke: branchColor,
|
lineWidth: 2,
|
},
|
name: 'count-link'
|
})
|
countLink.toBack()
|
|
if (collapsed) {
|
childCountGroup.show()
|
childCountText.show()
|
countLink.show()
|
}
|
else {
|
childCountGroup.hide()
|
childCountText.hide()
|
countLink.hide()
|
}
|
|
clickCircleY += 16
|
}
|
},
|
addBottomLine(group, props) {
|
const { x, width, stroke, lineWidth } = props
|
return group.addShape('path', {
|
attrs: {
|
path: [
|
['M', x - 1, 0],
|
['L', width, 0],
|
],
|
stroke,
|
lineWidth,
|
},
|
name: 'node-path-shape'
|
})
|
},
|
addName(group, props) {
|
const { label, x = 0, y, fill } = props
|
return group.addShape('text', {
|
attrs: {
|
text: label,
|
x,
|
y,
|
textAlign: 'start',
|
textBaseline: 'top',
|
fill,
|
fontSize: 14,
|
fontFamily: 'PingFangSC-Regular',
|
cursor: 'pointer',
|
},
|
name: 'not-root-text-shape'
|
})
|
},
|
draw(model, group) {
|
const { collapsed, depth, label, children, selected } = model
|
// 是否为根节点
|
const rootNode = depth === 0
|
// 子节点数量
|
const childCount = children ? children.length : 0
|
|
let width = 0
|
const height = 24
|
const x = 0
|
const y = -height / 2
|
const borderRadius = 4
|
// 名称文本
|
const text = this.addName(group, { label, x, y })
|
|
let textWidth = text.getBBox().width
|
width = textWidth + 20
|
|
const keyShapeAttrs = {
|
x,
|
y,
|
width,
|
height,
|
radius: borderRadius,
|
fill: undefined,
|
stroke: undefined,
|
}
|
|
const keyShape = group.addShape('rect', {
|
attrs: keyShapeAttrs,
|
name: 'root-key-shape-rect-shape'
|
})
|
|
// 底部横线
|
const bottomLine = this.addBottomLine(group, {
|
stroke: model.branchColor || '#AAB7C4',
|
lineWidth: 3,
|
x,
|
width
|
})
|
|
let nameColor = 'rgba(0, 0, 0, 0.85)'
|
|
if (selected) {
|
nameColor = systemColor
|
}
|
|
// 名称
|
text.attr({
|
y: y - 12,
|
fill: nameColor
|
})
|
text.toFront()
|
textWidth = text.getBBox().width
|
|
if (bottomLine) bottomLine.toFront()
|
|
this.addChildCount(group, childCount && !rootNode, {
|
collapsed,
|
branchColor: model.branchColor,
|
count: childCount ? `${childCount}` : undefined
|
})
|
|
const bbox = group.getBBox()
|
const backContainer = group.addShape('path', {
|
attrs: {
|
path: childCount ? [
|
['M', bbox.minX, bbox.minY],
|
['L', bbox.maxX, bbox.minY],
|
['L', bbox.maxX, bbox.maxY],
|
['L', bbox.minX + 20, bbox.maxY],
|
['L', bbox.minX + 20, bbox.maxY + 20],
|
['L', bbox.minX, bbox.maxY + 20],
|
['Z']
|
] : [
|
['M', bbox.minX, bbox.minY],
|
['L', bbox.maxX, bbox.minY],
|
['L', bbox.maxX, bbox.maxY],
|
['L', bbox.minX, bbox.maxY],
|
['Z']
|
],
|
fill: '#fff',
|
opacity: 0
|
}
|
})
|
backContainer.toBack()
|
return keyShape
|
}
|
})
|
|
G6.registerEdge('indentedEdge', {
|
afterDraw: (cfg, group) => {
|
const sourceNode = cfg.sourceNode && cfg.sourceNode.getModel()
|
const targetNode = cfg.targetNode && cfg.targetNode.getModel()
|
const color = sourceNode.branchColor || targetNode.branchColor || cfg.color || '#000'
|
|
const keyShape = group.get('children')[0]
|
keyShape.attr({
|
stroke: color,
|
lineWidth: 3 // branchThick
|
})
|
group.toBack()
|
},
|
getControlPoints: (cfg) => {
|
const startPoint = cfg.startPoint
|
const endPoint = cfg.endPoint
|
return [
|
startPoint,
|
{
|
x: startPoint.x,
|
y: endPoint.y,
|
},
|
endPoint
|
]
|
},
|
update: undefined
|
}, 'polyline')
|
|
G6.registerBehavior('wheel-scroll', {
|
getDefaultCfg() {
|
return {
|
direction: 'y',
|
zoomKey: 'ctrl',
|
sensitivity: 3,
|
scalableRange: -64
|
}
|
},
|
getEvents() {
|
return {
|
wheel: 'onWheel'
|
}
|
},
|
onWheel(ev) {
|
const graph = this.graph
|
let keyDown = ev[`${this.zoomKey}Key`]
|
if (this.zoomKey === 'control') keyDown = ev.ctrlKey
|
if (keyDown) {
|
const sensitivity = this.get('sensitivity')
|
const canvas = graph.get('canvas')
|
const point = canvas.getPointByClient(ev.clientX, ev.clientY)
|
let ratio = graph.getZoom()
|
if (ev.wheelDelta > 0) {
|
ratio *= (1 + 0.01 * sensitivity)
|
} else {
|
ratio *= (1 - 0.01 * sensitivity)
|
}
|
graph.zoomTo(ratio, {
|
x: point.x,
|
y: point.y
|
})
|
graph.emit('wheelzoom', ev)
|
} else {
|
let dx = ev.deltaX || ev.movementX
|
let dy = ev.deltaY || ev.movementY
|
if (!dy && navigator.userAgent.indexOf('Firefox') > -1) dy = (-ev.wheelDelta * 125) / 3
|
|
const width = this.graph.get('width')
|
const height = this.graph.get('height')
|
const graphCanvasBBox = this.graph.get('group').getCanvasBBox()
|
|
let expandWidth = this.scalableRange
|
let expandHeight = this.scalableRange
|
// 若 scalableRange 是 0~1 的小数,则作为比例考虑
|
if (expandWidth < 1 && expandWidth > -1) {
|
expandWidth = width * expandWidth
|
expandHeight = height * expandHeight
|
}
|
|
const { minX, maxX, minY, maxY } = graphCanvasBBox
|
|
if (dx > 0) {
|
if (maxX < -expandWidth) {
|
dx = 0
|
} else if (maxX - dx < -expandWidth) {
|
dx = maxX + expandWidth
|
}
|
} else if (dx < 0) {
|
if (minX > width + expandWidth) {
|
dx = 0
|
} else if (minX - dx > width + expandWidth) {
|
dx = minX - (width + expandWidth)
|
}
|
}
|
|
if (dy > 0) {
|
if (maxY < -expandHeight) {
|
dy = 0
|
} else if (maxY - dy < -expandHeight) {
|
dy = maxY + expandHeight
|
}
|
} else if (dy < 0) {
|
if (minY > height + expandHeight) {
|
dy = 0
|
} else if (minY - dy > height + expandHeight) {
|
dy = minY - (height + expandHeight)
|
}
|
}
|
|
if (this.get('direction') === 'x') {
|
dy = 0
|
} else if (this.get('direction') === 'y') {
|
dx = 0
|
}
|
|
graph.translate(-dx, -dy)
|
}
|
ev.preventDefault()
|
}
|
})
|
G6.registerBehavior('hover-node', {
|
getEvents() {
|
return {
|
'node:mouseover': 'onNodeMouseOver',
|
'node:mouseleave': 'onNodeMouseLeave',
|
'node:mouseenter': 'onNodeMouseEnter'
|
}
|
},
|
onNodeMouseEnter(ev) {
|
const { item } = ev
|
if (!item || item.get('destroyed')) return
|
item.toFront()
|
const model = item.getModel()
|
const { collapsed, depth } = model
|
const rootNode = depth === 0 || model.isRoot
|
const group = item.getContainer()
|
|
if (rootNode) return
|
|
// 控制子节点个数标记
|
if (!collapsed) {
|
const childCountGroup = group.find(e => e.get('name') === 'child-count-group')
|
if (childCountGroup) {
|
childCountGroup.show()
|
}
|
}
|
},
|
onNodeMouseOver(ev) {
|
const shape = ev.target
|
|
// tooltip显示、隐藏
|
this.graph.emit('tooltip: show', ev)
|
|
// expand 状态下,若 hover 到子节点个数标记,填充背景+显示收起 icon
|
const { item } = ev
|
const group = item.getContainer()
|
const model = item.getModel()
|
if (!model.collapsed) {
|
const childCountGroup = group.find(e => e.get('name') === 'child-count-group')
|
if (childCountGroup) {
|
childCountGroup.show()
|
const back = childCountGroup.find(e => e.get('name') === 'child-count-rect-shape')
|
const expandIcon = childCountGroup.find(e => e.get('name') === 'child-count-expand-icon')
|
const rootNode = model.depth === 0 || model.isRoot
|
const branchColor = rootNode ? '#576286' : model.branchColor
|
if (shape.get('parent').get('name') === 'child-count-group') {
|
if (back) {
|
back.attr('fill', branchColor || '#fff')
|
}
|
if (expandIcon) {
|
expandIcon.show()
|
}
|
} else {
|
if (back) {
|
back.attr('fill', '#fff')
|
}
|
if (expandIcon) {
|
expandIcon.hide()
|
}
|
}
|
}
|
}
|
},
|
onNodeMouseLeave(ev) {
|
const { item } = ev
|
const model = item.getModel()
|
const group = item.getContainer()
|
const { collapsed } = model
|
|
if (!collapsed) {
|
const childCountGroup = group.find(e => e.get('name') === 'child-count-group')
|
if (childCountGroup) {
|
childCountGroup.hide()
|
}
|
|
const iconsLinkPath = group.find(e => e.get('name') === 'icons-link-path')
|
if (iconsLinkPath) {
|
iconsLinkPath.hide()
|
}
|
}
|
|
this.graph.emit('tooltip: hide', ev)
|
}
|
})
|
const dataIndTransform = (data) => {
|
const changeData = (d) => {
|
let data = { ...d }
|
|
data.type = data.isRoot ? 'indentedRoot' : 'indentedNode'
|
|
if (d.children) {
|
data.children = d.children.map((child) => changeData(child))
|
}
|
// 给定 branchColor 和 0-2 层节点 depth
|
if (data.children && data.children.length) {
|
data.depth = 0
|
data.children.forEach((subtree, i) => {
|
subtree.branchColor = COLORS[i % COLORS.length]
|
// dfs
|
let currentDepth = 1
|
subtree.depth = currentDepth
|
Util.traverseTree(subtree, child => {
|
child.branchColor = COLORS[i % COLORS.length]
|
|
if (!child.depth) {
|
child.depth = currentDepth + 1
|
}
|
else currentDepth = subtree.depth
|
if (child.children) {
|
child.children.forEach(subChild => {
|
subChild.depth = child.depth + 1
|
})
|
}
|
|
if (!data.isRoot) {
|
child.collapsed = data.collapsed || false
|
}
|
return true
|
})
|
})
|
}
|
|
return data
|
}
|
return changeData(data)
|
}
|
|
// 知识图谱树
|
G6.registerNode('treeNode', {
|
draw: (cfg, group) => {
|
const { label, selected, children, isRoot } = cfg
|
const rootNode = !!isRoot
|
const hasChildren = children && children.length !== 0
|
|
let width = 0
|
const height = 28
|
const x = 0
|
const y = -height / 2
|
|
// 名称文本
|
const text = group.addShape('text', {
|
attrs: {
|
text: label,
|
x: x * 2,
|
y,
|
textAlign: 'left',
|
textBaseline: 'top',
|
fontFamily: 'PingFangSC-Regular',
|
},
|
cursor: 'pointer',
|
name: 'name-text-shape',
|
})
|
const textWidth = text.getBBox().width
|
width = textWidth + 20
|
|
width = width < 60 ? 60 : width
|
|
if (!rootNode && hasChildren) {
|
width += 22
|
}
|
|
const keyShapeAttrs = {
|
x,
|
y,
|
width,
|
height,
|
radius: 4
|
}
|
|
const keyShape = group.addShape('rect', {
|
attrs: keyShapeAttrs,
|
name: 'root-key-shape-rect-shape'
|
})
|
|
if (!rootNode) {
|
// 底部横线
|
group.addShape('path', {
|
attrs: {
|
path: [
|
['M', x - 1, 0],
|
['L', width, 0],
|
],
|
stroke: '#AAB7C4',
|
lineWidth: 1,
|
},
|
name: 'node-path-shape'
|
})
|
}
|
|
const mainX = x - 10
|
const mainY = -height + 15
|
|
if (rootNode) {
|
group.addShape('rect', {
|
attrs: {
|
x: mainX,
|
y: mainY,
|
width: width + 12,
|
height,
|
radius: 14,
|
fill: systemColor,
|
cursor: 'pointer',
|
},
|
name: 'main-shape'
|
})
|
}
|
|
let nameColor = 'rgba(0, 0, 0, 0.85)'
|
if (selected) {
|
nameColor = systemColor
|
}
|
|
// 名称
|
if (rootNode) {
|
group.addShape('text', {
|
attrs: {
|
text: label,
|
x: mainX + 18,
|
y: 1,
|
textAlign: 'left',
|
textBaseline: 'middle',
|
fill: '#ffffff',
|
fontSize: 12,
|
fontFamily: 'PingFangSC-Regular',
|
cursor: 'pointer',
|
},
|
name: 'root-text-shape'
|
})
|
} else {
|
group.addShape('text', {
|
attrs: {
|
text: label,
|
x: mainX + 6,
|
y: y - 5,
|
textAlign: 'start',
|
textBaseline: 'top',
|
fill: nameColor,
|
fontSize: 12,
|
fontFamily: 'PingFangSC-Regular',
|
cursor: 'pointer',
|
},
|
name: 'not-root-text-shape'
|
})
|
}
|
|
// 子类数量
|
if (hasChildren && !rootNode) {
|
const childCountHeight = 12
|
const childCountX = width - 22
|
const childCountY = -childCountHeight / 2
|
|
group.addShape('rect', {
|
attrs: {
|
width: 22,
|
height: 12,
|
stroke: systemColor,
|
fill: '#fff',
|
x: childCountX,
|
y: childCountY,
|
radius: 6,
|
cursor: 'pointer',
|
},
|
name: 'child-count-rect-shape',
|
})
|
group.addShape('text', {
|
attrs: {
|
text: `${children.length}`,
|
fill: 'rgba(0, 0, 0, .65)',
|
x: childCountX + 11,
|
y: childCountY + 12,
|
fontSize: 10,
|
width: 22,
|
textAlign: 'center',
|
cursor: 'pointer',
|
},
|
name: 'child-count-text-shape'
|
})
|
}
|
|
return keyShape
|
}
|
})
|
|
G6.registerEdge('smooth', {
|
draw(cfg, group) {
|
const { startPoint, endPoint } = cfg
|
const hgap = Math.abs(endPoint.x - startPoint.x)
|
|
const path = [
|
['M', startPoint.x, startPoint.y],
|
[
|
'C',
|
startPoint.x + hgap / 4,
|
startPoint.y,
|
endPoint.x - hgap / 2,
|
endPoint.y,
|
endPoint.x,
|
endPoint.y,
|
],
|
]
|
|
const shape = group.addShape('path', {
|
attrs: {
|
stroke: '#AAB7C4',
|
path,
|
},
|
name: 'smooth-path-shape',
|
})
|
return shape
|
},
|
})
|
|
class antvG6Chart extends Component {
|
static propTpyes = {
|
config: PropTypes.object
|
}
|
|
state = {
|
config: null,
|
BID: '',
|
BData: '',
|
plot: null,
|
chartId: Utils.getuuid(),
|
empty: true
|
}
|
|
data = []
|
mkgraph = null
|
selectedId = ''
|
loaded = false
|
|
UNSAFE_componentWillMount () {
|
const { config } = this.props
|
|
let _config = fromJS(config).toJS()
|
let BID = ''
|
let BData = ''
|
|
if (config.setting.supModule) {
|
BData = window.GLOB.CacheData.get(config.setting.supModule)
|
} else {
|
BData = window.GLOB.CacheData.get(config.$pageId)
|
}
|
if (BData) {
|
BID = BData.$BID || ''
|
}
|
|
if (_config.setting.sync === 'true') {
|
_config.setting.onload = 'false'
|
|
if (window.GLOB.SyncData.has(_config.dataName)) {
|
this.data = window.GLOB.SyncData.get(_config.dataName) || []
|
|
if (_config.$cache) {
|
Api.writeCacheConfig(_config.uuid, fromJS(this.data).toJS(), BID)
|
}
|
|
_config.setting.sync = 'false'
|
|
this.loaded = true
|
|
window.GLOB.SyncData.delete(_config.dataName)
|
}
|
}
|
|
_config.plot.height = Utils.getHeight(_config.plot.height)
|
_config.style.minHeight = _config.plot.height + 30
|
|
if (_config.plot.title) {
|
_config.style.minHeight = _config.style.minHeight + 45
|
}
|
|
this.setState({
|
config: _config,
|
BID: BID || '',
|
BData: BData || '',
|
plot: _config.plot
|
})
|
|
let that = this
|
|
if (config.plot.subtype === 'mindmap') {
|
G6.registerBehavior(config.uuid, {
|
getEvents() {
|
return {
|
'node:click': 'editNode',
|
'canvas:click': 'onCanvasClick'
|
}
|
},
|
editNode(evt) {
|
const item = evt.item
|
const model = item.get('model')
|
|
this.graph.getNodes().forEach(node => {
|
let _model = node.get('model')
|
if (_model.selected) {
|
_model.selected = false
|
this.graph.updateItem(node, _model, false)
|
}
|
})
|
|
model.selected = true
|
this.graph.updateItem(item, model, false)
|
|
that.handleClick(model)
|
},
|
onCanvasClick(e) {
|
this.graph.getNodes().forEach(node => {
|
let _model = node.get('model')
|
if (_model.selected) {
|
_model.selected = false
|
this.graph.updateItem(node, _model, false)
|
}
|
})
|
that.handleClick()
|
}
|
})
|
} else if (config.plot.subtype === 'indentTree') {
|
G6.registerBehavior(config.uuid, {
|
getEvents() {
|
return {
|
'node:click': 'onNodeClick',
|
'canvas:click': 'onCanvasClick'
|
}
|
},
|
onNodeClick(e) {
|
const { item, target } = e
|
const shape = target
|
const shapeName = shape.cfg.name
|
let model = item.getModel()
|
|
// 点击收起/展开 icon
|
if (shapeName === 'child-count-rect-shape' || shapeName === 'child-count-text-shape') {
|
const updatedCollapsed = !model.collapsed
|
this.graph.updateItem(item, { collapsed: updatedCollapsed })
|
this.graph.layout()
|
return
|
}
|
|
// 选中节点
|
this.graph.getNodes().forEach(node => {
|
let _model = node.get('model')
|
if (_model.selected) {
|
_model.selected = false
|
this.graph.updateItem(node, _model, false)
|
}
|
})
|
|
model.selected = true
|
this.graph.updateItem(item, model, false)
|
|
that.handleClick(model)
|
},
|
onCanvasClick(e) {
|
this.graph.getNodes().forEach(node => {
|
let _model = node.get('model')
|
if (_model.selected) {
|
_model.selected = false
|
this.graph.updateItem(node, _model, false)
|
}
|
})
|
|
that.handleClick()
|
}
|
})
|
} else if (config.plot.subtype === 'kapmap') {
|
G6.registerBehavior(config.uuid, {
|
getEvents() {
|
return {
|
'node:click': 'onNodeClick',
|
'canvas:click': 'onCanvasClick'
|
}
|
},
|
onNodeClick(e) {
|
const { item } = e
|
let model = item.getModel()
|
|
if (model.children) return
|
// 选中节点
|
this.graph.getNodes().forEach(node => {
|
let _model = node.get('model')
|
if (_model.selected) {
|
_model.selected = false
|
this.graph.updateItem(node, _model, false)
|
}
|
})
|
|
model.selected = true
|
this.graph.updateItem(item, model, false)
|
|
that.handleClick(model)
|
},
|
onCanvasClick(e) {
|
this.graph.getNodes().forEach(node => {
|
let _model = node.get('model')
|
if (_model.selected) {
|
_model.selected = false
|
this.graph.updateItem(node, _model, false)
|
}
|
})
|
|
that.handleClick()
|
}
|
})
|
}
|
}
|
|
shouldComponentUpdate (nextProps, nextState) {
|
return !is(fromJS(this.state), fromJS(nextState))
|
}
|
|
componentDidMount () {
|
const { config } = this.state
|
MKEmitter.addListener('reloadData', this.reloadData)
|
MKEmitter.addListener('resetSelectLine', this.resetParentParam)
|
|
if (config.setting.useMSearch) {
|
MKEmitter.addListener('searchRefresh', this.searchRefresh)
|
}
|
|
if (config.setting.sync === 'true') {
|
MKEmitter.addListener('transferSyncData', this.transferSyncData)
|
}
|
|
this.initExec()
|
}
|
|
/**
|
* @description 组件销毁,清除state更新,清除快捷键设置
|
*/
|
componentWillUnmount () {
|
this.setState = () => {
|
return
|
}
|
MKEmitter.removeListener('reloadData', this.reloadData)
|
MKEmitter.removeListener('searchRefresh', this.searchRefresh)
|
MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
|
MKEmitter.removeListener('transferSyncData', this.transferSyncData)
|
}
|
|
initExec = () => {
|
const { config, BID } = this.state
|
|
if (config.$cache) {
|
if (config.$time) {
|
if (!this.loaded) {
|
Api.getLCacheConfig(config.uuid, config.$time, BID).then(res => {
|
if (!res.valid && config.setting.onload === 'true') {
|
setTimeout(() => {
|
this.loadData('init')
|
}, config.setting.delay || 0)
|
}
|
|
if (!res.data || this.loaded) return
|
|
this.data = res.data
|
this.handleData()
|
})
|
} else {
|
this.handleData()
|
}
|
} else {
|
if (!this.loaded) {
|
Api.getLCacheConfig(config.uuid, 0, BID).then(res => {
|
if (!res.data || this.loaded) return
|
|
this.data = res.data
|
this.handleData()
|
})
|
}
|
|
if (config.setting.onload === 'true') {
|
setTimeout(() => {
|
this.loadData('init')
|
}, config.setting.delay || 0)
|
} else if (this.loaded) {
|
this.handleData()
|
}
|
}
|
} else if (config.setting.onload === 'true') {
|
setTimeout(() => {
|
this.loadData()
|
}, config.setting.delay || 0)
|
} else if (this.loaded) {
|
this.handleData()
|
}
|
}
|
|
transferSyncData = (syncId) => {
|
const { config, BID } = this.state
|
|
if (config.$syncId !== syncId) return
|
|
let _data = window.GLOB.SyncData.get(config.dataName) || []
|
|
if (config.$cache) {
|
Api.writeCacheConfig(config.uuid, fromJS(_data).toJS(), BID)
|
}
|
|
if (!is(fromJS(this.data), fromJS(_data))) {
|
this.data = _data
|
this.handleData()
|
}
|
|
this.loaded = true
|
|
window.GLOB.SyncData.delete(config.dataName)
|
|
MKEmitter.removeListener('transferSyncData', this.transferSyncData)
|
}
|
|
searchRefresh = (searchId) => {
|
const { config } = this.state
|
|
if (config.$searchId !== searchId) return
|
|
this.setState({}, () => {
|
this.loadData()
|
})
|
}
|
|
reloadData = (menuId) => {
|
const { config } = this.state
|
|
if (config.uuid !== menuId) return
|
|
this.loadData()
|
}
|
|
resetParentParam = (MenuID, id, data) => {
|
const { config } = this.state
|
|
if (!config.setting.supModule || config.setting.supModule !== MenuID) return
|
if (id !== this.state.BID || id !== '') {
|
this.setState({ BID: id, BData: data }, () => {
|
this.loadData()
|
})
|
}
|
}
|
|
async loadData (type) {
|
const { config, BID } = this.state
|
|
if (config.setting.supModule && !BID) { // BID 不存在时,不做查询
|
if (!is(fromJS(this.data), fromJS([]))) {
|
this.data = []
|
this.handleData()
|
}
|
this.loaded = true
|
return
|
}
|
|
let searches = []
|
if (config.setting.useMSearch) { // 主表搜索条件
|
searches = window.GLOB.SearchBox.get(config.$searchId) || []
|
}
|
|
if (config.$s_req && searches.filter(item => item.required && item.value === '').length > 0) {
|
return
|
}
|
|
this.setState({
|
loading: true
|
})
|
|
let _orderBy = config.setting.order || ''
|
let param = UtilsDM.getQueryDataParams(config.setting, searches, _orderBy, '', '', BID)
|
|
let result = await Api.genericInterface(param)
|
if (result.status) {
|
if (config.$cache && type === 'init') {
|
Api.writeCacheConfig(config.uuid, result.data || [], BID)
|
}
|
|
this.loaded = true
|
|
this.setState({
|
loading: false
|
})
|
|
if (!is(fromJS(this.data), fromJS(result.data || []))) {
|
this.data = result.data || []
|
this.handleData()
|
}
|
if (result.message) {
|
if (result.ErrCode === 'Y') {
|
Modal.success({
|
title: result.message
|
})
|
} else if (result.ErrCode === 'S') {
|
notification.success({
|
top: 92,
|
message: result.message,
|
duration: 2
|
})
|
}
|
}
|
} else {
|
this.setState({
|
loading: false
|
})
|
|
if (!result.message) return
|
if (result.ErrCode === 'N') {
|
Modal.error({
|
title: result.message,
|
})
|
} else if (result.ErrCode !== '-2') {
|
notification.error({
|
top: 92,
|
message: result.message,
|
duration: 10
|
})
|
}
|
}
|
}
|
|
getdata = () => {
|
const { plot, config, BData } = this.state
|
|
let root = {
|
label: 'Root',
|
id: 'Root'
|
}
|
|
if (plot.rootType === 'fixed') {
|
root.label = plot.rootLabel
|
root.id = plot.rootValue
|
} else if (plot.rootType === 'supvalue' && BData) {
|
let rootLabel = plot.rootLabel.toLowerCase()
|
let rootValue = plot.rootValue.toLowerCase()
|
let _bd = {}
|
|
Object.keys(BData).forEach(key => {
|
_bd[key.toLowerCase()] = BData[key]
|
})
|
|
root.label = _bd[rootLabel]
|
root.id = _bd[rootValue]
|
}
|
|
let _options = []
|
let logMap = new Map()
|
|
this.data.forEach(item => {
|
let pval = item[plot.parentField]
|
let val = item[plot.valueField]
|
let label = item[plot.labelField] || ''
|
|
if (!val || !label || logMap.has(val)) return
|
|
if (plot.rootType === 'line' && pval === plot.mark) {
|
root.label = label
|
root.id = val
|
}
|
|
logMap.set(val, true)
|
|
let _item = {
|
...item,
|
label: label,
|
id: val,
|
$parentId: pval
|
}
|
|
_item.$$uuid = item[config.setting.primaryKey] || ''
|
|
_options.push(_item)
|
})
|
|
root.nodeNumber = 0
|
root = this.getTree(root, _options, root)
|
root.children = root.children || []
|
|
if (root.selectedItem) {
|
let option = {...root.selectedItem}
|
setTimeout(() => {
|
MKEmitter.emit('resetSelectLine', config.uuid, option.id, option)
|
}, 20)
|
delete root.selectedItem
|
} else {
|
this.selectedId = ''
|
}
|
|
if (plot.subtype === 'mindmap') {
|
root.type = 'dice-mind-map-root'
|
|
if (plot.dirField) {
|
root.children = root.children.map(item => {
|
item.direction = item[plot.dirField] === plot.dirSign ? 'left' : 'right'
|
|
return item
|
})
|
}
|
|
root.children.forEach(item => {
|
if (item.direction === 'left') {
|
item.color = plot.leftColor || '#26C281'
|
} else {
|
item.direction = 'right'
|
item.color = plot.nodeColor || '#1890ff'
|
}
|
})
|
|
const collapse = (item) => {
|
if (!item.children) return
|
|
item.children.forEach(cell => {
|
cell.collapsed = plot.collapsed === 'true'
|
cell.direction = cell.direction || 'right'
|
cell.type = 'dice-mind-map-leaf'
|
cell.color = cell.color || item.color
|
collapse(cell)
|
})
|
}
|
|
collapse(root)
|
} else if (plot.subtype === 'indentTree') {
|
root.isRoot = true
|
root.collapsed = false
|
|
root.children.forEach(item => {
|
item.collapsed = plot.collapsed === 'true'
|
})
|
} else if (plot.subtype === 'kapmap') {
|
root.isRoot = true
|
root.collapsed = false
|
|
if (plot.collapsed === 'true') {
|
const collapse = (item) => {
|
if (!item.children) return
|
|
item.children.forEach(cell => {
|
cell.collapsed = true
|
collapse(cell)
|
})
|
}
|
|
collapse(root)
|
}
|
}
|
|
return root
|
}
|
|
getTree = (parent, options, root) => {
|
parent.children = []
|
// 添加菜单的子元素
|
options = options.filter(option => {
|
if (option.$parentId === parent.id) {
|
delete option.$parentId
|
|
if (this.selectedId && option.id === this.selectedId) {
|
root.selectedItem = {...option}
|
option.selected = true
|
}
|
|
parent.children.push(option)
|
|
root.nodeNumber++
|
|
return false
|
}
|
return true
|
})
|
|
if (parent.children.length === 0) {
|
parent.children = null
|
} else {
|
parent.children = parent.children.map(item => {
|
item = this.getTree(item, options, root)
|
|
return item
|
})
|
}
|
|
return parent
|
}
|
|
handleData = () => {
|
const { config } = this.state
|
|
MKEmitter.emit('resetSelectLine', config.uuid, '', '')
|
|
if (this.mkgraph) {
|
this.mkgraph.clear()
|
this.resetrender()
|
} else {
|
this.viewrender()
|
}
|
}
|
|
viewrender = () => {
|
const { plot } = this.state
|
|
this.selectedId = ''
|
if (this.data.length === 0) {
|
this.setState({empty: true})
|
} else {
|
this.setState({empty: false})
|
|
if (plot.subtype === 'mindmap') {
|
this.mindrender()
|
} else if (plot.subtype === 'indentTree') {
|
this.indentrender()
|
} else if (plot.subtype === 'kapmap') {
|
this.kapmaprender()
|
}
|
}
|
}
|
|
resetrender = () => {
|
const { plot } = this.state
|
|
if (this.data.length === 0) {
|
this.setState({empty: true})
|
this.selectedId = ''
|
} else {
|
this.setState({empty: false})
|
|
const data = this.getdata()
|
if (plot.subtype === 'mindmap') {
|
this.mkgraph.data(data)
|
|
this.mkgraph.render()
|
|
const width = this.wrap.scrollWidth - 30
|
|
if (plot.collapsed === 'true' && plot.dirField) {
|
this.mkgraph.zoomTo(1, { x: width / 2, y: plot.height / 2 })
|
} else if (plot.collapsed === 'true' || data.nodeNumber < 5) {
|
this.mkgraph.zoomTo(1, { x: 0, y: plot.height / 2 })
|
}
|
} else if (plot.subtype === 'indentTree') {
|
this.mkgraph.data(dataIndTransform(data))
|
|
this.mkgraph.render()
|
} else if (plot.subtype === 'kapmap') {
|
this.mkgraph.data(data)
|
this.mkgraph.render()
|
this.mkgraph.fitView()
|
|
if (plot.collapsed === 'true' || data.nodeNumber < 5) {
|
this.mkgraph.zoomTo(1, { x: 0, y: plot.height / 2 })
|
}
|
}
|
}
|
}
|
|
kapmaprender = () => {
|
const { plot, chartId, config } = this.state
|
const data = this.getdata()
|
|
const graph = new G6.TreeGraph({
|
container: chartId,
|
width: this.wrap.scrollWidth - 30,
|
height: plot.height,
|
modes: {
|
default: [
|
{
|
type: 'collapse-expand',
|
},
|
'drag-canvas',
|
'zoom-canvas',
|
config.uuid
|
],
|
},
|
defaultNode: {
|
type: 'treeNode',
|
anchorPoints: [
|
[0, 0.5],
|
[1, 0.5],
|
],
|
},
|
defaultEdge: {
|
type: 'smooth',
|
},
|
layout: {
|
type: 'compactBox',
|
direction: 'LR',
|
getId: function getId(d) {
|
return d.id
|
},
|
getHeight: function getHeight() {
|
return 16
|
},
|
getWidth: function getWidth(d) {
|
const labelWidth = G6.Util.getTextSize(d.label, 12)[0]
|
const width = 60 + labelWidth
|
return width
|
},
|
getVGap: function getVGap() {
|
return 15
|
},
|
getHGap: function getHGap() {
|
return 30
|
}
|
}
|
})
|
|
graph.data(data)
|
graph.render()
|
graph.fitView()
|
|
if (plot.collapsed === 'true' || data.nodeNumber < 5) {
|
graph.zoomTo(1, { x: 0, y: plot.height / 2 })
|
}
|
|
this.mkgraph = graph
|
}
|
|
indentrender = () => {
|
const { plot, chartId, config } = this.state
|
const data = this.getdata()
|
|
const tree = new G6.TreeGraph({
|
container: chartId,
|
width: this.wrap.scrollWidth - 30,
|
height: plot.height,
|
layout: {
|
type: 'indented',
|
direction: 'LR',
|
isHorizontal: true,
|
indent: 40,
|
getHeight: (d) => {
|
if (d.isRoot) {
|
return 30
|
}
|
if (d.collapsed && d.children && d.children.length) {
|
return 36
|
}
|
return 22
|
},
|
getVGap: () => {
|
return 10
|
},
|
},
|
defaultEdge: {
|
type: 'indentedEdge',
|
style: {
|
lineWidth: 2,
|
radius: 16
|
}
|
},
|
minZoom: 0.5,
|
modes: {
|
default: [
|
'drag-canvas',
|
'wheel-scroll',
|
'hover-node',
|
config.uuid
|
]
|
}
|
})
|
|
tree.on('afterrender', e => {
|
tree.getEdges().forEach(edge => {
|
const targetNode = edge.getTarget().getModel()
|
const color = targetNode.branchColor
|
tree.updateItem(edge, { color })
|
})
|
setTimeout(() => {
|
tree.moveTo(32, 32)
|
tree.zoomTo(0.7)
|
}, 16)
|
})
|
|
tree.data(dataIndTransform(data))
|
|
tree.render()
|
|
this.mkgraph = tree
|
}
|
|
/**
|
* @description 思维导图
|
*/
|
mindrender = () => {
|
const { config, plot, chartId } = this.state
|
const data = this.getdata()
|
const width = this.wrap.scrollWidth - 30
|
let modes = ['drag-canvas', 'zoom-canvas', config.uuid]
|
|
if (plot.collapsed === 'true') {
|
modes = [{ type: 'collapse-expand' }, 'drag-canvas', 'zoom-canvas', config.uuid]
|
}
|
|
const tree = new G6.TreeGraph({
|
container: chartId,
|
width: width,
|
height: plot.height,
|
fitView: true,
|
layout: {
|
type: 'mindmap',
|
direction: 'H',
|
getHeight: () => {
|
return 16
|
},
|
getWidth: (node) => {
|
return node.level === 0 ?
|
Util.getTextSize(node.label, 16)[0] + 12 :
|
Util.getTextSize(node.label, 12)[0]
|
},
|
getVGap: () => {
|
return 10
|
},
|
getHGap: () => {
|
return 60
|
},
|
getSide: (node) => {
|
return node.data.direction
|
}
|
},
|
defaultEdge: {
|
type: 'cubic-horizontal',
|
style: {
|
lineWidth: 2
|
}
|
},
|
minZoom: 0.5,
|
modes: {
|
default: modes
|
}
|
})
|
|
tree.data(data)
|
|
tree.render()
|
|
if (plot.collapsed === 'true' && plot.dirField) {
|
tree.zoomTo(1, { x: width / 2, y: plot.height / 2 })
|
} else if (plot.collapsed === 'true' || data.nodeNumber < 5) {
|
tree.zoomTo(1, { x: 0, y: plot.height / 2 })
|
}
|
|
this.mkgraph = tree
|
}
|
|
handleClick = (data = null) => {
|
const { plot, config } = this.state
|
|
if (plot.click === 'menus') {
|
if (!data) return
|
|
let menu = null
|
|
if (plot.menus && plot.menus.length > 0) {
|
let s = data[plot.menuType] + ''
|
plot.menus.forEach(m => {
|
if (s !== m.sign) return
|
menu = m
|
})
|
}
|
if (!menu || !menu.MenuID) return
|
|
let newtab = {
|
MenuID: menu.MenuID,
|
MenuName: menu.MenuName,
|
MenuNo: menu.MenuNo || '',
|
type: menu.tabType,
|
param: {}
|
}
|
|
if (plot.joint === 'true') {
|
newtab.param.$BID = data.$$uuid || ''
|
|
Object.keys(data).forEach(key => {
|
if (/^\$/.test(key)) return
|
newtab.param[key] = data[key]
|
})
|
}
|
|
MKEmitter.emit('modifyTabs', newtab, true)
|
} else if (plot.click === 'menu') {
|
if (!data) return
|
|
let menuId = plot.menu.slice(-1)[0]
|
let newtab = window.GLOB.mkThdMenus.filter(m => m.MenuID === menuId)[0]
|
|
if (!newtab && plot.MenuID) {
|
newtab = {
|
MenuID: plot.MenuID,
|
MenuName: plot.MenuName,
|
MenuNo: plot.MenuNo,
|
type: plot.tabType
|
}
|
} else if (!newtab) {
|
return
|
}
|
|
newtab = {
|
...newtab,
|
param: {}
|
}
|
|
if (plot.joint === 'true') {
|
newtab.param.$BID = data.$$uuid || ''
|
|
Object.keys(data).forEach(key => {
|
if (/^\$/.test(key)) return
|
newtab.param[key] = data[key]
|
})
|
}
|
|
MKEmitter.emit('modifyTabs', newtab, true)
|
} else {
|
if (data) {
|
this.selectedId = data.$$uuid || ''
|
MKEmitter.emit('resetSelectLine', config.uuid, data.$$uuid || '', data)
|
} else {
|
this.selectedId = ''
|
MKEmitter.emit('resetSelectLine', config.uuid, '', '')
|
}
|
}
|
}
|
|
render() {
|
const { config, loading, empty } = this.state
|
|
return (
|
<div className="custom-g6-plot-box" id={'anchor' + config.uuid} style={config.style}>
|
{loading ?
|
<div className="loading-mask">
|
<div className="ant-spin-blur"></div>
|
<Spin />
|
</div> : null
|
}
|
<NormalHeader config={config} />
|
{empty ? <Empty description={false}/> : null}
|
<div className="canvas" id={this.state.chartId} ref={ref => this.wrap = ref}></div>
|
</div>
|
)
|
}
|
}
|
|
export default antvG6Chart
|