2

I'm currently working on a project that involves building a dynamic diagram and am looking at using SVGs for this.

Based on this, I wish to see whether what I am after is actually possible with SVGs.

1) Using JavaScript and json, is it possible to build an SVG diagram within a HTML page dynamically, based on my json data?

Basically, I want to construct say a rectangle box within the page, where I can have say 1 to 10 svg lines as inputs into the rectangle box, on the left hand side. To determine how many actual lines appear, will come from my json object.

So as mentioned above, is this possible and if so, how might this be setup to draw this inline svg diagram?

2) Again, using JavaScript, is it possible to place hyperlink labels on these svg lines, again based on info within the json object?

I started playing with static inline SVG but unsure how to construct this using javascript instead, to cover off my two points above, i.e.:

<body>
  <h1>My SVG Test</h1><hr/>

  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">

    <text x="465" y="90" fill="red">Heading One</text>
    <image x="100" y="110" width="50%" height="50%"
       xlink:href="http://my-image.com/myimg.jpg" />

    <line x1="25" y1="80" x2="350" y2="80" style="stroke: #000000; stroke-width: 2;"/>
  </svg>

</body> 
halfer
  • 19,824
  • 17
  • 99
  • 186
tonyf
  • 34,479
  • 49
  • 157
  • 246
  • construct it via the DOM i.e. document.createElementNS – Robert Longson Apr 14 '16 at 14:54
  • @RobertLongson - I am sort of new to this SVG stuff so is it possible to point to me examples or possibly provide some, of using this via the DOM and whether I can use JSON to construct it? – tonyf Apr 14 '16 at 14:59
  • I'm sure given the keyword I've provided you can find all that yourself. Sure you can use JSON to construct it. – Robert Longson Apr 14 '16 at 15:00
  • SVG is awesome, and SMIL is seksi too. Rob's right with .createElementNS, for an SO type example you might look [here](http://stackoverflow.com/questions/16488884/add-svg-element-to-existing-svg-using-dom) but I know there's some good tutorials out there. – Chris W. Apr 14 '16 at 15:00
  • Appreciate the replies. @ChrisW. - any chance of posting a few links of the good tutorials you are referring too as with what I am after, do I need to call document.createElementNS for every SVG element I want to use, i.e. image, rectangle, line, hyperlinks? – tonyf Apr 14 '16 at 15:07
  • I'm sure google could be more helpful than I can, but you're basically just wanting to know how to [create and destroy](http://apike.ca/prog_svg_js_create.html) :) – Chris W. Apr 14 '16 at 15:14
  • With an image, do I Base64 encode it and place it with the svg tags or just img src to a url? – tonyf Apr 14 '16 at 15:18

1 Answers1

5

You can use Snap to easily create what you are looking for. In the below snippet,I added all the required attributes and type of the element and used .el() to create an svg element

The syntax for el is

Paper.el(name,attr)

Name is the element that you want to create, for example line,circle,path etc and attr is the attributes that you want to add. In the data below i have created two lines and one circle by specifying their attributes . I have also added fill and stroke

var data = [
{
  type:"line",
  attrs:{
    x1:0,
    x2:0,
    y1:0,
    y2:100,
    stroke:"black",
    "stroke-width":"5"
  }
},
{
  type:"line",
  attrs:{
    x1:100,
    x2:100,
    y1:0,
    y2:100,
    stroke:"black",
    "stroke-width":"5"
  }
},
{
  type:"circle",
  attrs:{
    cx:50,
    cy:50,
    r:40,
    fill:"orange", 
  }
} 
]
var s = Snap("svg");
for(var x=0;x<data.length;x++){
  s.el(data[x].type).attr(data[x].attrs);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js"></script>
<svg width="500" height="500" viewbox="0 0 100 100"></svg>

Adding a link is a bit hard and complex because you have to append a child text element to the a. So i have changed my code a bit.

In the following snippet i have added a new key to the json data called parent. And then set parent:true to those elements who have child elements and run another loop to append the child element to the parent

var data = [{
  type: "line",
  parent: false, //is false because it has no child elements
  attrs: {
    x1: 0,
    x2: 0,
    y1: 0,
    y2: 100,
    stroke: "black",
    "stroke-width": "5"
  }
}, {
  type: "line",
  parent: false,
  attrs: {
    x1: 100,
    x2: 100,
    y1: 0,
    y2: 100,
    stroke: "black",
    "stroke-width": "5"
  }
}, {
  type: "circle",
  parent: false,
  attrs: {
    cx: 50,
    cy: 50,
    r: 40,
    fill: "orange",
  }
}, {
  type: "a",
  parent: true, // Is true because this has child elements
  attrs: {
    x: 10,
    y: 50,
    "xlink:href": "http://snapsvg.io/docs/"
  },
  childs: [{
    type: "text",
    attrs: {
      x: 10,
      y: 50,
      text: "Snap is Cool",
    }
  }]
}, {
  type: "image",
  parent: false,
  attrs: {
    "xlink:href": "http://i.imgur.com/5NK0H1e.jpg",
    x: 0,
    y: 0,
    width: 50,
    height: 50
  }
}]
var s = Snap("svg");
for (var x = 0; x < data.length; x++) {
  var p = s.el(data[x].type).attr(data[x].attrs);
  if (data[x].parent) { //check if it is true
    for (var y = 0; y < data[x].childs.length; y++) {
      var c = s.el(data[x].childs[y].type).attr(data[x].childs[y].attrs);
      p.append(c);
    }
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js?wmode=transparent"></script>
<svg width="500" height="500" viewbox="0 0 100 100"></svg>

To add more child elements the following code should be used

var data = [{
  type: "g"
}, {
  type: "image",
  appendTo: 0,
  attrs: {
    "xlink:href": "http://lorempixel.com/500/500/",
    x: 0,
    y: 0,
    width: 50,
    height: 50
  }
}, {
  appendTo: 0,
  type: "a",
  parent: true,
  attrs: {
    x: 5,
    y: 5,
    target: "_blank",
    "xlink:href": "http://snapsvg.io/docs/"
  }
}, {
  appendTo: 2,
  type: "circle",
  attrs: {
    cx: 5,
    cy: 5,
    r: 2.5,
    fill: "orange"
  }
}]
var s = Snap("svg");
var elems = [];
for (var x = 0; x < data.length; x++) {
  var e = s.el(data[x].type).attr(data[x].attrs);
  if (data[x]["appendTo"] !== undefined) {
    var p = elems[data[x].appendTo];
    p.append(e);
  }
  elems.push(e);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/snap.svg/0.3.0/snap.svg-min.js"></script>
<div class="box">
  <svg width="100%" height="100%" viewBox="0 0 100 100"></svg>
</div>
Akshay
  • 14,138
  • 5
  • 46
  • 70
  • Snap get's a +1, [greensock](http://www.greensock.com) is worth a mention for tinkering also. – Chris W. Apr 14 '16 at 15:57
  • Thanks @ChrisW. , i have used Snap a lot but never tried (heard about) greensock , i will definitely try that :) – Akshay Apr 14 '16 at 16:02
  • Another thanks from me too @Akshay - will check it out. Can snap also take care of hyperlinks on a line in your example - say your second line, I would like to place this lable link just above this line, assuming it's horizontal? – tonyf Apr 14 '16 at 16:10
  • That is a bit hard @tonyf will edit my answer tomorrow (if i find a way) as it is getting late here – Akshay Apr 14 '16 at 16:23
  • @tonyf Edited my answer, check it now – Akshay Apr 14 '16 at 17:02
  • Appreciate the edit @Akshay - just been playing with it but can't seem to get an image to display based on a URL, have added to your json, : { type: "image", parent: false, attrs: { src: "http://www.myimages.com/assets/img/product.jpg", x: 100, y: 110, width: 50, height: 50 } } – tonyf Apr 15 '16 at 04:20
  • @tonyf That is because you used `src` , in svg it is `xlink:href`, check second snippet – Akshay Apr 15 '16 at 05:06
  • Thanks again @Akshay - can I have another image type as I need to display another image next to the one already - tried it and now both don't appear? – tonyf Apr 15 '16 at 05:21
  • @tonyf Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/109213/discussion-between-akshay-and-tonyf). – Akshay Apr 15 '16 at 05:22