Search code examples
javascripthtmlsvgnamespacescreateelement

How to dynamically create SVG text elements using JS


So, I have an SVG element that is a text. I would like to dynamically create more SVG text elements of exactly the same kind using javascript. (preferably using a for loop of some kind). One option would just to hardcode in the values, but I rather not do that. Here is my code:

var overlapThreshold = "50%";
var name_count = 0;
Draggable.create(".seat_name", {
  bounds: "svg",
  onDrag: function(e) {
    if (this.hitTest("#test1", overlapThreshold)) {
      document.getElementById("test1").setAttribute('fill', 'url(#gradRed)');
    } else {
      document.getElementById("test1").setAttribute('fill', 'url(#gradGreen)');
    }
  }
});

function change_name(event) {
  var name = prompt("Enter a New Name:");
  if (name != null && name != "") {
    event.target.textContent = name;
  }
}
  <button id="test_button" onclick="create_name_tags()">Test</button> <svg height="1000" width="1000">
  <defs>
    <lineargradient id="gradGreen" x1="0%" x2="100%" y1="0%" y2="0%">
      <stop offset="0%" style="stop-color:rgb(152, 251, 152);stop-opacity:1"></stop>
      <stop offset="100%" style="stop-color:rgb(0, 128, 0);stop-opacity:1"></stop>
    </lineargradient>
    <lineargradient id="gradRed" x1="0%" x2="100%" y1="0%" y2="0%">
      <stop offset="0%" style="stop-color:rgb(255, 0, 0);stop-opacity:1"></stop>
      <stop offset="100%" style="stop-color:rgb(178, 34, 34);stop-opacity:1"></stop>
    </lineargradient>
  </defs>
  <g class="circle_seat" id="circle_seats">
    <circle cx="70" cy="200" fill="url(#gradGreen)" id="test1" id="seat1" r="40" stroke="black" stroke-width="1"></circle>
  </g>
  <g class="seat_name" id="seat_name1">
    <text fill="#black" font-family="Verdana" font-size="20" id="seat1_details" ondblclick="change_name(event)" x="250" y="210">
      BLANK
    </text>
  </g>
  </svg>


Solution

  • This is how I create text dynamically. You will need to define an object with the text properties and the text content.

    const SVG_NS = "http://www.w3.org/2000/svg";
    // an object to define the properties and text content of the text element 
    let o = {
      props: {
        x: 50,
        y: 15,
        "dominant-baseline": "middle",
        "text-anchor": "middle"
      },
      txtConent: "test text"
    };
    
    // a function to create a text element 
    function drawText(o, parent) {
      // create a new text element
      let text = document.createElementNS(SVG_NS, "text");
      //set the attributes for the text
      for (var name in o.props) {
        if (o.props.hasOwnProperty(name)) {
          text.setAttributeNS(null, name, o.props[name]);
        }
      }
      // set the text content
      text.textContent = o.txtConent;
      // append the text to an svg element of your choice
      parent.appendChild(text);
      return text;
    }
    
    drawText(o, theSvg);
    svg{border:1px solid}
    <svg id="theSvg" viewBox="0 0 100 30"></svg>

    If you also need a way to change the text content dynamically this is how I would do it:

    const SVG_NS = "http://www.w3.org/2000/svg";
    // an object to define the initial properties and text content of the text element 
    let o = {
      props: {
        x: 50,
        y: 15,
        "dominant-baseline": "middle",
        "text-anchor": "middle"
      },
      txtConent: "your name"
    };
    
    // a function to create a text element 
    function drawText(o, parent) {
      var text = document.createElementNS(SVG_NS, "text");
      for (var name in o.props) {
        if (o.props.hasOwnProperty(name)) {
          text.setAttributeNS(null, name, o.props[name]);
        }
      }
      text.textContent = o.txtConent;
      parent.appendChild(text);
      return text;
    }
    
    // a function to update the text
    function updateText(text,txtConent){
      text.textContent = txtConent;
    }
    
    
    //you save the text in a variable
    let txt = drawText(o, theSvg);
    // you update the text content when the user is changing the value of the input
    theName.addEventListener("input", ()=>{updateText(txt,theName.value)})
    svg{border:1px solid}
    <p>The name: <input type="text" id="theName" /></p>
    <svg id="theSvg" viewBox="0 0 100 30"></svg>

    I hope it helps.