@meta2d/core
Version:
@meta2d/core: Powerful, Beautiful, Simple, Open - Web-Based 2D At Its Best .
137 lines • 4.6 kB
JavaScript
import { LineAnimateType, PenType } from '../../pen/model';
import { getLinePoints } from './line';
function lineHasArrowOrWaterDropAnimate(pen) {
const t = pen.lineAnimateType;
if (t == null) {
return false;
}
const list = Array.isArray(t) ? t : [t];
return list.some((x) => x === LineAnimateType.Arrow || x === LineAnimateType.WaterDrop);
}
function strokeChevronV(ctx, armLength, halfSpread) {
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(-armLength, -halfSpread);
ctx.moveTo(0, 0);
ctx.lineTo(-armLength, halfSpread);
ctx.stroke();
}
export function drawDefaultLineDirectionChevron(ctx, x, y, angleRad, armLength, halfSpread) {
ctx.save();
ctx.translate(x, y);
ctx.rotate(angleRad);
strokeChevronV(ctx, armLength, halfSpread);
ctx.restore();
}
function pointAndAngleOnPolyline(pts, segs, dist) {
// 二分查找找到距离所在的线段
let left = 0;
let right = segs.length - 1;
while (right - left > 1) {
const mid = (left + right) >> 1;
if (segs[mid] <= dist) {
left = mid;
}
else {
right = mid;
}
}
// 计算线段上的点
const segmentIndex = left;
const segmentStart = pts[segmentIndex];
const segmentEnd = pts[segmentIndex + 1];
const segmentLength = segs[segmentIndex + 1] - segs[segmentIndex];
// 线性插值计算点坐标
const t = segmentLength > 1e-6 ? (dist - segs[segmentIndex]) / segmentLength : 0;
const pointX = segmentStart.x + t * (segmentEnd.x - segmentStart.x);
const pointY = segmentStart.y + t * (segmentEnd.y - segmentStart.y);
// 计算角度
const angle = Math.atan2(segmentEnd.y - segmentStart.y, segmentEnd.x - segmentStart.x);
return { x: pointX, y: pointY, ang: angle };
}
export function renderLineDirectionMarkers(ctx, pen, store) {
if (pen.type !== PenType.Line) {
return;
}
const show = pen.dirMarkers || store.options.dirMarkers;
if (!show) {
return;
}
if (pen.calculative.pencil) {
return;
}
const anchors = pen.calculative.worldAnchors;
if (!anchors || anchors.length < 2) {
return;
}
if (pen.calculative.animatePos && lineHasArrowOrWaterDropAnimate(pen)) {
return;
}
const drawer = store.options.drawDirMarkers;
ctx.save();
ctx.setLineDash([]);
ctx.shadowBlur = 0;
ctx.shadowColor = '';
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
const pts = getLinePoints(pen);
if (pts.length < 2) {
ctx.restore();
return;
}
const scale = store.data.scale;
const interval = (pen.dirMarkerInterval ??
store.options.dirMarkerInterval ??
40) * scale;
const color = pen.dirMarkerColor ??
store.options.dirMarkerColor ??
'#ffffff';
const lineW = pen.calculative.lineWidth || 2;
const strokeW = (pen.dirMarkerLineWidth ?? store.options.dirMarkerLineWidth) != null
? (pen.dirMarkerLineWidth ?? store.options.dirMarkerLineWidth) * scale
: Math.min(lineW * 0.38, Math.max(0.75, lineW * 0.14));
const segs = [0]; // 各个点到起点的累计距离,方便后续根据方向标记的距离计算位置
let totalLen = 0;
for (let i = 0; i < pts.length - 1; i++) {
const dx = pts[i + 1].x - pts[i].x;
const dy = pts[i + 1].y - pts[i].y;
totalLen += Math.sqrt(dx * dx + dy * dy);
segs.push(totalLen);
}
if (totalLen <= 1e-6) {
ctx.restore();
return;
}
let ds = [];
for (let d = interval / 2; d < totalLen; d += interval) {
ds.push(d);
}
if (ds.length === 0 || ds.length === 1) {
ds = [totalLen / 2];
}
if (drawer) {
ctx.strokeStyle = color;
ctx.lineWidth = strokeW;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
for (const d of ds) {
const { x, y, ang } = pointAndAngleOnPolyline(pts, segs, d);
drawer(ctx, x, y, ang, color, pen);
}
}
else {
const innerW = Math.max(0, lineW - strokeW);
const halfSpread = innerW * 0.38;
const armLength = lineW * 0.52;
ctx.strokeStyle = color;
ctx.lineWidth = strokeW;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
for (const d of ds) {
const { x, y, ang } = pointAndAngleOnPolyline(pts, segs, d);
drawDefaultLineDirectionChevron(ctx, x, y, ang, armLength, halfSpread);
}
}
ctx.restore();
}
//# sourceMappingURL=dirMarkers.js.map