yjtgq-app/node_modules/echarts/lib/chart/chord/chordLayout.js

247 lines
9.3 KiB
JavaScript
Raw Normal View History

2025-11-22 14:43:07 +08:00
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { normalizeArcAngles } from 'zrender/lib/core/PathProxy.js';
import { getCircleLayout } from '../../util/layout.js';
var RADIAN = Math.PI / 180;
export default function chordCircularLayout(ecModel, api) {
ecModel.eachSeriesByType('chord', function (seriesModel) {
chordLayout(seriesModel, api);
});
}
function chordLayout(seriesModel, api) {
var nodeData = seriesModel.getData();
var nodeGraph = nodeData.graph;
var edgeData = seriesModel.getEdgeData();
var edgeCount = edgeData.count();
if (!edgeCount) {
return;
}
var _a = getCircleLayout(seriesModel, api),
cx = _a.cx,
cy = _a.cy,
r = _a.r,
r0 = _a.r0;
var padAngle = Math.max((seriesModel.get('padAngle') || 0) * RADIAN, 0);
var minAngle = Math.max((seriesModel.get('minAngle') || 0) * RADIAN, 0);
var startAngle = -seriesModel.get('startAngle') * RADIAN;
var endAngle = startAngle + Math.PI * 2;
var clockwise = seriesModel.get('clockwise');
var dir = clockwise ? 1 : -1;
// Normalize angles
var angles = [startAngle, endAngle];
normalizeArcAngles(angles, !clockwise);
var normalizedStartAngle = angles[0],
normalizedEndAngle = angles[1];
var totalAngle = normalizedEndAngle - normalizedStartAngle;
var allZero = nodeData.getSum('value') === 0 && edgeData.getSum('value') === 0;
// Sum of each node's edge values
var nodeValues = [];
var renderedNodeCount = 0;
nodeGraph.eachEdge(function (edge) {
// All links use the same value 1 when allZero is true
var value = allZero ? 1 : edge.getValue('value');
if (allZero && (value > 0 || minAngle)) {
// When allZero is true, angle is in direct proportion to number
// of links both in and out of the node.
renderedNodeCount += 2;
}
var node1Index = edge.node1.dataIndex;
var node2Index = edge.node2.dataIndex;
nodeValues[node1Index] = (nodeValues[node1Index] || 0) + value;
nodeValues[node2Index] = (nodeValues[node2Index] || 0) + value;
});
// Update nodeValues with data.value if exists
var nodeValueSum = 0;
nodeGraph.eachNode(function (node) {
var dataValue = node.getValue('value');
if (!isNaN(dataValue)) {
nodeValues[node.dataIndex] = Math.max(dataValue, nodeValues[node.dataIndex] || 0);
}
if (!allZero && (nodeValues[node.dataIndex] > 0 || minAngle)) {
// When allZero is false, angle is in direct proportion to node's
// value
renderedNodeCount++;
}
nodeValueSum += nodeValues[node.dataIndex] || 0;
});
if (renderedNodeCount === 0 || nodeValueSum === 0) {
return;
}
if (padAngle * renderedNodeCount >= Math.abs(totalAngle)) {
// Not enough angle to render the pad, minAngle has higher priority, and padAngle takes the rest
padAngle = Math.max(0, (Math.abs(totalAngle) - minAngle * renderedNodeCount) / renderedNodeCount);
}
if ((padAngle + minAngle) * renderedNodeCount >= Math.abs(totalAngle)) {
// Not enough angle to render the minAngle, so ignore the minAngle
minAngle = (Math.abs(totalAngle) - padAngle * renderedNodeCount) / renderedNodeCount;
}
var unitAngle = (totalAngle - padAngle * renderedNodeCount * dir) / nodeValueSum;
var totalDeficit = 0; // sum of deficits of nodes with span < minAngle
var totalSurplus = 0; // sum of (spans - minAngle) of nodes with span > minAngle
var totalSurplusSpan = 0; // sum of spans of nodes with span > minAngle
var minSurplus = Infinity; // min of (spans - minAngle) of nodes with span > minAngle
nodeGraph.eachNode(function (node) {
var value = nodeValues[node.dataIndex] || 0;
var spanAngle = unitAngle * (nodeValueSum ? value : 1) * dir;
if (Math.abs(spanAngle) < minAngle) {
totalDeficit += minAngle - Math.abs(spanAngle);
} else {
minSurplus = Math.min(minSurplus, Math.abs(spanAngle) - minAngle);
totalSurplus += Math.abs(spanAngle) - minAngle;
totalSurplusSpan += Math.abs(spanAngle);
}
node.setLayout({
angle: spanAngle,
value: value
});
});
var surplusAsMuchAsPossible = false;
if (totalDeficit > totalSurplus) {
// Not enough angle to spread the nodes, scale all
var scale_1 = totalDeficit / totalSurplus;
nodeGraph.eachNode(function (node) {
var spanAngle = node.getLayout().angle;
if (Math.abs(spanAngle) >= minAngle) {
node.setLayout({
angle: spanAngle * scale_1,
ratio: scale_1
}, true);
} else {
node.setLayout({
angle: minAngle,
ratio: minAngle === 0 ? 1 : spanAngle / minAngle
}, true);
}
});
} else {
// For example, if totalDeficit is 60 degrees and totalSurplus is 70
// degrees but one of the sector can only reduced by 1 degree,
// if we decrease it with the ratio of value to other surplused nodes,
// it will have smaller angle than minAngle itself.
// So we need to borrow some angle from other nodes.
nodeGraph.eachNode(function (node) {
if (surplusAsMuchAsPossible) {
return;
}
var spanAngle = node.getLayout().angle;
var borrowRatio = Math.min(spanAngle / totalSurplusSpan, 1);
var borrowAngle = borrowRatio * totalDeficit;
if (spanAngle - borrowAngle < minAngle) {
// It will have less than minAngle after borrowing
surplusAsMuchAsPossible = true;
}
});
}
var restDeficit = totalDeficit;
nodeGraph.eachNode(function (node) {
if (restDeficit <= 0) {
return;
}
var spanAngle = node.getLayout().angle;
if (spanAngle > minAngle && minAngle > 0) {
var borrowRatio = surplusAsMuchAsPossible ? 1 : Math.min(spanAngle / totalSurplusSpan, 1);
var maxBorrowAngle = spanAngle - minAngle;
var borrowAngle = Math.min(maxBorrowAngle, Math.min(restDeficit, totalDeficit * borrowRatio));
restDeficit -= borrowAngle;
node.setLayout({
angle: spanAngle - borrowAngle,
ratio: (spanAngle - borrowAngle) / spanAngle
}, true);
} else if (minAngle > 0) {
node.setLayout({
angle: minAngle,
ratio: spanAngle === 0 ? 1 : minAngle / spanAngle
}, true);
}
});
var angle = normalizedStartAngle;
var edgeAccAngle = [];
nodeGraph.eachNode(function (node) {
var spanAngle = Math.max(node.getLayout().angle, minAngle);
node.setLayout({
cx: cx,
cy: cy,
r0: r0,
r: r,
startAngle: angle,
endAngle: angle + spanAngle * dir,
clockwise: clockwise
}, true);
edgeAccAngle[node.dataIndex] = angle;
angle += (spanAngle + padAngle) * dir;
});
nodeGraph.eachEdge(function (edge) {
var value = allZero ? 1 : edge.getValue('value');
var spanAngle = unitAngle * (nodeValueSum ? value : 1) * dir;
var node1Index = edge.node1.dataIndex;
var sStartAngle = edgeAccAngle[node1Index] || 0;
var sSpan = Math.abs((edge.node1.getLayout().ratio || 1) * spanAngle);
var sEndAngle = sStartAngle + sSpan * dir;
var s1 = [cx + r0 * Math.cos(sStartAngle), cy + r0 * Math.sin(sStartAngle)];
var s2 = [cx + r0 * Math.cos(sEndAngle), cy + r0 * Math.sin(sEndAngle)];
var node2Index = edge.node2.dataIndex;
var tStartAngle = edgeAccAngle[node2Index] || 0;
var tSpan = Math.abs((edge.node2.getLayout().ratio || 1) * spanAngle);
var tEndAngle = tStartAngle + tSpan * dir;
var t1 = [cx + r0 * Math.cos(tStartAngle), cy + r0 * Math.sin(tStartAngle)];
var t2 = [cx + r0 * Math.cos(tEndAngle), cy + r0 * Math.sin(tEndAngle)];
edge.setLayout({
s1: s1,
s2: s2,
sStartAngle: sStartAngle,
sEndAngle: sEndAngle,
t1: t1,
t2: t2,
tStartAngle: tStartAngle,
tEndAngle: tEndAngle,
cx: cx,
cy: cy,
r: r0,
value: value,
clockwise: clockwise
});
edgeAccAngle[node1Index] = sEndAngle;
edgeAccAngle[node2Index] = tEndAngle;
});
}