How to draw a responsive SVG path with points on it?

2.1k Views Asked by At

I am trying to draw this SVG path.

SVG path

I could achieve it using SVG Line and Curve properties for a fixed height and width using fixed coordinates.

But, I need to draw this responsively which means, the width of the path, space between the lines, the distance between each point, and the curves at the sides should be responsive.

It contains levels indicated by numbers as shown in the image, and the length of the path should be determined by the number of levels given.

While trying to draw this responsively, I was stuck at

  1. Getting the start and end-point of the Lines
  2. Getting control points for the curves
  3. Responsive adjustment of the distance between each point and space between the curves
  4. Determining the length of the path based on the number of levels given

I am trying to do these using percentages based on the parent div's width by some mathematical calculations. But, it seems it breaks some or other cases due to its complexity.

There are some other things to do along with these, but this is the top-level version of what needs to be done.

Is there any direct method or formula or calculation for achieving this? (or) Is there any other approach to draw this? (or) Are there any tutorials for learning to draw these types of SVG paths?

1

There are 1 best solutions below

3
On

After creating the path you need to calculate the position of the numbers and circles on the path. For this you need to know the length of the path calculated with the getTotalLength() method. Next you need a loop to calculate the position of the numbers on the path. For this I've used the getPointAtLength() method. On each of this pointd you create a new circle (use) element and a new text element.

Please read the comments in the code.

//constants used to create a new element in svg
const SVG_NS = "http://www.w3.org/2000/svg";
const SVG_XLINK = "http://www.w3.org/1999/xlink";
//the total length of the path
let length= thePath.getTotalLength();
//the number of points on the path
let n = 15;
let step = length/n;


for(let i= 1; i<=n; i++){
//creates a new point on the path at a given length
let point = thePath.getPointAtLength(i*step);
  
//create a new use element (or a circle) and set the center of the circle on the calculated point
let use = document.createElementNS(SVG_NS, 'use');
use.setAttributeNS(SVG_XLINK, 'xlink:href', '#gc');
use.setAttribute("x", point.x);
use.setAttribute("y", point.y); 
//create a new text element on the same point. Thr text content is the i number
let text = document.createElementNS(SVG_NS, 'text');
text.setAttribute("x", point.x);
text.setAttribute("y", point.y); 
text.textContent = i;
//append the 2 new created elements to the svg
svg.appendChild(use);
svg.appendChild(text);  
}
svg {
  border: solid;
}
text {
  fill: black;
  font-size: 4px;
  text-anchor: middle;
  dominant-baseline: middle;
}
<svg viewBox="0 0 100 80" id="svg">
  <defs>
  <g id="gc">
    <circle fill="silver" r="3" />
  </g>
  </defs>
  <path id="thePath" fill="none" stroke="black" d="M10,10H70A10,10 0 0 1 70,30H20A10,10 0 0 0 20,50H70A10,10 0 0 1 70,70H20" />
</svg>

Please observe that since the svg element has a viewBox attribute and no with it takes all the available width making it responsive.