Reset checked status when switching between lists
[sgn.git] / mason / pedigree / stock_pedigree.mas
blob6e988c56b879272874abff504841bd48f7488d4d
1 <%doc>
2 =head1 NAME
4 stock_pedigree.mas
6 =head1 DESCRIPTION
8 This component displays a pedigree
10 =head1 AUTHORS
12 David Lyon      <dal333@cornell.edu>
13 Jeremy Edwards  <jde22@cornell.edu>
15 =head1 ARGUMENTS
17 =over 1
19 =item stock
21 $stock_id - the id of the stock for which pedigree information will be displayed
23 =back
24 =cut
26 </%doc>
28 <%args>
29 $stock_id
30 </%args>
32 <style>
33 .ui-autocomplete {
34     z-index: 2147483647;
36 #pdgv-wrap{
37     position: relative;
39 #pdgv-wrap>svg{
40     width: 100%;
42 </style>
44 <div class="modal fade" id="add_parent_dialog" name="add_parent_dialog" tabindex="-1" role="dialog" aria-labelledby="addParentDialog">
45     <div class="modal-dialog" role="document">
46         <div class="modal-content">
47             <div class="modal-header" style="text-align: center">
48                 <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
49                 <h4 class="modal-title" id="addParentDialog">Add Parent</h4>
50             </div>
51             <div class="modal-body">
52                 <div class="container-fluid">
54                     <form class="form-horizontal" role="form" method="post" id="add_parent_dialog_form" name="add_parent_dialog_form">
55                         <div class="form-group">
56                             <label class="col-sm-3 control-label">Stock Name: </label>
57                             <div class="col-sm-9" >
58                                 <input name="stock_autocomplete" id="stock_autocomplete" class="form-control" type="text" />
59                             </div>
60                         </div>
61                         <div class="form-group">
62                             <label class="col-sm-3 control-label">Parent is: </label>
63                             <div class="col-sm-9" >
64                                 <input type="radio" id="female" name="parent_type" value="female" checked="1"  /> female<br />
65                                 <input type="radio" id="male" name="parent_type" value="male" /> male<br />
66                             </div>
67                         </div>
68                         <div class="form-group" id="add_parent_cross_type_div">
69                             <label class="col-sm-3 control-label">Cross Type: </label>
70                             <div class="col-sm-9" >
71                                 <select class="form-control" id="add_parent_cross_type">
72                                     <option value="biparental">biparental</option>
73                                     <option value="self">self</option>
74                                     <option value="open">open pollinated</option>
75                                     <option value="sib">sib</option>
76                                     <option value="reselected">reselected</option>
77                                     <option value="bulk">bulk</option>
78                                     <option value="bulk_self">bulk selfed</option>
79                                     <option value="bulk_open">bulk and open pollinated</option>
80                                     <option value="doubled_haploid">doubled haploid</option>
81                                     <option value="dihaploid_induction">dihaploid induction</option>
82                                     <option value="polycross">polycross</option>
83                                     <option value="reciprocal">reciprocal</option>
84                                     <option value="multicross">multicross</option>
85                                 </select>
86                             </div>
87                         </div>
88                     </form>
90                 </div>
91             </div>
92             <div class="modal-footer">
93                 <button id="close_add_parent_dialog" type="button" class="btn btn-default" data-dismiss="modal">Close</button>
94                 <button type="button" class="btn btn-primary" name="add_parent_submit" id="add_parent_submit" title="Save Parent">Save</button>
95             </div>
96         </div>
97     </div>
98 </div>
100 <script>
102     jQuery('#add_parent_submit').click(function(){
103         associate_parent();
104     });
106     jQuery("#add_parent_link").click( function () {
107         jQuery("#add_parent_dialog" ).modal("show");
108     });
110     jQuery("#stock_autocomplete").autocomplete({
111         source: '/ajax/stock/accession_autocomplete'
112     });
114     jQuery('input:radio[name="parent_type"]').change(function(){
115         var type = jQuery("input:radio[name='parent_type']:checked").val();
116         if(type == 'female'){
117             jQuery('#add_parent_cross_type_div').show();
118         } else {
119             jQuery('#add_parent_cross_type_div').hide();
120             jQuery('#add_parent_cross_type').val('');
121         }
122     });
124     function associate_parent() {
125       var parentType = "";
126       parentType = jQuery("#add_parent_dialog").find("input:checked").val();
127       //alert("PARENTTYPE="+parentType);
128       var parentName = jQuery("#stock_autocomplete").val();
129       //alert("Parent name = "+parentName);
131       if (!parentName) { alert("We need a name here, sorry!"); return; }
133       var cross_type = jQuery('#add_parent_cross_type').val();
134       //alert(cross_type);
136       var stock_id = "<% $stock_id %>";
137       jQuery.ajax({
138         url: '/ajax/stock/add_stock_parent',
139         dataType: "json",
140         type: 'GET',
141         async: false,
142         data: 'stock_id='+stock_id+'&parent_name='+parentName+'&parent_type='+parentType+'&cross_type='+cross_type,
143         error: function(response) {
144             alert("An error occurred. Please try again later!"+response);
145         },
146         parseerror: function(response) {
147             alert("A parse error occurred. Please try again."+response);
148         },
149         success: function(response) {
150           if (response.error) { alert(response.error); }
151           else {
152             alert("The parent has been added. ["+response.error+"]");
153             jQuery("#add_parent_dialog").modal("hide");
154             document.location.reload(); // reload the entire page, because pedigree info is in several places.
155           }
156         },
157       });
160    }
162 </script>
165 <& /util/import_javascript.mas, classes => [ 'jqueryui' ] &>
168 <div>
169     <span style="white-space:nowrap;">
170         <span class="glyphicon glyphicon-move" aria-hidden="true">
171         </span> Drag to Pan
172     </span>&nbsp;&nbsp;
173     <span style="white-space:nowrap;">
174         <span class="glyphicon glyphicon-zoom-in" aria-hidden="true">
175         </span> Scroll to Zoom
176     </span>&nbsp;&nbsp;
177     <span style="white-space:nowrap;">
178         <span class="glyphicon glyphicon-minus" style="color:red;" aria-hidden="true">
179         </span> Female Parent
180     </span>&nbsp;&nbsp;
181     <span style="white-space:nowrap;">
182         <span class="glyphicon glyphicon-minus" style="color:blue;" aria-hidden="true">
183         </span> Male Parent
184     </span>&nbsp;&nbsp;
185     <span style="white-space:nowrap;">
186         <span class="glyphicon glyphicon-circle-arrow-right" style="color:purple;" aria-hidden="true">
187         </span> Expand Pedigree
188     </span>
190 </div>
191 <center>
192 <div id="pdgv-loading-indicator">
193     <br>
194     Loading... <img src="/documents/img/spinner.gif" />
195     <br>
196     <br>
197 </div>
198 <div id="pdgv-wrap" style="border:solid thin #ddd;width:100%;"></div>
199 </center>
200 <!-- <div style="border:solid thin black; padding:1em; margin-top:0.25em;">
201     <label class="checkbox-inline" style="display:inline-block;">
202         <input type="checkbox" id="inlineCheckbox1" value="option1"> Enable Overlay
203     </label>
204     <select class="form-control" style="max-width:12em; display:inline-block;">
205         <option selected disabled>Select Trait Type</option>
206         <option>Nominal/Catagorical</option>
207         <option>Scale/Numeric</option>
208     </select>
209     <select class="form-control" style="max-width:10em; display:inline-block;">
210         <option selected disabled>Select Trait</option>
211     </select>
212 </div> -->
214 <& /util/import_javascript.mas, classes => [ 'd3.d3v4Min', 'd3.d3-pedigree-tree', 'brapi.BrAPI', 'brapi.PedigreeViewer' ] &>
215 <script type="text/javascript">
216         "use strict";
218         // This function initializes and draws a Pedigree Viewer for a specified stock ID. 
219         // The Pedigree Viewer is configured with a base URL, an authentication token (if login is required), 
220         // and a callback function to generate links for each node in the viewer.        
221         function drawPedigreeViewer() {
222         
223             var STOCK_ID = "<% $stock_id %>";
224             var base_url="/brapi/v2";
225             var auth_token;
226             var require_login = "<%  $c->get_conf('brapi_require_login') %>";
227             if (require_login === '1'){
228                 auth_token = "<%  CXGN::Login->new($c->dbc->dbh)->get_login_cookie() %>";
229                 if (!auth_token){
230                     alert("Login required to display pedigree");
231                 }
232             }
234             var pdg = PedigreeViewer(base_url,auth_token,'v2.0',function(dbId){
235                 return "/stock/"+dbId+"/view";
236             });
238             pdg.newTree(STOCK_ID,function(){
239                 pdg.drawViewer("#pdgv-wrap",600,600);
240                 jQuery("#pdgv-loading-indicator").hide();
241             });
242         };
244         var onSwitchElement = document.getElementById('stock_pedigree_section_onswitch');
245         onSwitchElement.addEventListener('click', onSwitchHandler);
247         // display the viewer automatically - if the section is expanded by default
248         if ( onSwitchElement.style.display === 'none' ) {
249             onSwitchHandler();
250         }
252         // handler if viewer is collapsed - to trigger only once drawing after click
253         function onSwitchHandler() {
254             drawPedigreeViewer();
255             onSwitchElement.removeEventListener('click', onSwitchHandler);
256         }
257                 
258 // ;
259 // (function(){
260 //     var STOCK_ID = "<% $stock_id %>";
261 //     var loaded_nodes = {};
262 //     d3.json('/ajax/pedigrees/get_full?stock_id='+STOCK_ID,function(nodes){
263 //         nodes.forEach(function(node){
264 //             loaded_nodes[node.id] = node;
265 //         })
266 //         jQuery(document).ready(function(){
267 //             main(nodes);
268 //         });
269 //     });
270 //     function load_nodes(to_load,callback){
271 //         if (to_load.length<1) return;
272 //         var req_url = "/ajax/pedigrees/get_relationships";
273 //         var body = "stock_id="+to_load.join("&stock_id=");
274 //         d3.request(req_url)
275 //             .mimeType("application/json")
276 //             .header("X-Requested-With", "XMLHttpRequest")
277 //             .header("Content-Type", "application/x-www-form-urlencoded")
278 //             .response(function(xhr){return JSON.parse(xhr.responseText);})
279 //             .post(body,function(loaded){
280 //                 var nodes = loaded.filter(function(node){
281 //                     if (!loaded_nodes.hasOwnProperty(node.id)){
282 //                         loaded_nodes[node.id] = node;
283 //                         return true;
284 //                     }
285 //                     return false;
286 //                 });
287 //                 callback(nodes);
288 //             });
289 //     };
291 //     function main(start_nodes) {
292 //         var tree = d3.pedigreeTree()
293 //           .levelWidth(200)
294 //           .levelMidpoint(50)
295 //           .nodePadding(220)
296 //           .nodeWidth(10)
297 //           .linkPadding(25)
298 //           .vertical(true)
299 //           .parentsOrdered(true)
300 //           .parents(function(node){
301 //             return [loaded_nodes[node.parents.mother],loaded_nodes[node.parents.father]].filter(Boolean);
302 //           })
303 //           .id(function(node){
304 //             return node.id;
305 //           })
306 //           .groupChildless(true)
307 //           .iterations(10)
308 //           .data(start_nodes)
309 //           .excludeFromGrouping([STOCK_ID]);
310 //         drawTree(tree(),".pdgtree-canv");
311 //     }
313 //     function drawTree(layout,svg_selector,trans){
315 //         //set default change-transtion to no duration
316 //         trans = trans || d3.transition().duration(0);
318 //         //make wrapper(pdg)
319 //         var canv = d3.select(svg_selector);
320 //         var cbbox = canv.node().getBoundingClientRect();
321 //         var canvw = cbbox.width,
322 //             canvh = cbbox.height;
323 //         var pdg = canv.select('.pedigreeTree');
324 //         if (pdg.empty()){
325 //           pdg = canv.append('g').classed('pedigreeTree',true);
326 //         }
328 //         //make background
329 //         var bg = pdg.select('.pdg-bg');
330 //         if (bg.empty()){
331 //           bg = pdg.append('rect')
332 //             .classed('pdg-bg',true)
333 //             .attr("x",-canvw*500)
334 //             .attr("y",-canvh*500)
335 //             .attr('width',canvw*1000)
336 //             .attr('height',canvh*1000)
337 //             .attr('fill',"white")
338 //             .attr('stroke','none');
339 //         }
341 //         //make scaled content/zoom groups
342 //         var padding = 50;
343 //         var pdgtree_width = d3.max([500,layout.x[1]-layout.x[0]]);
344 //         var pdgtree_height = d3.max([500,layout.y[1]-layout.y[0]]);
345 //         var centeringx = d3.max([0,(500 - (layout.x[1]-layout.x[0]))/2]);
346 //         var centeringy = d3.max([0,(500 - (layout.y[1]-layout.y[0]))/2]);
347 //         var scale = get_fit_scale(canvw,canvh,pdgtree_width,pdgtree_height,padding);
348 //         var offsetx = (canvw-(pdgtree_width)*scale)/2 + centeringx*scale;
349 //         var offsety = (canvh-(pdgtree_height)*scale)/2 + centeringy*scale;
351 //         var content = pdg.select('.pdg-content');
352 //         if (content.empty()){
353 //           var zoom = d3.zoom();
354 //           var zoom_group = pdg.append('g').classed('pdg-zoom',true).data([zoom]);
356 //           content = zoom_group.append('g').classed('pdg-content',true);
357 //           content.datum({'zoom':zoom})
358 //           zoom.on("zoom",function(){
359 //             zoom_group.attr('transform',d3.event.transform);
360 //           });
361 //           bg.style("cursor", "all-scroll").call(zoom).call(zoom.transform, d3.zoomIdentity);
362 //           bg.on("dblclick.zoom",function(){
363 //             zoom.transform(bg.transition(),d3.zoomIdentity);
364 //             return false;
365 //           });
367 //           content.attr('transform',
368 //               d3.zoomIdentity
369 //                 .translate(offsetx,offsety)
370 //                 .scale(scale)
371 //             );
372 //         }
373 //         content.datum().zoom.scaleExtent([0.5,d3.max([pdgtree_height,pdgtree_width])/200])
374 //         content.transition(trans)
375 //           .attr('transform',
376 //             d3.zoomIdentity
377 //               .translate(offsetx,offsety)
378 //               .scale(scale)
379 //           );
382 //         //set up draw layers
383 //         var linkLayer = content.select('.link-layer');
384 //         if(linkLayer.empty()){
385 //             linkLayer = content.append('g').classed('link-layer',true);
386 //         }
387 //         var nodeLayer = content.select('.node-layer');
388 //         if(nodeLayer.empty()){
389 //             nodeLayer = content.append('g').classed('node-layer',true);
390 //         }
392 //         //link curve generators
393 //         var stepline = d3.line().curve(d3.curveStepAfter);
394 //         var curveline = d3.line().curve(d3.curveBasis);
395 //         var build_curve = function(d){
396 //           if (d.type=="parent->mid") return curveline(d.path);
397 //           if (d.type=="mid->child") return stepline(d.path);
398 //         };
400 //         //draw nodes
401 //         var nodes = nodeLayer.selectAll('.node')
402 //           .data(layout.nodes,function(d){return d.id;});
403 //         var newNodes = nodes.enter().append('g')
404 //           .classed('node',true)
405 //           .attr('transform',function(d){
406 //             var begin = d;
407 //             if(d3.event && d3.event.type=="click"){
408 //               begin = d3.select(d3.event.target).datum();
409 //             }
410 //             return 'translate('+begin.x+','+begin.y+')'
411 //           });
412 //         var nodeNodes = newNodes.filter(function(d){
413 //             return d.type=="node";
414 //         });
415 //         var groupNodes = newNodes.filter(function(d){
416 //             return d.type=="node-group";
417 //         });
418 //         //draw node group expanders
419 //         groupNodes.append("circle")
420 //           .style("cursor","pointer")
421 //           .attr("fill","purple")
422 //           .attr("stroke","purple")
423 //           .attr("cy",0)
424 //           .attr("r",10);
425 //         groupNodes.append('text')
426 //           .style("cursor","pointer")
427 //           .attr('y',6.5)
428 //           .attr("font-size","14px")
429 //           .attr("font-weight","bold")
430 //           .attr('text-anchor',"middle")
431 //           .attr('class', 'glyphicon')
432 //           .html("&#xe092;")
433 //           .attr('fill',"white");
434 //         //create expander handles on nodes
435 //         var expanders = nodeNodes.append('g').classed("expanders",true);
436 //         var child_expander = expanders.append("g").classed("child-expander",true)
437 //         child_expander.append("path")
438 //           .attr("fill","none")
439 //           .attr("stroke","purple")
440 //           .attr("stroke-width",4)
441 //           .attr("d",curveline([[0,20],[0,40]]));
442 //         child_expander.append("circle")
443 //           .style("cursor","pointer")
444 //           .attr("fill","purple")
445 //           .attr("stroke","purple")
446 //           .attr("cy",45)
447 //           .attr("r",10);
448 //         child_expander.append('text')
449 //           .style("cursor","pointer")
450 //           .attr('y',52)
451 //           .attr('x',-0.5)
452 //           .attr("font-size","14px")
453 //           .attr("font-weight","bold")
454 //           .attr('text-anchor',"middle")
455 //           .attr('class', 'glyphicon')
456 //           .html("&#xe094;")
457 //           .attr('fill',"white");
458 //         child_expander.on("click",function(d){
459 //           d3.select(this).on('click',null);
460 //           var end_blink = load_blink(d3.select(this).select("circle").node());
461 //           var to_load = d.value.children.mother_of.concat(d.value.children.father_of).filter(Boolean).map(String);
462 //           load_nodes(to_load,function(nodes){
463 //               end_blink();
464 //               layout.pdgtree.add(nodes);
465 //               drawTree(layout.pdgtree(),".pdgtree-canv",d3.transition().duration(700));
466 //           });
467 //         });
468 //         var parent_expander = expanders.append("g").classed("parent-expander",true)
469 //         parent_expander.append("path")
470 //           .attr("fill","none")
471 //           .attr("stroke","purple")
472 //           .attr("stroke-width",4)
473 //           .attr("d",curveline([[0,0],[0,-40]]));
474 //         parent_expander.append("circle")
475 //           .style("cursor","pointer")
476 //           .attr("fill","purple")
477 //           .attr("stroke","purple")
478 //           .attr("cy",-45)
479 //           .attr("r",10);
480 //         parent_expander.append('text')
481 //           .style("cursor","pointer")
482 //           .attr('y',-39)
483 //           .attr('x',-0.5)
484 //           .attr("font-size","14px")
485 //           .attr("font-weight","bold")
486 //           .attr('text-anchor',"middle")
487 //           .attr('class', 'glyphicon')
488 //           .html("&#xe093;")
489 //           .attr('fill',"white");
490 //         parent_expander.on("click",function(d){
491 //           d3.select(this).on('click',null);
492 //           var end_blink = load_blink(d3.select(this).select("circle").node());
493 //           var to_load = [d.value.parents.mother,d.value.parents.father].filter(Boolean).map(String);
494 //           load_nodes(to_load,function(nodes){
495 //               end_blink();
496 //               layout.pdgtree.add(nodes);
497 //               drawTree(layout.pdgtree(),".pdgtree-canv",d3.transition().duration(700));
498 //           });
499 //         });
500 //         nodeNodes.append('rect').classed("node-name-highlight",true)
501 //           .attr('fill',function(d){
502 //               return d.id==STOCK_ID?"pink":"none";
503 //           })
504 //           .attr('stroke-width',0)
505 //           .attr("width",220)
506 //           .attr("height",40)
507 //           .attr("y",-10)
508 //           .attr("rx",20)
509 //           .attr("ry",20)
510 //           .attr("x",-110);
511 //         nodeNodes.append('rect').classed("node-name-wrapper",true)
512 //           .attr('fill',"white")
513 //           .attr('stroke',"grey")
514 //           .attr('stroke-width',2)
515 //           .attr("width",200)
516 //           .attr("height",20)
517 //           .attr("y",0)
518 //           .attr("rx",10)
519 //           .attr("ry",10)
520 //           .attr("x",-100);
521 //         nodeNodes.filter(function(d){
522 //             return d.id!=STOCK_ID;
523 //           })
524 //           .append("a").attr("target","_blank")
525 //           .attr("href",function(d){
526 //             if(d.id==STOCK_ID) return null;
527 //             return "/stock/"+d.value.id+"/view";
528 //           })
529 //           .append('text').classed('node-name-text',true)
530 //           .attr('y',15)
531 //           .attr('text-anchor',"middle")
532 //           .html(function(d){
533 //             return d.value.name;
534 //           })
535 //           .attr('fill',"black");
536 //         nodeNodes.filter(function(d){
537 //             return d.id==STOCK_ID;
538 //           })
539 //           .append('text').classed('node-name-text',true)
540 //           .attr('y',15)
541 //           .attr('text-anchor',"middle")
542 //           .html(function(d){
543 //             return d.value.name;
544 //           })
545 //           .attr('fill',"black");
546 //         //set node width to text width
547 //         nodeNodes.each(function(d){
548 //             var nn = d3.select(this);
549 //             var ctl = nn.select('.node-name-text').node().getComputedTextLength();
550 //             var w = ctl+20;
551 //             nn.select('.node-name-wrapper')
552 //                 .attr("width",w)
553 //                 .attr("x",-w/2);
554 //             nn.select('.node-name-highlight')
555 //                 .attr("width",w+20)
556 //                 .attr("x",-(w+20)/2);
557 //         });
558 //         var allNodes = newNodes.merge(nodes);
559 //         //remove expander handles for nodes without unloaded relatives.
560 //         allNodes.each(function(d){
561 //             if (d.type=="node"){
562 //                 var parents_unloaded = [d.value.parents.mother,d.value.parents.father]
563 //                     .filter(function(node_id){
564 //                         return !!node_id && !loaded_nodes.hasOwnProperty(node_id);
565 //                     });
566 //                 var children_unloaded = d.value.children.mother_of.concat(d.value.children.father_of)
567 //                     .filter(function(node_id){
568 //                         return !!node_id && !loaded_nodes.hasOwnProperty(node_id);
569 //                     });
570 //                 if (parents_unloaded.length<1){
571 //                     d3.select(this).selectAll(".parent-expander").remove();
572 //                 }
573 //                 if (children_unloaded.length<1){
574 //                     d3.select(this).selectAll(".child-expander").remove();
575 //                 }
576 //             }
577 //         });
578 //         allNodes.transition(trans).attr('transform',function(d){
579 //           return 'translate('+d.x+','+d.y+')'
580 //         });
581 //         allNodes.filter(function(d){return d.type=="node-group"})
582 //           .style("cursor", "pointer")
583 //           .on("click",function(d){
584 //             layout.pdgtree.excludeFromGrouping(d.value.slice(0,10).map(function(d){return d.id;}));
585 //             drawTree(layout.pdgtree(),".pdgtree-canv",d3.transition().duration(700).ease(d3.easeLinear));
586 //         });
587 //         var oldNodes = nodes.exit().remove();
590 //         //link colors
591 //         var link_color = function(d){
592 //           if (d.type=="mid->child") return 'purple';
593 //           if (d.type=="parent->mid"){
594 //             //if its the first parent, red. Otherwise, blue.
595 //             var representative = d.sinks[0].type=="node-group"?
596 //                     d.sinks[0].value[0].value
597 //                     : d.sinks[0].value;
598 //             if (representative.parents.mother == d.source.id){
599 //                 return "red";
600 //             }
601 //             else {
602 //                 return "blue";
603 //             }
604 //           }
605 //           return 'gray';
606 //         }
608 //         //make links
609 //         var links = linkLayer.selectAll('.link')
610 //           .data(layout.links,function(d){return d.id;});
611 //         var newLinks = links.enter().append('g')
612 //           .classed('link',true);
613 //         newLinks.append('path')
614 //           .attr('d',function(d){
615 //             var begin = (d.sink || d.source);
616 //             if(d3.event && d3.event.type=="click"){
617 //               begin = d3.select(d3.event.target).datum();
618 //             }
619 //             return curveline([[begin.x,begin.y],[begin.x,begin.y],[begin.x,begin.y],[begin.x,begin.y]]);
620 //           })
621 //           .attr('fill','none')
622 //           .attr('stroke',link_color)
623 //           .attr('opacity',function(d){
624 //             if (d.type=="parent->mid") return 0.7;
625 //             return 0.999;
626 //           })
627 //           .attr('stroke-width',4);
628 //         var allLinks = newLinks.merge(links);
629 //         allLinks.transition(trans).select('path').attr('d',build_curve);
630 //         var oldNodes = links.exit().remove();
631 //     }
633 //     function load_blink(node){
634 //         var stop = false;
635 //         var original_fill = d3.select(node).style("fill");
636 //         var original_sw = d3.select(node).style("stroke-width");
637 //         function blink(){
638 //             if (!stop) d3.select(node)
639 //                 .transition()
640 //                 .duration(300)
641 //                 .style("fill", "white")
642 //                 .style("stroke-width", "5")
643 //                 .transition()
644 //                 .duration(300)
645 //                 .style("fill", original_fill)
646 //                 .style("stroke-width", original_sw)
647 //                 .on("end", blink);
648 //         }
649 //         blink();
650 //         return function(){
651 //             stop = true;
652 //         }
653 //     }
657 //     function get_fit_scale(w1,h1,w2,h2,pad){
658 //         w1 -= pad*2;
659 //         h1 -= pad*2;
660 //         if (w1/w2<h1/h2){
661 //             return w1/w2;
662 //         } else {
663 //             return h1/h2;
664 //         }
665 //     }
666 // })();
667 </script>