以及遵循svg多边形轮廓的svg路径

时间:2018-09-09 06:17:48

标签: html math svg

我正在尝试使用遵循svg多边形轮廓的svg路径创建形状。

我需要设置svg path元素的d属性,因为形状的大小会有所不同,具体取决于添加到文档中的<text />元素中有多少文本。我将使用多种形状,但为了简洁起见,这里仅展示一种形状。

我的逻辑是尝试基本上从中间开始,向右下移动60度,再回到中间,然后向左下移动60度,然后加入框的左边。

我的形状不太正确。有很多问题:

  1. 形状与六边形的点不对齐。

  2. 出现在对角线上的每条平线或H的长度都不相同。

  3. 有一条流氓线试图连接回形状点。

  4. 我需要在拐角处添加曲线,我不确定该怎么做。

const getPoint = ({
  sides,
  size,
  center,
  rotate,
  side
}) => {
  const degrees = (360 / sides) * side - rotate;
  const radians = (Math.PI / 180) * degrees;

  return {
    x: center.x + size * Math.cos(radians),
    y: center.y + size * Math.sin(radians)
  };
};

const path = document.querySelector('path');
const gRef = document.querySelector('.hierarchy-label__container');

gRef.setAttribute('transform', 'translate(0, -40)');

const gbBox = gRef.getBBox();
let startingX = gbBox.x + gbBox.width / 2;
const startingY = gbBox.y + gbBox.height;

startingX = startingX - 0.7;

const [bottomRight, bottomLeft] = [1, 4].map((side) =>
  getPoint({
    sides: 6,
    size: 30,
    center: { x: startingX, y: startingY },
    side,
    rotate: 30
  })
);

const bottomRightCoords = `${bottomRight.x} ${bottomRight.y}`;

path.setAttribute(
  'd',
  `M ${startingX} ${startingY} L ${bottomRightCoords} H ${gbBox.width} M ${startingX} ${startingY} L ${
    bottomLeft.x
  } ${bottomRight.y}  H -${gbBox.width + 4} V -${gbBox.height} H ${gbBox.width} L ${gbBox.width} ${
    bottomRight.y
  } M ${startingX} ${startingY} Z`
);
.hierarchy-label__text {
  fill: white;
  text-anchor: middle;
  font-size: 1.2rem;
}
<svg preserveAspectRatio="xMinYMin meet" viewBox="0 0 990 759">
  <g class="vx-group vx-cluster" transform="translate(100, 100)">
<g class="vx-group" transform="translate(0, 0)">
  <g class="vx-group node-vertical__container" transform="translate(490, 0)">
    <polygon points="25.98076211353316,-14.999999999999998 25.98076211353316,14.999999999999998 1.83697019872103e-15,30 -25.98076211353316,14.999999999999998 -25.980762113533157,-15.000000000000004 -5.510910596163089e-15,-30"></polygon>
    <g class="vx-group node-vertical__business-unit" transform="translate(0, 0)">
      <use xlink:href="#icon-BusinessUnit"></use>
    </g>
    <g class="hierarchy-label__container" transform="translate(0,-40)">
      <text class="hierarchy-label__text" width="50" fill="white" x="0" y="0" text-anchor="middle" style="pointer-events: none;">
        <tspan x="0" dy="0em">Finance</tspan>
      </text>
      <path></path>
    </g>
     </g>
   </g>
</g>
</svg>

1 个答案:

答案 0 :(得分:1)

为了清楚起见,我简化了很多代码。另外:我选择在JavaScript中绘制六边形,以便能够使用六边形顶点绘制放置文本的路径。

请阅读代码的注释

function drawHex(r){
  
  // this function draws a hexagon with the center in 0,0
  // and returns the array of points
  // r is the radius of the circumscribed circle
  let pointsRy = [];
       let a = Math.PI/3;
       for( let i = 0; i < 6; i++ ){
            let aRad = (a*i) - Math.PI/2;
            let Xp = parseFloat(r * Math.cos( aRad )).toFixed(3);
            let Yp = parseFloat(r * Math.sin( aRad )).toFixed(3);
            pointsRy.push({x:Xp,y:Yp,a:aRad});
      }
  // the points for the hexagon
  let points = pointsRy.map(p => `${p.x}, ${p.y}`).join(" ");
  hex.setAttributeNS(null,"points", points)
  // the function returns the array of points
  return pointsRy;
}

// ry: the array of points used to draw the hexagon: I'll be using the first & the second point to drae the textRect path
let ry = drawHex(30);

function drawTextPath(W,H){
  // W: the width of the text "rectangle"
  // H: the height of the text "rectangle"
  // the textRect & the text art translated upwards (in y). Please see svg
  let w = W/2 - (Number(ry[1].x) - Number(ry[0].x));
  let d = `M${ry[0].x},${ry[0].y} L${ry[1].x},${ry[1].y} h${w} v-${H} h-${W} v${H} h${w}`;

  
  textRect.setAttributeNS(null,"d",d)
  
}

drawTextPath(180,50)
svg{font-family: "Century Gothic",CenturyGothic,AppleGothic,sans-serif;}
text{fill:white; text-anchor:middle;pointer-events: none;}
<svg viewBox="-100 -70 200 200">
<polygon id="hex" /> 
<g transform="translate(0,-6)">
<path id="textRect"   />
<text y="-40">
        <tspan>Finance</tspan>
</text>
</g> 
</svg>

毫无疑问,还有其他方法可以得出此结果。希望您会发现我的解决方案有用。