admin管理员组

文章数量:1397031

I want to position elements on along an SVG curve. I found that we can use textpath to position text along the path of an SVG can we do the same with list-elements? If so how to achieve that functionality

Html for positioning text along an SVG

<svg viewBox="0 0 425 300">
    <path id="curve"
        d="M6,150C49.63,93,105.79,36.65,156.2,47.55,207.89,58.74,213,131.91,264,150c40.67,14.43,108.57-6.91,229-145" />
    <text x="25">
        <textPath xlink:href="#curve">
            This text is now curved
        </textPath>
    </text>
</svg>

CSS for the same - Just makes it look nice

body {
  background-color: #333;
  font-family: 'Luckiest Guy', cursive;
  font-size: 40px;
}

path {
  fill: transparent;
}

text {
  fill: #FF9800;
}  

body {
  background-color: #333;
  font-family: 'Luckiest Guy', cursive;
  font-size: 40px;
}

path {
  fill: transparent;
}

text {
  fill: #FF9800;
}
<svg viewBox="0 0 425 300">
    <path id="curve"
        d="M6,150C49.63,93,105.79,36.65,156.2,47.55,207.89,58.74,213,131.91,264,150c40.67,14.43,108.57-6.91,229-145" />
    <text x="25">
        <textPath xlink:href="#curve">
            This text is now curved
        </textPath>
    </text>
</svg>

I want to position elements on along an SVG curve. I found that we can use textpath to position text along the path of an SVG can we do the same with list-elements? If so how to achieve that functionality

Html for positioning text along an SVG

<svg viewBox="0 0 425 300">
    <path id="curve"
        d="M6,150C49.63,93,105.79,36.65,156.2,47.55,207.89,58.74,213,131.91,264,150c40.67,14.43,108.57-6.91,229-145" />
    <text x="25">
        <textPath xlink:href="#curve">
            This text is now curved
        </textPath>
    </text>
</svg>

CSS for the same - Just makes it look nice

body {
  background-color: #333;
  font-family: 'Luckiest Guy', cursive;
  font-size: 40px;
}

path {
  fill: transparent;
}

text {
  fill: #FF9800;
}  

body {
  background-color: #333;
  font-family: 'Luckiest Guy', cursive;
  font-size: 40px;
}

path {
  fill: transparent;
}

text {
  fill: #FF9800;
}
<svg viewBox="0 0 425 300">
    <path id="curve"
        d="M6,150C49.63,93,105.79,36.65,156.2,47.55,207.89,58.74,213,131.91,264,150c40.67,14.43,108.57-6.91,229-145" />
    <text x="25">
        <textPath xlink:href="#curve">
            This text is now curved
        </textPath>
    </text>
</svg>

Can I achieve this functionality for other elements? list elements for example

Note: My final objective is to position small circles (filled) along the curve that are equally spaced.

I'm not very well versed with CSS so if you could point me to resources that will help me achieve this functionality I'll be very grateful

Thanks in Advance

Share Improve this question edited Jun 20, 2021 at 19:31 Alexandr_TT 14.6k3 gold badges31 silver badges58 bronze badges asked Jun 11, 2021 at 16:29 Franticsword546Franticsword546 836 bronze badges 3
  • Why do you mention "list elements" twice? That normally means text, so your question is troubling me. Do you want that, or simply just the circles. Someone asked a very similar question a week or two ago, but appeared to not be happy with the answer they got. Was that you? – Paul LeBeau Commented Jun 12, 2021 at 8:13
  • Does "along the curve equaly spaced" mean "spread to fill the length of the curve", or just "at a specified spacing from one another starting at the beginning"? A mockup image would be useful. – Paul LeBeau Commented Jun 12, 2021 at 8:18
  • By along the curve equally spaced I meant that the circles should be spread to fill the length of the curve – Franticsword546 Commented Jun 14, 2021 at 3:41
Add a ment  | 

3 Answers 3

Reset to default 6

You can't do what you want with CSS.

You'll need to use some Javascript. Here's a little example where you can adjust the number of circles, and they will be spaced out evenly along the total length of the path.

let countField = document.getElementById("count");


function updateCircles()
{
   let n = countField.value;
   // Find the curve path element
   let curve = document.getElementById("curve");
   // Get the total length of the path
   let curveLength = curve.getTotalLength();
   // Calculate the spacing between the circles
   let spacing = curveLength / (n - 1);
   
   let svg = curve.ownerSVGElement;
   // Remove any existing circles
   let oldCircles = svg.querySelectorAll("circle");
   oldCircles.forEach(oldCircle => svg.removeChild(oldCircle));
   
   // Add the n new circles
   for (var i = 0; i < n; i++)
   {
      // Get the x,y position of a point x along the path
      let coords = curve.getPointAtLength(i * spacing);
      // Make a circle
      let circle = document.createElementNS(svg.namespaceURI, "circle");
      circle.cx.baseVal.value = coords.x;
      circle.cy.baseVal.value = coords.y;
      circle.r.baseVal.value = 6;
      // Append it to the SVG
      svg.appendChild(circle);
   }
}


