Angular 10中如何用SVG连接不同组件内动态创建的div?
Hey there! Let's work through this problem of drawing a line between your dynamic elements el1 and el2 in the SVG component. First, let's fix the obvious typo in your code, then break down how to calculate the correct coordinates.
Step 1: Fix the ID Typo
First, you're accidentally grabbing el1 twice for both elements. Let's correct that line:
const elTwoHtml: HTMLElement | null = document.getElementById('el2'); // Fixed ID from el1 to el2
Step 2: Understand Coordinate Systems
The key here is converting the viewport-relative coordinates (from getBoundingClientRect()) to container-relative coordinates since your SVG is absolutely positioned inside the containerRef div.
Here's what you need to account for:
getBoundingClientRect()returns positions relative to the browser's viewport, not the parent container.- Your SVG is positioned absolutely inside
containerRef, so we need to subtract the container's viewport position from the elements' viewport positions to get coordinates relative to the container. - For a clean line, you'll probably want to connect the centers of
el1andel2instead of their top-left corners.
Step 3: Calculate the Line Coordinates
Here's the updated createLine() method with full coordinate calculation. We'll also add safety checks in case the elements haven't rendered yet (since they're dynamic):
import { Component, ViewChild, ElementRef } from '@angular/core'; // ... your component decorator here export class LineComponent { @ViewChild('containerRef') containerRef!: ElementRef; public linePositionX1 = 0; public linePositionY1 = 0; public linePositionX2 = 0; public linePositionY2 = 0; public createLine(): void { // Grab the elements (with null checks) const elOneHtml: HTMLElement | null = document.getElementById('el1'); const elTwoHtml: HTMLElement | null = document.getElementById('el2'); const containerElement = this.containerRef.nativeElement; if (!elOneHtml || !elTwoHtml || !containerElement) { console.warn('One or more elements/container not found'); return; } // Get viewport-relative rects const parentDomRect: DOMRect = containerElement.getBoundingClientRect(); const elOneRect: DOMRect = elOneHtml.getBoundingClientRect(); const elTwoRect: DOMRect = elTwoHtml.getBoundingClientRect(); // Account for container scroll (if your container is scrollable) const containerScrollLeft = containerElement.scrollLeft; const containerScrollTop = containerElement.scrollTop; // Calculate center coordinates relative to the container // For el1 this.linePositionX1 = (elOneRect.left + elOneRect.width / 2) - parentDomRect.left + containerScrollLeft; this.linePositionY1 = (elOneRect.top + elOneRect.height / 2) - parentDomRect.top + containerScrollTop; // For el2 this.linePositionX2 = (elTwoRect.left + elTwoRect.width / 2) - parentDomRect.left + containerScrollLeft; this.linePositionY2 = (elTwoRect.top + elTwoRect.height / 2) - parentDomRect.top + containerScrollTop; } }
Key Explanations:
- Null Checks: We make sure all elements exist before calculations to avoid runtime errors, especially since
el1andel2are dynamically created. - Center Calculation: Adding
element.width/2andelement.height/2to the top-left position gives us the element's center point. - Scroll Adjustment: If your container is scrollable, we add
containerScrollLeftandcontainerScrollTopto correct for any scrolling that shifts the elements' positions relative to the container.
Step 4: Ensure the Method Runs at the Right Time
Since el1 and el2 are dynamically created, you need to call createLine() after these elements are rendered in the DOM. Some common ways to do this:
- Use
ngAfterViewChecked()(but add a guard to avoid infinite loops, since this runs on every change detection cycle). - Trigger
createLine()from the component that dynamically createsel1/el2(e.g., after a data load or component initialization). - Use a
ViewChildwithngAfterViewInit()if the elements are part of a child component's template.
Bonus: Clean Up SVG Positioning
Make sure your container has position: relative so the absolute-positioned SVG is correctly contained within it:
.container { position: relative; /* Add other styles like width, height as needed */ }
内容的提问来源于stack exchange,提问作者Anna

