Empirical
layout.h
Go to the documentation of this file.
1 
10 #ifndef EMP_D3_LAYOUT_H
11 #define EMP_D3_LAYOUT_H
12 
13 #include "d3_init.h"
14 #include "dataset.h"
15 #include "selection.h"
16 #include "svg_shapes.h"
17 
18 #include "../../tools/tuple_struct.h"
19 #include "../JSWrap.h"
20 
21 #include <functional>
22 #include <array>
23 
24 namespace D3{
25 
26  class Layout : public D3_Base {
27  protected:
28  Layout(int id) : D3_Base(id){;};
29  Layout() {;};
30  };
31 
32  struct JSONTreeNode {
33  EMP_BUILD_INTROSPECTIVE_TUPLE( double, x,
34  int, name,
35  int, parent,
36  double, y,
37  int, depth
38  )
39  };
40 
73  template <typename NODE_TYPE = JSONTreeNode>
74  class TreeLayout : public Layout {
75  protected:
76 
77  public:
80 
83 
86  TreeLayout(JSONDataset * dataset){
87  //Create layout object
88  EM_ASM_ARGS({js.objects[$0] = d3.tree();}, this->id);
89 
90  make_line = new D3::LinkGenerator("horizontal");
91 
92  // std::function<emp::array<double, 2>(NODE_TYPE, int, int)> projection = [](NODE_TYPE n, int i, int k){
93  // return emp::array<double, 2>({n.y(), n.x()});
94  // };
95  //
96  // emp::JSWrap(projection, "projection");
97  // make_line->SetProjection("projection");
98  SetDataset(dataset);
99  };
100 
103  //Create layout object
104  EM_ASM_ARGS({js.objects[$0] = d3.tree();}, this->id);
105 
106  make_line = new D3::LinkGenerator("horizontal");
107 
108  // std::function<emp::array<double, 2>(NODE_TYPE, int, int)> projection = [](NODE_TYPE n, int i, int k){
109  // return emp::array<double, 2>({{n.y(), n.x()}});
110  // };
111  //
112  // emp::JSWrap(projection, "projection");
113  // make_line->SetProjection("projection");
114  };
115 
116 
118  void SetDataset(JSONDataset * dataset) {
119  this->data = dataset;
120  }
121 
131  //Returns the enter selection for the nodes in case the user wants
132  //to do more with it. It would be nice to return the enter selection for
133  //links too, but C++ makes that super cumbersome, and it's definitely the less
134  //common use case
136  int node_enter = NextD3ID();
137  int node_exit = NextD3ID();
138  int link_enter = NextD3ID();
139  int link_exit = NextD3ID();
140  std::cout << "Tree data id: " << data->GetID() << std::endl;
141  // make_line->Log();
142  EM_ASM_ARGS({
143 
144  // Based on code from http://www.d3noob.org/2014/01/tree-diagrams-in-d3js_11.html
145  var root = d3.hierarchy(js.objects[$1][0]);
146  js.objects[$0](root);
147  var nodes = root.descendants();
148  var links = root.descendants().slice(1);
149  // nodes.forEach(function(d) { d.y = d.depth * 20; });
150 
151  // Declare the nodes
152  var node = js.objects[$3].selectAll("g.node")
153  .data(nodes, function(d) { return d.name; });
154 
155  var nodeExit = node.exit();
156  var nodeEnter = node.enter().append("g")
157  .attr("class", "node")
158  .attr("transform", function(d) {
159  return "translate(" + d.y + "," + d.x + ")"; });
160 
161  node.attr("transform", function(d) {
162  return "translate(" + d.y + "," + d.x + ")"; });
163 
164  var link = js.objects[$3].selectAll("path.link")
165  .data(links, function(d) { return d.name; });
166 
167  var linkExit = link.exit();
168  // Enter the links.
169  var linkEnter = link.enter().insert("path", "g")
170  .attr("class", "link")
171  .attr("d", function(d) {return "M" + d.y + "," + d.x
172  + "C" + (d.y + d.parent.y) / 2 + "," + d.x
173  + " " + (d.y + d.parent.y) / 2 + "," + d.parent.x
174  + " " + d.parent.y + "," + d.parent.x;})
175  .attr("fill", "none")
176  .attr("stroke", "black")
177  .attr("stroke-width", 1);
178 
179  link.attr("class", "link")
180  .attr("d", function(d) {return "M" + d.y + "," + d.x
181  + "C" + (d.y + d.parent.y) / 2 + "," + d.x
182  + " " + (d.y + d.parent.y) / 2 + "," + d.parent.x
183  + " " + d.parent.y + "," + d.parent.x;});
184 
185  js.objects[$4] = nodeEnter;
186  js.objects[$5] = nodeExit;
187  js.objects[$6] = linkEnter;
188  js.objects[$7] = linkExit;
189  }, this->id, data->GetID(), make_line->GetID(), svg.GetID(), node_enter, node_exit, link_enter, link_exit);
190  std::cout << "Done generating" << std::endl;
191  return emp::array<Selection, 4>{{Selection(node_enter), Selection(node_exit),
192  Selection(link_enter), Selection(link_exit)}};
193  }
194 
195 
197  void SetSize(int w, int h) {
198  EM_ASM_ARGS({js.objects[$0].size([$1,$2]);}, this->id, w, h);
199  }
200 
201  };
202 }
203 
204 
205 #endif
Definition: array.h:42
emp::array< Selection, 4 > GenerateNodesAndLinks(Selection svg)
Definition: layout.h:135
D3::LinkGenerator * make_line
Function used to make the lines for the edges in the tree.
Definition: layout.h:82
Layout()
Definition: layout.h:29
TreeLayout(JSONDataset *dataset)
Definition: layout.h:86
Definition: layout.h:32
TreeLayout()
Default constructor - if you use this you need connect a dataset with SetDataset. ...
Definition: layout.h:102
JSONDataset * data
Pointer to the data - must be in hierarchical JSON format.
Definition: layout.h:79
Definition: d3_init.h:43
void SetDataset(JSONDataset *dataset)
Change this TreeLayout&#39;s data to [dataset].
Definition: layout.h:118
int id
Definition: d3_init.h:45
void SetSize(int w, int h)
Set the width of the tree area to [w] and the height to [h].
Definition: layout.h:197
static const PrintStr endl("<br>")
Pre-define emp::endl to insert a "<br>" and thus acting like a newline.
Definition: svg_shapes.h:325
Definition: selection.h:936
int NextD3ID()
Definition: d3_init.h:31
Definition: layout.h:26
Tools to build common SVG shapes.
Definition: layout.h:74
Layout(int id)
Definition: layout.h:28
Definition: axis.h:20
Definition: dataset.h:64
Tools to maintain data in D3.
int GetID() const
Definition: d3_init.h:96