Формула для динамического интервала в svg

Как сделать базу динамического интервала из координат возвращенных данных?
Я хочу, чтобы, если возвращаются только одно значение, они располагались посередине. Если возвращены несколько данных, он будет скорректирован и так далее.

var prev = {
      "Prev": [{
          "type": "Prev1",
        },
        {
          "type": "Prev2",
        },
        {
          "type": "Prev3",
        },
       
      ]
    };
    
    var draw = document.getElementById('drawing');
    
    prev.Prev.forEach((p, i, arr) => {
      let x = 55;
      let y = 250/arr.length*i+50;
      draw.innerHTML += `<g transform="translate(${x} ${y})">
            <rect x="-50" y="-20" width="100" height="40" rx="10" />
            <text dominant-baseline="middle" text-anchor="middle" width="100">${p.type}</text>
            <line x1="50" y1="0" x2="100" y2="${250/arr.length-y+50}" /> 
            </g>`;
    });
    
        draw.innerHTML += `<g>
            <rect x="150" y="110" width="100" height="40" rx="10" />
            <text  x="200" y="130" dominant-baseline="middle" text-anchor="middle" width="100">BASE</text>
            </g>`;
line, rect {stroke-width: 1; stroke: navy; fill: none;}
        text {fill: navy;}
      
 <svg id="drawing" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg">
</svg>

Свободный перевод вопроса Formula for dynamic spacing in svg от участника @Jomari Ryan Ramirez.


Ответы (2 шт):

Автор решения: Alexandr_TT

Все очень просто. Вам для этого нужно вычислить верхнюю часть первого прямоугольника, а затем добавить в i раз больше расстояние от верха одного элемента до верха следующего.

var prev = {
  "Prev": [{
      "type": "Prev1",
    },
    {
      "type": "Prev2",
    },
    {
      "type": "Prev3",
    }
   
  ]
};

var draw = document.getElementById('drawing');
var RECT_HEIGHT = 40;
var RECT_SPACING = 50;
var SVG_HEIGHT = 300;

prev.Prev.forEach((p, i, arr) => {
// количество прямоугольников / элементов графика 
  let num = arr.length;
  // общая высота всех <num> 
  let totalHeight = num * RECT_HEIGHT + (num - 1) * RECT_SPACING;
  let x = 55;
  //конечная позиция = позиция первого прямоугольника + i * distance_between_rects 
  let y = (SVG_HEIGHT - totalHeight) / 2   // верх первого прямоугольника
          + i * (RECT_HEIGHT + RECT_SPACING);  // i * distance_between_rects

  draw.innerHTML += `<g transform="translate(${x} ${y})">
        <rect x="-50" y="0" width="100" height="40" rx="10" />
        <text y="20" dominant-baseline="middle" text-anchor="middle"
              width="100">${p.type}</text>
        <line x1="50" y1="20" x2="100" y2="${SVG_HEIGHT / 2 - y}" /> 
        </g>`;
});

/*
    draw.innerHTML += `<g>
        <rect x="150" y="110" width="100" height="40" rx="10" />
        <text  x="200" y="130" dominant-baseline="middle" text-anchor="middle" width="100">BASE</text>
        </g>`;
*/
svg {
  background: linen;
}
<svg id="drawing" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg">
  <style>
    line, rect {stroke-width: 1; stroke: navy; fill: none;}
    text {fill: navy;}
  </style>
</svg>

Свободный перевод ответа от участника @Paul LeBeau.

→ Ссылка
Автор решения: Alexandr_TT

Хорошо, это не проблема, это просто упражнение по внедрению. Я не привожу результат, а лишь намекаю. Это основные элементы вашего SVG. <g> группирует элементы и может перемещаться с помощью атрибута преобразования.

<svg viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg">
  <style>
    line, rect {stroke-width: 1; stroke: navy; fill: none;}
    text {fill: navy;}
  </style>
  <g transform="translate(200 150)">
    <rect x="-50" y="-20" width="100" height="40" rx="10" />
    <text dominant-baseline="middle" text-anchor="middle" width="100">Text 1</text>
    <line x1="50" y1="0" x2="100" y2="60" /> 
  </g>
</svg>

Элемент должен быть динамичным. Вы знаете размер каждого элемента и расстояние между ними. С помощью цикла forEach() вы можете перебрать все элементы в списке и «разложить» их. Я просто «добавляю» новые элементы SVG с помощью ... innerHTML + = ...

var prev = {
  "Prev": [{
      "type": "Prev1",
      "Count": 1,
      "Time": 0
    },
    {
      "type": "Prev2",
      "Count": 2,
      "Time": 0
    },
    {
      "type": "Prev3",
      "Count": 3,
      "Time": 0
    },
  ]
};

var drawing = document.getElementById('drawing');

prev.Prev.forEach((p, i, arr) => {
  let x = 55;
  let y = 250/arr.length*i+50;
  drawing.innerHTML += `<g transform="translate(${x} ${y})">
        <rect x="-50" y="-20" width="100" height="40" rx="10" />
        <text dominant-baseline="middle" text-anchor="middle" width="100">${p.type}</text>
        <line x1="50" y1="0" x2="100" y2="${250/arr.length-y+50}" /> 
      </g>`;
});
<svg id="drawing" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg">
  <style>
    line, rect {stroke-width: 1; stroke: navy; fill: none;}
    text {fill: navy;}
  </style>
</svg>

Свободный перевод ответа от участника @chrwahl.

→ Ссылка