in src/chart/helper/Line.ts [353:519]
beforeUpdate() {
const lineGroup = this;
const symbolFrom = lineGroup.childOfName('fromSymbol') as ECSymbol;
const symbolTo = lineGroup.childOfName('toSymbol') as ECSymbol;
const label = lineGroup.getTextContent() as InnerLineLabel;
// Quick reject
if (!symbolFrom && !symbolTo && (!label || label.ignore)) {
return;
}
let invScale = 1;
let parentNode = this.parent;
while (parentNode) {
if (parentNode.scaleX) {
invScale /= parentNode.scaleX;
}
parentNode = parentNode.parent;
}
const line = lineGroup.childOfName('line') as ECLinePath;
// If line not changed
// FIXME Parent scale changed
if (!this.__dirty && !line.__dirty) {
return;
}
const percent = line.shape.percent;
const fromPos = line.pointAt(0);
const toPos = line.pointAt(percent);
const d = vector.sub([], toPos, fromPos);
vector.normalize(d, d);
function setSymbolRotation(symbol: ECSymbol, percent: 0 | 1) {
// Fix #12388
// when symbol is set to be 'arrow' in markLine,
// symbolRotate value will be ignored, and compulsively use tangent angle.
// rotate by default if symbol rotation is not specified
const specifiedRotation = (symbol as LineECSymbol).__specifiedRotation;
if (specifiedRotation == null) {
const tangent = line.tangentAt(percent);
symbol.attr('rotation', (percent === 1 ? -1 : 1) * Math.PI / 2 - Math.atan2(
tangent[1], tangent[0]
));
}
else {
symbol.attr('rotation', specifiedRotation);
}
}
if (symbolFrom) {
symbolFrom.setPosition(fromPos);
setSymbolRotation(symbolFrom, 0);
symbolFrom.scaleX = symbolFrom.scaleY = invScale * percent;
symbolFrom.markRedraw();
}
if (symbolTo) {
symbolTo.setPosition(toPos);
setSymbolRotation(symbolTo, 1);
symbolTo.scaleX = symbolTo.scaleY = invScale * percent;
symbolTo.markRedraw();
}
if (label && !label.ignore) {
label.x = label.y = 0;
label.originX = label.originY = 0;
let textAlign: ZRTextAlign;
let textVerticalAlign: ZRTextVerticalAlign;
const distance = label.__labelDistance;
const distanceX = distance[0] * invScale;
const distanceY = distance[1] * invScale;
const halfPercent = percent / 2;
const tangent = line.tangentAt(halfPercent);
const n = [tangent[1], -tangent[0]];
const cp = line.pointAt(halfPercent);
if (n[1] > 0) {
n[0] = -n[0];
n[1] = -n[1];
}
const dir = tangent[0] < 0 ? -1 : 1;
if (label.__position !== 'start' && label.__position !== 'end') {
let rotation = -Math.atan2(tangent[1], tangent[0]);
if (toPos[0] < fromPos[0]) {
rotation = Math.PI + rotation;
}
label.rotation = rotation;
}
let dy;
switch (label.__position) {
case 'insideStartTop':
case 'insideMiddleTop':
case 'insideEndTop':
case 'middle':
dy = -distanceY;
textVerticalAlign = 'bottom';
break;
case 'insideStartBottom':
case 'insideMiddleBottom':
case 'insideEndBottom':
dy = distanceY;
textVerticalAlign = 'top';
break;
default:
dy = 0;
textVerticalAlign = 'middle';
}
switch (label.__position) {
case 'end':
label.x = d[0] * distanceX + toPos[0];
label.y = d[1] * distanceY + toPos[1];
textAlign = d[0] > 0.8 ? 'left' : (d[0] < -0.8 ? 'right' : 'center');
textVerticalAlign = d[1] > 0.8 ? 'top' : (d[1] < -0.8 ? 'bottom' : 'middle');
break;
case 'start':
label.x = -d[0] * distanceX + fromPos[0];
label.y = -d[1] * distanceY + fromPos[1];
textAlign = d[0] > 0.8 ? 'right' : (d[0] < -0.8 ? 'left' : 'center');
textVerticalAlign = d[1] > 0.8 ? 'bottom' : (d[1] < -0.8 ? 'top' : 'middle');
break;
case 'insideStartTop':
case 'insideStart':
case 'insideStartBottom':
label.x = distanceX * dir + fromPos[0];
label.y = fromPos[1] + dy;
textAlign = tangent[0] < 0 ? 'right' : 'left';
label.originX = -distanceX * dir;
label.originY = -dy;
break;
case 'insideMiddleTop':
case 'insideMiddle':
case 'insideMiddleBottom':
case 'middle':
label.x = cp[0];
label.y = cp[1] + dy;
textAlign = 'center';
label.originY = -dy;
break;
case 'insideEndTop':
case 'insideEnd':
case 'insideEndBottom':
label.x = -distanceX * dir + toPos[0];
label.y = toPos[1] + dy;
textAlign = tangent[0] >= 0 ? 'right' : 'left';
label.originX = distanceX * dir;
label.originY = -dy;
break;
}
label.scaleX = label.scaleY = invScale;
label.setStyle({
// Use the user specified text align and baseline first
verticalAlign: label.__verticalAlign || textVerticalAlign,
align: label.__align || textAlign
});
}
}