Render stripe as perpendicular tick marks along wire path

Replaces the helix-based stripe (which looked like a squiggling twisted
pair) with short perpendicular tick marks centered on the wire body,
spaced every 8px. This gives the characteristic slash/stripe appearance
of real striped wire, contained within the wire width.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-24 15:04:38 -04:00
parent e8905d312e
commit 353a2cb2ef
+43 -6
View File
@@ -970,7 +970,7 @@ class DiagramCanvas {
if (n.shield) n.shield.data(svgPath);
if (!wire.twisted_pair) {
n.main.data(svgPath);
if (n.stripe) n.stripe.data(this._computeHelixPath(pts, 20, false) || svgPath);
if (n.stripe) n.stripe.data(this._computeStripeTickPath(pts, 8, 2) || svgPath);
}
if (n.helix) n.helix.data(this._computeHelixPath(pts, wire.twist_pitch || 16, false));
if (n.helix2) n.helix2.data(this._computeHelixPath(pts, wire.twist_pitch || 16, true));
@@ -1478,6 +1478,43 @@ class DiagramCanvas {
// ── Wire rendering ────────────────────────────────────────────────────────────
// Returns SVG path of short perpendicular tick marks along the polyline — used for stripe rendering.
_computeStripeTickPath(pts, spacing = 8, halfLen = 2) {
if (!pts || pts.length < 4) return '';
const points = [];
let total = 0;
for (let i = 0; i < pts.length; i += 2) {
if (i === 0) { points.push({ x: pts[0], y: pts[1], d: 0 }); continue; }
const dx = pts[i] - pts[i-2], dy = pts[i+1] - pts[i-1];
total += Math.sqrt(dx*dx + dy*dy);
points.push({ x: pts[i], y: pts[i+1], d: total });
}
if (total < spacing) return '';
const interp = (d) => {
d = Math.max(0, Math.min(total, d));
for (let i = 1; i < points.length; i++) {
if (points[i].d >= d) {
const p0 = points[i-1], p1 = points[i];
const segLen = p1.d - p0.d;
if (segLen < 1e-6) return { x: p0.x, y: p0.y, nx: 0, ny: 1 };
const t = (d - p0.d) / segLen;
const len = Math.sqrt((p1.x-p0.x)**2 + (p1.y-p0.y)**2);
const ux = (p1.x-p0.x)/len, uy = (p1.y-p0.y)/len;
return { x: p0.x + t*(p1.x-p0.x), y: p0.y + t*(p1.y-p0.y), nx: -uy, ny: ux };
}
}
const last = points[points.length-1];
return { x: last.x, y: last.y, nx: 0, ny: 1 };
};
let d = '';
for (let dist = spacing / 2; dist <= total - spacing / 2; dist += spacing) {
const p = interp(dist);
d += `M ${(p.x - p.nx * halfLen).toFixed(1)} ${(p.y - p.ny * halfLen).toFixed(1)} `;
d += `L ${(p.x + p.nx * halfLen).toFixed(1)} ${(p.y + p.ny * halfLen).toFixed(1)} `;
}
return d.trim();
}
// Returns SVG path string of alternating bezier arcs along the polyline.
// flip=true starts arcs on the opposite side — used for the second wire of a twisted pair.
_computeHelixPath(pts, pitch = 16, flip = false) {
@@ -1547,11 +1584,11 @@ class DiagramCanvas {
let stripe = null;
if (wire.color_stripe && !wire.twisted_pair) {
const stripePath = this._computeHelixPath(pts, 20, false);
if (stripePath) {
const tickPath = this._computeStripeTickPath(pts, 8, 2);
if (tickPath) {
stripe = new Konva.Path({
data: stripePath, stroke: wire.color_stripe,
strokeWidth: 2, lineCap: "round", lineJoin: "round", fill: null, listening: false,
data: tickPath, stroke: wire.color_stripe,
strokeWidth: 2, lineCap: "round", fill: null, listening: false,
});
}
}
@@ -1654,7 +1691,7 @@ class DiagramCanvas {
if (n.shield) n.shield.data(svgPath);
if (!wire.twisted_pair) {
n.main.data(svgPath);
if (n.stripe) n.stripe.data(this._computeHelixPath(pts, 20, false) || svgPath);
if (n.stripe) n.stripe.data(this._computeStripeTickPath(pts, 8, 2) || svgPath);
}
if (n.helix) n.helix.data(this._computeHelixPath(pts, wire.twist_pitch || 16, false));
if (n.helix2) n.helix2.data(this._computeHelixPath(pts, wire.twist_pitch || 16, true));