Home > Software design >  Path centroid calculation
Path centroid calculation

Time:10-10

I'm trying to display an icon in the center of each path element but it doesn't look right

enter image description here

My code simply calculated the center point based on the width & height of the path

const center = {
  x: (bbox.x - svg_box.x)   bbox.width / 2,
  y: (bbox.y - svg_box.y)   bbox.height / 2,
}

JSFiddle

Can this be improved using a centroid function? Or using d3?
I could not figure out how to find the centroid of an existing path using d3.

Thank you

CodePudding user response:

D3 has two centroid methods: arc.centroid and path.centroid (from d3-geo), and none will work with path elements like you have here.

However, we can use path.centroid for getting the centroids of those paths, but it's quite hacky, and you'd be better creating your own code. That said, we can iterate over each path, getting its length and setting a dummy geoJSON object:

const pathLength = n[i].getTotalLength();
let index = 0;
const geoJSONObject = {
    "type": "Polygon",
    "coordinates": [
      []
    ]
};

Then, we move along the path and populate the geoJSON object (here 400/1237 is just a quick way to calculate the viewport values, you can use a proper matrix if you want)...

while (index < pathLength) {
    const point = n[i].getPointAtLength(index);
    geoJSONObject.coordinates[0].push([point.x * (400 / 1237), point.y * (400 / 1232)]);
    index  = precision;
};

...and finally we pass that object to path.centroid:

const centroid = path.centroid(geoJSONObject);

Here's the snippet with that solution:

const controls = d3.select(".controls"),
  path = d3.geoPath()
  .projection(d3.geoIdentity()),
  precision = 100;

d3.selectAll("path").each((_, i, n) => {
  const pathLength = n[i].getTotalLength();
  let index = 0;
  const geoJSONObject = {
    "type": "Polygon",
    "coordinates": [
      []
    ]
  };
  while (index < pathLength) {
    const point = n[i].getPointAtLength(index);
    geoJSONObject.coordinates[0].push([point.x * (400 / 1237), point.y * (400 / 1232)]);
    index  = precision;
  };
  const centroid = path.centroid(geoJSONObject);
  controls.append("div")
    .style("left", centroid[0]   "px")
    .style("top", centroid[1]   "px");
})
.container {
  position: relative;
  display: inline-flex;
}

path {
  outline: 1px solid #0F0;
}

.controls {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.controls>div {
  position: absolute;
  width: 5px;
  height: 5px;
  background-color: red;
}
<script src="https://d3js.org/d3.v7.min.js"></script>

<div >

  <div ></div>

  <?xml version="1.0" encoding="utf-8"?>
  <!-- Generator: Adobe Illustrator 25.4.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
  <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" x="0px" y="0px" viewBox="0 0 1237 1232" style="enable-background:new 0 0 1237 1232;" xml:space="preserve">
        <style type="text/css">
          .st1 {
            fill: none;
            stroke: #000000;
            stroke-miterlimit: 10;
          }

        </style>
        <g>
          <path  d="M1036.3,1040.8C893.1,896.6,750.5,753,607.8,609.4c0.1-0.4,0.3-0.8,0.4-1.2c3.4,0.4,6.9,0.8,10.3,1.4
        c37.9,6.1,75.9,12.3,113.8,18.5c40.4,6.5,80.8,13.1,121.2,19.6c40.2,6.5,80.5,13,120.7,19.5c39.9,6.5,79.8,12.9,119.7,19.4
        c36.5,5.9,72.9,11.8,109.4,17.8c1.8,0.3,3.9,1.3,4.8,2.6c0.5,0.7-1,3.2-2.1,4.5c-35.1,42-67.4,86.1-92.8,134.8
        c-20.4,39.2-36.2,80.4-51.4,121.9c-8.4,23-16.1,46.2-24.1,69.3C1037.4,1038.2,1037,1039.1,1036.3,1040.8z" />
          <path  d="M604.1,609.4c0.9,5.3,1.9,10.6,2.7,15.9c3.6,23.1,7.2,46.2,10.7,69.3c3.1,20.5,6.2,41,9.4,61.4
        c3.5,22.4,7.1,44.9,10.5,67.3c3.2,20.5,6.3,41,9.4,61.4c3.2,20.5,6.4,40.9,9.6,61.4c2.8,18.2,5.6,36.4,8.4,54.6
        c3.5,22.6,7,45.2,10.5,67.8c3.2,20.5,6.3,40.9,9.5,61.4c3.1,20.3,6.3,40.6,9.4,60.9c0.7,4.7,1.8,9.5,2.3,14.2
        c0.2,1.8,0.2,4.5-0.9,5.5c-0.9,0.8-3.7,0.2-5.3-0.4c-43.3-17.2-87-33.3-131.7-46.7c-31.9-9.5-64.4-14.5-97.8-15.8
        c-45-1.8-89.9,0.3-135.9,2.9c92.9-180.7,185.4-360.9,278-541.1C603.4,609.4,603.8,609.4,604.1,609.4z" />
          <path  d="M511.8,1.5c31.1,200.5,62,400.4,93,600.2c-0.3,0.2-0.6,0.4-0.9,0.6c-2.2-2.1-4.5-4.2-6.7-6.3
        c-26.4-26.6-52.8-53.3-79.2-79.9c-22.7-22.8-45.4-45.6-68.1-68.4c-49.7-50-99.3-100-149-150c-36.8-37-73.5-74-110.3-111
        c-3.8-3.8-7.5-7.5-11.1-11.5c-1.3-1.5-2.1-3.5-3.1-5.2c1.7-0.8,3.4-1.9,5.2-2.3c21.6-4.8,43.3-9,64.7-14.4
        c44.9-11.3,89.2-24.6,130.9-44.9c39-19,72.8-45.5,103.9-75.5C491.4,22.9,501.1,12.4,511.8,1.5z" />
          <path  d="M600.9,606.3c-10.5,5.3-21,10.6-31.5,16c-69.1,34.9-138.3,69.8-207.4,104.7c-62.6,31.6-125.2,63.2-187.7,94.9
        c-36.4,18.4-72.8,36.9-109.2,55.3c-0.9,0.5-1.7,1.1-2.7,1.3c-1.4,0.4-2.8,0.5-4.2,0.7c-0.2-1.6-0.9-3.2-0.6-4.6
        c1.6-9.2,3.8-18.2,4.9-27.5c2.3-20.2,4.6-40.3,5.7-60.6c1.8-30.3,0.1-60.6-4-90.7c-5.7-41.4-15.8-81.6-31.6-120.3
        C23.7,554,13,533.3,3.2,512.2c-0.5-1-1-2-2.1-4.3c200.5,32.5,400.1,64.8,599.6,97C600.7,605.4,600.8,605.9,600.9,606.3z" />
          <path  d="M1150.2,329.6c-180,90.5-359.5,180.8-540.4,271.8c1.2-2.8,1.6-4.3,2.3-5.7c30.1-58.7,60.3-117.3,90.4-176
        c22.5-43.9,45-87.7,67.5-131.6c37.8-73.6,75.6-147.3,113.5-220.8c0.8-1.6,2.5-2.7,3.8-4.1c1.2,1.5,2.8,2.7,3.7,4.4
        c24.3,46.6,51.6,91.3,84.4,132.6c33.1,41.6,74.4,73.3,119.8,99.9c16.9,9.9,34.6,18.6,51.9,27.8
        C1148.1,328.4,1148.9,328.9,1150.2,329.6z" />
        </g>
      </svg>
</div>

  • Related