@antv/g6
Version:
graph visualization frame work
153 lines (146 loc) • 4.9 kB
JavaScript
const Shape = require('../shape');
const Util = require('../../util');
const PolylineUtil = require('./polyline-util');
const Global = require('../../global');
const CLS_SHAPE_SUFFIX = '-shape';
const CLS_LABEL_SUFFIX = '-label';
// 折线
Shape.registerEdge('polyline', {
options: {
color: '#999',
style: {
stroke: '#333',
lineWidth: 1,
radius: 0,
offset: 5,
x: 0,
y: 0
},
// 文本样式配置
labelCfg: {
style: {
fill: '#595959'
}
},
stateStyles: {
// 鼠标hover状态下的配置
hover: {
lineWidth: 3
},
// 选中边状态下的配置
selected: {
lineWidth: 5
}
}
},
shapeType: 'polyline',
// 文本位置
labelPosition: 'center',
drawShape(cfg, group) {
const shapeStyle = this.getShapeStyle(cfg);
const keyShape = group.addShape('path', {
className: 'edge-shape',
attrs: shapeStyle
});
return keyShape;
},
getShapeStyle(cfg) {
const customOptions = this.getCustomConfig(cfg) || {};
const { style: defaultStyle } = this.options;
const { style: customStyle } = customOptions;
const strokeStyle = {
stroke: cfg.color
};
const style = Util.deepMix({}, defaultStyle, customStyle, strokeStyle, cfg.style);
cfg = this.getPathPoints(cfg);
this.radius = style.radius;
this.offset = style.offset;
const startPoint = cfg.startPoint;
const endPoint = cfg.endPoint;
const controlPoints = this.getControlPoints(cfg);
let points = [ startPoint ]; // 添加起始点
// 添加控制点
if (controlPoints) {
points = points.concat(controlPoints);
}
// 添加结束点
points.push(endPoint);
const source = cfg.sourceNode;
const target = cfg.targetNode;
let routeCfg = { radius: style.radius };
if (!controlPoints) {
routeCfg = { source, target, offset: style.offset, radius: style.radius };
}
const path = this.getPath(points, routeCfg);
const attrs = Util.deepMix({}, Global.defaultEdge.style, style, {
lineWidth: cfg.size
}, { path });
return attrs;
},
getPath(points, routeCfg) {
const { source, target, offset, radius } = routeCfg;
if (!offset) {
let path = [];
if (radius) {
path = PolylineUtil.getPathWithBorderRadiusByPolyline(points, radius);
} else {
Util.each(points, (point, index) => {
if (index === 0) {
path.push([ 'M', point.x, point.y ]);
} else {
path.push([ 'L', point.x, point.y ]);
}
});
}
return path;
}
if (radius) {
const polylinePoints = PolylineUtil.simplifyPolyline(
PolylineUtil.getPolylinePoints(points[0], points[points.length - 1], source, target, offset)
);
return PolylineUtil.getPathWithBorderRadiusByPolyline(polylinePoints, radius);
}
const polylinePoints = PolylineUtil.getPolylinePoints(points[0],
points[points.length - 1], source, target, offset);
return Util.pointsToPolygon(polylinePoints);
},
update(cfg, item) {
const group = item.getContainer();
const shapeClassName = this.itemType + CLS_SHAPE_SUFFIX;
const shape = group.findByClassName(shapeClassName);
if (!cfg.style) {
cfg.style = {};
}
const oriShapeAttrs = shape.attr();
cfg.style.radius = cfg.style.radius || oriShapeAttrs.radius;
cfg.style.offset = cfg.style.offset || oriShapeAttrs.offset;
const shapeStyle = this.getShapeStyle(cfg);
shape.attr(shapeStyle);
const labelClassName = this.itemType + CLS_LABEL_SUFFIX;
const label = group.findByClassName(labelClassName);
// 此时需要考虑之前是否绘制了 label 的场景存在三种情况
// 1. 更新时不需要 label,但是原先存在 label,此时需要删除
// 2. 更新时需要 label, 但是原先不存在,创建节点
// 3. 如果两者都存在,更新
if (!cfg.label) {
label && label.remove();
} else {
if (!label) {
const newLabel = this.drawLabel(cfg, group);
newLabel.set('className', labelClassName);
} else {
const { labelCfg: defaultLabelCfg } = this.options;
const { labelCfg: customLabelCfg } = this.getCustomConfig(cfg) || {};
const labelCfg = Util.deepMix({}, defaultLabelCfg, customLabelCfg, cfg.labelCfg);
const labelStyle = this.getLabelStyle(cfg, labelCfg, group);
/**
* fixme g中shape的rotate是角度累加的,不是label的rotate想要的角度
* 由于现在label只有rotate操作,所以在更新label的时候如果style中有rotate就重置一下变换
* 后续会基于g的Text复写一个Label出来处理这一类问题
*/
label.resetMatrix();
label.attr(labelStyle);
}
}
}
}, 'single-line');