Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Handlebar with D3.js

I have a Handlebar template i want to include a svg graph generated from d3 into that template.Graph should be inside the template

D3 Graph

var dataset = [1200,3000,3200];
// dataset will change dynamically.

<script type="text/javascript">

    var w = 154;
    var h = 42;
    var rect_1_h = 5;
    var rect_2_h = rect_1_h * 2;
    var rect_2_w = rect_1_h/2;
    var rect_1_color = "#A1C9D9";
    var rect_2_color = "#999999";
    var text_color = "#555555";
    var font_size = 18;
    var font_family = "Segoe UI"

    var dataset = [1200,3000,3200];

    /*------controller----*/

    var xScale = d3.scale.linear().domain([dataset[0],dataset[2]])
    .range([0,w]);

    var svg = d3.select("body").append("svg").attr("width",w).attr("height",h);
    var rect1 = svg.append("rect").attr("x",0).attr("y",3*h/4).attr("width",w).attr("height",rect_1_h)
    .style("fill",rect_1_color);
    var rect2 = svg.append("rect").attr("x",xScale(dataset[1])).attr("y",3*h/4-rect_1_h/2).attr("width",rect_2_w)
    .attr("height",rect_2_h).style("fill",rect_2_color);

    //var texts = svg.selectAll("text").data(dataset).enter().append("text").text(function(d){ return d; }).attr("fill","red").attr("x",function(d,i){ return i*50  }).attr("y",30)

    var text1 = svg.append("text").attr("x",2).attr("y",h/3+2).text(dataset[0]).style("fill",text_color)
    .attr("font-size",font_size).attr("font-family",font_family);
    var text2 = svg.append("text").attr("x",w-42).attr("y",h/3+2).text(dataset[2]).style("fill",text_color)
    .attr("font-size",font_size).attr("font-family",font_family);
</script>

Handlebar template

<script id="datatemplate" type="text/x-handlebars-template">
      {{#each objects}}
      <tr>
      <td>{{lp}}<span class="text1">{{lp2}}</span></td>
      <td>{{dc}}<span class="text1">{{dc2}}</span></td>
      <td>{{lp}}<span class="text1">{{lp2}}</span></td>
      </tr>
      {{/each}} 
</script>
like image 471
Tabraiz Ali Avatar asked Feb 08 '13 11:02

Tabraiz Ali


1 Answers

If there should be only one instance of the graph inside the template, then all you need to do is tell d3 to append the svg element inside the <script id="datatemplate"> tag instead of the body.

var svg = d3.select("#datatemplate").append("svg").attr("width",w).attr("height",h);

If, on the other hand, you would like your template to generate a d3 graph each time it is called, I don't think this is the proper way of doing things. Since d3 binds data to DOM elements and Handlebars generates HTML strings from data structures.

You could wrap your graph code inside a closure to which you pass your data and element you wish to bind to and then generate a new instance of the graph from a Handlebars helper:

function graphic( dataset, element ) {
  var w = 154;
  var h = 42;
  var rect_1_h = 5;
  var rect_2_h = rect_1_h * 2;
  var rect_2_w = rect_1_h/2;
  var rect_1_color = "#A1C9D9";
  var rect_2_color = "#999999";
  var text_color = "#555555";
  var font_size = 18;
  var font_family = "Segoe UI";

  /*------controller----*/

  var xScale = d3.scale.linear().domain([dataset[0],dataset[2]])
        .range([0,w]);

  var svg = d3.select( element ).append("svg").attr("width",w).attr("height",h);
  var rect1 = svg.append("rect").attr("x",0).attr("y",3*h/4).attr("width",w).attr("height",rect_1_h)
        .style("fill",rect_1_color);
  var rect2 = svg.append("rect").attr("x",xScale(dataset[1])).attr("y",3*h/4-rect_1_h/2).attr("width",rect_2_w)
        .attr("height",rect_2_h).style("fill",rect_2_color);

  //var texts = svg.selectAll("text").data(dataset).enter().append("text").text(function(d){ return d; }).attr("fill","red").attr("x",function(d,i){ return i*50  }).attr("y",30)

  var text1 = svg.append("text").attr("x",2).attr("y",h/3+2).text(dataset[0]).style("fill",text_color)
        .attr("font-size",font_size).attr("font-family",font_family);
  var text2 = svg.append("text").attr("x",w-42).attr("y",h/3+2).text(dataset[2]).style("fill",text_color)
        .attr("font-size",font_size).attr("font-family",font_family);

  return svg;
};

Handlebars.registerHelper('graphics', function( dataset, id ) {
  graphic( dataset, '#' + id );
});

And then in your template:

<script id="datatemplate" type="text/x-handlebars-template">
  {{#each objects}}
  <tr>
  <td>{{lp}}<span class="text1">{{lp2}}</span></td>
  <td>{{dc}}<span class="text1">{{dc2}}</span></td>
  <td>{{lp}}<span class="text1">{{lp2}}</span></td>
  </tr>
  {{/each}}
  <div id={{ id }}></div>
  {{graphics dataset id}} 
</script>
like image 121
mor Avatar answered Sep 21 '22 17:09

mor