How to add a path with 'd' attributes to a svg dynamically

Neil S

I'm having a problem dynamically generating path elements inside an empty svg with javascript. I'm not interested in using third-party libraries, I'd like to understand how it works in vanilla javascript. For the following codepen, I'm using jQuery for simplicity's sake.

here is the javascript for those not interested in visiting the codepen link:

$(function() {
  function calculateX(degrees, radius) {
    var radians = Math.PI * degrees / 180;
    return Math.ceil(radius + (radius * Math.cos(radians)));
  }

  function calculateY(degrees, radius) {
    var radians = Math.PI * degrees / 180;
    return Math.ceil(radius + (radius * Math.sin(radians)));
  }
  var d, opacity, len = 6,
    path, endAngle, degrees = 360 / len,
    startAngle = 270;
  for (var i = 0; i < len; i++) {
    opacity = 'rgba(255,0,0,' +parseFloat((i / len).toPrecision(2)) + ')';
    endAngle = (startAngle + degrees) % 360;
    d = 'M100 100 L' + calculateX(startAngle, 100) + ' ' +
      calculateY(startAngle, 100) + ' A100 100 0 0 1 ' +
      calculateX(endAngle, 100) + ' ' +
      calculateY(endAngle, 100) + ' Z';
    path = $('<path>').appendTo('svg');
    path.css({'background': opacity, 'fill': opacity});
    path[0].setAttribute('d', d);
    startAngle = endAngle;
  }

});

If I cut and paste the generated html from the developer console into the html section of the codepen, the result is exactly what I want, so I think my d attributes are being generated correctly, it just seems the DOM is not being updated properly or needs some sort of signal to redraw the svg?

here is the html fragment that is generated:

<svg viewBox="0 0 200 200"><path d="M100 100 L100 0 A100 100 0 0 1 187 50 Z" style="fill: rgba(255, 0, 0, 0); background: rgba(255, 0, 0, 0);"></path><path d="M100 100 L187 50 A100 100 0 0 1 187 150 Z" style="fill: rgba(255, 0, 0, 0.168627); background: rgba(255, 0, 0, 0.168627);"></path><path d="M100 100 L187 150 A100 100 0 0 1 100 200 Z" style="fill: rgba(255, 0, 0, 0.329412); background: rgba(255, 0, 0, 0.329412);"></path><path d="M100 100 L100 200 A100 100 0 0 1 14 150 Z" style="fill: rgba(255, 0, 0, 0.498039); background: rgba(255, 0, 0, 0.498039);"></path><path d="M100 100 L14 150 A100 100 0 0 1 14 50 Z" style="fill: rgba(255, 0, 0, 0.670588); background: rgba(255, 0, 0, 0.670588);"></path><path d="M100 100 L14 50 A100 100 0 0 1 100 0 Z" style="fill: rgba(255, 0, 0, 0.831373); background: rgba(255, 0, 0, 0.831373);"></path></svg>

r3mainer

When you create an object in a different namespace, you have to use document.createElementNS() instead of document.createElement().

JQuery's appendTo() function doesn't invoke createElementNS(), so although your code is creating a perfectly valid SVG element, you aren't seeing anything because the HTML parser doesn't understand it.

This works:

$(function() {
  function calculateX(degrees, radius) {
    var radians = Math.PI * degrees / 180;
    return Math.ceil(radius + (radius * Math.cos(radians)));
  }

  function calculateY(degrees, radius) {
    var radians = Math.PI * degrees / 180;
    return Math.ceil(radius + (radius * Math.sin(radians)));
  }
  var d, opacity, len = 6,
    path, endAngle, degrees = 360 / len,
    startAngle = 270,
    svg = document.getElementById('piechart'),
    ns = 'http://www.w3.org/2000/svg';
  for (var i = 0; i < len; i++) {
    fill = 'rgba(255,0,0,' +parseFloat((i / len).toPrecision(2)) + ')';
    endAngle = (startAngle + degrees) % 360;
    d = 'M100 100 L' + calculateX(startAngle, 100) + ' ' +
      calculateY(startAngle, 100) + ' A100 100 0 0 1 ' +
      calculateX(endAngle, 100) + ' ' +
      calculateY(endAngle, 100) + ' Z';
    path = document.createElementNS(ns,'path');
    path.setAttribute('fill', fill);
    path.setAttribute('d', d);
    svg.appendChild(path);
    startAngle = endAngle;
  }

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<svg id="piechart" xmlns="http://www.w3.org/2000/svg"
     width="200" height="200" viewBox="0 0 200 200">
</svg>

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related