// 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.functiondrawNonMono( 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 === 1continue; }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 nullwhile (nextP &&isPointNull(points[nextIdx])) { nextIdx += dir; nextP = points[nextIdx]; } }var ratioNextSeg =0.5;var prevP = points[prevIdx];var nextP = points[nextIdx];// Last pointif (!nextP ||isPointNull(nextP)) {v2Copy(cp1, p); } else {// If next data is null in not connect caseif (isPointNull(nextP) &&!connectNulls) { nextP = p; }vec2.sub(v, nextP, prevP); // v = nextP - prevPvar 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 segmentscaleAndAdd(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.functiondrawMono( 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 bothvar 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;}