UNPKG

@meta2d/core

Version:

@meta2d/core: Powerful, Beautiful, Simple, Open - Web-Based 2D At Its Best .

220 lines 10.7 kB
import { LineAnimateType } from '../../pen'; import { deepClone } from '../../utils'; import { getBezierPoint, getQuadraticPoint } from './curve'; //箭头动画 export function drawArrow(pen, ctx) { const path = !ctx ? new Path2D() : ctx; let worldAnchors = pen.calculative.worldAnchors; let scale = pen.calculative.canvas.store.data.scale; let size = (pen.calculative.animateLineWidth || 6) * scale; // 箭头大小 let arrowLength = (pen.animateLineWidth * 2 || 12) * scale; // 箭头长度 if (pen.lineAnimateType === LineAnimateType.WaterDrop) { arrowLength = (pen.animateLineWidth * 4 || 24) * scale; // 水滴长度 } let d = (pen.animateInterval || 100) * scale; // 箭头间距 let smoothLenth = pen.calculative.lineWidth * (pen.calculative.lineSmooth || 0); //*scale; let lineWidth = (pen.calculative.animateLineWidth / 2 || 3) * scale; if (pen.animateReverse) { //箭头反向 arrowLength = -arrowLength; size = -size; } if (worldAnchors.length > 1) { let from; // 上一个点 let lastLength = 0; if (pen.close) { worldAnchors = deepClone(worldAnchors); worldAnchors.push(worldAnchors[0]); } if (['polyline', 'line'].includes(pen.lineName)) { for (let i = 0; i < worldAnchors.length; i++) { let pt = worldAnchors[i]; //获取箭头角度 if (from) { let angle = getAngle(from, pt); let newP = { x: from.x + ((pen.calculative.animatePos - lastLength) % d) * Math.cos((angle * Math.PI) / 180), y: from.y - ((pen.calculative.animatePos - lastLength) % d) * Math.sin((angle * Math.PI) / 180), }; if (pen.animateReverse) { newP = { x: from.x + ((pen.length - (pen.calculative.animatePos + lastLength)) % d) * Math.cos((angle * Math.PI) / 180), y: from.y - ((pen.length - (pen.calculative.animatePos + lastLength)) % d) * Math.sin((angle * Math.PI) / 180), }; } let newPTFrom = Math.sqrt((newP.x - from.x) ** 2 + (newP.y - from.y) ** 2); let ptTFrom = Math.sqrt((pt.x - from.x) ** 2 + (pt.y - from.y) ** 2); while (newPTFrom < ptTFrom) { if (((pen.animateReverse && newPTFrom - arrowLength < ptTFrom) || //不允许超出连线绘制 (!pen.animateReverse && newPTFrom > arrowLength)) && newPTFrom > (smoothLenth + arrowLength) && ptTFrom - newPTFrom > smoothLenth) { if (pen.lineAnimateType === LineAnimateType.Arrow) { arrow(path, newP, size, angle, lineWidth, arrowLength); } else if (pen.lineAnimateType === LineAnimateType.WaterDrop) { waterDrop(path, newP, pen.animateReverse, angle, lineWidth, arrowLength); } } newP.x += d * Math.cos((angle * Math.PI) / 180); newP.y -= d * Math.sin((angle * Math.PI) / 180); newPTFrom = Math.sqrt((newP.x - from.x) ** 2 + (newP.y - from.y) ** 2); } } from = pt; } } else { let from; // 上一个点 let pos = (pen.calculative.animatePos % d) / d; if (pos > 1) { pos = 1; } if (pen.animateReverse) { pos = 1 - pos; } let step = 1 / (worldAnchors[0].lineLength / d); let lastPos = pos * step; let i; worldAnchors.forEach((pt) => { let to = pt; if (from) { step = 1 / (from.lineLength / d); // pos = pos % step; if (from.next) { if (to.prev) { for (i = lastPos; i < 1; i += step) { let point = getBezierPoint(i, from, from.next, to.prev, to); let pointNext = getBezierPoint(i + 0.001, from, from.next, to.prev, to); let angle = getAngle(point, pointNext); if (pen.lineAnimateType === LineAnimateType.Arrow) { arrow(path, point, size, angle, lineWidth, arrowLength); } else if (pen.lineAnimateType === LineAnimateType.WaterDrop) { waterDrop(path, point, pen.animateReverse, angle, lineWidth, arrowLength); } } } else { for (i = lastPos; i < 1; i += step) { let point = getQuadraticPoint(i, from, from.next, to); let pointNext = getQuadraticPoint(i + 0.001, from, from.next, to); let angle = getAngle(point, pointNext); if (pen.lineAnimateType === LineAnimateType.Arrow) { arrow(path, point, size, angle, lineWidth, arrowLength); } else if (pen.lineAnimateType === LineAnimateType.WaterDrop) { waterDrop(path, point, pen.animateReverse, angle, lineWidth, arrowLength); } } } } else { if (to.prev) { for (i = lastPos; i < 1; i += step) { let point = getQuadraticPoint(i, from, to.prev, to); let pointNext = getQuadraticPoint(i + 0.001, from, to.prev, to); let angle = getAngle(point, pointNext); if (pen.lineAnimateType === LineAnimateType.Arrow) { arrow(path, point, size, angle, lineWidth, arrowLength); } else if (pen.lineAnimateType === LineAnimateType.WaterDrop) { waterDrop(path, point, pen.animateReverse, angle, lineWidth, arrowLength); } } } else { let angle = getAngle(from, to); for (i = lastPos; i < 1; i += step) { let point = { x: from.x + (to.x - from.x) * i, y: from.y + (to.y - from.y) * i, }; if (pen.lineAnimateType === LineAnimateType.Arrow) { arrow(path, point, size, angle, lineWidth, arrowLength); } else if (pen.lineAnimateType === LineAnimateType.WaterDrop) { waterDrop(path, point, pen.animateReverse, angle, lineWidth, arrowLength); } } } } } from = pt; if (!i) { i = lastPos; } else { lastPos = i - 1; } }); } } if (path instanceof Path2D) return path; } //获取两点连线和水平线的夹角 function getAngle(p1, p2) { let dx = p2.x - p1.x; let dy = p2.y - p1.y; let angle = (Math.atan(dy / dx) * 180) / Math.PI; if (p2.x >= p1.x) { angle = -angle; } else { angle = 180 - angle; } return angle; } //获取p相对rp旋转_angle后的点坐标 function getRotatePoint(p, rp, _angle) { let angle = ((180 - _angle) * Math.PI) / 180; return { x: (p.x - rp.x) * Math.cos(angle) - (p.y - rp.y) * Math.sin(angle) + rp.x, y: (p.x - rp.x) * Math.sin(angle) + (p.y - rp.y) * Math.cos(angle) + rp.y, }; } //标准箭头 function arrow(path, newP, size, angle, lineWidth, arrowLength) { let pr = getRotatePoint({ x: newP.x + size, y: newP.y + 0.57 * size }, { x: newP.x, y: newP.y }, angle); let pl = getRotatePoint({ x: newP.x + size, y: newP.y - 0.57 * size }, { x: newP.x, y: newP.y }, angle); let pr1 = getRotatePoint({ x: newP.x + size, y: newP.y + lineWidth / 2 }, { x: newP.x, y: newP.y }, angle); let pr2 = getRotatePoint({ x: newP.x + arrowLength, y: newP.y + lineWidth / 2 }, { x: newP.x, y: newP.y }, angle); let pl1 = getRotatePoint({ x: newP.x + size, y: newP.y - lineWidth / 2 }, { x: newP.x, y: newP.y }, angle); let pl2 = getRotatePoint({ x: newP.x + arrowLength, y: newP.y - lineWidth / 2 }, { x: newP.x, y: newP.y }, angle); path.moveTo(pr.x, pr.y); path.lineTo(newP.x, newP.y); path.lineTo(pl.x, pl.y); path.lineTo(pl1.x, pl1.y); path.lineTo(pl2.x, pl2.y); path.lineTo(pr2.x, pr2.y); path.lineTo(pr1.x, pr1.y); path.lineTo(pr.x, pr.y); } //水滴 function waterDrop(path, newP, reverse, angle, lineWidth, arrowLength) { let dis = lineWidth / 2; if (reverse) { dis = -lineWidth / 2; } let pl1 = getRotatePoint({ x: newP.x, y: newP.y + dis }, { x: newP.x, y: newP.y }, angle); let pE = getRotatePoint({ x: newP.x + arrowLength, y: newP.y }, { x: newP.x, y: newP.y }, angle); let rAngle = Math.PI / 2; if (reverse) { rAngle = -Math.PI / 2; } path.moveTo(newP.x, newP.y); path.arc(newP.x, newP.y, lineWidth / 2, -rAngle - angle / 180 * Math.PI, rAngle - angle / 180 * Math.PI, false); path.lineTo(pE.x, pE.y); path.lineTo(pl1.x, pl1.y); } //# sourceMappingURL=arrow.js.map