source: SMC/trunk/SMC/src/web/scripts/js/cmd-dep-graph.js @ 2456

Last change on this file since 2456 was 2456, checked in by vronk, 11 years ago

added highlighting on mouseover
reorganized and cleaned up code

File size: 28.5 KB
Line 
1
2
3var item_li = null;
4
5var svg  = null; // main svg-element
6var data_all = null; // global holder for all (input) data
7var nodes_sel = null; // global holder for selected data (selected nodes)
8var data_show = null; // global holder for data to show  closure over nodes_sel
9var nest = {}; 
10var detail_data = null; // global holder for detail-data (in html) 
11 
12
13var index_container_selector = "#index-container";
14var graph_container_selector = '#infovis';
15var navi_container_selector = '#navigate';
16var detail_container_selector = "#detail-container";
17var detail_info_holder_selector =  '#detail-info-holder';
18
19var graph_container = null;
20var index_container = null; 
21
22var input_prefix = "input-";
23var select_rect_min_size = 5;
24var min_circle = 4;
25var comp_reg_url = "http://catalog.clarin.eu/ds/ComponentRegistry/?item=";     
26/*var source_file = "../scripts/cmd-dep-graph-d3_all_svg.json"*/
27var source_file = "file:/C:/Users/m/3/clarin/_repo/SMC/output/cmd-dep-graph.d3.js"
28var detail_file = "file:/C:/Users/m/3/clarin/_repo/SMC/output/smc_stats_detail.html"
29
30var opts = {"depth-before": {"value":2, "min":0, "max":10, "widget":"slider"}, 
31            "depth-after":{"value":2, "min":0, "max":10, "widget":"slider"}, 
32            "link-distance": {"value":80, "min":10, "max":200, "widget":"slider" }, 
33            "charge":{"value":400, "min":10, "max":1000, "widget":"slider" },
34            "node-weight": {"value":"1", "values":["1","usage"], "widget":"selectone" },
35            "curve": {"value":"straight", "values":["straight","arc"], "widget":"selectone" },
36            "layout": {"value":"horizontal-tree", "values":["vertical-tree", "horizontal-tree", "weak-tree","force","dot"], "widget":"selectone" },
37            "labels": {"value":"hide", "values":["show","hide"], "widget":"selectone" },                         
38            };
39
40
41
42/**  gets the data for the graph and calls rendering of the lists
43 * @name initGraph
44 * @function
45 */
46 function initGraph ()
47    {
48    graph_container = $(graph_container_selector);
49   
50    fillOpts(navi_container_selector);
51   
52    $('#infovis-wrapper').resizable( {
53                   start: function(event, ui) {
54                            graph_container.hide();
55                        },
56                   stop: function(event, ui) {
57                            graph_container.show();
58                            renderGraph();
59                       }
60                }
61                );
62
63   
64    $("#navigate .slider").slider();
65   
66     // load data
67     d3.json(source_file , 
68                function(json) {       
69                    // return if data missing
70                    if (json==null) { notify("source data missing: " + source_file ); return null}           
71                    data_all = json;
72                    data_all.links.forEach(function(d) { 
73                                        //resolve numeric index to node references
74                                                src_ix = d.source;
75                                                d.source = data_all.nodes[src_ix];
76                                                d.source.index = src_ix;
77                                                trg_ix = d.target;
78                                                d.target = data_all.nodes[trg_ix];
79                                                d.target.index = trg_ix;
80                                                src_key = d.source.key;
81                                                trg_key = d.target.key;
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   
94                });       
95}
96
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
112    @param nodes - accepts an array of nodes (like in data.nodes)
113*/ 
114function renderNodeList (nodes, target_container_selector) {
115
116    nest = d3.nest()
117    .key(function(d) { return d.type; })
118    .sortValues(function(a, b) { return d3.ascending(a.name, b.name); })
119    .entries(nodes);
120 
121    target_container = d3.select(target_container_selector);
122        target_container.selectAll("div").remove();
123       
124       
125           
126        var group_divs = target_container.selectAll("div").data(nest)
127                        .enter().append("div")
128                        .attr("id", function (d) { return "detail-" + d.key })
129                        .classed("cmds-ui-block init-show", 1);
130                       
131      var group_headers = group_divs.append("div").classed("header", 1)
132                        .text(function (d) { return d.key + " |" + d.values.length + "|"});
133                       
134      var list =  group_divs.append("div").classed("content",1)
135                    .append("ul");
136      var item_li = list.selectAll(".node-item")       
137                    .data(function(d) { return d.values; })
138                    .enter().append("li")
139                    .attr("class", "node-item")
140                    .text(function (d) { return d.name})
141                    .on("click", function(d) { d.selected= d.selected ? 0 : 1 ; updateSelected() });
142         
143                   
144            /* slightly different behaviour for the main-index and rendering of the selected nodes in the detail-view */
145          //  console.log("target_container:" + target_container_selector);
146            if (target_container_selector == index_container_selector) {
147                index_container = target_container;
148                item_li.attr("id", function (d) { return "n-" + d.name });
149                item_li.classed("highlight", function (d) { return d.selected });
150               
151              } else {
152                 var item_detail = item_li.append("div")
153                                          .classed("node-detail", 1);
154                           
155                 item_detail.append("a")
156                            .attr("href",function (d) { if (d.type.toLowerCase()=='datcat') return d.id 
157                                                        else return comp_reg_url + d.id })
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                                    }
167                          });
168                           
169              }
170                       
171   handleUIBlock($(target_container_selector).find(".cmds-ui-block"));
172 
173}
174
175function filterIndex (search_string){
176    var filtered_index_nodes = data_all.nodes.filter(function(d, i) { 
177     //   console.log(d.name.indexOf(search_string));
178        return d.name.toLowerCase().indexOf(search_string) > -1; 
179    });
180   
181   renderIndex(filtered_index_nodes, index_container_selector);
182}
183
184
185function renderGraph () {
186    renderGraph(data_show, graph_container);
187}
188
189/** render the data as graph  into target-container */
190function renderGraph (data, target_container=graph_container) {
191
192    data = dataToShow(nodes_sel);
193
194    if (data == null) { 
195       $(target_container).text("no data to show"); 
196       return;
197     } else {
198       $(target_container).text("");
199     }
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 
207 
208   var w = $(target_container).width(),
209        h = $(target_container).height(); 
210     
211 
212        // console.log (w + '-' + h);
213     var force = d3.layout.force()
214            .nodes(data.nodes)
215            .links(data.links)
216            .size([w, h])
217           // .gravity(0.3)
218            .linkDistance(parseInt(opt("link-distance")))
219            .charge(parseInt(opt("charge")) * -1)
220            .on("tick", tick) 
221            .start();
222//    console.log ("gravity: " + force.gravity() );             
223 
224       // remove old render:
225          d3.select(graph_container_selector).selectAll("svg").remove();
226                 
227        svg = d3.select(graph_container_selector).append("svg:svg")
228            .attr("width", w)        .attr("height", h);
229       
230        // Per-type markers, as they don't inherit styles.
231        svg.append("svg:defs").selectAll("marker")
232          .data(["uses"])
233          .enter().append("svg:marker")
234            .attr("id", String)
235            .attr("viewBox", "0 -5 10 10")
236            .attr("refX", 15)
237            .attr("refY", -1.5)
238            .attr("markerWidth", 6)
239            .attr("markerHeight", 6)
240            .attr("orient", "auto")
241          .append("svg:path")
242            .attr("d", "M0,-3L10,0L0,3");
243       
244        var path = svg.append("svg:g").selectAll("path")
245            .data(force.links())
246            .enter().append("svg:path")
247/*            .attr("class", function(d) { return "link uses"; })*/
248            .classed("link", 1)
249            .classed("uses", 1)
250            .classed("highlight", function(d) { d.highlight } )
251            .attr("marker-end", function(d) { return "url(#uses)"; });
252/*            .style("stroke-width", function(d) { return Math.sqrt(d.value); });*/
253
254           
255           
256        var circle = svg.append("svg:g")
257             .selectAll("circle")
258            .data(force.nodes())
259            .enter().append("svg:circle")
260/*            .attr("r", 6)*/
261            .attr("r", function(d) { if (opt("node-weight")=="1"){ return min_circle }
262                                        else {return (Math.sqrt(d.count)>min_circle ? Math.sqrt(d.count) * 2 : min_circle); } })
263          /*  .attr("x", function(d) {return d.x;})
264            .attr("y", function(d) {return d.y;})*/
265            .call(force.drag); 
266       
267         circle.append("title")
268            .text(function(d) { return d.name; });
269       
270       svg.selectAll("circle")
271            .attr("class", function(d) { return "type-" + d.type.toLowerCase()})
272            .classed("selected", function(d) { return d.selected; })
273          .on("click", function(d) {d.selected= d.selected ? 0 : 1; updateSelected() })
274          .on("mouseover", highlight("in")).on("mouseout", highlight("out"));
275       
276      /*   
277        var textgroup = svg.append("svg:g").selectAll("g")
278            .data(data.nodes)
279          .enter().append("svg:g")
280          .attr("class", function(d) { return "type-" + d.type.toLowerCase()})
281          .on("click", function(d) {d.selected= d.selected ? 0 : 1; updateSelected() });
282       
283       
284         textgroup.attr("data-key", function (d) { return d.name } );
285         
286        // A copy of the text with a thick white stroke for legibility.
287        textgroup.append("svg:text")
288            .attr("x", 8)
289            .attr("y", ".31em")
290            .attr("class", "shadow")
291           
292            .text(function(d) { return d.name; });
293       
294        textgroup.append("svg:text")
295            .attr("x", 8)
296            .attr("y", ".31em")
297            .text(function(d) { return d.name; });
298*/
299
300   function tick(e) {
301    var link_distance_int = parseInt(opt("link-distance"));     
302    var k =  10 * e.alpha;
303          if (opt("layout")=='dot') {
304            data.links.forEach(function(d, i) {
305              d.source.x = (d.source.init_x / 150 * link_distance_int) ;
306              d.target.x = (d.target.init_x / 150 * link_distance_int);
307           
308            });
309          } else if (opt("layout")=='weak-tree') {
310              data.links.forEach(function(d, i) {
311              d.source.x -= k;
312                d.target.x += k;
313                });
314          } else if (opt("layout")=='vertical-tree') {
315                   var ky= 1.4 * e.alpha, kx = .4 * e.alpha;
316                   data.links.forEach(function(d, i) {
317                     if (d.source.level==0) { d.source.y = 20 };
318                     d.target.x += (d.source.x - d.target.x)  * kx;
319                     d.target.y += (d.source.y - d.target.y + link_distance_int) * ky;
320                    });
321           } else if (opt("layout")=='horizontal-tree') {
322                   var kx= 1.4 * e.alpha, ky = .4 * e.alpha;
323                   data.links.forEach(function(d, i) {
324                       if (d.source.level==0) { d.source.x = 20 };
325                       d.target.y += (d.source.y - d.target.y)  * ky;
326                       d.target.x += (d.source.x - d.target.x + link_distance_int  ) * kx;
327                  });
328            }
329     
330           /*  parent foci
331                  var kx = 1.2 * e.alpha;
332    data.links.forEach(function(d, i) {
333      d.target.x += (d.target.level * link_distance  - d.target.x) * kx;
334      });*/
335     
336         
337       transform();
338   } // end  tick()
339
340
341    function transform () { 
342         
343       path.attr("d", function(d) {
344             // links as elliptical arc path segments
345            if (opt("curve")=="arc") 
346            {   var dx = d.target.x - d.source.x,
347                    dy = d.target.y - d.source.y,
348                    dr = Math.sqrt(dx * dx + dy * dy);
349                return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
350            } else { 
351            // or straight
352                return "M" + d.source.x + "," + d.source.y + "L" + d.target.x + "," + d.target.y;
353            } 
354       });
355         
356         circle.attr("cx", function(d) {return d.x;})
357                .attr("cy", function(d) {return d.y;});
358      /* circle.attr("transform", function(d) {
359            return "translate(" + d.x + "," + d.y + ")";
360       });*/
361       
362  /*     textgroup.attr("transform", function(d) {
363            return "translate(" + d.x + "," + d.y + ")";
364       });*/
365    }
366       
367        // Highlight selected nodes using the quadtree.
368        svg.on("mousedown", function() {
369          var m0 = d3.mouse(this);
370       
371          var rect = d3.select(this).append("rect")
372              .style("fill", "#999")
373              .style("fill-opacity", .5);
374       
375          d3.select(window).on("mousemove", function() {
376            var m1 = d3.mouse(rect.node()),
377                x0 = Math.min(w, m0[0], m1[0]),
378                y0 = Math.min(w, m0[1], m1[1]),
379                x1 = Math.max(0, m0[0], m1[0]),
380                y1 = Math.max(0, m0[1], m1[1]);
381                // console.log("DEBUG: mousedown: " + (x1-x0) + ( y1-y0));       
382                    selectNodes(data.nodes, x0, y0, x1, y1);                   
383                    rect.attr("x", x0).attr("y", y0).attr("width", x1 - x0).attr("height", y1 - y0);
384                   
385          });
386       
387          d3.select(window).on("mouseup", function() {
388            // only change selection, if the rectangle was big enough
389            // (mainly to prevent clearing of the graph on clicks that look like mousemoves to the system)
390            if (rect.attr("width") > select_rect_min_size && rect.attr("height") > select_rect_min_size) {
391                updateSelected();
392            }
393            rect.remove();
394            d3.select(window).on("mousemove", null).on("mouseup", null);
395          });
396       
397          d3.event.preventDefault();
398        });
399}  // end renderGraph
400
401
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
420/**  select the nodes within the specified rectangle. */
421function selectNodes(nodes, x0, y0, x3, y3) {
422   
423  var points = [];
424  nodes.forEach(function(n) {   
425    if (n && (n.x >= x0) && (n.x < x3) && (n.y >= y0) && (n.y < y3)) {
426            points.push(n);
427            n.selected = 1;
428        } else {
429            n.selected = 0;
430        }
431/*    return x1 >= x3 || y1 >= y3 || x2 < x0 || y2 < y0;*/
432  });
433  return points;
434}
435
436
437function updateSelected () {
438    nodes_sel = data_all.nodes.filter(function (d) { return d.selected });
439   
440    renderGraph();
441    renderDetail(nodes_sel);
442   
443 //   index_container.selectAll("li").classed("highlight", function (d) { return d.selected });   
444}
445
446
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
472
473/**  generates the subset of data to display (based on selected nodes + options)
474fills global variable: data_show !
475*/
476function dataToShow (nodes) {
477     data_show = {};
478     data_show.nodes = nodes;
479        var data_show_collect = {nodes:[],links:[]};
480       
481        nodes.forEach(function(n) {
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"));
484                        data_show_collect.nodes = data_show_collect.nodes.concat(data_add_in.nodes).concat(data_add_out.nodes);
485                        data_show_collect.links = data_show_collect.links.concat(data_add_in.links).concat(data_add_out.links);
486                    });
487           
488/*         deduplicate nodes and edges */
489     data_show.nodes = unique_nodes(nodes.concat(data_show_collect.nodes));
490     data_show.links = unique_links(data_show_collect.links);
491     
492     // extend the object, with some lookup hashes on neighbourhood
493     add_lookups(data_show);
494 
495     return data_show;
496    }
497
498/** 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
501*/
502function add_lookups(data) {
503
504    var links = data.links;
505    var neighbours = {"links_index": {}, 
506                      "nodes_in": {}, "nodes_out": {},
507                      "links_in": {}, "links_out": {}};
508   
509        links.forEach(function(d) { 
510                            src_key = d.source.key;
511                            trg_key = d.target.key;
512                         // generate lookup hashes for neighbours;
513                            neighbours.links_index[src_key + "," + trg_key] = d;
514                            if (d.source) { 
515                                    if (! neighbours.nodes_in[trg_key]) { 
516                                        neighbours.nodes_in[trg_key] = [d.source];
517                                        neighbours.links_in[trg_key] = [d];
518                                     }  else {
519                                        neighbours.nodes_in[trg_key].push(d.source);
520                                        neighbours.links_in[trg_key].push(d);
521                                     }
522                             }
523                            if (d.target) { 
524                                    if (! neighbours.nodes_out[src_key]) { 
525                                        neighbours.nodes_out[src_key] = [d.target];
526                                        neighbours.links_out[src_key] = [d];
527                                    } else { 
528                                        neighbours.nodes_out[src_key].push(d.target);
529                                        neighbours.links_out[src_key].push(d) ;
530                                    }
531                             }
532                       });
533                       
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                                                       })*/
542function dataShowCount(n_key, info_type) { 
543
544    if (data_show[info_type][n_key]) {
545        return data_show[info_type][n_key].length;
546       } else {
547        return 0
548       }
549}
550
551/** returns appropriate link
552*/
553function neighboring(a, b) {
554  return linkedByIndex[a.index + "," + b.index];
555}
556
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
565*/
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] : [] ;
573       
574        var result_n = {nodes:[], links:[]};
575        if (dir == 'in' ) { result_n.nodes = n_in; result_n.links = l_in; }
576                   else if (dir == 'out' ) { result_n.nodes = n_out; result_n.links = l_out; }
577                   else { result_n.nodes = n_out.concat(n_in); result_n.links = l_out.concat(l_in);  }
578        var n_nextlevel = {nodes:[], links:[]};
579        if (depth > 0 || depth < 0) { 
580         result_n.nodes.forEach (function(n) 
581                     { var n_neighbours = neighboursWithLinks(data, n, dir, depth - 1);
582                     n_nextlevel.nodes = n_nextlevel.nodes.concat(n_neighbours.nodes); 
583                     n_nextlevel.links = n_nextlevel.links.concat(n_neighbours.links);
584                     })
585         }
586         result_n.nodes = result_n.nodes.concat(n_nextlevel.nodes);
587         result_n.links = result_n.links.concat(n_nextlevel.links);
588       
589        return result_n;
590       
591}
592
593/** deduplicates based on index-property */
594function unique_nodes(nodes) 
595{
596    var hash = {}, result = [];
597    for ( var i = 0, l = nodes.length; i < l; ++i ) {
598           n_key = nodes[i].key;
599        if ( !hash[n_key] ) { //it works with objects! in FF, at least
600            hash[ n_key ] = true;
601            result.push(nodes[i]);
602        }
603    }
604    return result;
605}
606
607/** deduplicates links (based on source-target-index
608based on: http://stackoverflow.com/questions/1890203/unique-for-arrays-in-javascript
609*/
610function unique_links(links) 
611{
612    var hash = {}, result = [];
613    for ( var i = 0, l = links.length; i < l; ++i ) {
614            src_key = links[i].source.key;
615            trg_key = links[i].target.key;
616            key = src_key + "," + trg_key;
617        if ( !hash[key] ) {
618            hash[ key] = true;
619            result.push(links[i]);
620        }
621    }
622    return result;
623}
624
625/**
626gets an option, checking with the values in the navigation-UI
627*/
628function opt(key) {
629
630    if ($('#' + input_prefix + key) && (opts[key].value != $('#' + input_prefix + key).val())) {
631        opts[key].value = $('#' + input_prefix + key).val();   
632     } else if (opts[key].value)  {
633        return opts[key].value
634     } else if (opts[key])  {
635        return opts[key]
636     } else {
637        return ""
638     }
639}
640
641function setOpt(input_object) {
642
643    var id = $(input_object).attr("id");
644    var val = $(input_object).val();
645    key = id.substring(id.indexOf(input_prefix) + input_prefix.length)
646    opts[key].value = val;
647    return opts[key].value;
648}
649
650
651function fillOpts(trg_container) {
652
653  for ( var key in opts ) {
654    if ($('#' + input_prefix + key).length) {
655        $('#' + input_prefix + key).value = opts[key].value;   
656     } else if (trg_container)  {
657        var new_input_label = "<label>" + key + "</label>";
658        var new_input;
659       
660       if (opts[key].widget == "slider") {
661            [new_input,new_widget] = genSlider(key, opts[key].values);
662         } else if (opts[key].widget =="selectone") {
663            [new_input,new_widget] = genCombo(key, opts[key].values);
664            // set initial value
665            $(new_input).val(opts[key].value);
666           
667        //     $(new_input).autocomplete({"source":opts[key].values});
668         }
669         
670    /* hook changing  options + redrawing the graph, when values in navigation changed */
671         new_input.change(function () {
672               setOpt(this);
673               var related_widget = $(this).data("related-widget");
674           if ( $(related_widget).hasClass("widget-slider")) {$(related_widget).slider("option", "value", $(this).val()); }
675               renderGraph(); 
676            });
677               
678        $(trg_container).append(new_input_label, new_input, new_widget);
679       
680     }
681   }
682   
683   
684}
685
686/** generating my own comboboxes, because very annoying trying to use some of existing jquery plugins (easyui.combo, combobox, jquery-ui.autocomplete) */ 
687function genCombo (key, data) {
688   
689    var select = $("<select id='widget-" + key + "' />")
690        select.attr("id", input_prefix + key)
691    data.forEach(function(v) { $(select).append("<option value='" + v +"' >" + v + "</option>") });
692    return [select, null];
693}
694
695function genSlider (key, data) {
696
697    var new_input = $("<input />");
698            new_input.attr("id", input_prefix + key)
699                 .val(opts[key].value)
700/*                 .attr("type", "text")*/
701                 .attr("size", 3);
702     
703    var new_widget = $("<div class='widget-" + opts[key].widget + "'></div>");
704        new_widget.attr("id", "widget-" + key);
705        new_widget.slider( opts[key]);
706           
707        // set both-ways references between the input-field and its slider - necessary for updating
708        new_widget.data("related-input-field",new_input);
709        new_input.data("related-widget",new_widget);
710     
711//           console.log("widget:" + opts[key].widget);
712       
713        new_widget.bind( "slidechange", function(event, ui) {
714            //   console.log(ui.value);
715               $(this).data("related-input-field").val(ui.value);
716               // update the opts-object, but based on the (updated) value of the related input-field
717                setOpt($(this).data("related-input-field"));
718               renderGraph();
719         });
720         
721   return [new_input,new_widget]; 
722} 
723
724
725function notify (msg) {
726  $("#notify").append(msg);
727}
Note: See TracBrowser for help on using the repository browser.