1

I need to dynamically create sparklines with SVG/polyline elements, the sample with pure HTML works perfectly the problem appear when i create the elements with JavaScript and add attributes.

Function to create elements

    function createElement(type, attributes, someElement) {
        var element = type == "svg" ? document.createElementNS('http://www.w3.org/2000/svg', 'svg') : document.createElement(type);
        for (var key in attributes) {
            if (key === "class") {
                var cls = attributes[key];
                for (var c in cls)
                    element.classList.add(cls[c]);
            } else {
                element[key] = attributes[key];
            }
        }
        someElement.appendChild(element);
    }

Here I create the SVG element and add it to a div called filter_r_inner and afterwards add attributes.

                    var newElement = createElement("svg", {
                        "class": ['mktcap_spark'],
                        "id": "weekly_svg",
                        "viewBox": "0 0 500 100"
                    }, filter_r_inner);
                    var weekly_svg = document.getElementById("weekly_svg");
                    weekly_svg.setAttribute("viewBox", "0 0 500 100");

Here I create the polyline element and add it to the SVG element and afterwards add attributes.

                    var newElement = createElement("polyline", {
                        "id": "weekly_poly"
                    }, weekly_svg);
                    var weekly_poly = document.getElementById("weekly_poly");
                    weekly_poly.setAttribute('points', "00,120 20,60 40,120 60,10 80,80 100,80 120,60 140,100 160,90 180,80 200, 110 220, 10 240, 70 260, 100 280, 100 300, 40 320, 0 340, 100 360, 100 380, 120 400, 60 420, 70 440, 80 460, 20 480, 50 500, 30");
                    weekly_poly.setAttribute("fill", "none");
                    weekly_poly.setAttribute("stroke", "#e9be3d");
                    weekly_poly.setAttribute("stroke-width", "8");

The above does not render the SVG sparkline as i was expecting it to, all the attributes are however added, but nothing shows.

I've also tried adding points this way from this question, this gives me an error of weekly_svg.points is undefined

            var point = weekly_svg.createSVGPoint();
            point.x = 10;
            point.y = 20;
            weekly_poly.points.appendItem(point);

I've also looked into setAttributeNS but it required a 'namespace', i tried this but still nothing shows.

        weekly_poly.setAttributeNS('http://www.w3.org/2000/svg', 'points', "00,120 20,60 40,120 60,10 80,80 100,80 120,60 140,100 160,90 180,80 200, 110 220, 10 240, 70 260, 100 280, 100 300, 40 320, 0 340, 100 360, 100 380, 120 400, 60 420, 70 440, 80 460, 20 480, 50 500, 30");
        weekly_poly.setAttributeNS('http://www.w3.org/2000/svg', "fill", "none");
        weekly_poly.setAttributeNS('http://www.w3.org/2000/svg', "stroke", "#e9be3d");
        weekly_poly.setAttributeNS('http://www.w3.org/2000/svg', "stroke-width", "8");

This sample right here works perfectly with pure HTML.

<svg viewBox="0 0 500 100" class="mktcap_spark">
                    <polyline
                        fill="none"
                        stroke="#e9be3d"
                        stroke-width="8"
                        points="
                        00,120
                        20,60
                        40,120
                        60,10
                        80,80
                        100,80
                        120,60
                        140,100
                        160,90
                        180,80
                        200, 110
                        220, 10
                        240, 70
                        260, 100
                        280, 100
                        300, 40
                        320, 0
                        340, 100
                        360, 100
                        380, 120
                        400, 60
                        420, 70
                        440, 80
                        460, 20
                        480, 50
                        500, 30
                        "
                        />

                    </svg>

It renders a sparkline looking like this

enter image description here

CSS

.mktcap_spark {

  width: 130px;
  height: 50px;
  min-width: 130px;
}
ii iml0sto1
  • 1,654
  • 19
  • 37
  • 3 Years later and i have the same problem again, i google it and find my own question as the thirst thing on google... gg – ii iml0sto1 Dec 09 '21 at 15:42

1 Answers1

5

A couple of things spring to mind here. The first of which is that you've created a function that matches one that already exists. Not exactly a robust idea - it will break and you'll cry at some point in the future.

The next is that you use the (non svg) regular dom method of createElement - uh-uh, no can do when working with svgs, you need to use the createElementNS function.

Drawing on some old code and yours, I come up with something looking like this:

window.addEventListener('load', onDocLoad, false);

function onDocLoad(evt) {
  document.body.appendChild(makeSVG(svgData));
}


var svgData = [{
    type: 'svg',
    data: {
      viewBox: "0 0 500 100"
    }
  },
  {
    type: 'polyline',
    data: {
      fill: "none",
      stroke: "#e9be3d",
      strokeWidth: "8",
      points: "00,120 20,60 40,120 60,10 80,80 100,80 120,60 140,100"
    }
  },
];


function getNode(n, v) {
  n = document.createElementNS("http://www.w3.org/2000/svg", n);
  for (var p in v) {
    n.setAttributeNS(null, p.replace(/[A-Z]/g, function(m, p, o, s) {
      return "-" + m.toLowerCase();
    }), v[p]);
  }
  return n
}

function makeSVG(data) {
  var result;
  data.forEach(
    function(elem, index, array) {
      if (index)
        result.appendChild(getNode(elem.type, elem.data));
      else
        result = getNode(elem.type, elem.data);
    }
  );
  return result;
}
enhzflep
  • 12,927
  • 2
  • 32
  • 51
  • Now I remember EXACTLY why I made the function, and it was to avoid the problem of 'viewBox' to view-box and 'strokeWidth' to 'stroke-width' problem (viewBox will turn into view-box which will not work, in your example).... And by the way the function has never broken, it has been running smooth, it is easy to use and works. thanks for the answer anyway it made me realize what I did wrong. – ii iml0sto1 Sep 25 '18 at 04:14