Changeset 2456 for SMC


Ignore:
Timestamp:
01/13/13 14:23:17 (11 years ago)
Author:
vronk
Message:

added highlighting on mouseover
reorganized and cleaned up code

File:
1 edited

Legend:

Unmodified
Added
Removed
  • SMC/trunk/SMC/src/web/scripts/js/cmd-dep-graph.js

    r2455 r2456  
    66var data_all = null; // global holder for all (input) data
    77var nodes_sel = null; // global holder for selected data (selected nodes)
    8 var data_show = null; // global holder for data to show  closure over data_sel
     8var data_show = null; // global holder for data to show  closure over nodes_sel
    99var nest = {};
    1010var detail_data = null; // global holder for detail-data (in html) 
     
    3030var opts = {"depth-before": {"value":2, "min":0, "max":10, "widget":"slider"},
    3131            "depth-after":{"value":2, "min":0, "max":10, "widget":"slider"},
    32             "link-distance": {"value":30, "min":10, "max":200, "widget":"slider" },
     32            "link-distance": {"value":80, "min":10, "max":200, "widget":"slider" },
    3333            "charge":{"value":400, "min":10, "max":1000, "widget":"slider" },
    3434            "node-weight": {"value":"1", "values":["1","usage"], "widget":"selectone" },
    3535            "curve": {"value":"straight", "values":["straight","arc"], "widget":"selectone" },
    3636            "layout": {"value":"horizontal-tree", "values":["vertical-tree", "horizontal-tree", "weak-tree","force","dot"], "widget":"selectone" },
    37            
     37            "labels": {"value":"hide", "values":["show","hide"], "widget":"selectone" },                         
    3838            };
    3939
    40 /** for faster/simpler neighborhood lookup
    41 from: http://stackoverflow.com/questions/8739072/highlight-selected-node-its-links-and-its-children-in-a-d3-js-force-directed-g
    42 */
    43 var linkedByIndex = {};
    44 var neighbours_in = {};
    45 var links_in = {};
    46 var neighbours_out = {};
    47 var links_out = {};
    48 
    49 /** loads from separate file detail info about individual nodes (in html)
    50 later used in renderDetail()
    51 invoked during the (jquery-)initalization */
    52 
    53 function loadDetailInfo () {
    54      
    55   $(detail_info_holder_selector).load(detail_file,function(data) {
    56      $(detail_container_selector).html(getDetailInfo("summary", "overall"));
    57   });
    58  
    59  
    60   /* $.get(detail_file, function(data) {
    61     detail_data = data; 
    62     notify('Detail data loaded');
    63  
    64 }); */
    65 }
    66 
    67 function getDetailInfo(type, id) {
    68     notify("getDetailInfo: #" + type + "-" + id );
    69     var d = $(detail_info_holder_selector).find("#" + type + "-" + id );
    70     // notify(d);
    71     return d.html();
    72 }
    7340
    7441
     
    11380                                                src_key = d.source.key;
    11481                                                trg_key = d.target.key;
    115                                              // generate lookup hashes for neighbours;
    116                                                 linkedByIndex[src_key + "," + trg_key] = d;
    117                                                 if (d.source) {
    118                                                         if (! neighbours_in[trg_key]) {
    119                                                             neighbours_in[trg_key] = [d.source];
    120                                                             links_in[trg_key] = [d];
    121                                                          }  else {
    122                                                             neighbours_in[trg_key].push(d.source);
    123                                                             links_in[trg_key].push(d);
    124                                                          }
    125                                                  }
    126                                                 if (d.target) {
    127                                                         if (! neighbours_out[src_key]) {
    128                                                             neighbours_out[src_key] = [d.target];
    129                                                             links_out[src_key] = [d];
    130                                                         } else {
    131                                                             neighbours_out[src_key].push(d.target);
    132                                                             links_out[src_key].push(d) ;
    133                                                         }
    134                                                  }
    135                                            });
    136 
    137                     renderIndex_default();
    138                     //renderGraph(data_all, graph_container);
     82                                             });
     83                // generate lookup hashes for neighbours;                                             
     84                 add_lookups(data_all);
     85                 
     86                 // should be delivered by the data directly
     87                   data_all.nodes.forEach(function(d,i) {
     88                       d.x = d.init_x;
     89                       d.y = d.init_y;
     90                     });
     91   
     92              renderIndex();
     93   
    13994                });       
    14095}
    14196
    142 /* there was a strange problem with overloading */
    143 function renderIndex_default () {
    144     renderIndex (data_all.nodes, index_container_selector)
    145 }
    146 
    147 /** generate the index lists
     97/** put grouped list of nodes into the target container*/
     98function renderIndex () {
     99    renderNodeList (data_all.nodes, index_container_selector)
     100}
     101
     102
     103/** generate the detail lists
     104    @param nodes
     105*/ 
     106function renderDetail (nodes) {   
     107    renderNodeList (nodes, detail_container_selector);
     108}
     109
     110
     111/** generate a grouped (by type) list of nodes
    148112    @param nodes - accepts an array of nodes (like in data.nodes)
    149113*/ 
    150 function renderIndex (nodes, target_container_selector) {
     114function renderNodeList (nodes, target_container_selector) {
    151115
    152116    nest = d3.nest()
     
    158122        target_container.selectAll("div").remove();
    159123       
    160         // rendering extra-information about the displayed data only in detail-index
    161         if (target_container_selector != index_container_selector) {
    162            target_container.append("span")
    163                 .text("show nodes: " + data_show.nodes.length + "; "
    164                         + "show links: " + data_show.links.length);
    165            }
     124       
    166125           
    167126        var group_divs = target_container.selectAll("div").data(nest)
     
    192151              } else {
    193152                 var item_detail = item_li.append("div")
    194                             .classed("node-detail", 1);
     153                                          .classed("node-detail", 1);
    195154                           
    196                         item_detail.text(function (d) { return "links_in: " +  dataShowCount(d.key, "links_in") +  "; links_out: " +  dataShowCount(d.key, "links_out") ;
    197                                                        })
    198                                 .append("a")
    199                       .attr("href",function (d) { if (d.type.toLowerCase()=='datcat') return d.id
     155                 item_detail.append("a")
     156                            .attr("href",function (d) { if (d.type.toLowerCase()=='datcat') return d.id
    200157                                                        else return comp_reg_url + d.id })
    201                       .text(function (d) { return d.id });
    202             item_detail.append("div").html(
    203                           function (d) { var detail_info_div = getDetailInfo(d.type.toLowerCase(), d.key);
    204                                             if (detail_info_div) {return detail_info_div } else
    205                                                 { return  "<div>No detail</div>"; }
     158                            .text(function (d) { return d.id });
     159                 item_detail.append("div").html(
     160                                 function (d) {
     161                                    var detail_info_div = getDetailInfo(d.type.toLowerCase(), d.key);
     162                                    if (detail_info_div) {
     163                                        return detail_info_div
     164                                    } else {
     165                                        return  "<div>No detail</div>";
     166                                    }
    206167                          });
    207                             
    208          
     168                           
     169              }
    209170                       
    210               }
    211                         //.classed("detail", 1);
    212                         //console.log($(target_container_selector).find(".cmds-ui-block"));
    213171   handleUIBlock($(target_container_selector).find(".cmds-ui-block"));
    214172 
     
    220178        return d.name.toLowerCase().indexOf(search_string) > -1;
    221179    });
    222     console.log(filtered_index_nodes);
    223     renderIndex(filtered_index_nodes, index_container_selector);
     180   
     181   renderIndex(filtered_index_nodes, index_container_selector);
    224182}
    225183
     
    240198       $(target_container).text("");
    241199     }
    242    
     200 
     201  // information about the displayed data
     202        notify("show nodes: " + data_show.nodes.length + "; "
     203                        + "show links: " + data_show.links.length);
     204       
     205 
     206 
    243207 
    244208   var w = $(target_container).width(),
     
    251215            .links(data.links)
    252216            .size([w, h])
    253         //   .gravity(0)
    254             .linkDistance(opt("link-distance"))
    255             .charge(opt("charge") * -1)
     217           // .gravity(0.3)
     218            .linkDistance(parseInt(opt("link-distance")))
     219            .charge(parseInt(opt("charge")) * -1)
    256220            .on("tick", tick)
    257221            .start();
    258     console.log ("gravity: " + force.gravity() );             
    259          // remove old render:
     222//    console.log ("gravity: " + force.gravity() );             
     223 
     224       // remove old render:
    260225          d3.select(graph_container_selector).selectAll("svg").remove();
    261       // console.log(force.size())               
     226                 
    262227        svg = d3.select(graph_container_selector).append("svg:svg")
    263228            .attr("width", w)        .attr("height", h);
     
    280245            .data(force.links())
    281246            .enter().append("svg:path")
    282             .attr("class", function(d) { return "link uses"; })
     247/*            .attr("class", function(d) { return "link uses"; })*/
     248            .classed("link", 1)
     249            .classed("uses", 1)
     250            .classed("highlight", function(d) { d.highlight } )
    283251            .attr("marker-end", function(d) { return "url(#uses)"; });
    284252/*            .style("stroke-width", function(d) { return Math.sqrt(d.value); });*/
     
    303271            .attr("class", function(d) { return "type-" + d.type.toLowerCase()})
    304272            .classed("selected", function(d) { return d.selected; })
    305           .on("click", function(d) {d.selected= d.selected ? 0 : 1; updateSelected() });
    306           .on("mouseover", function(d) {console.log(this)});
    307        
    308          
     273          .on("click", function(d) {d.selected= d.selected ? 0 : 1; updateSelected() })
     274          .on("mouseover", highlight("in")).on("mouseout", highlight("out"));
     275       
     276      /*   
    309277        var textgroup = svg.append("svg:g").selectAll("g")
    310278            .data(data.nodes)
     
    328296            .attr("y", ".31em")
    329297            .text(function(d) { return d.name; });
    330 
    331 
    332 
    333   /*
    334   force.start();
    335         force.tick();
    336         force.stop();
    337        
    338         force.on("tick",tick);
    339        force.start();   
    340            var n = 100;
    341            console.log("start ticking");
    342 for (var i = 0; i < n; ++i) force.tick();
    343 force.stop();
    344298*/
    345         /*   
    346           data.links.forEach(function(d, i) {
    347             d.source.x -= d.source.init_x;
    348             d.target.x += d.target.init_x;
    349           });
    350 */
    351 
    352    function statick(e) {
    353      
    354       data.nodes.forEach(function(d,i) {
    355         d.x = d.init_x;
    356         d.y = d.init_y;
    357       });
    358      
    359       transform();
    360    }
    361299
    362300   function tick(e) {
    363     var link_distance = parseInt(opt("link-distance"));     
    364    var k =  10 * e.alpha;
     301    var link_distance_int = parseInt(opt("link-distance"));     
     302    var k =  10 * e.alpha;
    365303          if (opt("layout")=='dot') {
    366             var link_distance_int = parseInt(opt("link-distance"));
    367304            data.links.forEach(function(d, i) {
    368305              d.source.x = (d.source.init_x / 150 * link_distance_int) ;
    369306              d.target.x = (d.target.init_x / 150 * link_distance_int);
    370               //d.target.y  += (d.target.init_y / 300 ) * k;
    371   /*            d.source.x = (d.source.level * link_distance_int) + link_distance_int;
    372               d.target.x = (d.target.level * link_distance_int) + link_distance_int;*/
    373               /*d.source.x = d.source.level * 2 * opt("link-distance") + 50;
    374               d.target.x = d.target.level * 2 * opt("link-distance") + 50;*/
     307           
    375308            });
    376309          } else if (opt("layout")=='weak-tree') {
     
    378311              d.source.x -= k;
    379312                d.target.x += k;
    380                
    381                 //d.source.x -= k * d.source.level / (dataShowCount(d.source.key, "links_out") + 0.1);  // 0.1 to prevent div/0
    382                 //d.target.x += k * d.target.level / (dataShowCount(d.target.key, "links_in") + 0.1);
    383313                });
    384314          } else if (opt("layout")=='vertical-tree') {
     
    387317                     if (d.source.level==0) { d.source.y = 20 };
    388318                     d.target.x += (d.source.x - d.target.x)  * kx;
    389                      d.target.y += (d.source.y - d.target.y + link_distance) * ky;
     319                     d.target.y += (d.source.y - d.target.y + link_distance_int) * ky;
    390320                    });
    391321           } else if (opt("layout")=='horizontal-tree') {
     
    394324                       if (d.source.level==0) { d.source.x = 20 };
    395325                       d.target.y += (d.source.y - d.target.y)  * ky;
    396                        d.target.x += (d.source.x - d.target.x + link_distance  ) * kx;
     326                       d.target.x += (d.source.x - d.target.x + link_distance_int  ) * kx;
    397327                  });
    398328            }
     
    404334      });*/
    405335     
    406       /*  obsoleted:
    407       /*data.links.forEach(function(d, i) {
    408                 d.source.x -= (k * d.source.init_x  / (200 * Math.sqrt(d.source.count)) );
    409                 d.target.x += (k * d.target.init_x / (50 * Math.sqrt(d.target.count)) );
    410                 });*/
    411          
    412          /*d.source.y = d.source.init_y - d.source.y * k;
    413            d.target.y = d.target.init_y + d.target.y * k;*/
    414               /*d.source.x -= k * d.target.sum_level ;
    415              d.target.x += k *  d.source.sum_level ;*/
    416              /* d.source.y = d.source.init_y ;
    417              d.target.y = d.target.init_y;*/
    418               //d.source.x -= d.source.level * 0.2 ;
    419               //d.target.x += d.target.level * 0.2;
    420336         
    421337       transform();
     
    444360       });*/
    445361       
    446        textgroup.attr("transform", function(d) {
     362  /*     textgroup.attr("transform", function(d) {
    447363            return "translate(" + d.x + "," + d.y + ")";
    448        });
     364       });*/
    449365    }
    450366       
     
    484400
    485401
    486 /** generate the detail lists
    487     @param nodes
    488 */ 
    489 function renderDetail (nodes) {
    490    
    491     renderIndex (nodes, detail_container_selector);
    492 }
    493 
    494 function renderDetail_old (nodes) {
    495     /*
    496     nest = d3.nest()
    497     .key(function(d) { return d.group; })
    498     .sortValues(function(a, b) { return d3.ascending(a.name, b.name); })
    499     .entries(nodes);
    500   */
    501     detail_container = d3.select("#detail-container");
    502       detail_container.selectAll("div").remove();
    503       /*
    504       var group_divs = detail_container.selectAll("div").data(nest)
    505                         .enter().append("div")
    506                         .attr("id", function (d) { return "detail-" + d.key })
    507                         .classed("cmds-ui-block init-show", 1);
    508                        
    509       var group_headers = group_divs.append("div").classed("header", 1)
    510                         .text(function (d) { return d.key});
    511         */               
    512       var item_li = detail_container.append("div")
    513                     .append("ul").selectAll(".node-item")       
    514                     .data(nodes)
    515                     .enter().append("li")
    516                     .attr("class", "node-item")
    517                     .attr("id", function (d) { return "n-" + d.name });
    518                item_li.append("span")
    519                       .text(function (d) { return d.type + ": " + d.name})
    520                       .on("click", function(d) { d.selected= d.selected ? 0 : 1 ; updateSelected() });
    521          var item_detail = item_li.append("div")
    522                             .classed("node-detail", 1);
    523          
    524              item_detail.append("a")
    525                       .attr("href",function (d) { if (d.type.toLowerCase()=='datcat') return d.id
    526                                                         else return comp_reg_url + d.id })
    527                       .text(function (d) { return d.id });
    528             item_detail.append("div").html(
    529                           function (d) { var detail_info_div = getDetailInfo(d.type.toLowerCase(), d.key);
    530                                             if (detail_info_div) {return detail_info_div } else
    531                                                 { return  "<div>No detail</div>"; }
    532                           });
    533                            
    534                          
    535   // handleUIBlock($(".cmds-ui-block"));   
    536 }
    537 
    538        
     402/** loads detail info about individual nodes (in html) from separate file 
     403later used in renderDetail()
     404invoked during the (jquery-)initalization */
     405function loadDetailInfo () {
     406     
     407  $(detail_info_holder_selector).load(detail_file,function(data) {
     408     $(detail_container_selector).html(getDetailInfo("summary", "overall"));
     409  });
     410}
     411
     412function getDetailInfo(type, id) {
     413    //notify("getDetailInfo: #" + type + "-" + id );
     414    var d = $(detail_info_holder_selector).find("#" + type + "-" + id );
     415    // notify(d);
     416    return d.html();
     417}
     418
     419
    539420/**  select the nodes within the specified rectangle. */
    540421function selectNodes(nodes, x0, y0, x3, y3) {
     
    564445
    565446
     447// Returns an event handler for fading a given chord group.
     448function highlight() {
     449  return function(d, i) {
     450    // console.log ("fade:" + d.key);
     451    var connected_subgraph_in = neighboursWithLinks(data_show, d,'in', -1);
     452    var connected_subgraph_out = neighboursWithLinks(data_show, d,'out', -1);
     453    var connected_subgraph = {"nodes": [], "links": []};
     454        connected_subgraph.nodes = connected_subgraph.nodes.concat(connected_subgraph_in.nodes).concat(connected_subgraph_out.nodes);
     455        connected_subgraph.links = connected_subgraph.links.concat(connected_subgraph_in.links).concat(connected_subgraph_out.links);
     456       add_lookups(connected_subgraph);                 
     457    svg.selectAll("path.link")
     458/*        .filter( d.source.index != i && d.target.index != i; })*/
     459/*      .transition()*/
     460        .classed("highlight", function(p) { return connected_subgraph.links_index[p.source.key + ',' + p.target.key] })
     461        .classed("fade", function(p) { return !(connected_subgraph.links_index[p.source.key + ',' + p.target.key]) });
     462   
     463    svg.selectAll("circle")
     464/*        .filter( d.source.index != i && d.target.index != i; })*/
     465/*      .transition()*/
     466        .classed("highlight", function(d) { return connected_subgraph.nodes_in[d.key]  || connected_subgraph.nodes_out[d.key]  })
     467        .classed("fade", function(d) { return !(connected_subgraph.nodes_in[d.key] || connected_subgraph.nodes_out[d.key])   });
     468       
     469  };
     470}
     471
    566472
    567473/**  generates the subset of data to display (based on selected nodes + options)
     
    574480       
    575481        nodes.forEach(function(n) {
    576                         var data_add_in = neighboursWithLinks(n,'in', opt("depth-before"));
    577                         var data_add_out = neighboursWithLinks(n,'out', opt("depth-after"));
     482                        var data_add_in = neighboursWithLinks(data_all, n,'in', opt("depth-before"));
     483                        var data_add_out = neighboursWithLinks(data_all, n,'out', opt("depth-after"));
    578484                        data_show_collect.nodes = data_show_collect.nodes.concat(data_add_in.nodes).concat(data_add_out.nodes);
    579485                        data_show_collect.links = data_show_collect.links.concat(data_add_in.links).concat(data_add_out.links);
     
    584490     data_show.links = unique_links(data_show_collect.links);
    585491     
    586      // extend the object, with some lookup hashes on neighbourhood
    587      hashes = gen_neighbours(data_show.links);
    588      data_show = $.extend(data_show, hashes);
    589 /* data_show.nodes.forEach; data_all.links;
    590 .filter(function(e) {*/
    591 /*                console.log ("DEBUG: links.filter::" + (nodes_sel.indexOf(e.target) > -1 ) )*/
    592 /*               return (data_show.nodes.indexOf(data_all.nodes[e.target]) > -1 || data_show.nodes.indexOf(data_all.nodes[e.source]) > -1)    */
    593 /*            return (data_show.nodes.indexOf(data_all.nodes[e.s]) > -1 || data_show.nodes.indexOf(e.target) > -1)
    594          });*/
    595      
     492     // extend the object, with some lookup hashes on neighbourhood
     493     add_lookups(data_show);
     494 
    596495     return data_show;
    597496    }
    598497
    599498/** generate lookup hashes for neighbours;
     499    for faster/simpler neighborhood lookup
     500from: http://stackoverflow.com/questions/8739072/highlight-selected-node-its-links-and-its-children-in-a-d3-js-force-directed-g
    600501*/
    601 function gen_neighbours(links) {
    602 
     502function add_lookups(data) {
     503
     504    var links = data.links;
    603505    var neighbours = {"links_index": {},
    604506                      "nodes_in": {}, "nodes_out": {},
     
    630532                       });
    631533                       
    632 return neighbours;
    633 
    634 }
    635 
     534    data = $.extend(data, neighbours);
     535    return data;
     536}
     537
     538
     539
     540/*                        item_detail.text(function (d) { return "links_in: " +  dataShowCount(d.key, "links_in") +  "; links_out: " +  dataShowCount(d.key, "links_out") ;
     541                                                       })*/
    636542function dataShowCount(n_key, info_type) {
    637543
     
    642548       }
    643549}
     550
    644551/** returns appropriate link
    645552*/
     
    648555}
    649556
    650 /** access function to retrieve the neigbours from the hashes
    651 especially handles the (necessarily?) empty elements (undefined),
    652 as not every position is filled
    653 (perhaps other key, than index would be less confusing)
     557
     558function neighboursWithLinks (n, dir, depth=1) {
     559 return neighboursWithLinks (data_all, n, dir, depth);
     560}
     561/** access function to retrieve the neighbours from the hashes
     562@param dir in|out|any  - but "any" branches in unexpected ways (because it goes in and out on every level = it takes all the children of the parent)
     563@param depth 0-n - go depth-levels; negative depth := no depth restriction = go to the end of the paths;
     564@returns a sub-graph
    654565*/
    655 function neighbours (n, dir, depth=1) {
    656         var n_in = neighbours_in[n.key] ? neighbours_in[n.key] : [] ;
    657         var n_out = neighbours_out[n.key] ? neighbours_out[n.key] : [] ;
    658         var result_n;
    659         if (dir == 'in' ) { result_n = n_in; }
    660                    else if (dir == 'out' ) { result_n = n_out; }
    661                    else { result_n = n_out.concat(n_in); }
    662         var n_nextlevel = [];
    663         if (depth > 1) {
    664          result_n.forEach (function(n)
    665                      { var n_neighbours = neighbours(n, dir, depth - 1);
    666                      n_nextlevel = n_nextlevel.concat(n_neighbours); }
    667                             )
    668          }
    669         return result_n.concat(n_nextlevel);
    670        
    671 }
    672 
    673 function neighboursWithLinks (n, dir, depth=1) {
    674         var n_in = neighbours_in[n.key] ? neighbours_in[n.key] : [] ;
    675         var n_out = neighbours_out[n.key] ? neighbours_out[n.key] : [] ;
    676         var l_in = links_in[n.key] ? links_in[n.key] : [] ;
    677         var l_out = links_out[n.key] ? links_out[n.key] : [] ;
     566function neighboursWithLinks (data, n, dir, depth=1) {
     567    if (depth==0) { return {nodes:[], links:[]};}
     568
     569        var n_in = data.nodes_in[n.key] ? data.nodes_in[n.key] : [] ;
     570        var n_out = data.nodes_out[n.key] ? data.nodes_out[n.key] : [] ;
     571        var l_in = data.links_in[n.key] ? data.links_in[n.key] : [] ;
     572        var l_out = data.links_out[n.key] ? data.links_out[n.key] : [] ;
    678573       
    679574        var result_n = {nodes:[], links:[]};
     
    682577                   else { result_n.nodes = n_out.concat(n_in); result_n.links = l_out.concat(l_in);  }
    683578        var n_nextlevel = {nodes:[], links:[]};
    684         if (depth > 1) {
     579        if (depth > 0 || depth < 0) {
    685580         result_n.nodes.forEach (function(n)
    686                      { var n_neighbours = neighboursWithLinks(n, dir, depth - 1);
     581                     { var n_neighbours = neighboursWithLinks(data, n, dir, depth - 1);
    687582                     n_nextlevel.nodes = n_nextlevel.nodes.concat(n_neighbours.nodes);
    688583                     n_nextlevel.links = n_nextlevel.links.concat(n_neighbours.links);
     
    694589        return result_n;
    695590       
    696 }
    697 
    698 function neighbour_links (nodes, dir) {
    699     var l_result = []
    700    
    701         nodes.forEach (function(n) {
    702                var l_in = links_in[n.key] ? links_in[n.key] : [] ;
    703                var l_out = links_out[n.key] ? links_out[n.key] : [] ;
    704                if (dir == 'in' ) { l_result = l_result.concat(l_in); }
    705                else if (dir == 'out' ) { l_result = l_result.concat(l_out); }
    706                else { l_result = l_result.concat(l_out.concat(l_in)); }
    707             } );       
    708  
    709     return l_result;
    710591}
    711592
     
    723604    return result;
    724605}
    725 
    726606
    727607/** deduplicates links (based on source-target-index
     
    801681   }
    802682   
    803    
    804   /*   
    805      d3.select(trg_container).selectAll("input").data(opts[)
    806             .enter().append("input")
    807             .attr("id", "k")
    808             .attr("type", "text")
    809             .attr("value", "val")
    810 //            .attr("value", function (d) { return d } )
    811          ;
    812        
    813 */     
     683   
    814684}
    815685
Note: See TracChangeset for help on using the changeset viewer.