// Draw smoothed line in non-monotone, in may cause undesired curve in extreme
// situations. This should be used when points are non-monotone neither in x or
// y dimension.
function drawNonMono(
ctx,
points,
start,
segLen,
allLen,
dir,
smoothMin,
smoothMax,
smooth,
smoothMonotone,
connectNulls
) {
var prevIdx = 0;
var idx = start;
for (var k = 0; k < segLen; k++) {
// segLen:points长度
var p = points[idx];
if (idx >= allLen || idx < 0) {
// points数组下标越界
break;
}
if (isPointNull(p)) {
if (connectNulls) {
//connectNulls为true时会跳过这个值,将前一个值和后一个值相连
idx += dir; // dir === 1
continue;
}
break;
}
if (idx === start) {
// 起始点:移动到该点;非起始点:画线
ctx[dir > 0 ? "moveTo" : "lineTo"](p[0], p[1]);
v2Copy(cp0, p);
} else {
if (smooth > 0) {
// 是否平滑绘制
var nextIdx = idx + dir;
var nextP = points[nextIdx];
if (connectNulls) {
// Find next point not null
while (nextP && isPointNull(points[nextIdx])) {
nextIdx += dir;
nextP = points[nextIdx];
}
}
var ratioNextSeg = 0.5;
var prevP = points[prevIdx];
var nextP = points[nextIdx];
// Last point
if (!nextP || isPointNull(nextP)) {
v2Copy(cp1, p);
} else {
// If next data is null in not connect case
if (isPointNull(nextP) && !connectNulls) {
nextP = p;
}
vec2.sub(v, nextP, prevP); // v = nextP - prevP
var lenPrevSeg;
var lenNextSeg;
if (smoothMonotone === "x" || smoothMonotone === "y") {
var dim = smoothMonotone === "x" ? 0 : 1;
lenPrevSeg = Math.abs(p[dim] - prevP[dim]);
lenNextSeg = Math.abs(p[dim] - nextP[dim]);
} else {
lenPrevSeg = vec2.dist(p, prevP);
lenNextSeg = vec2.dist(p, nextP);
}
// Use ratio of seg length
ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg);
scaleAndAdd(cp1, p, v, -smooth * (1 - ratioNextSeg));
}
// Smooth constraint,造成不平滑的原因
vec2Min(cp0, cp0, smoothMax); // cp0 = min(lastP, smoothMax)
vec2Max(cp0, cp0, smoothMin); // cp0 = max(cp0, smoothMin)
vec2Min(cp1, cp1, smoothMax); // cp1 = min(modifiedP, smoothMax)
vec2Max(cp1, cp1, smoothMin); // cp1 = max(cp1, smoothMin)
ctx.bezierCurveTo(
// 控制点1: cp0;控制点2: cp1;终点:p
cp0[0],
cp0[1],
cp1[0],
cp1[1],
p[0],
p[1]
);
// cp0 of next segment
scaleAndAdd(cp0, p, v, smooth * ratioNextSeg);
} else {
ctx.lineTo(p[0], p[1]);
}
}
prevIdx = idx;
idx += dir;
}
return k;
}
Echarts 计算平滑曲线新算法
// Draw smoothed line in monotone, in which only vertical or horizontal bezier
// control points will be used. This should be used when points are monotone
// either in x or y dimension.
function drawMono(
ctx,
points,
start,
segLen,
allLen,
dir,
smoothMin,
smoothMax,
smooth,
smoothMonotone,
connectNulls
) {
var prevIdx = 0;
var idx = start;
for (var k = 0; k < segLen; k++) {
var p = points[idx];
if (idx >= allLen || idx < 0) {
break;
}
if (isPointNull(p)) {
if (connectNulls) {
idx += dir;
continue;
}
break;
}
if (idx === start) {
ctx[dir > 0 ? "moveTo" : "lineTo"](p[0], p[1]);
} else {
if (smooth > 0) {
var prevP = points[prevIdx];
var dim = smoothMonotone === "y" ? 1 : 0;
// Length of control point to p, either in x or y, but not both
var ctrlLen = (p[dim] - prevP[dim]) * smooth;
v2Copy(cp0, prevP);
cp0[dim] = prevP[dim] + ctrlLen;
v2Copy(cp1, p);
cp1[dim] = p[dim] - ctrlLen;
ctx.bezierCurveTo(cp0[0], cp0[1], cp1[0], cp1[1], p[0], p[1]);
} else {
ctx.lineTo(p[0], p[1]);
}
}
prevIdx = idx;
idx += dir;
}
return k;
}