// Update the circles at the start to show the initial set of circles
updateCircles();
// Update the circles whenever the input changes
countField.addEventListener("input", updateCircles);
path {
  fill: none;
  stroke: linen;
}

circle {
  fill: rgba(0,0,0, 0.5);
}
<svg viewBox="0 0 500 160">
    <path id="curve"
        d="M6,150C49.63,93,105.79,36.65,156.2,47.55,207.89,58.74,213,131.91,264,150c40.67,14.43,108.57-6.91,229-145" />
</svg>


<input type="range" id="count" value="4" min="3" max="32"/>

Note: My final objective is to position small circles (filled) along the curve that are equally spaced.

textPath is used to place text along a curve. But you can use Unicode characters instead of text characters.

By using textPath and placing unicode characters inside

<tspan dx =" 5 "fill =" gold "> &#9899; </ tspan> tags, you can easily place as many circles as you like on one curve.

Here is a link to the unicode characters of the various circles.

Unicode characters can be styled - fill =" red ", resized - font-size =" 32px " set the distance between circles dx =" 10 "

<svg width="600" height="400" viewBox="80 100 400 300">
 <path id="pathChain" d="M100,200 C100,100 250,100 250,200 S 400,300 400,200" stroke="skyblue" fill="none"/>
<text font-size="14px" x="0" y="0" font-family="Times New Roman" fill="grey" shape-rendering ="crispEdges" >
<textPath id="result"    xlink:href="#pathChain">
  <tspan dx="0" dy="-2" fill="green" > &#9899; </tspan> <tspan dx="5" dy="-2" fill="gold"> &#9899;</tspan><tspan dx="5" fill="crimson"> &#9899;</tspan><tspan dx="10" fill="dodgerblue">  &#9899;</tspan><tspan dx="0" fill="green" > &#9899; </tspan> <tspan dx="5" fill="gold"> &#9899;</tspan><tspan dx="5" fill="crimson"> &#9899;</tspan><tspan dx="10" fill="dodgerblue">  &#9899;</tspan><tspan dx="0" fill="green" > &#9899; </tspan> <tspan dx="5" fill="gold"> &#9899;</tspan><tspan dx="5" fill="crimson"> &#9899;</tspan><tspan dx="10" fill="dodgerblue">  &#9899;</tspan><tspan dx="0" fill="green" > &#9899; </tspan> <tspan dx="5" fill="gold"> &#9899;</tspan><tspan dx="5" fill="crimson"> &#9899;</tspan><tspan dx="10" fill="dodgerblue">  &#9899;</tspan>
  </textPath>
</text>             
</svg>

Another example that mimics the chain using unicode characters
Added animation of chain links movement

<svg width="600" height="400" viewBox="100 100 400 300">
 <path id="pathChain" d="M100,200 C100,100 250,100 250,200 S 400,300 400,200" stroke="grey" fill="none"/>
<text font-size="36"  font-family="Times New Roman" fill="grey" >
  <textPath id="result"    xlink:href="#pathChain">
  <tspan dx="0" > &#7441; </tspan> <tspan dx="-15">   &#45; </tspan><tspan dx="-15"> &#7441;</tspan><tspan dx="-15">   &#45;</tspan><tspan dx="-15">   &#7441; </tspan><tspan dx="-15">   &#45; </tspan><tspan dx="-15"> &#7441;</tspan><tspan dx="-15">   &#45;</tspan><tspan dx="-15">   &#7441; </tspan><tspan dx="-15">   &#45; </tspan><tspan dx="-15"> &#7441;</tspan><tspan dx="-15">   &#45;</tspan><tspan dx="-15">   &#7441; </tspan><tspan dx="-15">   &#45; </tspan><tspan dx="-15"> &#7441;</tspan><tspan dx="-15">   &#45;</tspan><tspan dx="-15">   &#7441; </tspan><tspan dx="-15">   &#45; </tspan><tspan dx="-15"> &#7441;</tspan><tspan dx="-15">   &#45;</tspan><tspan dx="-15">   &#7441; </tspan>
<animate  dur="10s" repeatCount="2" attributeName="startOffset" values="1%;55%;1%"/> 
</textPath>
</text>             
</svg>   

You can't place shapes arbitrarily along a path in SVG using just CSS. Your choices here are:

  • Don't use a shape, use a text element with tabs and circle characters instead ( e.g. Unicode circle (U+23FA)) and change the font-color to whatever you want
  • Use a marker - but placement of these is set to the start, middle & end of each curve segment (marker tutorial)
  • Use javascript (e.g. pointAtLength) to calculate the locations of points along a path that you would like to draw circles and set the cx, cy of your circles to those points.

本文标签: javascriptPosition any kind of elements on SVG CurvesStack Overflow