и путь SVG, который следует за контуром многоугольника SVG - PullRequest
0 голосов
/ 09 сентября 2018

Я пытаюсь создать фигуру, используя путь SVG, который следует контуру многоугольника SVG.

Мне нужно установить атрибут d элемента пути svg, потому что размер фигуры будет отличаться в зависимости от того, сколько текста содержится в элементе <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 голосов
/ 09 сентября 2018

Ради ясности я значительно упростил ваш код. Также: я решил нарисовать шестиугольник в 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>

Без сомнения, есть и другие способы сделать это. Надеюсь, вы найдете мое решение полезным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...