mirror of
https://gitee.com/antv/g6.git
synced 2024-12-04 20:59:15 +08:00
feat: update shape style
This commit is contained in:
parent
2222dd8680
commit
2930ba7080
@ -434,11 +434,14 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getStateStyle(cfg) {
|
||||
|
||||
}
|
||||
}, 'triangle')
|
||||
G6.registerNode('triangle2', {
|
||||
labelPosition: 'center',
|
||||
getCustomConfig() {
|
||||
getCustomConfig(cfg) {
|
||||
return {
|
||||
default: {
|
||||
direction: 'down',
|
||||
|
135
demos/test-graph-node-style.html
Normal file
135
demos/test-graph-node-style.html
Normal file
@ -0,0 +1,135 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="mountNode"></div>
|
||||
<script src="../build/g6.js"></script>
|
||||
<script>
|
||||
|
||||
const data = {
|
||||
nodes: [
|
||||
{
|
||||
id: 'triangle',
|
||||
label: '主题 ModelRect Title',
|
||||
description: '这里是一顿描述信息,不知道长短',
|
||||
x: 150,
|
||||
y: 100
|
||||
}
|
||||
]
|
||||
}
|
||||
const graph = new G6.Graph({
|
||||
container: 'mountNode',
|
||||
width: 800,
|
||||
height: 600,
|
||||
defaultNode: {
|
||||
shape: 'modelRect',
|
||||
style: {
|
||||
fill: 'red'
|
||||
},
|
||||
icon: {
|
||||
show: true,
|
||||
width: 30,
|
||||
height: 30
|
||||
},
|
||||
linkPoints: {
|
||||
top: false,
|
||||
fill: '#fff',
|
||||
size: 5
|
||||
}
|
||||
},
|
||||
nodeStateStyles: {
|
||||
select: {
|
||||
fill: 'red'
|
||||
},
|
||||
hover: {
|
||||
fill: 'blue'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 这里优先级大于graph中的nodeStyle
|
||||
graph.node(node => {
|
||||
let fill = 'red'
|
||||
let shape = 'diamond'
|
||||
if (node.inDegree > 200) {
|
||||
fill = '#36cfc9'
|
||||
shape = 'diamond'
|
||||
}
|
||||
return {
|
||||
shape,
|
||||
icon: {
|
||||
show: true,
|
||||
width: 25,
|
||||
height: 25
|
||||
},
|
||||
linkPoints: {
|
||||
top: true,
|
||||
bottom: true
|
||||
},
|
||||
style: {
|
||||
fill,
|
||||
stroke: '#eaff8f',
|
||||
radius: 15
|
||||
},
|
||||
stateStyles: {
|
||||
hover: {
|
||||
fill: '#bae637',
|
||||
stroke: '#87e8de',
|
||||
width: 130,
|
||||
height: 200,
|
||||
r: 100
|
||||
},
|
||||
select: {
|
||||
fill: '#ccc'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
graph.data(data)
|
||||
graph.render()
|
||||
console.log(graph.save())
|
||||
|
||||
graph.on('node:click', evt => {
|
||||
const { item } = evt
|
||||
// graph.setItemState(item, 'select', true)
|
||||
graph.updateItem(item, {
|
||||
size: [ 160, 130],
|
||||
style: {
|
||||
fill: '#b5f5ec'
|
||||
},
|
||||
preRect: {
|
||||
fill: '#ff4d4f'
|
||||
},
|
||||
stateIcon: {
|
||||
img: 'https://gw.alipayobjects.com/zos/basement_prod/c781088a-c635-452a-940c-0173663456d4.svg'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
graph.on('node:mouseenter', evt => {
|
||||
const { item } = evt
|
||||
|
||||
// graph.setItemState(item, 'hover', true)
|
||||
// graph.updateItem(item, {
|
||||
// style: {
|
||||
// r: 45,
|
||||
// icon: {
|
||||
// img: 'https://gw.alipayobjects.com/zos/basement_prod/c781088a-c635-452a-940c-0173663456d4.svg'
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
})
|
||||
|
||||
graph.on('node:mouseleave', evt => {
|
||||
const { item } = evt
|
||||
// graph.setItemState(item, 'hover', false)
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -5,6 +5,7 @@ const NODE = 'node';
|
||||
const EDGE = 'edge';
|
||||
const CFG_PREFIX = 'default';
|
||||
const MAPPER_SUFFIX = 'Mapper';
|
||||
const STATE_SUFFIX = 'stateStyles';
|
||||
const hasOwnProperty = Object.hasOwnProperty;
|
||||
|
||||
class ItemController {
|
||||
@ -16,14 +17,14 @@ class ItemController {
|
||||
const parent = graph.get(type + 'Group') || graph.get('group');
|
||||
const upperType = Util.upperFirst(type);
|
||||
let item;
|
||||
let styles = graph.get(type + 'Style') || {};
|
||||
let styles = graph.get(type + Util.upperFirst(STATE_SUFFIX)) || {};
|
||||
const defaultModel = graph.get(CFG_PREFIX + upperType);
|
||||
const mapper = graph.get(type + MAPPER_SUFFIX);
|
||||
if (mapper) {
|
||||
const mappedModel = mapper(model);
|
||||
if (mappedModel.styles) {
|
||||
styles = mappedModel.styles;
|
||||
delete mappedModel.styles;
|
||||
if (mappedModel[STATE_SUFFIX]) {
|
||||
styles = mappedModel[STATE_SUFFIX];
|
||||
delete mappedModel[STATE_SUFFIX];
|
||||
}
|
||||
Util.each(mappedModel, (val, cfg) => {
|
||||
model[cfg] = val;
|
||||
|
@ -401,16 +401,16 @@ class Graph extends EventEmitter {
|
||||
* 若是自定义节点切在各种状态下
|
||||
* graph.node(node => {
|
||||
* return {
|
||||
* default: {
|
||||
* fill: 'red',
|
||||
* opacity: 1
|
||||
* },
|
||||
* selected: {
|
||||
* style: {
|
||||
* fill: 'blue',
|
||||
* opacity: 0.2
|
||||
* }
|
||||
* }
|
||||
* {
|
||||
shape: 'rect',
|
||||
label: node.id,
|
||||
style: { fill: '#666' },
|
||||
styles: {
|
||||
default: { fill: 'red' },
|
||||
selected: { fill: 'blue' },
|
||||
custom: { fill: 'green' }
|
||||
}
|
||||
}
|
||||
* }
|
||||
* });
|
||||
* @param {function} nodeFn 指定每个节点样式
|
||||
|
@ -30,7 +30,8 @@ const singleNodeDefinition = Util.mix({}, SingleShapeMixin, {
|
||||
* @return {Array} 宽高
|
||||
*/
|
||||
getSize(cfg) {
|
||||
let size = cfg.size || Global.defaultNode.size;
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
let size = cfg.size || customOptions.size || this.options.size || Global.defaultNode.size;
|
||||
if (!Util.isArray(size)) {
|
||||
size = [ size, size ];
|
||||
}
|
||||
|
@ -5,64 +5,70 @@ const deepMix = require('@antv/util/lib/deep-mix');
|
||||
Shape.registerNode('circle', {
|
||||
// 自定义节点时的配置
|
||||
options: {
|
||||
// 默认配置
|
||||
default: {
|
||||
r: 20,
|
||||
stroke: '#69c0ff',
|
||||
fill: '#e6f7ff',
|
||||
lineWidth: 1,
|
||||
size: 30,
|
||||
style: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
// 文本样式配置
|
||||
labelCfg: {
|
||||
style: {
|
||||
fill: '#595959'
|
||||
}
|
||||
stroke: '#87e8de',
|
||||
fill: '#36cfc9',
|
||||
lineWidth: 1
|
||||
},
|
||||
labelCfg: {
|
||||
style: {
|
||||
fill: '#595959'
|
||||
},
|
||||
// 节点上左右上下四个方向上的链接circle配置
|
||||
linkPoints: {
|
||||
top: false,
|
||||
right: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
// circle的大小
|
||||
size: 3,
|
||||
lineWidth: 1,
|
||||
fill: '#72CC4A',
|
||||
stroke: '#72CC4A'
|
||||
offset: 15
|
||||
},
|
||||
stateStyles: {
|
||||
// 鼠标hover状态下的配置
|
||||
hover: {
|
||||
lineWidth: 3
|
||||
},
|
||||
// 节点中icon配置
|
||||
icon: {
|
||||
// 是否显示icon,值为 false 则不渲染icon
|
||||
show: false,
|
||||
// icon的地址,字符串类型
|
||||
img: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg',
|
||||
width: 16,
|
||||
height: 16
|
||||
// 选中节点状态下的配置
|
||||
select: {
|
||||
lineWidth: 5
|
||||
}
|
||||
},
|
||||
// 鼠标hover状态下的配置
|
||||
hover: {
|
||||
lineWidth: 3
|
||||
// 节点上左右上下四个方向上的链接circle配置
|
||||
linkPoints: {
|
||||
top: false,
|
||||
right: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
// circle的大小
|
||||
size: 3,
|
||||
lineWidth: 1,
|
||||
fill: '#72CC4A',
|
||||
stroke: '#72CC4A'
|
||||
},
|
||||
// 选中节点状态下的配置
|
||||
select: {
|
||||
lineWidth: 5
|
||||
// 节点中icon配置
|
||||
icon: {
|
||||
// 是否显示icon,值为 false 则不渲染icon
|
||||
show: false,
|
||||
// icon的地址,字符串类型
|
||||
img: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg',
|
||||
width: 16,
|
||||
height: 16
|
||||
}
|
||||
},
|
||||
shapeType: 'circle',
|
||||
// 文本位置
|
||||
labelPosition: 'bottom',
|
||||
drawShape(cfg, group) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { icon, linkPoints, ...circleStyle } = style;
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { style: defaultStyle, icon: defaultIcon } = this.options;
|
||||
const { style: customStyle, icon: customIcon } = customOptions;
|
||||
const style = deepMix({}, defaultStyle, customStyle, cfg.style);
|
||||
const icon = deepMix({}, defaultIcon, customIcon, cfg.icon);
|
||||
const size = this.getSize(cfg);
|
||||
const r = size[0];
|
||||
const keyShape = group.addShape('circle', {
|
||||
attrs: circleStyle
|
||||
attrs: {
|
||||
...style,
|
||||
r
|
||||
}
|
||||
});
|
||||
|
||||
const { r } = circleStyle;
|
||||
const { width, height, show } = icon;
|
||||
if (show) {
|
||||
const image = group.addShape('image', {
|
||||
@ -77,20 +83,35 @@ Shape.registerNode('circle', {
|
||||
image.set('capture', false);
|
||||
}
|
||||
|
||||
const { top, left, right, bottom, size,
|
||||
fill: anchorFill, stroke: anchorStroke, lineWidth: borderWidth } = linkPoints;
|
||||
this.drawLinkPoints(cfg, group);
|
||||
|
||||
return keyShape;
|
||||
},
|
||||
/**
|
||||
* 绘制节点上的LinkPoints
|
||||
* @param {Object} cfg data数据配置项
|
||||
* @param {Group} group Group实例
|
||||
*/
|
||||
drawLinkPoints(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { linkPoints: defaultLinkPoints } = this.options;
|
||||
const { linkPoints: customLinkPoints } = customOptions;
|
||||
const linkPoints = deepMix({}, defaultLinkPoints, customLinkPoints, cfg.linkPoints);
|
||||
|
||||
const { top, left, right, bottom, size: markSize,
|
||||
...markStyle } = linkPoints;
|
||||
const size = this.getSize(cfg);
|
||||
const r = size[0];
|
||||
if (left) {
|
||||
// left circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: -r,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'circle-anchor-left'
|
||||
className: 'circle-mark-left'
|
||||
});
|
||||
}
|
||||
|
||||
@ -98,14 +119,12 @@ Shape.registerNode('circle', {
|
||||
// right circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: r,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'circle-anchor-right'
|
||||
className: 'circle-mark-right'
|
||||
});
|
||||
}
|
||||
|
||||
@ -113,14 +132,12 @@ Shape.registerNode('circle', {
|
||||
// top circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: 0,
|
||||
y: -r,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'circle-anchor-top'
|
||||
className: 'circle-mark-top'
|
||||
});
|
||||
}
|
||||
|
||||
@ -128,46 +145,33 @@ Shape.registerNode('circle', {
|
||||
// bottom circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: 0,
|
||||
y: r,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'circle-anchor-bottom'
|
||||
className: 'circle-mark-bottom'
|
||||
});
|
||||
}
|
||||
|
||||
return keyShape;
|
||||
},
|
||||
/**
|
||||
* 获取节点宽高
|
||||
* @internal 返回节点的大小,以 [width, height] 的方式维护
|
||||
* @param {Object} cfg 节点的配置项
|
||||
* @return {Array} 宽高
|
||||
*/
|
||||
getSize(cfg) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { r } = style;
|
||||
|
||||
return [ 2 * r, 2 * r ];
|
||||
},
|
||||
update(cfg, item) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default || {};
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { icon, linkPoints, labelCfg: defaultLabelCfg, ...circleStyle } = style;
|
||||
const { r } = circleStyle;
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { style: defaultStyle, icon: defaultIcon, labelCfg: defaultLabelCfg } = this.options;
|
||||
const { style: customStyle, icon: customIcon, labelCfg: customLabelCfg } = customOptions;
|
||||
const style = deepMix({}, defaultStyle, customStyle, cfg.style);
|
||||
const icon = deepMix({}, defaultIcon, customIcon, cfg.icon);
|
||||
const size = this.getSize(cfg);
|
||||
const r = size[0];
|
||||
|
||||
const group = item.getContainer();
|
||||
|
||||
const keyShape = item.get('keyShape');
|
||||
keyShape.attr(circleStyle);
|
||||
keyShape.attr({
|
||||
...style,
|
||||
r
|
||||
});
|
||||
|
||||
const labelCfg = deepMix({}, defaultLabelCfg, cfg.labelCfg);
|
||||
const labelCfg = deepMix({}, defaultLabelCfg, customLabelCfg, cfg.labelCfg);
|
||||
const labelStyle = this.getLabelStyle(cfg, labelCfg, group);
|
||||
|
||||
const text = group.findByClassName('node-label');
|
||||
@ -187,52 +191,68 @@ Shape.registerNode('circle', {
|
||||
});
|
||||
}
|
||||
|
||||
const { size, fill: anchorFill, stroke: anchorStroke, lineWidth: borderWidth } = linkPoints;
|
||||
this.updateLinkPoints(cfg, group);
|
||||
},
|
||||
/**
|
||||
* 更新linkPoints
|
||||
* @param {Object} cfg 节点数据配置项
|
||||
* @param {Group} group Item所在的group
|
||||
*/
|
||||
updateLinkPoints(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { linkPoints: defaultLinkPoints } = this.options;
|
||||
const { linkPoints: customLinkPoints } = customOptions;
|
||||
const linkPoints = deepMix({}, defaultLinkPoints, customLinkPoints, cfg.linkPoints);
|
||||
|
||||
const anchorLeft = group.findByClassName('circle-anchor-left');
|
||||
if (anchorLeft) {
|
||||
anchorLeft.attr({
|
||||
const { size: markSize, fill: markFill, stroke: markStroke, lineWidth: borderWidth } = linkPoints;
|
||||
|
||||
const size = this.getSize(cfg);
|
||||
const r = size[0];
|
||||
|
||||
const markLeft = group.findByClassName('circle-mark-left');
|
||||
if (markLeft) {
|
||||
markLeft.attr({
|
||||
x: -r,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
||||
const anchorRight = group.findByClassName('circle-anchor-right');
|
||||
if (anchorRight) {
|
||||
anchorRight.attr({
|
||||
const markRight = group.findByClassName('circle-mark-right');
|
||||
if (markRight) {
|
||||
markRight.attr({
|
||||
x: r,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
||||
const anchorTop = group.findByClassName('circle-anchor-top');
|
||||
if (anchorTop) {
|
||||
anchorTop.attr({
|
||||
const markTop = group.findByClassName('circle-mark-top');
|
||||
if (markTop) {
|
||||
markTop.attr({
|
||||
x: 0,
|
||||
y: -r,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
||||
const anchorBottom = group.findByClassName('circle-anchor-bottom');
|
||||
if (anchorBottom) {
|
||||
anchorBottom.attr({
|
||||
const markBottom = group.findByClassName('circle-mark-bottom');
|
||||
if (markBottom) {
|
||||
markBottom.attr({
|
||||
x: 0,
|
||||
y: r,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
@ -5,63 +5,65 @@ const deepMix = require('@antv/util/lib/deep-mix');
|
||||
Shape.registerNode('diamond', {
|
||||
// 自定义节点时的配置
|
||||
options: {
|
||||
// 默认配置
|
||||
default: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
stroke: '#69c0ff',
|
||||
fill: '#e6f7ff',
|
||||
lineWidth: 1,
|
||||
// 文本样式配置
|
||||
labelCfg: {
|
||||
style: {
|
||||
fill: '#595959'
|
||||
}
|
||||
},
|
||||
// 节点上左右上下四个方向上的链接circle配置
|
||||
linkPoints: {
|
||||
top: false,
|
||||
right: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
// circle的大小
|
||||
size: 3,
|
||||
lineWidth: 1,
|
||||
fill: '#72CC4A',
|
||||
stroke: '#72CC4A'
|
||||
},
|
||||
// 节点中icon配置
|
||||
icon: {
|
||||
// 是否显示icon,值为 false 则不渲染icon
|
||||
show: false,
|
||||
// icon的地址,字符串类型
|
||||
img: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg',
|
||||
width: 16,
|
||||
height: 16
|
||||
size: [ 100, 100 ],
|
||||
style: {
|
||||
stroke: '#87e8de',
|
||||
fill: '#36cfc9',
|
||||
lineWidth: 1
|
||||
},
|
||||
// 文本样式配置
|
||||
labelCfg: {
|
||||
style: {
|
||||
fill: '#595959'
|
||||
}
|
||||
},
|
||||
// 鼠标hover状态下的配置
|
||||
hover: {
|
||||
lineWidth: 3
|
||||
stateStyles: {
|
||||
// 鼠标hover状态下的配置
|
||||
hover: {
|
||||
lineWidth: 3
|
||||
},
|
||||
// 选中节点状态下的配置
|
||||
select: {
|
||||
lineWidth: 5
|
||||
}
|
||||
},
|
||||
// 选中节点状态下的配置
|
||||
select: {
|
||||
lineWidth: 5
|
||||
// 节点上左右上下四个方向上的链接circle配置
|
||||
linkPoints: {
|
||||
top: false,
|
||||
right: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
// circle的大小
|
||||
size: 3,
|
||||
lineWidth: 1,
|
||||
fill: '#72CC4A',
|
||||
stroke: '#72CC4A'
|
||||
},
|
||||
// 节点中icon配置
|
||||
icon: {
|
||||
// 是否显示icon,值为 false 则不渲染icon
|
||||
show: false,
|
||||
// icon的地址,字符串类型
|
||||
img: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg',
|
||||
width: 16,
|
||||
height: 16
|
||||
}
|
||||
},
|
||||
shapeType: 'circle',
|
||||
// 文本位置
|
||||
labelPosition: 'center',
|
||||
drawShape(cfg, group) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { icon, linkPoints, width, height, ...diamondStyle } = style;
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { style: defaultStyle, icon: defaultIcon } = this.options;
|
||||
const { style: customStyle, icon: customIcon } = customOptions;
|
||||
const style = deepMix({}, defaultStyle, customStyle, cfg.style);
|
||||
const icon = deepMix({}, defaultIcon, customIcon, cfg.icon);
|
||||
|
||||
const path = this.getPath(cfg);
|
||||
const keyShape = group.addShape('path', {
|
||||
attrs: {
|
||||
path,
|
||||
...diamondStyle
|
||||
...style
|
||||
}
|
||||
});
|
||||
|
||||
@ -79,20 +81,36 @@ Shape.registerNode('diamond', {
|
||||
image.set('capture', false);
|
||||
}
|
||||
|
||||
const { top, left, right, bottom, size,
|
||||
fill: anchorFill, stroke: anchorStroke, lineWidth: borderWidth } = linkPoints;
|
||||
this.drawLinkPoints(cfg, group);
|
||||
|
||||
return keyShape;
|
||||
},
|
||||
/**
|
||||
* 绘制节点上的LinkPoints
|
||||
* @param {Object} cfg data数据配置项
|
||||
* @param {Group} group Group实例
|
||||
*/
|
||||
drawLinkPoints(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { linkPoints: defaultLinkPoints } = this.options;
|
||||
const { linkPoints: customLinkPoints } = customOptions;
|
||||
const linkPoints = deepMix({}, defaultLinkPoints, customLinkPoints, cfg.linkPoints);
|
||||
|
||||
const { top, left, right, bottom, size: markSize,
|
||||
...markStyle } = linkPoints;
|
||||
const size = this.getSize(cfg);
|
||||
const width = size[0];
|
||||
const height = size[1];
|
||||
if (left) {
|
||||
// left circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: -width / 2,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'diamond-anchor-left'
|
||||
className: 'diamond-mark-left'
|
||||
});
|
||||
}
|
||||
|
||||
@ -100,14 +118,12 @@ Shape.registerNode('diamond', {
|
||||
// right circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: width / 2,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'diamond-anchor-right'
|
||||
className: 'diamond-mark-right'
|
||||
});
|
||||
}
|
||||
|
||||
@ -115,14 +131,12 @@ Shape.registerNode('diamond', {
|
||||
// top circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: 0,
|
||||
y: -height / 2,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'diamond-anchor-top'
|
||||
className: 'diamond-mark-top'
|
||||
});
|
||||
}
|
||||
|
||||
@ -130,27 +144,19 @@ Shape.registerNode('diamond', {
|
||||
// bottom circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: 0,
|
||||
y: height / 2,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'diamond-anchor-bottom'
|
||||
className: 'diamond-mark-bottom'
|
||||
});
|
||||
}
|
||||
|
||||
return keyShape;
|
||||
},
|
||||
shouldUpdate() {
|
||||
return false;
|
||||
},
|
||||
getPath(cfg) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { width, height } = style;
|
||||
const size = this.getSize(cfg);
|
||||
const width = size[0];
|
||||
const height = size[1];
|
||||
const path = [
|
||||
[ 'M', 0, -height / 2 ], // 上部顶点
|
||||
[ 'L', width / 2, 0 ], // 右侧点
|
||||
@ -160,35 +166,22 @@ Shape.registerNode('diamond', {
|
||||
];
|
||||
return path;
|
||||
},
|
||||
/**
|
||||
* 获取节点宽高
|
||||
* @internal 返回节点的大小,以 [width, height] 的方式维护
|
||||
* @param {Object} cfg 节点的配置项
|
||||
* @return {Array} 宽高
|
||||
*/
|
||||
getSize(cfg) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { width, height } = style;
|
||||
|
||||
return [ width, height ];
|
||||
},
|
||||
update(cfg, item) {
|
||||
const group = item.getContainer();
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default || {};
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { style: defaultStyle, icon: defaultIcon, labelCfg: defaultLabelCfg } = this.options;
|
||||
const { style: customStyle, icon: customIcon, labelCfg: customLabelCfg } = customOptions;
|
||||
const style = deepMix({}, defaultStyle, customStyle, cfg.style);
|
||||
const icon = deepMix({}, defaultIcon, customIcon, cfg.icon);
|
||||
|
||||
const { width, height, icon, linkPoints, labelCfg: defaultLabelCfg, ...diamondStyle } = style;
|
||||
const keyShape = item.get('keyShape');
|
||||
const path = this.getPath(cfg);
|
||||
keyShape.attr({
|
||||
path,
|
||||
...diamondStyle
|
||||
...style
|
||||
});
|
||||
|
||||
const labelCfg = deepMix({}, defaultLabelCfg, cfg.labelCfg);
|
||||
const labelCfg = deepMix({}, defaultLabelCfg, customLabelCfg, cfg.labelCfg);
|
||||
const labelStyle = this.getLabelStyle(cfg, labelCfg, group);
|
||||
|
||||
const text = group.findByClassName('node-label');
|
||||
@ -208,52 +201,69 @@ Shape.registerNode('diamond', {
|
||||
});
|
||||
}
|
||||
|
||||
const { size, fill: anchorFill, stroke: anchorStroke, lineWidth: borderWidth } = linkPoints;
|
||||
this.updateLinkPoints(cfg, group);
|
||||
},
|
||||
/**
|
||||
* 更新linkPoints
|
||||
* @param {Object} cfg 节点数据配置项
|
||||
* @param {Group} group Item所在的group
|
||||
*/
|
||||
updateLinkPoints(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { linkPoints: defaultLinkPoints } = this.options;
|
||||
const { linkPoints: customLinkPoints } = customOptions;
|
||||
const linkPoints = deepMix({}, defaultLinkPoints, customLinkPoints, cfg.linkPoints);
|
||||
|
||||
const anchorLeft = group.findByClassName('diamond-anchor-left');
|
||||
if (anchorLeft) {
|
||||
anchorLeft.attr({
|
||||
const { size: markSize, fill: markFill, stroke: markStroke, lineWidth: borderWidth } = linkPoints;
|
||||
|
||||
const size = this.getSize(cfg);
|
||||
const width = size[0];
|
||||
const height = size[1];
|
||||
|
||||
const markLeft = group.findByClassName('diamond-mark-left');
|
||||
if (markLeft) {
|
||||
markLeft.attr({
|
||||
x: -width / 2,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
||||
const anchorRight = group.findByClassName('diamond-anchor-right');
|
||||
if (anchorRight) {
|
||||
anchorRight.attr({
|
||||
const markRight = group.findByClassName('diamond-mark-right');
|
||||
if (markRight) {
|
||||
markRight.attr({
|
||||
x: width / 2,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
||||
const anchorTop = group.findByClassName('diamond-anchor-top');
|
||||
if (anchorTop) {
|
||||
anchorTop.attr({
|
||||
const markTop = group.findByClassName('diamond-mark-top');
|
||||
if (markTop) {
|
||||
markTop.attr({
|
||||
x: 0,
|
||||
y: -height / 2,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
||||
const anchorBottom = group.findByClassName('diamond-anchor-bottom');
|
||||
if (anchorBottom) {
|
||||
anchorBottom.attr({
|
||||
const markBottom = group.findByClassName('diamond-mark-bottom');
|
||||
if (markBottom) {
|
||||
markBottom.attr({
|
||||
x: 0,
|
||||
y: height / 2,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
@ -7,68 +7,78 @@ const deepMix = require('@antv/util/lib/deep-mix');
|
||||
Shape.registerNode('ellipse', {
|
||||
// 自定义节点时的配置
|
||||
options: {
|
||||
// 默认配置
|
||||
default: {
|
||||
rx: 60,
|
||||
ry: 30,
|
||||
stroke: '#69c0ff',
|
||||
fill: '#e6f7ff',
|
||||
lineWidth: 1,
|
||||
size: [ 60, 30 ],
|
||||
style: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
// 文本样式配置
|
||||
labelCfg: {
|
||||
style: {
|
||||
fill: '#595959'
|
||||
}
|
||||
},
|
||||
// 节点中icon配置
|
||||
icon: {
|
||||
// 是否显示icon,值为 false 则不渲染icon
|
||||
show: false,
|
||||
// icon的地址,字符串类型
|
||||
img: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg',
|
||||
width: 36,
|
||||
height: 36
|
||||
},
|
||||
// 节点上左右上下四个方向上的链接circle配置
|
||||
linkPoints: {
|
||||
top: false,
|
||||
right: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
// circle的大小
|
||||
size: 3,
|
||||
lineWidth: 1,
|
||||
fill: '#72CC4A',
|
||||
stroke: '#72CC4A'
|
||||
},
|
||||
// 连接点,默认为左右
|
||||
anchorPoints: [[ 0, 0.5 ], [ 1, 0.5 ]]
|
||||
stroke: '#87e8de',
|
||||
fill: '#36cfc9',
|
||||
lineWidth: 1
|
||||
},
|
||||
// 鼠标hover状态下的配置
|
||||
hover: {
|
||||
lineWidth: 3
|
||||
// 文本样式配置
|
||||
labelCfg: {
|
||||
style: {
|
||||
fill: '#595959'
|
||||
}
|
||||
},
|
||||
// 选中节点状态下的配置
|
||||
select: {
|
||||
lineWidth: 5
|
||||
}
|
||||
stateStyles: {
|
||||
// 鼠标hover状态下的配置
|
||||
hover: {
|
||||
lineWidth: 3
|
||||
},
|
||||
// 选中节点状态下的配置
|
||||
select: {
|
||||
lineWidth: 5
|
||||
}
|
||||
},
|
||||
// 节点上左右上下四个方向上的链接circle配置
|
||||
linkPoints: {
|
||||
top: false,
|
||||
right: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
// circle的大小
|
||||
size: 3,
|
||||
lineWidth: 1,
|
||||
fill: '#72CC4A',
|
||||
stroke: '#72CC4A'
|
||||
},
|
||||
// 节点中icon配置
|
||||
icon: {
|
||||
// 是否显示icon,值为 false 则不渲染icon
|
||||
show: false,
|
||||
// icon的地址,字符串类型
|
||||
img: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg',
|
||||
width: 36,
|
||||
height: 36
|
||||
},
|
||||
// 连接点,默认为左右
|
||||
anchorPoints: [[ 0, 0.5 ], [ 1, 0.5 ]]
|
||||
},
|
||||
shapeType: 'ellipse',
|
||||
// 文本位置
|
||||
labelPosition: 'center',
|
||||
drawShape(cfg, group) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
// const customStyle = this.getCustomConfig(cfg) || {};
|
||||
// const defaultConfig = customStyle.default;
|
||||
// const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
|
||||
// 使用用户配置的size大小
|
||||
const { linkPoints, icon, ...ellipseStyle } = style;
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { style: defaultStyle, icon: defaultIcon } = this.options;
|
||||
const { style: customStyle, icon: customIcon } = customOptions;
|
||||
const style = deepMix({}, defaultStyle, customStyle, cfg.style);
|
||||
const icon = deepMix({}, defaultIcon, customIcon, cfg.icon);
|
||||
const size = this.getSize(cfg);
|
||||
|
||||
const rx = size[0];
|
||||
const ry = size[1];
|
||||
|
||||
const { rx, ry } = ellipseStyle;
|
||||
const keyShape = group.addShape('ellipse', {
|
||||
attrs: ellipseStyle
|
||||
attrs: {
|
||||
...style,
|
||||
rx,
|
||||
ry
|
||||
}
|
||||
});
|
||||
|
||||
const { width, height, show } = icon;
|
||||
@ -85,20 +95,37 @@ Shape.registerNode('ellipse', {
|
||||
image.set('capture', false);
|
||||
}
|
||||
|
||||
const { top, left, right, bottom, size,
|
||||
fill: anchorFill, stroke: anchorStroke, lineWidth: borderWidth } = linkPoints;
|
||||
this.drawLinkPoints(cfg, group);
|
||||
|
||||
return keyShape;
|
||||
},
|
||||
/**
|
||||
* 绘制节点上的LinkPoints
|
||||
* @param {Object} cfg data数据配置项
|
||||
* @param {Group} group Group实例
|
||||
*/
|
||||
drawLinkPoints(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { linkPoints: defaultLinkPoints } = this.options;
|
||||
const { linkPoints: customLinkPoints } = customOptions;
|
||||
const linkPoints = deepMix({}, defaultLinkPoints, customLinkPoints, cfg.linkPoints);
|
||||
|
||||
const { top, left, right, bottom, size: markSize,
|
||||
...markStyle } = linkPoints;
|
||||
const size = this.getSize(cfg);
|
||||
const rx = size[0];
|
||||
const ry = size[1];
|
||||
|
||||
if (left) {
|
||||
// left circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: -rx,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'ellipse-anchor-left'
|
||||
className: 'ellipse-mark-left'
|
||||
});
|
||||
}
|
||||
|
||||
@ -106,14 +133,12 @@ Shape.registerNode('ellipse', {
|
||||
// right circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: rx,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'ellipse-anchor-right'
|
||||
className: 'ellipse-mark-right'
|
||||
});
|
||||
}
|
||||
|
||||
@ -121,14 +146,12 @@ Shape.registerNode('ellipse', {
|
||||
// top circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: 0,
|
||||
y: -ry,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'ellipse-anchor-top'
|
||||
className: 'ellipse-mark-top'
|
||||
});
|
||||
}
|
||||
|
||||
@ -136,47 +159,44 @@ Shape.registerNode('ellipse', {
|
||||
// bottom circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: 0,
|
||||
y: ry,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'ellipse-anchor-bottom'
|
||||
className: 'ellipse-mark-bottom'
|
||||
});
|
||||
}
|
||||
|
||||
return keyShape;
|
||||
},
|
||||
/**
|
||||
* 获取节点宽高
|
||||
* @internal 返回节点的大小,以 [width, height] 的方式维护
|
||||
* @param {Object} cfg 节点的配置项
|
||||
* @return {Array} 宽高
|
||||
*/
|
||||
getSize(cfg) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { rx, ry } = style;
|
||||
|
||||
return [ 2 * rx, 2 * ry ];
|
||||
},
|
||||
update(cfg, item) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default || {};
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { icon, linkPoints, labelCfg: defaultLabelCfg, ...ellipseStyle } = style;
|
||||
// const customStyle = this.getCustomConfig(cfg) || {};
|
||||
// const defaultConfig = customStyle.default || {};
|
||||
// const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
// const { icon, linkPoints, labelCfg: defaultLabelCfg, ...ellipseStyle } = style;
|
||||
|
||||
// const { rx, ry } = ellipseStyle;
|
||||
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { style: defaultStyle, icon: defaultIcon, labelCfg: defaultLabelCfg } = this.options;
|
||||
const { style: customStyle, icon: customIcon, labelCfg: customLabelCfg } = customOptions;
|
||||
const style = deepMix({}, defaultStyle, customStyle, cfg.style);
|
||||
const icon = deepMix({}, defaultIcon, customIcon, cfg.icon);
|
||||
const size = this.getSize(cfg);
|
||||
|
||||
const rx = size[0];
|
||||
const ry = size[1];
|
||||
|
||||
const { rx, ry } = ellipseStyle;
|
||||
const keyShape = item.get('keyShape');
|
||||
|
||||
keyShape.attr(ellipseStyle);
|
||||
keyShape.attr({
|
||||
...style,
|
||||
rx,
|
||||
ry
|
||||
});
|
||||
|
||||
const group = item.getContainer();
|
||||
|
||||
const labelCfg = deepMix({}, defaultLabelCfg, cfg.labelCfg);
|
||||
const labelCfg = deepMix({}, defaultLabelCfg, customLabelCfg, cfg.labelCfg);
|
||||
const labelStyle = this.getLabelStyle(cfg, labelCfg, group);
|
||||
const text = group.findByClassName('node-label');
|
||||
if (text) {
|
||||
@ -195,53 +215,62 @@ Shape.registerNode('ellipse', {
|
||||
});
|
||||
}
|
||||
|
||||
const { size, fill: anchorFill, stroke: anchorStroke, lineWidth: borderWidth } = linkPoints;
|
||||
this.updateLinkPoints(cfg, group);
|
||||
},
|
||||
/**
|
||||
* 更新linkPoints
|
||||
* @param {Object} cfg 节点数据配置项
|
||||
* @param {Group} group Item所在的group
|
||||
*/
|
||||
updateLinkPoints(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { linkPoints: defaultLinkPoints } = this.options;
|
||||
const { linkPoints: customLinkPoints } = customOptions;
|
||||
const linkPoints = deepMix({}, defaultLinkPoints, customLinkPoints, cfg.linkPoints);
|
||||
|
||||
const anchorLeft = group.findByClassName('ellipse-anchor-left');
|
||||
if (anchorLeft) {
|
||||
anchorLeft.attr({
|
||||
const { size: markSize, ...markStyles } = linkPoints;
|
||||
|
||||
const size = this.getSize(cfg);
|
||||
const rx = size[0];
|
||||
const ry = size[1];
|
||||
|
||||
const markLeft = group.findByClassName('ellipse-mark-left');
|
||||
if (markLeft) {
|
||||
markLeft.attr({
|
||||
...markStyles,
|
||||
x: -rx,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
});
|
||||
}
|
||||
|
||||
const anchorRight = group.findByClassName('ellipse-anchor-right');
|
||||
if (anchorRight) {
|
||||
anchorRight.attr({
|
||||
const markRight = group.findByClassName('ellipse-mark-right');
|
||||
if (markRight) {
|
||||
markRight.attr({
|
||||
...markStyles,
|
||||
x: rx,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
});
|
||||
}
|
||||
|
||||
const anchorTop = group.findByClassName('ellipse-anchor-top');
|
||||
if (anchorTop) {
|
||||
anchorTop.attr({
|
||||
const markTop = group.findByClassName('ellipse-mark-top');
|
||||
if (markTop) {
|
||||
markTop.attr({
|
||||
...markStyles,
|
||||
x: 0,
|
||||
y: -ry,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
});
|
||||
}
|
||||
|
||||
const anchorBottom = group.findByClassName('ellipse-anchor-bottom');
|
||||
if (anchorBottom) {
|
||||
anchorBottom.attr({
|
||||
const markBottom = group.findByClassName('ellipse-mark-bottom');
|
||||
if (markBottom) {
|
||||
markBottom.attr({
|
||||
...markStyles,
|
||||
x: 0,
|
||||
y: ry,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -6,95 +6,98 @@ Shape.registerNode('modelRect', {
|
||||
// labelPosition: 'center',
|
||||
// 自定义节点时的配置
|
||||
options: {
|
||||
// 默认配置
|
||||
default: {
|
||||
width: 185,
|
||||
height: 70,
|
||||
size: [ 185, 70 ],
|
||||
style: {
|
||||
radius: 5,
|
||||
stroke: '#69c0ff',
|
||||
fill: '#ffffff',
|
||||
lineWidth: 1,
|
||||
fillOpacity: 1,
|
||||
// 文本样式配置
|
||||
labelCfg: {
|
||||
style: {
|
||||
fill: '#595959',
|
||||
fontSize: 14
|
||||
},
|
||||
offset: 30
|
||||
},
|
||||
preRect: {
|
||||
show: true,
|
||||
width: 4,
|
||||
fill: '#40a9ff',
|
||||
radius: 2
|
||||
},
|
||||
// 节点上左右上下四个方向上的链接circle配置
|
||||
linkPoints: {
|
||||
top: false,
|
||||
right: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
// circle的大小
|
||||
size: 3,
|
||||
lineWidth: 1,
|
||||
fill: '#72CC4A',
|
||||
stroke: '#72CC4A'
|
||||
},
|
||||
|
||||
// 节点中icon配置
|
||||
logoIcon: {
|
||||
// 是否显示icon,值为 false 则不渲染icon
|
||||
show: true,
|
||||
x: 0,
|
||||
y: 0,
|
||||
// icon的地址,字符串类型
|
||||
img: 'https://gw.alipayobjects.com/zos/basement_prod/4f81893c-1806-4de4-aff3-9a6b266bc8a2.svg',
|
||||
width: 16,
|
||||
height: 16
|
||||
},
|
||||
// 节点中表示状态的icon配置
|
||||
stateIcon: {
|
||||
// 是否显示icon,值为 false 则不渲染icon
|
||||
show: true,
|
||||
// icon的地址,字符串类型
|
||||
img: 'https://gw.alipayobjects.com/zos/basement_prod/300a2523-67e0-4cbf-9d4a-67c077b40395.svg',
|
||||
width: 16,
|
||||
height: 16
|
||||
},
|
||||
// 连接点,默认为左右
|
||||
anchorPoints: [[ 0, 0.5 ], [ 1, 0.5 ]]
|
||||
fillOpacity: 1
|
||||
},
|
||||
// hover状态下的配置
|
||||
hover: {
|
||||
lineWidth: 2,
|
||||
stroke: '#1890ff',
|
||||
fill: '#e6f7ff'
|
||||
// 文本样式配置
|
||||
labelCfg: {
|
||||
style: {
|
||||
fill: '#595959',
|
||||
fontSize: 14
|
||||
},
|
||||
offset: 30
|
||||
},
|
||||
// 节点选中状态下的配置
|
||||
select: {
|
||||
lineWidth: 3,
|
||||
stroke: '#1890ff',
|
||||
fill: '#e6f7ff'
|
||||
}
|
||||
stateStyles: {
|
||||
// hover状态下的配置
|
||||
hover: {
|
||||
lineWidth: 2,
|
||||
stroke: '#1890ff',
|
||||
fill: '#e6f7ff'
|
||||
},
|
||||
// 节点选中状态下的配置
|
||||
select: {
|
||||
lineWidth: 3,
|
||||
stroke: '#1890ff',
|
||||
fill: '#e6f7ff'
|
||||
}
|
||||
},
|
||||
preRect: {
|
||||
show: true,
|
||||
width: 4,
|
||||
fill: '#40a9ff',
|
||||
radius: 2
|
||||
},
|
||||
// 节点上左右上下四个方向上的链接circle配置
|
||||
linkPoints: {
|
||||
top: false,
|
||||
right: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
// circle的大小
|
||||
size: 3,
|
||||
lineWidth: 1,
|
||||
fill: '#72CC4A',
|
||||
stroke: '#72CC4A'
|
||||
},
|
||||
// 节点中icon配置
|
||||
logoIcon: {
|
||||
// 是否显示icon,值为 false 则不渲染icon
|
||||
show: true,
|
||||
x: 0,
|
||||
y: 0,
|
||||
// icon的地址,字符串类型
|
||||
img: 'https://gw.alipayobjects.com/zos/basement_prod/4f81893c-1806-4de4-aff3-9a6b266bc8a2.svg',
|
||||
width: 16,
|
||||
height: 16
|
||||
},
|
||||
// 节点中表示状态的icon配置
|
||||
stateIcon: {
|
||||
// 是否显示icon,值为 false 则不渲染icon
|
||||
show: true,
|
||||
// icon的地址,字符串类型
|
||||
img: 'https://gw.alipayobjects.com/zos/basement_prod/300a2523-67e0-4cbf-9d4a-67c077b40395.svg',
|
||||
width: 16,
|
||||
height: 16
|
||||
},
|
||||
// 连接点,默认为左右
|
||||
anchorPoints: [[ 0, 0.5 ], [ 1, 0.5 ]]
|
||||
},
|
||||
shapeType: 'modelRect',
|
||||
drawShape(cfg, group) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { width, height, linkPoints, preRect,
|
||||
logoIcon, stateIcon, ...rectStyle } = style;
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { style: defaultStyle, preRect: defaultPreRect } = this.options;
|
||||
const { style: customStyle, preRect: customPreRect } = customOptions;
|
||||
const style = deepMix({}, defaultStyle, customStyle, cfg.style);
|
||||
const size = this.getSize(cfg);
|
||||
const width = size[0];
|
||||
const height = size[1];
|
||||
|
||||
const keyShape = group.addShape('rect', {
|
||||
attrs: {
|
||||
...style,
|
||||
x: -width / 2,
|
||||
y: -height / 2,
|
||||
width,
|
||||
height,
|
||||
...rectStyle
|
||||
height
|
||||
}
|
||||
});
|
||||
|
||||
const preRect = deepMix({}, defaultPreRect, customPreRect, cfg.preRect);
|
||||
const { show: preRectShow, ...preRectStyle } = preRect;
|
||||
if (preRectShow) {
|
||||
group.addShape('rect', {
|
||||
@ -108,6 +111,26 @@ Shape.registerNode('modelRect', {
|
||||
});
|
||||
}
|
||||
|
||||
this.drawLogoIcon(cfg, group);
|
||||
|
||||
this.drawStateIcon(cfg, group);
|
||||
|
||||
this.drawLinkPoints(cfg, group);
|
||||
return keyShape;
|
||||
},
|
||||
/**
|
||||
* 绘制模型矩形左边的logo图标
|
||||
* @param {Object} cfg 数据配置项
|
||||
* @param {Group} group Group实例
|
||||
*/
|
||||
drawLogoIcon(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { logoIcon: defaultLogoIcon } = this.options;
|
||||
const { logoIcon: customLogoIcon } = customOptions;
|
||||
const logoIcon = deepMix({}, defaultLogoIcon, customLogoIcon, cfg.logoIcon);
|
||||
const size = this.getSize(cfg);
|
||||
const width = size[0];
|
||||
|
||||
if (logoIcon.show) {
|
||||
const { width: w, height: h, x, y, ...logoIconStyle } = logoIcon;
|
||||
const image = group.addShape('image', {
|
||||
@ -115,14 +138,25 @@ Shape.registerNode('modelRect', {
|
||||
...logoIconStyle,
|
||||
x: x || -width / 2 + w,
|
||||
y: y || -h / 2
|
||||
// width: w,
|
||||
// height: h
|
||||
},
|
||||
className: 'rect-logo-icon'
|
||||
});
|
||||
|
||||
image.set('capture', false);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 绘制模型矩形右边的状态图标
|
||||
* @param {Object} cfg 数据配置项
|
||||
* @param {Group} group Group实例
|
||||
*/
|
||||
drawStateIcon(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { stateIcon: defaultStateIcon } = this.options;
|
||||
const { stateIcon: customStateIcon } = customOptions;
|
||||
const stateIcon = deepMix({}, defaultStateIcon, customStateIcon, cfg.stateIcon);
|
||||
const size = this.getSize(cfg);
|
||||
const width = size[0];
|
||||
|
||||
if (stateIcon.show) {
|
||||
const { width: w, height: h, x, y } = stateIcon;
|
||||
@ -137,21 +171,34 @@ Shape.registerNode('modelRect', {
|
||||
|
||||
image.set('capture', false);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 绘制节点上的LinkPoints
|
||||
* @param {Object} cfg data数据配置项
|
||||
* @param {Group} group Group实例
|
||||
*/
|
||||
drawLinkPoints(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { linkPoints: defaultLinkPoints } = this.options;
|
||||
const { linkPoints: customLinkPoints } = customOptions;
|
||||
const linkPoints = deepMix({}, defaultLinkPoints, customLinkPoints, cfg.linkPoints);
|
||||
|
||||
const { top, left, right, bottom, size: markSize,
|
||||
...markStyle } = linkPoints;
|
||||
const size = this.getSize(cfg);
|
||||
const width = size[0];
|
||||
const height = size[1];
|
||||
|
||||
const { top, left, right, bottom, size,
|
||||
fill: anchorFill, stroke: anchorStroke, lineWidth: borderWidth } = linkPoints;
|
||||
if (left) {
|
||||
// left circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: -width / 2,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'rect-anchor-left'
|
||||
className: 'rect-mark-left'
|
||||
});
|
||||
}
|
||||
|
||||
@ -159,14 +206,12 @@ Shape.registerNode('modelRect', {
|
||||
// right circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: width / 2,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'rect-anchor-right'
|
||||
className: 'rect-mark-right'
|
||||
});
|
||||
}
|
||||
|
||||
@ -174,14 +219,12 @@ Shape.registerNode('modelRect', {
|
||||
// top circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: 0,
|
||||
y: -height / 2,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'rect-anchor-top'
|
||||
className: 'rect-mark-top'
|
||||
});
|
||||
}
|
||||
|
||||
@ -189,26 +232,29 @@ Shape.registerNode('modelRect', {
|
||||
// bottom circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: 0,
|
||||
y: height / 2,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'rect-anchor-bottom'
|
||||
className: 'rect-mark-bottom'
|
||||
});
|
||||
}
|
||||
return keyShape;
|
||||
},
|
||||
drawLabel(cfg, group) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default || {};
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const labelCfg = deepMix({}, style.labelCfg, cfg.labelCfg);
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { labelCfg: defaultLabelCfg, logoIcon: defaultLogoIcon } = this.options;
|
||||
const { labelCfg: customLabelCfg, logoIcon: customLogoIcon } = customOptions;
|
||||
|
||||
const logoIcon = deepMix({}, defaultLogoIcon, customLogoIcon, cfg.logoIcon);
|
||||
|
||||
const labelCfg = deepMix({}, defaultLabelCfg, customLabelCfg, cfg.labelCfg);
|
||||
|
||||
const size = this.getSize(cfg);
|
||||
const width = size[0];
|
||||
|
||||
let label = null;
|
||||
|
||||
const { logoIcon, width } = style;
|
||||
const { show, width: w } = logoIcon;
|
||||
let offsetX = -width / 2 + labelCfg.offset;
|
||||
|
||||
@ -223,13 +269,13 @@ Shape.registerNode('modelRect', {
|
||||
...fontStyle,
|
||||
y: -5,
|
||||
x: offsetX,
|
||||
text: Util.fittingString(cfg.label, 70, 14)
|
||||
text: Util.fittingString(cfg.label, 100, 14)
|
||||
}
|
||||
});
|
||||
|
||||
group.addShape('text', {
|
||||
attrs: {
|
||||
text: Util.fittingString(cfg.description, 80, 12),
|
||||
text: Util.fittingString(cfg.description, 75, 12),
|
||||
fontSize: 12,
|
||||
x: offsetX,
|
||||
y: 17,
|
||||
@ -249,40 +295,39 @@ Shape.registerNode('modelRect', {
|
||||
}
|
||||
return label;
|
||||
},
|
||||
getAnchorPoints() {
|
||||
const defaultOptions = this.options;
|
||||
return defaultOptions.anchorPoints;
|
||||
},
|
||||
getSize(cfg) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { width, height } = style;
|
||||
|
||||
return [ width, height ];
|
||||
getAnchorPoints(cfg) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { anchorPoints: defaultAnchorPoints } = this.options;
|
||||
const { anchorPoints: customAnchorPoints } = customOptions;
|
||||
const anchorPoints = deepMix({}, defaultAnchorPoints, customAnchorPoints);
|
||||
return anchorPoints;
|
||||
},
|
||||
update(cfg, item) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { width, height, linkPoints, logoIcon, stateIcon,
|
||||
labelCfg: defaultLabelCfg, ...rectStyle } = style;
|
||||
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { style: defaultStyle, labelCfg: defaultLabelCfg, preRect: defaultPreRect,
|
||||
logoIcon: defaultLogoIcon, stateIcon: defaultStateIcon } = this.options;
|
||||
const { style: customStyle, labelCfg: customLabelCfg, preRect: customPreRect,
|
||||
logoIcon: customLogoIcon, stateIcon: customStateIcon } = customOptions;
|
||||
const style = deepMix({}, defaultStyle, customStyle, cfg.style);
|
||||
const size = this.getSize(cfg);
|
||||
const width = size[0];
|
||||
const height = size[1];
|
||||
const keyShape = item.get('keyShape');
|
||||
keyShape.attr({
|
||||
...style,
|
||||
x: -width / 2,
|
||||
y: -height / 2,
|
||||
width,
|
||||
height,
|
||||
...rectStyle
|
||||
height
|
||||
});
|
||||
|
||||
const group = item.getContainer();
|
||||
|
||||
const labelCfg = deepMix({}, defaultLabelCfg, cfg.labelCfg);
|
||||
// const labelStyle = this.getLabelStyle(cfg, labelCfg, group);
|
||||
const labelCfg = deepMix({}, defaultLabelCfg, customLabelCfg, cfg.labelCfg);
|
||||
const text = group.findByClassName('node-label');
|
||||
|
||||
const logoIcon = deepMix({}, defaultLogoIcon, customLogoIcon, cfg.logoIcon);
|
||||
|
||||
const { show, width: w } = logoIcon;
|
||||
|
||||
const { offset, style: fontStyle } = labelCfg;
|
||||
@ -318,7 +363,9 @@ Shape.registerNode('modelRect', {
|
||||
|
||||
const preRectShape = group.findByClassName('pre-rect');
|
||||
if (preRectShape) {
|
||||
const preRect = deepMix({}, defaultPreRect, customPreRect, cfg.preRect);
|
||||
preRectShape.attr({
|
||||
...preRect,
|
||||
x: -width / 2,
|
||||
y: -height / 2,
|
||||
height
|
||||
@ -327,8 +374,9 @@ Shape.registerNode('modelRect', {
|
||||
|
||||
const logoIconShape = group.findByClassName('rect-logo-icon');
|
||||
if (logoIconShape) {
|
||||
const { width: w, height: h, x, y } = logoIcon;
|
||||
const { width: w, height: h, x, y, ...logoIconStyle } = logoIcon;
|
||||
logoIconShape.attr({
|
||||
...logoIconStyle,
|
||||
x: x || -width / 2 + w,
|
||||
y: y || -h / 2,
|
||||
width: w,
|
||||
@ -338,8 +386,10 @@ Shape.registerNode('modelRect', {
|
||||
|
||||
const stateIconShape = group.findByClassName('rect-state-icon');
|
||||
if (stateIconShape) {
|
||||
const { width: w, height: h, x, y } = stateIcon;
|
||||
const stateIcon = deepMix({}, defaultStateIcon, customStateIcon, cfg.stateIcon);
|
||||
const { width: w, height: h, x, y, ...stateIconStyle } = stateIcon;
|
||||
stateIconShape.attr({
|
||||
...stateIconStyle,
|
||||
x: x || width / 2 - w * 2 + 8,
|
||||
y: y || -h / 2,
|
||||
width: w,
|
||||
@ -347,52 +397,69 @@ Shape.registerNode('modelRect', {
|
||||
});
|
||||
}
|
||||
|
||||
const { size, fill: anchorFill, stroke: anchorStroke, lineWidth: borderWidth } = linkPoints;
|
||||
this.updateLinkPoints(cfg, group);
|
||||
},
|
||||
/**
|
||||
* 更新linkPoints
|
||||
* @param {Object} cfg 节点数据配置项
|
||||
* @param {Group} group Item所在的group
|
||||
*/
|
||||
updateLinkPoints(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { linkPoints: defaultLinkPoints } = this.options;
|
||||
const { linkPoints: customLinkPoints } = customOptions;
|
||||
const linkPoints = deepMix({}, defaultLinkPoints, customLinkPoints, cfg.linkPoints);
|
||||
|
||||
const anchorLeft = group.findByClassName('rect-anchor-left');
|
||||
if (anchorLeft) {
|
||||
anchorLeft.attr({
|
||||
const { size: markSize, fill: markFill, stroke: markStroke, lineWidth: borderWidth } = linkPoints;
|
||||
|
||||
const size = this.getSize(cfg);
|
||||
const width = size[0];
|
||||
const height = size[1];
|
||||
|
||||
const markLeft = group.findByClassName('rect-mark-left');
|
||||
if (markLeft) {
|
||||
markLeft.attr({
|
||||
x: -width / 2,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
||||
const anchorRight = group.findByClassName('rect-anchor-right');
|
||||
if (anchorRight) {
|
||||
anchorRight.attr({
|
||||
const markRight = group.findByClassName('rect-mark-right');
|
||||
if (markRight) {
|
||||
markRight.attr({
|
||||
x: width / 2,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
||||
const anchorTop = group.findByClassName('rect-anchor-top');
|
||||
if (anchorTop) {
|
||||
anchorTop.attr({
|
||||
const markTop = group.findByClassName('rect-mark-top');
|
||||
if (markTop) {
|
||||
markTop.attr({
|
||||
x: 0,
|
||||
y: -height / 2,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
||||
const anchorBottom = group.findByClassName('rect-anchor-bottom');
|
||||
if (anchorBottom) {
|
||||
anchorBottom.attr({
|
||||
const markBottom = group.findByClassName('rect-mark-bottom');
|
||||
if (markBottom) {
|
||||
markBottom.attr({
|
||||
x: 0,
|
||||
y: height / 2,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
@ -4,81 +4,100 @@ const deepMix = require('@antv/util/lib/deep-mix');
|
||||
Shape.registerNode('rect', {
|
||||
// 自定义节点时的配置
|
||||
options: {
|
||||
// 默认配置
|
||||
default: {
|
||||
width: 100,
|
||||
height: 30,
|
||||
size: [ 100, 30 ],
|
||||
style: {
|
||||
radius: 0,
|
||||
stroke: '#69c0ff',
|
||||
fill: '#e6f7ff',
|
||||
stroke: '#87e8de',
|
||||
fill: '#36cfc9',
|
||||
lineWidth: 1,
|
||||
fillOpacity: 1,
|
||||
// 文本样式配置
|
||||
labelCfg: {
|
||||
style: {
|
||||
fill: '#595959',
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
// 节点上左右上下四个方向上的链接circle配置
|
||||
linkPoints: {
|
||||
top: false,
|
||||
right: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
// circle的大小
|
||||
size: 3,
|
||||
lineWidth: 1,
|
||||
fill: '#72CC4A',
|
||||
stroke: '#72CC4A'
|
||||
},
|
||||
// 连接点,默认为左右
|
||||
anchorPoints: [[ 0, 0.5 ], [ 1, 0.5 ]]
|
||||
fillOpacity: 1
|
||||
},
|
||||
// hover状态下的配置
|
||||
hover: {
|
||||
lineWidth: 2,
|
||||
stroke: '#1890ff'
|
||||
// 文本样式配置
|
||||
labelCfg: {
|
||||
style: {
|
||||
fill: '#595959',
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
// 节点选中状态下的配置
|
||||
select: {
|
||||
lineWidth: 3,
|
||||
stroke: '#1890ff',
|
||||
fill: '#91d5ff'
|
||||
}
|
||||
stateStyles: {
|
||||
// hover状态下的配置
|
||||
hover: {
|
||||
lineWidth: 2,
|
||||
stroke: '#1890ff'
|
||||
},
|
||||
// 节点选中状态下的配置
|
||||
select: {
|
||||
lineWidth: 3,
|
||||
stroke: '#1890ff',
|
||||
fill: '#91d5ff'
|
||||
}
|
||||
},
|
||||
// 节点上左右上下四个方向上的链接circle配置
|
||||
linkPoints: {
|
||||
top: false,
|
||||
right: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
// circle的大小
|
||||
size: 3,
|
||||
lineWidth: 1,
|
||||
fill: '#72CC4A',
|
||||
stroke: '#72CC4A'
|
||||
},
|
||||
// 连接点,默认为左右
|
||||
markPoints: [[ 0, 0.5 ], [ 1, 0.5 ]]
|
||||
},
|
||||
shapeType: 'rect',
|
||||
drawShape(cfg, group) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { width, height, linkPoints, ...rectStyle } = style;
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { style: defaultStyle } = this.options;
|
||||
const { style: customStyle } = customOptions;
|
||||
const style = deepMix({}, defaultStyle, customStyle, cfg.style);
|
||||
const size = this.getSize(cfg);
|
||||
const width = size[0];
|
||||
const height = size[1];
|
||||
|
||||
const keyShape = group.addShape('rect', {
|
||||
attrs: {
|
||||
...style,
|
||||
x: -width / 2,
|
||||
y: -height / 2,
|
||||
width,
|
||||
height,
|
||||
...rectStyle
|
||||
height
|
||||
},
|
||||
className: 'rect-keyShape'
|
||||
});
|
||||
|
||||
const { top, left, right, bottom, size,
|
||||
fill: anchorFill, stroke: anchorStroke, lineWidth: borderWidth } = linkPoints;
|
||||
this.drawLinkPoints(cfg, group);
|
||||
return keyShape;
|
||||
},
|
||||
/**
|
||||
* 绘制节点上的LinkPoints
|
||||
* @param {Object} cfg data数据配置项
|
||||
* @param {Group} group Group实例
|
||||
*/
|
||||
drawLinkPoints(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { linkPoints: defaultLinkPoints } = this.options;
|
||||
const { linkPoints: customLinkPoints } = customOptions;
|
||||
const linkPoints = deepMix({}, defaultLinkPoints, customLinkPoints, cfg.linkPoints);
|
||||
|
||||
const { top, left, right, bottom, size: markSize,
|
||||
...markStyle } = linkPoints;
|
||||
const size = this.getSize(cfg);
|
||||
const width = size[0];
|
||||
const height = size[1];
|
||||
|
||||
if (left) {
|
||||
// left circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: -width / 2,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'rect-anchor-left'
|
||||
className: 'rect-mark-left'
|
||||
});
|
||||
}
|
||||
|
||||
@ -86,14 +105,12 @@ Shape.registerNode('rect', {
|
||||
// right circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: width / 2,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'rect-anchor-right'
|
||||
className: 'rect-mark-right'
|
||||
});
|
||||
}
|
||||
|
||||
@ -101,14 +118,12 @@ Shape.registerNode('rect', {
|
||||
// top circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: 0,
|
||||
y: -height / 2,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'rect-anchor-top'
|
||||
className: 'rect-mark-top'
|
||||
});
|
||||
}
|
||||
|
||||
@ -116,35 +131,30 @@ Shape.registerNode('rect', {
|
||||
// bottom circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: 0,
|
||||
y: height / 2,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'rect-anchor-bottom'
|
||||
className: 'rect-mark-bottom'
|
||||
});
|
||||
}
|
||||
return keyShape;
|
||||
},
|
||||
getAnchorPoints() {
|
||||
const defaultOptions = this.options;
|
||||
return defaultOptions.anchorPoints;
|
||||
},
|
||||
getSize(cfg) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { width, height } = style;
|
||||
|
||||
return [ width, height ];
|
||||
getAnchorPoints(cfg) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { anchorPoints: defaultAnchorPoints } = this.options;
|
||||
const { anchorPoints: customAnchorPoints } = customOptions;
|
||||
const anchorPoints = deepMix({}, defaultAnchorPoints, customAnchorPoints);
|
||||
return anchorPoints;
|
||||
},
|
||||
update(cfg, item) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { width, height, linkPoints, labelCfg: defaultLabelCfg, ...rectStyle } = style;
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { style: defaultStyle, labelCfg: defaultLabelCfg } = this.options;
|
||||
const { style: customStyle, labelCfg: customLabelCfg } = customOptions;
|
||||
const style = deepMix({}, defaultStyle, customStyle, cfg.style);
|
||||
const size = this.getSize(cfg);
|
||||
const width = size[0];
|
||||
const height = size[1];
|
||||
|
||||
const keyShape = item.get('keyShape');
|
||||
keyShape.attr({
|
||||
@ -152,12 +162,12 @@ Shape.registerNode('rect', {
|
||||
y: -height / 2,
|
||||
width,
|
||||
height,
|
||||
...rectStyle
|
||||
...style
|
||||
});
|
||||
|
||||
const group = item.getContainer();
|
||||
|
||||
const labelCfg = deepMix({}, defaultLabelCfg, cfg.labelCfg);
|
||||
const labelCfg = deepMix({}, defaultLabelCfg, customLabelCfg, cfg.labelCfg);
|
||||
const labelStyle = this.getLabelStyle(cfg, labelCfg, group);
|
||||
const text = group.findByClassName('node-label');
|
||||
if (text) {
|
||||
@ -165,53 +175,69 @@ Shape.registerNode('rect', {
|
||||
...labelStyle
|
||||
});
|
||||
}
|
||||
this.updateLinkPoints(cfg, group);
|
||||
},
|
||||
/**
|
||||
* 更新linkPoints
|
||||
* @param {Object} cfg 节点数据配置项
|
||||
* @param {Group} group Item所在的group
|
||||
*/
|
||||
updateLinkPoints(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { linkPoints: defaultLinkPoints } = this.options;
|
||||
const { linkPoints: customLinkPoints } = customOptions;
|
||||
const linkPoints = deepMix({}, defaultLinkPoints, customLinkPoints, cfg.linkPoints);
|
||||
|
||||
const { size, fill: anchorFill, stroke: anchorStroke, lineWidth: borderWidth } = linkPoints;
|
||||
const { size: markSize, fill: markFill, stroke: markStroke, lineWidth: borderWidth } = linkPoints;
|
||||
|
||||
const anchorLeft = group.findByClassName('rect-anchor-left');
|
||||
if (anchorLeft) {
|
||||
anchorLeft.attr({
|
||||
const size = this.getSize(cfg);
|
||||
const width = size[0];
|
||||
const height = size[1];
|
||||
|
||||
const markLeft = group.findByClassName('rect-mark-left');
|
||||
if (markLeft) {
|
||||
markLeft.attr({
|
||||
x: -width / 2,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
||||
const anchorRight = group.findByClassName('rect-anchor-right');
|
||||
if (anchorRight) {
|
||||
anchorRight.attr({
|
||||
const markRight = group.findByClassName('rect-mark-right');
|
||||
if (markRight) {
|
||||
markRight.attr({
|
||||
x: width / 2,
|
||||
y: 0,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
||||
const anchorTop = group.findByClassName('rect-anchor-top');
|
||||
if (anchorTop) {
|
||||
anchorTop.attr({
|
||||
const markTop = group.findByClassName('rect-mark-top');
|
||||
if (markTop) {
|
||||
markTop.attr({
|
||||
x: 0,
|
||||
y: -height / 2,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
||||
const anchorBottom = group.findByClassName('rect-anchor-bottom');
|
||||
if (anchorBottom) {
|
||||
anchorBottom.attr({
|
||||
const markBottom = group.findByClassName('rect-mark-bottom');
|
||||
if (markBottom) {
|
||||
markBottom.attr({
|
||||
x: 0,
|
||||
y: height / 2,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
r: markSize,
|
||||
fill: markFill,
|
||||
stroke: markStroke,
|
||||
lineWidth: borderWidth
|
||||
});
|
||||
}
|
||||
|
@ -1,69 +1,71 @@
|
||||
const Shape = require('../shape');
|
||||
const deepMix = require('@antv/util/lib/deep-mix');
|
||||
|
||||
// 菱形shape
|
||||
// 五角星shape
|
||||
Shape.registerNode('star', {
|
||||
// 自定义节点时的配置
|
||||
options: {
|
||||
// 默认配置
|
||||
default: {
|
||||
outerR: 60,
|
||||
innerR: 20,
|
||||
stroke: '#69c0ff',
|
||||
fill: '#e6f7ff',
|
||||
lineWidth: 1,
|
||||
// 文本样式配置
|
||||
labelCfg: {
|
||||
style: {
|
||||
fill: '#595959'
|
||||
},
|
||||
offset: 0
|
||||
size: [ 20, 60 ],
|
||||
style: {
|
||||
stroke: '#87e8de',
|
||||
fill: '#36cfc9',
|
||||
lineWidth: 1
|
||||
},
|
||||
// 文本样式配置
|
||||
labelCfg: {
|
||||
style: {
|
||||
fill: '#595959'
|
||||
},
|
||||
// 节点上左右上下四个方向上的链接circle配置
|
||||
linkPoints: {
|
||||
top: false,
|
||||
right: false,
|
||||
left: false,
|
||||
leftBottom: false,
|
||||
rightBottom: false,
|
||||
// circle的大小
|
||||
size: 3,
|
||||
lineWidth: 1,
|
||||
fill: '#fff',
|
||||
stroke: '#72CC4A'
|
||||
offset: 0
|
||||
},
|
||||
stateStyles: {
|
||||
// 鼠标hover状态下的配置
|
||||
hover: {
|
||||
lineWidth: 3
|
||||
},
|
||||
// 节点中icon配置
|
||||
icon: {
|
||||
// 是否显示icon,值为 false 则不渲染icon
|
||||
show: false,
|
||||
// icon的地址,字符串类型
|
||||
img: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg',
|
||||
width: 16,
|
||||
height: 16
|
||||
// 选中节点状态下的配置
|
||||
select: {
|
||||
lineWidth: 5
|
||||
}
|
||||
},
|
||||
// 鼠标hover状态下的配置
|
||||
hover: {
|
||||
lineWidth: 3
|
||||
// 节点上左右上下四个方向上的链接circle配置
|
||||
linkPoints: {
|
||||
top: false,
|
||||
right: false,
|
||||
left: false,
|
||||
leftBottom: false,
|
||||
rightBottom: false,
|
||||
// circle的大小
|
||||
size: 3,
|
||||
lineWidth: 1,
|
||||
fill: '#fff',
|
||||
stroke: '#72CC4A'
|
||||
},
|
||||
// 选中节点状态下的配置
|
||||
select: {
|
||||
lineWidth: 5
|
||||
// 节点中icon配置
|
||||
icon: {
|
||||
// 是否显示icon,值为 false 则不渲染icon
|
||||
show: false,
|
||||
// icon的地址,字符串类型
|
||||
img: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg',
|
||||
width: 16,
|
||||
height: 16
|
||||
}
|
||||
},
|
||||
shapeType: 'star',
|
||||
// 文本位置
|
||||
labelPosition: 'center',
|
||||
drawShape(cfg, group) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { icon, linkPoints, outerR, ...starStyle } = style;
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { style: defaultStyle, icon: defaultIcon } = this.options;
|
||||
const { style: customStyle, icon: customIcon } = customOptions;
|
||||
const style = deepMix({}, defaultStyle, customStyle, cfg.style);
|
||||
const icon = deepMix({}, defaultIcon, customIcon, cfg.icon);
|
||||
|
||||
const path = this.getPath(cfg);
|
||||
const keyShape = group.addShape('path', {
|
||||
attrs: {
|
||||
path,
|
||||
...starStyle
|
||||
...style
|
||||
}
|
||||
});
|
||||
|
||||
@ -81,8 +83,25 @@ Shape.registerNode('star', {
|
||||
image.set('capture', false);
|
||||
}
|
||||
|
||||
const { top, left, right, leftBottom, rightBottom, size,
|
||||
fill: anchorFill, stroke: anchorStroke, lineWidth: borderWidth } = linkPoints;
|
||||
this.drawLinkPoints(cfg, group);
|
||||
|
||||
return keyShape;
|
||||
},
|
||||
/**
|
||||
* 绘制节点上的LinkPoints
|
||||
* @param {Object} cfg data数据配置项
|
||||
* @param {Group} group Group实例
|
||||
*/
|
||||
drawLinkPoints(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { linkPoints: defaultLinkPoints } = this.options;
|
||||
const { linkPoints: customLinkPoints } = customOptions;
|
||||
const linkPoints = deepMix({}, defaultLinkPoints, customLinkPoints, cfg.linkPoints);
|
||||
|
||||
const { top, left, right, leftBottom, rightBottom, size: markSize,
|
||||
...markStyle } = linkPoints;
|
||||
const size = this.getSize(cfg);
|
||||
const outerR = size[1];
|
||||
|
||||
if (right) {
|
||||
// right circle
|
||||
@ -92,14 +111,12 @@ Shape.registerNode('star', {
|
||||
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: x1,
|
||||
y: -y1,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'star-anchor-right'
|
||||
className: 'star-mark-right'
|
||||
});
|
||||
}
|
||||
|
||||
@ -111,14 +128,12 @@ Shape.registerNode('star', {
|
||||
// top circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: x1,
|
||||
y: -y1,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'star-anchor-top'
|
||||
className: 'star-mark-top'
|
||||
});
|
||||
}
|
||||
|
||||
@ -130,14 +145,12 @@ Shape.registerNode('star', {
|
||||
// left circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: x1,
|
||||
y: -y1,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'star-anchor-left'
|
||||
className: 'star-mark-left'
|
||||
});
|
||||
}
|
||||
|
||||
@ -149,14 +162,12 @@ Shape.registerNode('star', {
|
||||
// left bottom circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: x1,
|
||||
y: -y1,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'star-anchor-left-bottom'
|
||||
className: 'star-mark-left-bottom'
|
||||
});
|
||||
}
|
||||
|
||||
@ -168,27 +179,19 @@ Shape.registerNode('star', {
|
||||
// left bottom circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: x1,
|
||||
y: -y1,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'star-anchor-right-bottom'
|
||||
className: 'star-mark-right-bottom'
|
||||
});
|
||||
}
|
||||
|
||||
return keyShape;
|
||||
},
|
||||
shouldUpdate() {
|
||||
return false;
|
||||
},
|
||||
getPath(cfg) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { outerR, innerR } = style;
|
||||
const size = this.getSize(cfg);
|
||||
const innerR = size[0];
|
||||
const outerR = size[1];
|
||||
const path = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const x1 = Math.cos((18 + 72 * i) / 180 * Math.PI) * outerR;
|
||||
@ -216,36 +219,22 @@ Shape.registerNode('star', {
|
||||
|
||||
return path;
|
||||
},
|
||||
/**
|
||||
* 获取节点宽高
|
||||
* @internal 返回节点的大小,以 [width, height] 的方式维护
|
||||
* @param {Object} cfg 节点的配置项
|
||||
* @return {Array} 宽高
|
||||
*/
|
||||
getSize(cfg) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { outerR } = style;
|
||||
|
||||
return [ outerR, outerR ];
|
||||
},
|
||||
update(cfg, item) {
|
||||
const group = item.getContainer();
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default || {};
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { style: defaultStyle, icon: defaultIcon, labelCfg: defaultLabelCfg } = this.options;
|
||||
const { style: customStyle, icon: customIcon, labelCfg: customLabelCfg } = customOptions;
|
||||
const style = deepMix({}, defaultStyle, customStyle, cfg.style);
|
||||
const icon = deepMix({}, defaultIcon, customIcon, cfg.icon);
|
||||
|
||||
const { icon, linkPoints, outerR,
|
||||
labelCfg: defaultLabelCfg, ...starStyle } = style;
|
||||
const keyShape = item.get('keyShape');
|
||||
const path = this.getPath(cfg);
|
||||
keyShape.attr({
|
||||
path,
|
||||
...starStyle
|
||||
...style
|
||||
});
|
||||
|
||||
const labelCfg = deepMix({}, defaultLabelCfg, cfg.labelCfg);
|
||||
const labelCfg = deepMix({}, defaultLabelCfg, customLabelCfg, cfg.labelCfg);
|
||||
const labelStyle = this.getLabelStyle(cfg, labelCfg, group);
|
||||
|
||||
const text = group.findByClassName('node-label');
|
||||
@ -265,84 +254,90 @@ Shape.registerNode('star', {
|
||||
});
|
||||
}
|
||||
|
||||
const { size, fill: anchorFill, stroke: anchorStroke, lineWidth: borderWidth } = linkPoints;
|
||||
this.updateLinkPoints(cfg, group);
|
||||
},
|
||||
/**
|
||||
* 更新linkPoints
|
||||
* @param {Object} cfg 节点数据配置项
|
||||
* @param {Group} group Item所在的group
|
||||
*/
|
||||
updateLinkPoints(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { linkPoints: defaultLinkPoints } = this.options;
|
||||
const { linkPoints: customLinkPoints } = customOptions;
|
||||
const linkPoints = deepMix({}, defaultLinkPoints, customLinkPoints, cfg.linkPoints);
|
||||
|
||||
const anchorRight = group.findByClassName('star-anchor-right');
|
||||
if (anchorRight) {
|
||||
const { size: markSize, ...markStyle } = linkPoints;
|
||||
|
||||
const size = this.getSize(cfg);
|
||||
const outerR = size[1];
|
||||
|
||||
const markRight = group.findByClassName('star-mark-right');
|
||||
if (markRight) {
|
||||
const x = Math.cos((18 + 72 * 0) / 180 * Math.PI) * outerR;
|
||||
const y = Math.sin((18 + 72 * 0) / 180 * Math.PI) * outerR;
|
||||
|
||||
anchorRight.attr({
|
||||
markRight.attr({
|
||||
...markStyle,
|
||||
x,
|
||||
y: -y,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
});
|
||||
}
|
||||
|
||||
const anchorTop = group.findByClassName('star-anchor-top');
|
||||
if (anchorTop) {
|
||||
const markTop = group.findByClassName('star-mark-top');
|
||||
if (markTop) {
|
||||
const x = Math.cos((18 + 72 * 1) / 180 * Math.PI) * outerR;
|
||||
const y = Math.sin((18 + 72 * 1) / 180 * Math.PI) * outerR;
|
||||
|
||||
// top circle
|
||||
anchorTop.attr({
|
||||
markTop.attr({
|
||||
...markStyle,
|
||||
x,
|
||||
y: -y,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
});
|
||||
}
|
||||
|
||||
const anchorLeft = group.findByClassName('star-anchor-left');
|
||||
if (anchorLeft) {
|
||||
const markLeft = group.findByClassName('star-mark-left');
|
||||
if (markLeft) {
|
||||
const x = Math.cos((18 + 72 * 2) / 180 * Math.PI) * outerR;
|
||||
const y = Math.sin((18 + 72 * 2) / 180 * Math.PI) * outerR;
|
||||
|
||||
// left circle
|
||||
anchorLeft.attr({
|
||||
markLeft.attr({
|
||||
...markStyle,
|
||||
x,
|
||||
y: -y,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
});
|
||||
}
|
||||
|
||||
const anchorLeftBottom = group.findByClassName('star-anchor-left-bottom');
|
||||
if (anchorLeftBottom) {
|
||||
const markLeftBottom = group.findByClassName('star-mark-left-bottom');
|
||||
if (markLeftBottom) {
|
||||
const x = Math.cos((18 + 72 * 3) / 180 * Math.PI) * outerR;
|
||||
const y = Math.sin((18 + 72 * 3) / 180 * Math.PI) * outerR;
|
||||
|
||||
// bottom circle
|
||||
anchorLeftBottom.attr({
|
||||
markLeftBottom.attr({
|
||||
...markStyle,
|
||||
x,
|
||||
y: -y,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
});
|
||||
}
|
||||
|
||||
const anchorRightBottom = group.findByClassName('star-anchor-right-bottom');
|
||||
if (anchorRightBottom) {
|
||||
const markRightBottom = group.findByClassName('star-mark-right-bottom');
|
||||
if (markRightBottom) {
|
||||
const x = Math.cos((18 + 72 * 4) / 180 * Math.PI) * outerR;
|
||||
const y = Math.sin((18 + 72 * 4) / 180 * Math.PI) * outerR;
|
||||
|
||||
// bottom circle
|
||||
anchorRightBottom.attr({
|
||||
markRightBottom.attr({
|
||||
...markStyle,
|
||||
x,
|
||||
y: -y,
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -5,66 +5,69 @@ const deepMix = require('@antv/util/lib/deep-mix');
|
||||
Shape.registerNode('triangle', {
|
||||
// 自定义节点时的配置
|
||||
options: {
|
||||
// 默认配置
|
||||
default: {
|
||||
len: 40,
|
||||
direction: 'up',
|
||||
stroke: '#69c0ff',
|
||||
fill: '#e6f7ff',
|
||||
lineWidth: 1,
|
||||
// 文本样式配置
|
||||
labelCfg: {
|
||||
style: {
|
||||
fill: '#595959'
|
||||
},
|
||||
offset: 15
|
||||
size: 40,
|
||||
direction: 'up',
|
||||
style: {
|
||||
stroke: '#87e8de',
|
||||
fill: '#36cfc9',
|
||||
lineWidth: 1
|
||||
},
|
||||
// 文本样式配置
|
||||
labelCfg: {
|
||||
style: {
|
||||
fill: '#595959'
|
||||
},
|
||||
// 节点上左右上下四个方向上的链接circle配置
|
||||
linkPoints: {
|
||||
top: false,
|
||||
right: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
// circle的大小
|
||||
size: 5,
|
||||
lineWidth: 1,
|
||||
fill: '#fff',
|
||||
stroke: '#72CC4A'
|
||||
offset: 15
|
||||
},
|
||||
stateStyles: {
|
||||
// 鼠标hover状态下的配置
|
||||
hover: {
|
||||
lineWidth: 3
|
||||
},
|
||||
// 节点中icon配置
|
||||
icon: {
|
||||
// 是否显示icon,值为 false 则不渲染icon
|
||||
show: false,
|
||||
// icon的地址,字符串类型
|
||||
img: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg',
|
||||
width: 16,
|
||||
height: 16,
|
||||
offset: 0
|
||||
// 选中节点状态下的配置
|
||||
select: {
|
||||
lineWidth: 5
|
||||
}
|
||||
},
|
||||
// 鼠标hover状态下的配置
|
||||
hover: {
|
||||
lineWidth: 3
|
||||
// 节点上左右上下四个方向上的链接circle配置
|
||||
linkPoints: {
|
||||
top: false,
|
||||
right: false,
|
||||
bottom: false,
|
||||
left: false,
|
||||
// circle的大小
|
||||
size: 5,
|
||||
lineWidth: 1,
|
||||
fill: '#fff',
|
||||
stroke: '#72CC4A'
|
||||
},
|
||||
// 选中节点状态下的配置
|
||||
select: {
|
||||
lineWidth: 5
|
||||
// 节点中icon配置
|
||||
icon: {
|
||||
// 是否显示icon,值为 false 则不渲染icon
|
||||
show: false,
|
||||
// icon的地址,字符串类型
|
||||
img: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg',
|
||||
width: 16,
|
||||
height: 16,
|
||||
offset: 6
|
||||
}
|
||||
},
|
||||
shapeType: 'circle',
|
||||
shapeType: 'triangle',
|
||||
// 文本位置
|
||||
labelPosition: 'bottom',
|
||||
drawShape(cfg, group) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { icon, linkPoints,
|
||||
direction, len, ...triangleStyle } = style;
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { style: defaultStyle, icon: defaultIcon, direction: defaultDirection } = this.options;
|
||||
const { style: customStyle, icon: customIcon, direction: customDirection } = customOptions;
|
||||
const style = deepMix({}, defaultStyle, customStyle, cfg.style);
|
||||
const icon = deepMix({}, defaultIcon, customIcon, cfg.icon);
|
||||
|
||||
const direction = cfg.direction || customDirection || defaultDirection;
|
||||
const path = this.getPath(cfg);
|
||||
const keyShape = group.addShape('path', {
|
||||
attrs: {
|
||||
path,
|
||||
...triangleStyle
|
||||
...style
|
||||
}
|
||||
});
|
||||
|
||||
@ -90,8 +93,28 @@ Shape.registerNode('triangle', {
|
||||
image.set('capture', false);
|
||||
}
|
||||
|
||||
const { top, left, right, bottom, size,
|
||||
fill: anchorFill, stroke: anchorStroke, lineWidth: borderWidth } = linkPoints;
|
||||
this.drawLinkPoints(cfg, group);
|
||||
|
||||
return keyShape;
|
||||
},
|
||||
/**
|
||||
* 绘制节点上的LinkPoints
|
||||
* @param {Object} cfg data数据配置项
|
||||
* @param {Group} group Group实例
|
||||
*/
|
||||
drawLinkPoints(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { linkPoints: defaultLinkPoints, direction: defaultDirection } = this.options;
|
||||
const { linkPoints: customLinkPoints, direction: customDirection } = customOptions;
|
||||
const linkPoints = deepMix({}, defaultLinkPoints, customLinkPoints, cfg.linkPoints);
|
||||
|
||||
const direction = cfg.direction || customDirection || defaultDirection;
|
||||
|
||||
const { top, left, right, bottom, size: markSize,
|
||||
...markStyle } = linkPoints;
|
||||
const size = this.getSize(cfg);
|
||||
const len = size[0];
|
||||
|
||||
if (left) {
|
||||
// up down left right 四个方向的坐标均不相同
|
||||
let leftPos = null;
|
||||
@ -109,14 +132,12 @@ Shape.registerNode('triangle', {
|
||||
// left circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: leftPos[0],
|
||||
y: leftPos[1],
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'triangle-anchor-left'
|
||||
className: 'triangle-mark-left'
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -138,14 +159,12 @@ Shape.registerNode('triangle', {
|
||||
if (rightPos) {
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: rightPos[0],
|
||||
y: rightPos[1],
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'triangle-anchor-right'
|
||||
className: 'triangle-mark-right'
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -167,14 +186,12 @@ Shape.registerNode('triangle', {
|
||||
// top circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: topPos[0],
|
||||
y: topPos[1],
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'triangle-anchor-top'
|
||||
className: 'triangle-mark-top'
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -196,28 +213,25 @@ Shape.registerNode('triangle', {
|
||||
// bottom circle
|
||||
group.addShape('circle', {
|
||||
attrs: {
|
||||
...markStyle,
|
||||
x: bottomPos[0],
|
||||
y: bottomPos[1],
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
},
|
||||
className: 'triangle-anchor-bottom'
|
||||
className: 'triangle-mark-bottom'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return keyShape;
|
||||
},
|
||||
shouldUpdate() {
|
||||
return false;
|
||||
},
|
||||
getPath(cfg) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { len, direction } = style;
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { direction: defaultDirection } = this.options;
|
||||
const { direction: customDirection } = customOptions;
|
||||
|
||||
const direction = cfg.direction || customDirection || defaultDirection;
|
||||
const size = this.getSize(cfg);
|
||||
const len = size[0];
|
||||
|
||||
const diffY = len * Math.sin((1 / 3) * Math.PI);
|
||||
const r = len * Math.sin((1 / 3) * Math.PI);
|
||||
let path = [
|
||||
@ -251,36 +265,21 @@ Shape.registerNode('triangle', {
|
||||
}
|
||||
return path;
|
||||
},
|
||||
/**
|
||||
* 获取节点宽高
|
||||
* @internal 返回节点的大小,以 [width, height] 的方式维护
|
||||
* @param {Object} cfg 节点的配置项
|
||||
* @return {Array} 宽高
|
||||
*/
|
||||
getSize(cfg) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
const { len } = style;
|
||||
|
||||
return [ len, len ];
|
||||
},
|
||||
update(cfg, item) {
|
||||
const group = item.getContainer();
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default || {};
|
||||
const style = deepMix({}, this.options.default, defaultConfig, cfg.style);
|
||||
|
||||
const { icon, linkPoints, direction, len,
|
||||
labelCfg: defaultLabelCfg, ...triangleStyle } = style;
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { style: defaultStyle, icon: defaultIcon, labelCfg: defaultLabelCfg } = this.options;
|
||||
const { style: customStyle, icon: customIcon, labelCfg: customLabelCfg } = customOptions;
|
||||
const style = deepMix({}, defaultStyle, customStyle, cfg.style);
|
||||
const icon = deepMix({}, defaultIcon, customIcon, cfg.icon);
|
||||
const keyShape = item.get('keyShape');
|
||||
const path = this.getPath(cfg);
|
||||
keyShape.attr({
|
||||
path,
|
||||
...triangleStyle
|
||||
...style
|
||||
});
|
||||
|
||||
const labelCfg = deepMix({}, defaultLabelCfg, cfg.labelCfg);
|
||||
const labelCfg = deepMix({}, defaultLabelCfg, customLabelCfg, cfg.labelCfg);
|
||||
const labelStyle = this.getLabelStyle(cfg, labelCfg, group);
|
||||
|
||||
const text = group.findByClassName('node-label');
|
||||
@ -300,10 +299,29 @@ Shape.registerNode('triangle', {
|
||||
});
|
||||
}
|
||||
|
||||
const { size, fill: anchorFill, stroke: anchorStroke, lineWidth: borderWidth } = linkPoints;
|
||||
this.updateLinkPoints(cfg, group);
|
||||
},
|
||||
/**
|
||||
* 更新linkPoints
|
||||
* @param {Object} cfg 节点数据配置项
|
||||
* @param {Group} group Item所在的group
|
||||
*/
|
||||
updateLinkPoints(cfg, group) {
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { linkPoints: defaultLinkPoints, direction: defaultDirection } = this.options;
|
||||
const { linkPoints: customLinkPoints, direction: customDirection } = customOptions;
|
||||
const linkPoints = deepMix({}, defaultLinkPoints, customLinkPoints, cfg.linkPoints);
|
||||
|
||||
const anchorLeft = group.findByClassName('triangle-anchor-left');
|
||||
if (anchorLeft) {
|
||||
const direction = cfg.direction || customDirection || defaultDirection;
|
||||
|
||||
|
||||
const { size: markSize, ...markStyle } = linkPoints;
|
||||
|
||||
const size = this.getSize(cfg);
|
||||
const len = size[0];
|
||||
|
||||
const markLeft = group.findByClassName('triangle-mark-left');
|
||||
if (markLeft) {
|
||||
let leftPos = null;
|
||||
const diffY = len * Math.sin((1 / 3) * Math.PI);
|
||||
const r = len * Math.sin((1 / 3) * Math.PI);
|
||||
@ -317,19 +335,17 @@ Shape.registerNode('triangle', {
|
||||
|
||||
if (leftPos) {
|
||||
// left circle
|
||||
anchorLeft.attr({
|
||||
markLeft.attr({
|
||||
...markStyle,
|
||||
x: leftPos[0],
|
||||
y: leftPos[1],
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const anchorRight = group.findByClassName('triangle-anchor-right');
|
||||
if (anchorRight) {
|
||||
const markRight = group.findByClassName('triangle-mark-right');
|
||||
if (markRight) {
|
||||
let rightPos = null;
|
||||
const diffY = len * Math.sin((1 / 3) * Math.PI);
|
||||
const r = len * Math.sin((1 / 3) * Math.PI);
|
||||
@ -342,19 +358,17 @@ Shape.registerNode('triangle', {
|
||||
}
|
||||
|
||||
if (rightPos) {
|
||||
anchorRight.attr({
|
||||
markRight.attr({
|
||||
...markStyle,
|
||||
x: rightPos[0],
|
||||
y: rightPos[1],
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const anchorTop = group.findByClassName('triangle-anchor-top');
|
||||
if (anchorTop) {
|
||||
const markTop = group.findByClassName('triangle-mark-top');
|
||||
if (markTop) {
|
||||
let topPos = null;
|
||||
const diffY = len * Math.sin((1 / 3) * Math.PI);
|
||||
const r = len * Math.sin((1 / 3) * Math.PI);
|
||||
@ -368,19 +382,17 @@ Shape.registerNode('triangle', {
|
||||
|
||||
if (topPos) {
|
||||
// top circle
|
||||
anchorTop.attr({
|
||||
markTop.attr({
|
||||
...markStyle,
|
||||
x: topPos[0],
|
||||
y: topPos[1],
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const anchorBottom = group.findByClassName('triangle-anchor-bottom');
|
||||
if (anchorBottom) {
|
||||
const markBottom = group.findByClassName('triangle-mark-bottom');
|
||||
if (markBottom) {
|
||||
let bottomPos = null;
|
||||
const diffY = len * Math.sin((1 / 3) * Math.PI);
|
||||
const r = len * Math.sin((1 / 3) * Math.PI);
|
||||
@ -395,13 +407,11 @@ Shape.registerNode('triangle', {
|
||||
|
||||
if (bottomPos) {
|
||||
// bottom circle
|
||||
anchorBottom.attr({
|
||||
markBottom.attr({
|
||||
...markStyle,
|
||||
x: bottomPos[0],
|
||||
y: bottomPos[1],
|
||||
r: size,
|
||||
fill: anchorFill,
|
||||
stroke: anchorStroke,
|
||||
lineWidth: borderWidth
|
||||
r: markSize
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -40,10 +40,11 @@ const SingleShape = {
|
||||
|
||||
},
|
||||
drawLabel(cfg, group) {
|
||||
const customStyle = this.getCustomConfig(cfg) || {};
|
||||
const defaultConfig = customStyle.default;
|
||||
const style = merge({}, this.options.default, defaultConfig);
|
||||
const labelCfg = merge({}, style.labelCfg, cfg.labelCfg);
|
||||
const customOptions = this.getCustomConfig(cfg) || {};
|
||||
const { labelCfg: defaultLabelCfg } = this.options;
|
||||
const { labelCfg: customLabelCfg } = customOptions;
|
||||
|
||||
const labelCfg = merge({}, defaultLabelCfg, customLabelCfg, cfg.labelCfg);
|
||||
const labelStyle = this.getLabelStyle(cfg, labelCfg, group);
|
||||
const label = group.addShape('text', {
|
||||
attrs: labelStyle
|
||||
@ -154,15 +155,23 @@ const SingleShape = {
|
||||
* @return {object} 样式
|
||||
*/
|
||||
getStateStyle(name, value, item) {
|
||||
const defaultStyle = this.options;
|
||||
const model = item.getModel();
|
||||
const customStyle = this.getCustomConfig(model) || {};
|
||||
const customOptions = this.getCustomConfig(model) || {};
|
||||
const { style: defaultStyle, stateStyles: defaultStateStyle } = this.options;
|
||||
const { style: customStyle, stateStyles: customStateStyle } = customOptions;
|
||||
|
||||
const stateStyles = merge({}, defaultStateStyle, customStateStyle);
|
||||
let currentStateStyle = defaultStyle;
|
||||
|
||||
if (stateStyles[name]) {
|
||||
currentStateStyle = stateStyles[name];
|
||||
}
|
||||
if (value) {
|
||||
return merge({}, get(defaultStyle, name, {}), get(customStyle, name, {}));
|
||||
return currentStateStyle;
|
||||
}
|
||||
|
||||
const states = item.getStates();
|
||||
const resultStyle = merge({}, get(defaultStyle, 'default', {}), get(customStyle, 'default', {}));
|
||||
const resultStyle = merge({}, defaultStyle, customStyle);
|
||||
const style = cloneDeep(resultStyle);
|
||||
states.forEach(state => {
|
||||
merge(style, get(defaultStyle, state, {}), get(customStyle, state, {}));
|
||||
|
Loading…
Reference in New Issue
Block a user