324 lines
9.9 KiB
JavaScript
324 lines
9.9 KiB
JavaScript
"use strict";
|
|
|
|
var _tslib = require("tslib");
|
|
var _g6Core = require("@antv/g6-core");
|
|
var _util = require("@antv/util");
|
|
var defaultSubjectColors = _g6Core.Util.defaultSubjectColors;
|
|
var FAN_NAME_PREFIX = 'fan-shape-';
|
|
/**
|
|
* calculate the total value and format single value for each fan
|
|
* @param donutAttrs
|
|
* @param donutColorMap
|
|
* @returns
|
|
*/
|
|
var getDonutConfig = function getDonutConfig(donutAttrs, donutColorMap) {
|
|
var totalValue = 0;
|
|
var configs = [];
|
|
Object.keys(donutAttrs).forEach(function (name) {
|
|
var value = +donutAttrs[name];
|
|
if (isNaN(value)) return;
|
|
configs.push({
|
|
key: name,
|
|
value: value,
|
|
color: donutColorMap[name]
|
|
});
|
|
totalValue += value;
|
|
});
|
|
return {
|
|
totalValue: totalValue,
|
|
configs: configs
|
|
};
|
|
};
|
|
/**
|
|
* calculate the lineWidth and radius for fan shapes according to the keyShape's radius
|
|
* @param keyShape
|
|
* @returns
|
|
*/
|
|
var getDonutSize = function getDonutSize(keyShape) {
|
|
var keyShapeR = keyShape.attr('r');
|
|
var innerR = 0.6 * keyShapeR; // 甜甜圈的内环半径
|
|
var arcR = (keyShapeR + innerR) / 2; // 内环半径与外环半径的平均值
|
|
var lineWidth = keyShapeR - innerR;
|
|
return {
|
|
lineWidth: lineWidth,
|
|
arcR: arcR
|
|
};
|
|
};
|
|
/**
|
|
* draws one fan shape and returns the next position and angle
|
|
* @param group
|
|
* @param fanConfig
|
|
* @returns
|
|
*/
|
|
var drawFan = function drawFan(group, fanConfig) {
|
|
var arcR = fanConfig.arcR,
|
|
arcBegin = fanConfig.arcBegin,
|
|
beginAngle = fanConfig.beginAngle,
|
|
config = fanConfig.config,
|
|
fanIndex = fanConfig.fanIndex,
|
|
lineWidth = fanConfig.lineWidth,
|
|
totalValue = fanConfig.totalValue,
|
|
_a = fanConfig.drawWhole,
|
|
drawWhole = _a === void 0 ? false : _a,
|
|
_b = fanConfig.updateShape,
|
|
updateShape = _b === void 0 ? undefined : _b;
|
|
var percent = config.value / totalValue;
|
|
if (percent < 0.001) {
|
|
// too small to add a fan
|
|
return {
|
|
beginAngle: beginAngle,
|
|
arcBegin: arcBegin,
|
|
shape: undefined,
|
|
shouldEnd: false
|
|
};
|
|
}
|
|
var arcEnd, endAngle, isBig;
|
|
// draw a path represents the whole circle, or the percentage is close to 1
|
|
if (drawWhole || percent > 0.999) {
|
|
arcEnd = [arcR, 0.0001]; // [arcR * cos(2 * PI), -arcR * sin(2 * PI)]
|
|
isBig = 1;
|
|
} else {
|
|
var angle = percent * Math.PI * 2;
|
|
endAngle = beginAngle + angle;
|
|
arcEnd = [arcR * Math.cos(endAngle), -arcR * Math.sin(endAngle)];
|
|
isBig = angle > Math.PI ? 1 : 0;
|
|
}
|
|
var style = {
|
|
path: [['M', arcBegin[0], arcBegin[1]], ['A', arcR, arcR, 0, isBig, 0, arcEnd[0], arcEnd[1]]],
|
|
stroke: config.color || (updateShape === null || updateShape === void 0 ? void 0 : updateShape.attr('stroke')) || defaultSubjectColors[fanIndex % defaultSubjectColors.length],
|
|
lineWidth: lineWidth
|
|
};
|
|
if (updateShape) {
|
|
// update
|
|
updateShape.attr(style);
|
|
} else {
|
|
// draw
|
|
group['shapeMap']["".concat(FAN_NAME_PREFIX).concat(fanIndex)] = group.addShape('path', {
|
|
attrs: style,
|
|
name: "".concat(FAN_NAME_PREFIX).concat(fanIndex),
|
|
draggable: true
|
|
});
|
|
}
|
|
return {
|
|
beginAngle: endAngle,
|
|
arcBegin: arcEnd,
|
|
shape: group['shapeMap']["".concat(FAN_NAME_PREFIX).concat(fanIndex)],
|
|
shouldEnd: drawWhole || percent > 0.999
|
|
};
|
|
};
|
|
/**
|
|
* draws the fan shapes
|
|
* @param cfg
|
|
* @param group
|
|
* @param keyShape
|
|
* @returns
|
|
*/
|
|
var drawFans = function drawFans(cfg, group, keyShape) {
|
|
var _a = cfg.donutAttrs,
|
|
donutAttrs = _a === void 0 ? {} : _a,
|
|
_b = cfg.donutColorMap,
|
|
donutColorMap = _b === void 0 ? {} : _b;
|
|
var attrNum = Object.keys(donutAttrs).length;
|
|
if (donutAttrs && attrNum > 1) {
|
|
var _c = getDonutConfig(donutAttrs, donutColorMap),
|
|
configs = _c.configs,
|
|
totalValue = _c.totalValue;
|
|
if (totalValue) {
|
|
var _d = getDonutSize(keyShape),
|
|
lineWidth = _d.lineWidth,
|
|
arcR = _d.arcR;
|
|
var arcBegin = [arcR, 0];
|
|
var beginAngle = 0;
|
|
if (attrNum === 1) {
|
|
// draw a path represents a circle
|
|
drawFan(group, {
|
|
arcR: arcR,
|
|
arcBegin: arcBegin,
|
|
beginAngle: beginAngle,
|
|
config: configs[0],
|
|
fanIndex: 0,
|
|
lineWidth: lineWidth,
|
|
totalValue: totalValue,
|
|
drawWhole: true
|
|
});
|
|
return;
|
|
}
|
|
for (var i = 0; i < configs.length; i++) {
|
|
var result = drawFan(group, {
|
|
arcR: arcR,
|
|
arcBegin: arcBegin,
|
|
beginAngle: beginAngle,
|
|
config: configs[i],
|
|
fanIndex: i,
|
|
lineWidth: lineWidth,
|
|
totalValue: totalValue
|
|
});
|
|
if (result.shouldEnd) return;
|
|
arcBegin = result.arcBegin;
|
|
beginAngle = result.beginAngle;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* utilizes the existing fan shapes, update them with new configs
|
|
* removes the redundent fan shapes
|
|
* or adds more fan shapes
|
|
* @param cfg
|
|
* @param item
|
|
* @param keyShape
|
|
*/
|
|
var updateFans = function updateFans(cfg, item, keyShape) {
|
|
var donutAttrs = cfg.donutAttrs,
|
|
_a = cfg.donutColorMap,
|
|
donutColorMap = _a === void 0 ? {} : _a;
|
|
var visitMap = {};
|
|
var group = item.getContainer();
|
|
if (donutAttrs) {
|
|
var _b = getDonutConfig(donutAttrs, donutColorMap),
|
|
configs = _b.configs,
|
|
totalValue = _b.totalValue;
|
|
if (totalValue) {
|
|
var _c = getDonutSize(keyShape),
|
|
lineWidth = _c.lineWidth,
|
|
arcR = _c.arcR;
|
|
var arcBegin = [arcR, 0];
|
|
var beginAngle = 0;
|
|
for (var i = 0; i < configs.length; i++) {
|
|
var shapeName = "".concat(FAN_NAME_PREFIX).concat(i);
|
|
var result = drawFan(group, {
|
|
arcR: arcR,
|
|
arcBegin: arcBegin,
|
|
beginAngle: beginAngle,
|
|
config: configs[i],
|
|
fanIndex: i,
|
|
lineWidth: lineWidth,
|
|
totalValue: totalValue,
|
|
drawWhole: configs.length === 1,
|
|
updateShape: group['shapeMap'][shapeName]
|
|
});
|
|
if (result.shape) visitMap[shapeName] = true;
|
|
if (result.shouldEnd) break;
|
|
arcBegin = result.arcBegin;
|
|
beginAngle = result.beginAngle;
|
|
}
|
|
}
|
|
}
|
|
// remove the old shapes which are not visited, including the situation taht donutAttrs is empty
|
|
var fanKeys = Object.keys(group['shapeMap']).filter(function (key) {
|
|
return key.includes(FAN_NAME_PREFIX);
|
|
});
|
|
fanKeys.forEach(function (key) {
|
|
if (!visitMap[key]) {
|
|
group['shapeMap'][key].remove(true);
|
|
delete group['shapeMap'][key];
|
|
}
|
|
});
|
|
};
|
|
// 饼图节点
|
|
(0, _g6Core.registerNode)('donut', {
|
|
// 自定义节点时的配置
|
|
options: {
|
|
size: _g6Core.BaseGlobal.defaultNode.size,
|
|
style: {
|
|
x: 0,
|
|
y: 0,
|
|
stroke: _g6Core.BaseGlobal.defaultNode.style.stroke,
|
|
fill: _g6Core.BaseGlobal.defaultNode.style.fill,
|
|
lineWidth: _g6Core.BaseGlobal.defaultNode.style.lineWidth
|
|
},
|
|
labelCfg: {
|
|
style: {
|
|
fill: _g6Core.BaseGlobal.nodeLabel.style.fill,
|
|
fontSize: _g6Core.BaseGlobal.nodeLabel.style.fontSize,
|
|
fontFamily: _g6Core.BaseGlobal.windowFontFamily
|
|
}
|
|
},
|
|
// 节点上左右上下四个方向上的链接circle配置
|
|
linkPoints: {
|
|
top: false,
|
|
right: false,
|
|
bottom: false,
|
|
left: false,
|
|
// circle的大小
|
|
size: _g6Core.BaseGlobal.defaultNode.linkPoints.size,
|
|
lineWidth: _g6Core.BaseGlobal.defaultNode.linkPoints.lineWidth,
|
|
fill: _g6Core.BaseGlobal.defaultNode.linkPoints.fill,
|
|
stroke: _g6Core.BaseGlobal.defaultNode.linkPoints.stroke
|
|
},
|
|
// 节点中icon配置
|
|
icon: {
|
|
// 是否显示icon,值为 false 则不渲染icon
|
|
show: false,
|
|
// icon的地址,字符串类型
|
|
img: 'https://gw.alipayobjects.com/zos/bmw-prod/5d015065-8505-4e7a-baec-976f81e3c41d.svg',
|
|
width: 20,
|
|
height: 20
|
|
},
|
|
stateStyles: (0, _tslib.__assign)({}, _g6Core.BaseGlobal.nodeStateStyles)
|
|
},
|
|
shapeType: 'circle',
|
|
// 文本位置
|
|
labelPosition: 'center',
|
|
drawShape: function drawShape(cfg, group) {
|
|
var _a = (this.mergeStyle || this.getOptions(cfg)).icon,
|
|
defaultIcon = _a === void 0 ? {} : _a;
|
|
var style = this.getShapeStyle(cfg);
|
|
var icon = (0, _util.deepMix)({}, defaultIcon, cfg.icon);
|
|
var keyShape = group.addShape('circle', {
|
|
attrs: style,
|
|
className: "".concat(this.type, "-keyShape"),
|
|
draggable: true,
|
|
name: "".concat(this.type, "-keyShape")
|
|
});
|
|
group['shapeMap']["".concat(this.type, "-keyShape")] = keyShape;
|
|
var width = icon.width,
|
|
height = icon.height,
|
|
show = icon.show,
|
|
text = icon.text;
|
|
if (show) {
|
|
if (text) {
|
|
group['shapeMap']["".concat(this.type, "-icon")] = group.addShape('text', {
|
|
attrs: (0, _tslib.__assign)({
|
|
x: 0,
|
|
y: 0,
|
|
fontSize: 12,
|
|
fill: '#000',
|
|
stroke: '#000',
|
|
textBaseline: 'middle',
|
|
textAlign: 'center'
|
|
}, icon),
|
|
className: "".concat(this.type, "-icon"),
|
|
name: "".concat(this.type, "-icon"),
|
|
draggable: true
|
|
});
|
|
} else {
|
|
group['shapeMap']["".concat(this.type, "-icon")] = group.addShape('image', {
|
|
attrs: (0, _tslib.__assign)({
|
|
x: -width / 2,
|
|
y: -height / 2
|
|
}, icon),
|
|
className: "".concat(this.type, "-icon"),
|
|
name: "".concat(this.type, "-icon"),
|
|
draggable: true
|
|
});
|
|
}
|
|
}
|
|
// draw the fan shapes
|
|
drawFans(cfg, group, keyShape);
|
|
this.drawLinkPoints(cfg, group);
|
|
return keyShape;
|
|
},
|
|
updateShape: function updateShape(cfg, item, keyShapeStyle, hasIcon, updateType) {
|
|
// here cfg is merged configure including old model and new configs
|
|
var keyShape = item.get('keyShape');
|
|
keyShape.attr((0, _tslib.__assign)({}, keyShapeStyle));
|
|
updateFans(cfg, item, keyShape);
|
|
if (!undefined || (updateType === null || updateType === void 0 ? void 0 : updateType.includes('label'))) {
|
|
this.updateLabel(cfg, item, updateType);
|
|
}
|
|
if (hasIcon) {
|
|
this.updateIcon(cfg, item);
|
|
}
|
|
}
|
|
}, 'circle'); |