简体   繁体   中英

Find the center of SVG groups or shapes

I need to position markers (circles) in the center of rooms on a SVG floor plan. Each room could be either a single shape - like a rectangle - or a group of shapes. The circle should cover about 1/4 of the room: radius = (width + height) / 8

The svg needs to resize to its div container. 在此处输入图像描述

After a lot of trial and error, I have come up with code that seems to work, but also looks overly complicated as I use getBBox(), getBoundingClientRect(), and matrixTransform():

  • getBBox gives me the correct width and height, but x = y = 0 for group elements
  • getBoundingClientRect + matrixTransform gives me the correct cx and cy coordinates, but not the correct room width and height.

Is there a simpler way?

 const draw = document.getElementsByTagName("svg")[0]; const NS = draw.getAttribute("xmlns"); // Get titles const titleElements = draw.getElementsByTagNameNS(NS, "title"); Array.from(titleElements).forEach((titleElement) => { let parentElement = titleElement.parentElement; let clientRect = parentElement.getBoundingClientRect(); let bbox = parentElement.getBBox(); let point = draw.createSVGPoint(); point.x = clientRect.left + clientRect.width / 2; point.y = clientRect.top + clientRect.height / 2; // Convert screen coordinates into SVG document coordinates const svgP = point.matrixTransform(draw.getScreenCTM().inverse()); // clientRect doesn't resize with the svg // let radius = (clientRect.width + clientRect.height) / 8; // bbox resizes with the svg let radius = (bbox.width + bbox.height) / 8; let circle = document.createElementNS(NS, "circle"); circle.setAttribute("cx", svgP.x.toString()); circle.setAttribute("cy", svgP.y.toString()); circle.setAttribute("r", radius.toString()); circle.setAttribute("fill", "cyan"); draw.appendChild(circle); });
 <:DOCTYPE html> <html> <head> <title>Floor Plan</title> <meta charset="UTF-8" /> </head> <body> <div id="app" style="width;300px:height;300px:"> <svg xmlns="http.//www.w3:org/2000/svg" xmlns:xlink="http.//www.w3:org/1999/xlink" xmlns:ev="http.//www.w3:org/2001/xml-events" viewBox="0 0 792 612" xml.space="preserve" color-interpolation-filters="sRGB" class="st7" > <g> <g id="group1-1" transform="translate(659,691.-186.346) rotate(60)"> <title>Space.1001</title> <g id="shape1-2"> <rect x="0" y="508.5" width="90" height="90" class="st1" /> </g> </g> <g id="group1000-10" transform="translate(482,508.-114.75) rotate(60)"> <title>Space.1000</title> <g id="shape1000-11"> <rect x="0" y="208.5" width="90" height="90" class="st4" /> </g> </g> <g id="group1002-18" transform="translate(659,691.-67.0962) rotate(60)"> <title>Space.1002</title> <g id="shape1002-19"> <rect x="0" y="508.5" width="90" height="90" class="st5" /> </g> </g> <rect x="0" y="208.5" width="90" height="90" class="st6"> <title>Space.1004</title> </rect> </g> </svg> </div> </body> </html>

Here's some code that's a bit simpler.

 const draw = document.getElementsByTagName("svg")[0]; const NS = draw.namespaceURI; // Do the rooms that are groups let rooms = document.querySelectorAll("title + g"); rooms.forEach(room => { room.appendChild( makeDot(room.getBBox()) ); }); // Do the rooms where the title is in a rect let titles = document.querySelectorAll("rect > title"); titles.forEach(title => { let rect = title.parentElement; rect.insertAdjacentElement('afterend', makeDot(rect.getBBox()) ); }); // Make the circle element function makeDot(roomBounds) { let radius = (roomBounds.width + roomBounds.height) / 8; let circle = document.createElementNS(NS, "circle"); circle.setAttribute("cx", roomBounds.x + roomBounds.width / 2); circle.setAttribute("cy", roomBounds.y + roomBounds.height / 2); circle.setAttribute("r", radius); circle.setAttribute("fill", "cyan"); return circle; }
 <div id="app" style="width:300px;height:300px;"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" viewBox="0 0 792 612" xml:space="preserve" color-interpolation-filters="sRGB" class="st7" > <g> <g id="group1-1" transform="translate(659.691,-186.346) rotate(60)"> <title>Space.1001</title> <g id="shape1-2"> <rect x="0" y="508.5" width="90" height="90" class="st1" /> </g> </g> <g id="group1000-10" transform="translate(482.508,-114.75) rotate(60)"> <title>Space.1000</title> <g id="shape1000-11"> <rect x="0" y="208.5" width="90" height="90" class="st4" /> </g> </g> <g id="group1002-18" transform="translate(659.691,-67.0962) rotate(60)"> <title>Space.1002</title> <g id="shape1002-19"> <rect x="0" y="508.5" width="90" height="90" class="st5" /> </g> </g> <rect x="0" y="208.5" width="90" height="90" class="st6"> <title>Space.1004</title> </rect> </g> </svg> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM