簡體   English   中英

如何獲得內部SVG元素相對於外部SVG元素視口的位置?

[英]How do I get an internal SVG element's position relative to the viewport of an outer SVG element?

假設我有一個包含一些東西的SVG元素:

<div style="margin-left:50px; width: 100%; min-height: 400px;">
  <svg>
    <g transform="translate(34.34,47.5) scale(0.345)" height="100%" width="100%">
      <svg x="20" y ="50" style="overflow: visible">
        <circle cx="0" cy="0" r="35" stroke="red" fill="blue">
        <text>a bunch of text</text>
      </svg>
      <line />
    </g>
  <svg>
<div>

我試圖找到<g>相對於外部<svg>元素的視口的中心位置,這樣我就可以將<g>轉換為在外部<svg>居中,並將其縮放以適合。

我能夠使用getBoundingClientRect()並調整變換比例,但這在Firefox中不起作用,因為<g>容器內的<g> <svg>元素不受約束到其顯示部分的邊界框內容(而不是外部<svg>大小,有一些縮放)。

可能有一個使用createSVGPoint()getScreenCTM()getCTM()的解決方案,但坦率地說,我不確定我應該使用什么。

沒有viewBox屬性的SVG的寬度為300px,高度為150px。 我添加了一個viewBox="0 0 300 150" 你可以刪除它。

我還添加了一個矩形,以便能夠看到<g>元素的位置和大小。 你也可以刪除它。

我如何使<g>元素居中 :由於<g>元素被轉換,獲得它的大小和位置的最簡單方法是將<g>元素包裝在另一個元素中,在這種情況下<g id="wrap">接下來我可以獲得wrap的邊界框: wrap.getBBox()

為了使包裹居中,我需要知道主svg畫布的中心:x = 300/2; Y =二分之一百五十。 現在我可以將包裹翻譯成中心

 let c = {x:150,y:75}//the center of the main svg element let bb = wrap.getBBox()//the bounding box of the wrap let transformation = `translate(${cx - bb.x - bb.width/2}, ${cy - bb.y - bb.height/2})` wrap.setAttributeNS(null,"transform",transformation) 
 svg{border:1px solid;width:100vh;} text{fill:black;} path{fill:none;stroke:black} 
 <div style="margin-left:50px; width: 100%; min-height: 400px;"> <svg id="main" viewBox="0 0 300 150" > <g id="wrap"> <rect x="29.165" y="47.5" width="45.03" height="29.325" fill="gold" fill-opacity=".5" /> <g transform="translate(34.34,47.5) scale(0.345)" height="100%" width="100%"> <svg x="20" y ="50" style="overflow: visible"> <circle cx="0" cy="0" r="35" stroke="red" fill="blue"/> <text>a bunch of text</text> </svg> <line /> </g> </g> <path d="M0,0L300,150M0,150L300,0" /> <svg> <div> 

我希望這就是你所要求的。

我設法使用d3.zoom轉換方法(我們使用d3.zoom管理轉換/縮放轉換)和SVGElement.getBBox()來找出解決方案。 我最初使用的是這種方法,但搞砸了計算; 這種方式雖然有效。

 const selection = d3.select(group); const zoomBehavior = d3.zoom().on('zoom', () => { selectionTransform = d3.event.transform; }); selection.call(zoomBehavior); const scaleAndTransformTo = () => { selection.call(zoomBehavior.translateBy, Math.random() * 100, Math.random() * 150); group.setAttribute("transform", selectionTransform.toString()); } scaleAndTransformTo(); reset.addEventListener('click', scaleAndTransformTo); run.addEventListener('click', () => { const { width: containerWidth, height: containerHeight } = container.getBoundingClientRect(); const containerCenter = [containerWidth / 2, containerHeight / 2]; const { height, width, x, y } = group.getBBox(); const nodeBBoxCenter = [x + (width / 2), y + (height / 2)]; // Apply the current interpolated translate/scale to the BBox center to get the actual position const groupCenterCoords = selectionTransform.apply(nodeBBoxCenter); const translationOffset = [ (containerCenter[0] - groupCenterCoords[0]) / selectionTransform.k, (containerCenter[1] - groupCenterCoords[1]) / selectionTransform.k, ]; selection.call(zoomBehavior.translateBy, ...translationOffset); group.setAttribute("transform", selectionTransform.toString()); }); 
 #page { display: flex; flex-direction: column; position: relative; align-items: stretch; margin-left: 100px; } #container { background-color: grey; flex-grow: 1; flex-shrink: 0; min-height: 500px; border: 1px solid red; } #group > svg { overflow: visible; } #group > svg > circle { overflow: visible; } text { fill: black; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <div id="page"> <div> <button id="run">Run</button> <button id="reset">Reset</button> </div> <svg id="container"> <gx="0" y="0" id="group" width="100%" height="100%"> <line x1="20" y1="50" x2="150" y2="150" stroke="brown" /> <svg x="20" y ="50"> <circle cx="0" cy="0" r="35" stroke="red" fill="blue"> <text x="35" y="0" height="100%" width="100%">a bunch of text</text> </svg> <line x1="100" y1="350" x2="160" y2="340" stroke="brown" /> <svg x="100" y ="350"> <circle cx="0" cy="0" r="35" stroke="red" fill="blue"> <text x="35" y="0" height="100%" width="100%">a bunch of text 3</text> </svg> </g> <svg> <div> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM