UNPKG

@wavequery/conductor

Version:
115 lines 4.47 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EdgeComponent = void 0; class EdgeComponent { constructor(options = {}) { this.animationOffset = 0; this.animationFrame = null; this.options = { stroke: "#999", strokeWidth: 2, arrowSize: 10, animated: false, animationDuration: 1500, dashArray: [5, 5], labelOffset: 20, labelFontSize: 12, ...options, }; } render(context, edge, sourceNode, targetNode) { context.save(); // Calculate edge path const { start, end, controlPoints } = this.calculateEdgePath(sourceNode, targetNode); // Draw edge context.beginPath(); context.moveTo(start.x, start.y); if (controlPoints.length === 2) { context.bezierCurveTo(controlPoints[0].x, controlPoints[0].y, controlPoints[1].x, controlPoints[1].y, end.x, end.y); } else { context.lineTo(end.x, end.y); } // Apply style context.strokeStyle = this.options.stroke; context.lineWidth = this.options.strokeWidth; // Handle animation if (this.options.animated) { context.setLineDash(this.options.dashArray); context.lineDashOffset = -this.animationOffset; this.updateAnimation(); } context.stroke(); // Draw arrow this.drawArrow(context, end, this.calculateAngle(start, end)); // Draw label if exists if (edge.label) { this.drawLabel(context, edge.label, start, end); } context.restore(); } calculateEdgePath(source, target) { const start = { x: source.position.x, y: source.position.y }; const end = { x: target.position.x, y: target.position.y }; const controlPoints = []; // Calculate control points for curved edges if nodes are close const dx = end.x - start.x; const dy = end.y - start.y; const distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { const midX = (start.x + end.x) / 2; const midY = (start.y + end.y) / 2; const normalX = -dy / distance; const normalY = dx / distance; controlPoints.push({ x: midX + normalX * 50, y: midY + normalY * 50 }, { x: midX + normalX * 50, y: midY + normalY * 50 }); } return { start, end, controlPoints }; } calculateAngle(start, end) { return Math.atan2(end.y - start.y, end.x - start.x); } drawArrow(context, position, angle) { const arrowSize = this.options.arrowSize; context.save(); context.translate(position.x, position.y); context.rotate(angle); context.beginPath(); context.moveTo(-arrowSize, -arrowSize / 2); context.lineTo(0, 0); context.lineTo(-arrowSize, arrowSize / 2); context.strokeStyle = this.options.stroke; context.lineWidth = this.options.strokeWidth; context.stroke(); context.restore(); } drawLabel(context, label, start, end) { const midX = (start.x + end.x) / 2; const midY = (start.y + end.y) / 2; context.font = `${this.options.labelFontSize}px Arial`; context.fillStyle = this.options.stroke; context.textAlign = "center"; context.textBaseline = "middle"; // Draw background for better readability const metrics = context.measureText(label); const padding = 4; context.fillStyle = "rgba(255, 255, 255, 0.8)"; context.fillRect(midX - metrics.width / 2 - padding, midY - this.options.labelFontSize / 2 - padding, metrics.width + padding * 2, this.options.labelFontSize + padding * 2); context.fillStyle = this.options.stroke; context.fillText(label, midX, midY); } updateAnimation() { if (!this.options.animated) return; this.animationOffset = (this.animationOffset + 1) % (this.options.dashArray[0] + this.options.dashArray[1]); this.animationFrame = requestAnimationFrame(() => this.updateAnimation()); } dispose() { if (this.animationFrame !== null) { cancelAnimationFrame(this.animationFrame); } } } exports.EdgeComponent = EdgeComponent; //# sourceMappingURL=edge.js.map