Revisions
-
rdpoor revised this gist
Apr 19, 2016 . No changes.There are no files selected for viewing
-
rdpoor revised this gist
Apr 19, 2016 . 2 changed files with 134 additions and 45 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1 +1,5 @@ This is a nearly verbatim copy of Mike Bostock's [Modifying a Force Layout example](https://bl.ocks.org/mbostock/1095795) -- the main difference is it has ample documentation explaining what's going on. We've taken the liberty of renaming some variables and methods to make them more descriptive, and in one case (can you spot it?) made a small pessimization to the code in the name of clarity. From the original version: This example demonstrates how to add and remove nodes and links from a force layout. The graph initially appears with three nodes A, B and C connected in a loop. Three seconds later, node B is removed, along with the links B-A and B-C. At six seconds, node B is reintroduced, restoring the original links B-A and B-C. This example uses the [general update pattern](http://bl.ocks.org/3808218) for [data joins](http://bost.ocks.org/mike/join/). This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -8,87 +8,172 @@ } .node { fill: #000; /* this is over-ridden by node.a (etc) below */ stroke: #fff; stroke-width: 1.5px; } /* the class of the node determines its color */ .node.a { fill: #1f77b4; } .node.b { fill: #ff7f0e; } .node.c { fill: #2ca02c; } </style> <body> <script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script> <script> var width = 960, // width and height of the SVG canvas height = 500; // A list of node objects. We represent each node as {id: "name"}, but the D3 // system will decorate the node with addtional fields, notably x: and y: for // the force layout and index" as part of the binding mechanism. var nodes = []; // A list of links. We represent a link as {source: <node>, target: <node>}, // and in fact, the force layout mechanism expects those names. links = []; // Create the force layout. After a call to force.start(), the tick method will // be called repeatedly until the layout "gels" in a stable configuration. var force = d3.layout.force() .nodes(nodes) .links(links) .linkDistance(100) .size([width, height]) .on("tick", tick); // add an SVG element inside the DOM's BODY element var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); function update_graph() { // First update the links... // The call to <selection>.data() gets the link objects that need updating // and associates them with the corresponding DOM elements, in this case, // SVG line elements. The first argument, force.links() simply returns our // links[] array. The second argument is a function that produces a unique // and invariate identifier for each link. This makes it possible for D3 to // correctly associate each link object with each line element in the DOM, // even if the link object moves around in memory. // // link_update, in addition to processing objects that need updating, // defines two custom methods, .enter() and .exit(), that refer to link // objects that are newly added and that have been deleted (respectively). // See below to see how these methods are used. var link_update = svg.selectAll(".link").data( force.links(), function(d) { return d.source.id + "-" + d.target.id; } ); // link_update.enter() creates an SVG line element for each new link // object. Note that we call .insert("line", ".node") to add SVG line // elements to the DOM before any elements with class="node". This // guarantees that the lines will be drawn first. (Try changing that to // .append("line") to see what happens...) link_update.enter() .insert("line", ".node") .attr("class", "link"); // link_update.exit() processes link objects that have been removed // by removing its corresponding SVG line element. link_update.exit() .remove(); // Now update the nodes. This is similar in structure to what we just // did for the links: // // node_selection.data() returns a selection of nodes that need updating // and defines two custom methods, .enter() and .exit(), that will process // newly created node objects and deleted node objects. // // Note that, similar to what we did for links, we've provided an id method // that returns a unique and invariate identifier for each node. This is // what lets D3 associate each node object with its corresponding circle // element in the DOM, even if the node object moves around in memory. var node_update = svg.selectAll(".node").data( force.nodes(), function(d) { return d.id;} ); // Create an SVG circle for each new node added to the graph. Note that we // use a function to set the class of each node, because in this demo, the // color is determined by the class of the node, e.g. // // <style> // .node.a { fill: #1f77b4; } // </style> // ... // <circle class="node a" r="8"</circle> // // ... but other techniques are possible node_update.enter() .append("circle") .attr("class", function(d) { return "node " + d.id; }) .attr("r", 8); // Remove the SVG circle whenever a node vanishes from the node list. node_update.exit() .remove(); // Start calling the tick() method repeatedly to lay out the graph. force.start(); } // This tick method is called repeatedly until the layout stabilizes. // // NOTE: the order in which we update nodes and links does NOT determine which // gets drawn first -- the drawing order is determined by the ordering in the // DOM. See the notes under link_update.enter() above for one technique for // setting the ordering in the DOM. function tick() { // Drawing the nodes: Update the cx, cy attributes of each circle element // from the x, y fields of the corresponding node object. svg.selectAll(".node") .attr("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }) // Drawing the links: Update the start and end points of each line element // from the x, y fields of the corresponding source and target node objects. svg.selectAll(".link") .attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); } // ================================================================ // Toplevel methods start here // 1. Add three nodes and three links. setTimeout(function() { var a = {id: "a"}, b = {id: "b"}, c = {id: "c"}; nodes.push(a, b, c); links.push({source: a, target: b}, {source: a, target: c}, {source: b, target: c}); update_graph(); }, 0); // 2. Remove node B and associated links. setTimeout(function() { nodes.splice(1, 1); // remove b links.shift(); // remove a-b links.pop(); // remove b-c update_graph(); }, 3000); // 3. Add node B back. setTimeout(function() { var a = nodes[0], b = {id: "b"}, c = nodes[1]; nodes.push(b); links.push({source: a, target: b}, {source: b, target: c}); update_graph(); }, 6000); </script> -
mbostock revised this gist
Feb 9, 2016 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1 @@ license: gpl-3.0 -
mbostock revised this gist
Oct 30, 2015 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -19,7 +19,7 @@ </style> <body> <script src="//d3js.org/d3.v3.min.js"></script> <script> var width = 960, -
mbostock revised this gist
Jun 11, 2015 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -19,7 +19,7 @@ </style> <body> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> <script> var width = 960, -
mbostock revised this gist
Dec 20, 2012 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
LoadingSorry, something went wrong. Reload?Sorry, we cannot display this file.Sorry, this file is invalid so it cannot be displayed. -
mbostock revised this gist
Dec 8, 2012 . 2 changed files with 3 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1 +1 @@ This example demonstrates how to add and remove nodes and links from a force layout. The graph initially appears with three nodes A, B and C connected in a loop. Three seconds later, node B is removed, along with the links B-A and B-C. At six seconds, node B is reintroduced, restoring the original links B-A and B-C. This example uses the [general update pattern](http://bl.ocks.org/3808218) for [data joins](http://bost.ocks.org/mike/join/). This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -53,15 +53,15 @@ start(); }, 0); // 2. Remove node B and associated links. setTimeout(function() { nodes.splice(1, 1); // remove b links.shift(); // remove a-b links.pop(); // remove b-c start(); }, 3000); // Add node B back. setTimeout(function() { var a = nodes[0], b = {id: "b"}, c = nodes[1]; nodes.push(b); -
mbostock revised this gist
Dec 8, 2012 . 1 changed file with 4 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,12 +3,14 @@ <style> .link { stroke: #000; stroke-width: 1.5px; } .node { fill: #000; stroke: #fff; stroke-width: 1.5px; } .node.a { fill: #1f77b4; } @@ -32,6 +34,7 @@ .nodes(nodes) .links(links) .charge(-400) .linkDistance(120) .size([width, height]) .on("tick", tick); -
mbostock revised this gist
Dec 8, 2012 . 1 changed file with 4 additions and 5 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -31,6 +31,7 @@ var force = d3.layout.force() .nodes(nodes) .links(links) .charge(-400) .size([width, height]) .on("tick", tick); @@ -41,23 +42,21 @@ var node = svg.selectAll(".node"), link = svg.selectAll(".link"); // 1. Add three nodes and three links. setTimeout(function() { var a = {id: "a"}, b = {id: "b"}, c = {id: "c"}; nodes.push(a, b, c); links.push({source: a, target: b}, {source: a, target: c}, {source: b, target: c}); start(); }, 0); // 2. Remove node bbb and associated links. setTimeout(function() { nodes.splice(1, 1); // remove b links.shift(); // remove a-b links.pop(); // remove b-c start(); }, 3000); // Add node bbb back. setTimeout(function() { @@ -73,7 +72,7 @@ link.exit().remove(); node = node.data(force.nodes(), function(d) { return d.id;}); node.enter().append("circle").attr("class", function(d) { return "node " + d.id; }).attr("r", 8); node.exit().remove(); force.start(); -
mbostock revised this gist
Dec 8, 2012 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1 @@ This example demonstrates how to add and remove nodes and links from a force layout. -
mbostock revised this gist
Dec 8, 2012 . 1 changed file with 10 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -11,6 +11,10 @@ stroke: #fff; } .node.a { fill: #1f77b4; } .node.b { fill: #ff7f0e; } .node.c { fill: #2ca02c; } </style> <body> <script src="http://d3js.org/d3.v3.min.js"></script> @@ -19,6 +23,8 @@ var width = 960, height = 500; var color = d3.scale.category10(); var nodes = [], links = []; @@ -39,7 +45,7 @@ // 1. Add three nodes and three links. setTimeout(function() { var a = {id: "a"}, b = {id: "b"}, c = {id: "c"}; nodes.push(a, b, c); links.push({source: a, target: b}, {source: a, target: c}, {source: b, target: c}); start(); @@ -55,19 +61,19 @@ // Add node bbb back. setTimeout(function() { var a = nodes[0], b = {id: "b"}, c = nodes[1]; nodes.push(b); links.push({source: a, target: b}, {source: b, target: c}); start(); }, 6000); function start() { link = link.data(force.links(), function(d) { return d.source.id + "-" + d.target.id; }); link.enter().insert("line", ".node").attr("class", "link"); link.exit().remove(); node = node.data(force.nodes(), function(d) { return d.id;}); node.enter().append("circle").attr("class", function(d) { return "node " + d.id; }).attr("r", 4.5); node.exit().remove(); force.start(); -
mbostock revised this gist
Dec 8, 2012 . 1 changed file with 56 additions and 86 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,116 +1,86 @@ <!DOCTYPE html> <meta charset="utf-8"> <style> .link { stroke: #ccc; } .node { fill: #000; stroke: #fff; } </style> <body> <script src="http://d3js.org/d3.v3.min.js"></script> <script> var width = 960, height = 500; var nodes = [], links = []; var force = d3.layout.force() .nodes(nodes) .links(links) .size([width, height]) .on("tick", tick); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); var node = svg.selectAll(".node"), link = svg.selectAll(".link"); start(); // 1. Add three nodes and three links. setTimeout(function() { var a = {id: "aaa"}, b = {id: "bbb"}, c = {id: "ccc"}; nodes.push(a, b, c); links.push({source: a, target: b}, {source: a, target: c}, {source: b, target: c}); start(); }, 2000); // 2. Remove node bbb and associated links. setTimeout(function() { nodes.splice(1, 1); // remove b links.shift(); // remove a-b links.pop(); // remove b-c start(); }, 4000); // Add node bbb back. setTimeout(function() { var a = nodes[0], b = {id: "bbb"}, c = nodes[1]; nodes.push(b); links.push({source: a, target: b}, {source: b, target: c}); start(); }, 4000); function start() { link = link.data(force.links(), function(d) { return d.source.id + "-" + d.target.id; }); link.enter().insert("line", ".node").attr("class", "link"); link.exit().remove(); node = node.data(force.nodes(), function(d) { return d.id;}); node.enter().append("circle").attr("class", "node").attr("r", 4.5); node.exit().remove(); force.start(); } function tick() { node.attr("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }) link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); } </script> -
mbostock revised this gist
Oct 12, 2012 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
LoadingSorry, something went wrong. Reload?Sorry, we cannot display this file.Sorry, this file is invalid so it cannot be displayed. -
mbostock revised this gist
Sep 18, 2011 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -51,7 +51,7 @@ var link = vis.selectAll("line.link") .data(links, function(d) { return d.source.id + "-" + d.target.id; }); link.enter().insert("svg:line", "g.node") .attr("class", "link"); link.exit().remove(); -
mbostock revised this gist
Sep 18, 2011 . 1 changed file with 85 additions and 114 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,145 +1,116 @@ <!DOCTYPE html> <html> <head> <script type="text/javascript" src="http://mbostock.github.com/d3/d3.js?2.1.3"></script> <script type="text/javascript" src="http://mbostock.github.com/d3/d3.geom.js?2.1.3"></script> <script type="text/javascript" src="http://mbostock.github.com/d3/d3.layout.js?2.1.3"></script> <style type="text/css"> .link { stroke: #ccc; } .nodetext { pointer-events: none; font: 10px sans-serif; } </style> </head> <body> <script type="text/javascript"> var w = 960, h = 500; var force = d3.layout.force() .gravity(.05) .distance(100) .charge(-100) .size([w, h]); var nodes = force.nodes(), links = force.links(); var vis = d3.select("body").append("svg:svg") .attr("width", w) .attr("height", h); force.on("tick", function() { vis.selectAll("g.node") .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); vis.selectAll("line.link") .attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); }); function restart() { var link = vis.selectAll("line.link") .data(links, function(d) { return d.source.id + "-" + d.target.id; }); link.enter().append("svg:line") .attr("class", "link"); link.exit().remove(); var node = vis.selectAll("g.node") .data(nodes, function(d) { return d.id;}); var nodeEnter = node.enter().append("svg:g") .attr("class", "node") .call(force.drag); nodeEnter.append("svg:image") .attr("class", "circle") .attr("xlink:href", "https://d3nwyuy0nl342s.cloudfront.net/images/icons/public.png") .attr("x", "-8px") .attr("y", "-8px") .attr("width", "16px") .attr("height", "16px"); nodeEnter.append("svg:text") .attr("class", "nodetext") .attr("dx", 12) .attr("dy", ".35em") .text(function(d) { return d.id }); node.exit().remove(); force.start(); } // Add three nodes and three links. function step1() { var a = {id: "aaa"}, b = {id: "bbb"}, c = {id: "ccc"}; nodes.push(a, b, c); links.push({source: a, target: b}, {source: a, target: c}, {source: b, target: c}); restart(); } // Remove node bbb and associated links. function step2() { nodes.splice(1, 1); // remove b links.shift(); // remove a-b links.pop(); // remove b-c restart(); } // Add node bbb back. function step3() { var a = nodes[0], b = {id: "bbb"}, c = nodes[1]; nodes.push(b); links.push({source: a, target: b}, {source: b, target: c}); restart(); } restart(); setTimeout(step1, 2000); setTimeout(step2, 4000); setTimeout(step3, 6000); </script> </body> </html> -
mbostock revised this gist
Sep 18, 2011 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -93,8 +93,8 @@ var nA = {id: 'aaa'}; var nB = {id: 'bbb'}; var nC = {id: 'ccc'}; nodes.push(nB); nodes.push(nA); nodes.push(nC); var lAB = {source: nA, target: nB}; -
mbostock revised this gist
Jul 20, 2011 . 1 changed file with 4 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -78,7 +78,10 @@ node.exit().remove(); force .nodes(nodes) .links(links) .start(); } -
mbostock renamed this gist
Jul 20, 2011 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
ZoltanLajosKis created this gist
Jul 20, 2011 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,142 @@ <!DOCTYPE html> <html> <head> <script type="text/javascript" src="http://mbostock.github.com/d3/d3.js"></script> <script type="text/javascript" src="http://mbostock.github.com/d3/d3.layout.js"></script> <script type="text/javascript" src="http://mbostock.github.com/d3/d3.geom.js"></script> <style type="text/css"> .link { stroke: #ccc; } .nodetext { pointer-events: none; font: 10px sans-serif; } </style> </head> <body> <script type="text/javascript"> var w = 960, h = 500 var nodes = [], links = []; var vis = d3.select("body").append("svg:svg") .attr("width", w) .attr("height", h); var force = self.force = d3.layout.force() .nodes(nodes) .links(links) .gravity(.05) .distance(100) .charge(-100) .size([w, h]); force.on("tick", function() { var node = vis.selectAll("g.node") .data(nodes, function(d) { return d.id;} ) var link = vis.selectAll("line.link") .data(links, function(d) { return d.source.id + ',' + d.target.id}) link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); }); function recalc() { var link = vis.selectAll("line.link") .data(links, function(l) { return l.source.id + '-' + l.target.id; }); link.enter().append("svg:line") .attr("class", "link") .attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); link.exit().remove(); var node = vis.selectAll("g.node") .data(nodes, function(d) { return d.dpid;}).call(force.drag); var nodeEnter = node.enter().append("svg:g") .attr("class", "node") .call(force.drag); nodeEnter.append("svg:image") .attr("class", "circle") .attr("xlink:href", "https://d3nwyuy0nl342s.cloudfront.net/images/icons/public.png") .attr("x", "-8px") .attr("y", "-8px") .attr("width", "16px") .attr("height", "16px"); nodeEnter.append("svg:text") .attr("class", "nodetext") .attr("dx", 12) .attr("dy", ".35em") .text(function(d) { return d.id }); node.exit().remove(); force.start(); } /* Scenario */ /* step 1: add three nodes and three links */ function step1() { var nA = {id: 'aaa'}; var nB = {id: 'bbb'}; var nC = {id: 'ccc'}; nodes.push(nA); nodes.push(nB); nodes.push(nC); var lAB = {source: nA, target: nB}; var lAC = {source: nA, target: nC}; var lBC = {source: nB, target: nC}; links.push(lAB ); links.push(lAC); links.push(lBC); recalc(); } /* step 2: node B disappears with links */ function step2() { nodes = nodes.filter(function(n) { return n.id !== 'bbb'; }); links = links.filter(function(l) { return (l.source.id !== 'bbb' && l.target.id !== 'bbb'); }); recalc(); } /* step 3: node B reappears with links */ function step3() { var nB = {id: 'bbb'}; nodes.push(nB); /* find exiting nodes for links */ var nA = nodes.filter(function(n) { return n.id === 'aaa'; })[0]; var nC = nodes.filter(function(n) { return n.id === 'ccc'; })[0]; var lAB = {source: nA, target: nB}; var lBC = {source: nB, target: nC}; links.push(lAB); links.push(lBC); recalc(); } window.setTimeout(step1, 2000); window.setTimeout(step2, 4000); window.setTimeout(step3, 6000); force.start(); recalc(); </script> </body> </html>