- Go backend (server/)
- Frontend (web/, server/static/)
- Database and deployment files
- Scripts and docs
Co-Authored-By: 狸花猫/Claude-Qwen3.6-Plus 🐾
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'); |