From 93dc51ad3c34bf96d17c5a26a93c43c676c72318 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Tue, 16 Jun 2015 14:21:48 +0100 Subject: [PATCH 01/73] baseline for the new update pattern code to display the subnet graph --- static/js/graphSub.js | 23 ++++++++--------------- static/tests/graphSubTests.html | 15 ++++----------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/static/js/graphSub.js b/static/js/graphSub.js index 4058fa7..232582f 100644 --- a/static/js/graphSub.js +++ b/static/js/graphSub.js @@ -20,7 +20,7 @@ var makeSubNodesArr = function(visited, propname, nodes){ // remove properties added by d3, preserve use defined properties obj = _.omit(obj, ['index', 'fixed', 'weight', 'px', 'py', 'x', 'y']) result.push(obj); - console.log('### ', result); + console.log('makeSubNodesArr ', result); }; return result; }; @@ -40,6 +40,7 @@ var makeSubLinksArr = function(subNodes, propname, subLinks){ // create a new subLinksArr based on the subNodeArr for (var i = 0; i < subLinks.length; i++) { obj = subLinks[i]; + // look up propname and get its array indice obj.source = nodeIndex[obj.source[propname]]; obj.target = nodeIndex[obj.target[propname]]; result.push(obj); @@ -48,18 +49,11 @@ var makeSubLinksArr = function(subNodes, propname, subLinks){ return result }; -// return a sub-network of n nodes around a source node +// return a sub-network of n layers around a source node var graphSub = function(datum, propname, distanceToFetch, links, nodes){ - console.log(arguments); - // this function looks at the distance from the source nodes - // it expands outwards, distance times. this is equivelent - // to 'distance' in graph theory. + // console.log(arguments); - // the algorithim here is concerned with collecting the links making up paths - // add the initial datum to toVisit - // pop the tovisit array - // find all the links involving popped item and store them in subLinks, store the other id into toVisit - // repeat the above distanceToFetch times. + // initialise variable. var count = 0, toVisit = [], visited = [], @@ -74,14 +68,14 @@ var graphSub = function(datum, propname, distanceToFetch, links, nodes){ current = toVisit.pop(toVisit); for (var i = 0; i < links.length; i++) { - + // collect links that 'current' point to if(links[i].source[propname] === current){ // dont store if present, uses underscore.js union subLinks = _.union([links[i]], subLinks); toVisit = _.union([links[i].target[propname]], toVisit); visited = _.union([links[i].target[propname]], visited); }; - + // collect the links that point to 'current' if(links[i].target[propname] === current){ // dont store if present, uses underscore.js union subLinks = _.union([links[i]], subLinks); @@ -93,10 +87,9 @@ var graphSub = function(datum, propname, distanceToFetch, links, nodes){ count = count + 1; }; - console.log('i just vistited-> ', visited); result.nodes = makeSubNodesArr(visited, propname, nodes); result.links = makeSubLinksArr(result.nodes, propname, subLinks) - console.log('final ', JSON.stringify(result)); + console.log('RESULT ', JSON.stringify(result)); return result; }; \ No newline at end of file diff --git a/static/tests/graphSubTests.html b/static/tests/graphSubTests.html index 75ef088..15145eb 100644 --- a/static/tests/graphSubTests.html +++ b/static/tests/graphSubTests.html @@ -65,12 +65,12 @@ var actual, expected, message; -/* + actual = graphSub(this.testNodes[0], "name", n, this.testLinks, this.testNodes); expected = {nodes: [{'name': 'a'}], links: []}; message = 'sub network from a when n = 0'; assert.deepEqual(actual, expected, message); -/* + actual = graphSub(this.testNodes[1], "name", n, this.testLinks, this.testNodes); expected = {nodes: [{'name': 'b'}], links: []}; message = 'sub network from b when n = 0'; @@ -80,15 +80,8 @@ expected = {nodes: [{'name': 'c'}], links: []}; message = 'sub network from c when n = 0'; assert.deepEqual(actual, expected, message); -*/ -///* - n = 1; - - actual = graphSub(this.testNodes[0], "name", n, this.testLinks, this.testNodes); - expected = {"nodes":[{"name":"h"},{"name":"g"},{"name":"f"},{"name":"b"},{"name":"a"}],"links":[{"source":4,"target":0,"value":1},{"source":4,"target":1,"value":1},{"source":4,"target":2,"value":1},{"source":4,"target":3,"value":1}]}; - message = 'sub network from a when n = 1'; - assert.deepEqual(actual, expected, message); -//*/ + + }); From ce00903a69b311ae5a9dc2ebbf45ed68dc56f5dc Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Wed, 17 Jun 2015 00:04:18 +0100 Subject: [PATCH 02/73] first draft of update code --- graphSub.html | 187 ++++++++++++++++++++++++-------- static/js/graphSub.js | 10 +- static/tests/graphSubTests.html | 2 +- 3 files changed, 145 insertions(+), 54 deletions(-) diff --git a/graphSub.html b/graphSub.html index cc6ea1e..8e80c04 100644 --- a/graphSub.html +++ b/graphSub.html @@ -30,66 +30,159 @@

graphSub

var width = 960, height = 500; + // decalare a colour pallete var color = d3.scale.category20(); + // create the force layout var force = d3.layout.force() .charge(-120) .linkDistance(200) .size([width, height]); + // create the svg element in the DOM var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); - d3.json("data/fm.json", function(error, graph) { - force - .nodes(graph.nodes) - .links(graph.links) - .start(); - - var link = svg.selectAll(".link") - .data(graph.links) - .enter().append("line") - .attr("class", "link") - .style("stroke-width", function(d) { return Math.sqrt(d.value); }); - - // grouped nodes(gnodes) - var gnodes = svg.selectAll(".node") - .data(graph.nodes) - .enter() - .append('g') - - function test(d, i){ - console.log('node ', d, i); - //console.log(graph.nodes); - var n = 1; - - // pass a deep copy, not the actualy dataset, else problems - var res = graphSub(d, "name", n, JSON.parse(JSON.stringify(graph.links)), JSON.parse(JSON.stringify(graph.nodes))); + // load the JSON data into memory + var jsonData; + d3.json("data/fm.json", function(error, graph){ + console.log("Loading Data...."); + + if (error) { + throw { + name: 'JSONError', + message: error + }; + }else{ + jsonData = graph; + console.log("Success...", graph); + update(graph); + }; + }); + + function click (datum, i) { + console.log(datum.name, 'has been cliked...'); + var n = 1, + result; + + // create unique deep copies of data and nodes + var links = JSON.parse(JSON.stringify(jsonData.links)); + var nodes = JSON.parse(JSON.stringify(jsonData.nodes)); - }; - var node = gnodes.append("circle") - .attr("class", "node") - .attr("r", 20) - .style("fill", function(d) { return color(d.group); }) - .on('click', test) - .call(force.drag); - - var labels = gnodes.append("text") - .text(function(d) { return d.name; }); - - force.on("tick", function() { - 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; }); - - // Translate the groups - gnodes.attr("transform", function(d) { - return 'translate(' + [d.x, d.y] + ')'; - }); - }); + result = graphSub(datum, + "name", + n, + links, + nodes); + + console.log('Sub-graph complete', result); + } + function update (graph) { + console.log("Updating graph...", graph.links); + + force + .nodes(graph.nodes) + .links(graph.links) + .start(); + + // DATA JOIN + // Join new data with old elements, if any. + var link = svg.selectAll(".link") + .data(graph.links); + + var gnodes = svg.selectAll(".node") + .data(graph.nodes); + + // UPDATE + // Update old elements as needed. + + + // ENTER + // Create new elements as needed. + link.enter().append("line") + .attr("class", "link") + .style("stroke-width", function(d) { return Math.sqrt(d.value); }); + + gnodes.enter() + .append('g') + .append("circle") + .attr("class", "node") + .attr("r", 20) + .style("fill", function(d) { return color(d.group); }) + .on('click', click) // bind a mouse-click to each node + .call(force.drag) + .append("text") + .text(function(d) { return d.name; }); + + force.on("tick", function() { + 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; }); + + // Translate the groups + gnodes.attr("transform", function(d) { + return 'translate(' + [d.x, d.y] + ')'; + }); + }); + + } + // load the JSON data + /* + d3.json("data/fm.json", function(error, graph) { + force + .nodes(graph.nodes) + .links(graph.links) + .start(); + + // create a line for each item in graph.links + // create a data join + var link = svg.selectAll(".link") + .data(graph.links) + .enter().append("line") + .attr("class", "link") + .style("stroke-width", function(d) { return Math.sqrt(d.value); }); + + // grouped nodes(gnodes) + // create a data join + var gnodes = svg.selectAll(".node") + .data(graph.nodes) + .enter() + .append('g') + + function update(d, i){ + //console.log('node ', d, i); + //console.log(graph.nodes); + var n = 1; + + // pass a deep copy, not the actualy dataset, else problems + var res = graphSub(d, "name", n, JSON.parse(JSON.stringify(graph.links)), JSON.parse(JSON.stringify(graph.nodes))); + + }; + var node = gnodes.append("circle") + .attr("class", "node") + .attr("r", 20) + .style("fill", function(d) { return color(d.group); }) + .on('click', update) // bind a mouse-click to each node + .call(force.drag); + + var labels = gnodes.append("text") + .text(function(d) { return d.name; }); + + force.on("tick", function() { + 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; }); + + // Translate the groups + gnodes.attr("transform", function(d) { + return 'translate(' + [d.x, d.y] + ')'; + }); + }); }); +*/ \ No newline at end of file diff --git a/static/js/graphSub.js b/static/js/graphSub.js index 232582f..cacf23c 100644 --- a/static/js/graphSub.js +++ b/static/js/graphSub.js @@ -20,7 +20,7 @@ var makeSubNodesArr = function(visited, propname, nodes){ // remove properties added by d3, preserve use defined properties obj = _.omit(obj, ['index', 'fixed', 'weight', 'px', 'py', 'x', 'y']) result.push(obj); - console.log('makeSubNodesArr ', result); + //console.log('makeSubNodesArr ', result); }; return result; }; @@ -45,14 +45,13 @@ var makeSubLinksArr = function(subNodes, propname, subLinks){ obj.target = nodeIndex[obj.target[propname]]; result.push(obj); }; - + //console.log('makeSubLinksArr ', result); return result }; // return a sub-network of n layers around a source node var graphSub = function(datum, propname, distanceToFetch, links, nodes){ - // console.log(arguments); - + // initialise variable. var count = 0, toVisit = [], @@ -89,7 +88,6 @@ var graphSub = function(datum, propname, distanceToFetch, links, nodes){ result.nodes = makeSubNodesArr(visited, propname, nodes); result.links = makeSubLinksArr(result.nodes, propname, subLinks) - console.log('RESULT ', JSON.stringify(result)); - + return result; }; \ No newline at end of file diff --git a/static/tests/graphSubTests.html b/static/tests/graphSubTests.html index 15145eb..14dc512 100644 --- a/static/tests/graphSubTests.html +++ b/static/tests/graphSubTests.html @@ -80,7 +80,7 @@ expected = {nodes: [{'name': 'c'}], links: []}; message = 'sub network from c when n = 0'; assert.deepEqual(actual, expected, message); - + }); From 0e85b7f56e1e9f014ee1b09e8a5a28aeecced612 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Thu, 18 Jun 2015 21:27:15 +0100 Subject: [PATCH 03/73] can display graph but updates are buggy --- dynamicForce.html | 288 ++++++++++++++++++++++++++++++++++++++++++ graphSub.html | 158 +++++++++++------------ static/js/graphSub.js | 32 ++++- 3 files changed, 388 insertions(+), 90 deletions(-) create mode 100644 dynamicForce.html diff --git a/dynamicForce.html b/dynamicForce.html new file mode 100644 index 0000000..fbe2afd --- /dev/null +++ b/dynamicForce.html @@ -0,0 +1,288 @@ + + + + Animating Changes in Force Diagram + + + + + + + + + + \ No newline at end of file diff --git a/graphSub.html b/graphSub.html index 8e80c04..6356648 100644 --- a/graphSub.html +++ b/graphSub.html @@ -18,6 +18,7 @@ +

graphSub

@@ -30,22 +31,28 @@

graphSub

var width = 960, height = 500; - // decalare a colour pallete + // declare a colour pallete var color = d3.scale.category20(); // create the force layout var force = d3.layout.force() - .charge(-120) - .linkDistance(200) - .size([width, height]); + .charge(-120) + .linkDistance(200) + .size([width, height]); + + var nodes, + links; // create the svg element in the DOM - var svg = d3.select("body").append("svg") + var svg = d3.select("body").append("svg:svg") .attr("width", width) - .attr("height", height); + .attr("height", height) + .append('svg:g'); + + var nodes, + links; // load the JSON data into memory - var jsonData; d3.json("data/fm.json", function(error, graph){ console.log("Loading Data...."); @@ -55,9 +62,20 @@

graphSub

message: error }; }else{ - jsonData = graph; - console.log("Success...", graph); - update(graph); + + // On start, the layout initializes various attributes on the + // associated nodes. Called when nodes or links change. + force + .nodes(graph.nodes) + .links(graph.links) + .start(); + + nodes = force.nodes(); + links = force.links(); + console.log(nodes); + + console.log("Success..."); + update(); }; }); @@ -66,40 +84,45 @@

graphSub

var n = 1, result; + // TODO move inside graphSub // create unique deep copies of data and nodes - var links = JSON.parse(JSON.stringify(jsonData.links)); - var nodes = JSON.parse(JSON.stringify(jsonData.nodes)); - result = graphSub(datum, "name", n, links, - nodes); + nodes); console.log('Sub-graph complete', result); - } - function update (graph) { - console.log("Updating graph...", graph.links); + + nodes = result.nodes; + links = result.links; - force - .nodes(graph.nodes) - .links(graph.links) - .start(); + update(); + } + function update () { + console.log("Updating graph..."); // DATA JOIN // Join new data with old elements, if any. var link = svg.selectAll(".link") - .data(graph.links); + .data(links, function (d) { + return d.source.name + "-" + d.target.name; + } + ); var gnodes = svg.selectAll(".node") - .data(graph.nodes); - + .data(nodes, function (d) { + return d.name; + } + ); + // UPDATE // Update old elements as needed. // ENTER // Create new elements as needed. + link.enter().append("line") .attr("class", "link") .style("stroke-width", function(d) { return Math.sqrt(d.value); }); @@ -108,81 +131,46 @@

graphSub

.append('g') .append("circle") .attr("class", "node") - .attr("r", 20) + .attr("r", 10) .style("fill", function(d) { return color(d.group); }) .on('click', click) // bind a mouse-click to each node .call(force.drag) - .append("text") + + var labels = gnodes.append("text") .text(function(d) { return d.name; }); + // EXIT + // Remove old elements as needed. + gnodes.exit() + .transition() + .duration(750) + .attr("y", 60) + .style("fill-opacity", 1e-6) + .remove(); + + link.exit() + .transition() + .duration(750) + .attr("y", 60) + .style("fill-opacity", 1e-6) + .remove(); + force.on("tick", function() { 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; }); - // Translate the groups - gnodes.attr("transform", function(d) { - return 'translate(' + [d.x, d.y] + ')'; - }); + // Translate the groups + gnodes.attr("transform", function(d) { + return 'translate(' + [d.x, d.y] + ')'; + }); }); - } - // load the JSON data - /* - d3.json("data/fm.json", function(error, graph) { - force - .nodes(graph.nodes) - .links(graph.links) - .start(); - - // create a line for each item in graph.links - // create a data join - var link = svg.selectAll(".link") - .data(graph.links) - .enter().append("line") - .attr("class", "link") - .style("stroke-width", function(d) { return Math.sqrt(d.value); }); + // Restart the force layout + force.start(); - // grouped nodes(gnodes) - // create a data join - var gnodes = svg.selectAll(".node") - .data(graph.nodes) - .enter() - .append('g') - - function update(d, i){ - //console.log('node ', d, i); - //console.log(graph.nodes); - var n = 1; - - // pass a deep copy, not the actualy dataset, else problems - var res = graphSub(d, "name", n, JSON.parse(JSON.stringify(graph.links)), JSON.parse(JSON.stringify(graph.nodes))); - - }; - var node = gnodes.append("circle") - .attr("class", "node") - .attr("r", 20) - .style("fill", function(d) { return color(d.group); }) - .on('click', update) // bind a mouse-click to each node - .call(force.drag); - - var labels = gnodes.append("text") - .text(function(d) { return d.name; }); - - force.on("tick", function() { - 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; }); - - // Translate the groups - gnodes.attr("transform", function(d) { - return 'translate(' + [d.x, d.y] + ')'; - }); - }); -}); -*/ + } \ No newline at end of file diff --git a/static/js/graphSub.js b/static/js/graphSub.js index cacf23c..1d44d4a 100644 --- a/static/js/graphSub.js +++ b/static/js/graphSub.js @@ -11,6 +11,7 @@ // create a list of the nodes in the subnet var makeSubNodesArr = function(visited, propname, nodes){ + console.log(visited); var result = [], searchPair = {}, obj; @@ -18,10 +19,12 @@ var makeSubNodesArr = function(visited, propname, nodes){ searchPair[propname] = visited[i]; obj = _.findWhere(nodes, searchPair) // remove properties added by d3, preserve use defined properties - obj = _.omit(obj, ['index', 'fixed', 'weight', 'px', 'py', 'x', 'y']) + obj = _.omit(obj, ['index']) result.push(obj); //console.log('makeSubNodesArr ', result); }; + console.log(nodes); + return result; }; @@ -29,6 +32,10 @@ var makeSubNodesArr = function(visited, propname, nodes){ var makeSubLinksArr = function(subNodes, propname, subLinks){ var result = [], nodeIndex = {}, + sourceIndex, + sourceObject = {}, + targetIndex, + targetObject = {}, obj; // {'a': 0, 'b': 1, 'c': '2' etc} @@ -36,13 +43,24 @@ var makeSubLinksArr = function(subNodes, propname, subLinks){ for (var i = 0; i < subNodes.length; i++) { nodeIndex[subNodes[i][propname]] = i; }; + console.log(JSON.stringify(nodeIndex)); // create a new subLinksArr based on the subNodeArr for (var i = 0; i < subLinks.length; i++) { obj = subLinks[i]; + console.log(JSON.stringify(obj)); // look up propname and get its array indice - obj.source = nodeIndex[obj.source[propname]]; - obj.target = nodeIndex[obj.target[propname]]; + sourceIndex = nodeIndex[obj.source[propname]]; + sourceObject.index = sourceIndex; + sourceObject.propname = subNodes[sourceIndex][propname]; + + targetIndex = nodeIndex[obj.target[propname]]; + targetObject.index = targetIndex; + targetObject.propname = subNodes[targetIndex][propname]; + + obj.source = sourceObject; + obj.target = targetObject; + result.push(obj); }; //console.log('makeSubLinksArr ', result); @@ -52,6 +70,10 @@ var makeSubLinksArr = function(subNodes, propname, subLinks){ // return a sub-network of n layers around a source node var graphSub = function(datum, propname, distanceToFetch, links, nodes){ + // create deep copies of data + var nodes = JSON.parse(JSON.stringify(nodes)); + var links = JSON.parse(JSON.stringify(links)); + // initialise variable. var count = 0, toVisit = [], @@ -85,9 +107,9 @@ var graphSub = function(datum, propname, distanceToFetch, links, nodes){ count = count + 1; }; - result.nodes = makeSubNodesArr(visited, propname, nodes); - result.links = makeSubLinksArr(result.nodes, propname, subLinks) + result.links = makeSubLinksArr(result.nodes, propname, JSON.parse(JSON.stringify(subLinks))); + console.log('result', result); return result; }; \ No newline at end of file From 00f18d6da0c85c52e7c5729624b6dc8a156be756 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Fri, 19 Jun 2015 23:44:19 +0100 Subject: [PATCH 04/73] complete re-write based on closures, http://bost.ocks.org/mike/chart/ --- graphSub.html | 331 ++++++++++++++++++++++++++------------------------ 1 file changed, 175 insertions(+), 156 deletions(-) diff --git a/graphSub.html b/graphSub.html index 6356648..409795c 100644 --- a/graphSub.html +++ b/graphSub.html @@ -6,171 +6,190 @@ graphSub + Animating Changes in Force Diagram + + + + .link { + stroke: #2E2E2E; + stroke-width: 2px; + } + + .node { + stroke: #fff; + stroke-width: 2px; + } + .textClass { + stroke: #323232; + font-family: "Lucida Grande", "Droid Sans", Arial, Helvetica, sans-serif; + font-weight: normal; + stroke-width: .5; + font-size: 14px; + } + - -
-

graphSub

-
-
-
- - - - \ No newline at end of file From 9d442c636c40cd1ac738747ae2f29d388a89e449 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Sat, 20 Jun 2015 23:57:20 +0100 Subject: [PATCH 05/73] re-write with custom Array method --- dynamicForce.html | 2 + graphSub.html | 313 ++++++++++++++++++++++++++-------------------- 2 files changed, 179 insertions(+), 136 deletions(-) diff --git a/dynamicForce.html b/dynamicForce.html index fbe2afd..750b06c 100644 --- a/dynamicForce.html +++ b/dynamicForce.html @@ -112,6 +112,8 @@ links = force.links(); //#################################################################### var update = function () { + console.log(nodes); + var link = vis.selectAll("line") .data(links, function (d) { return d.source.id + "-" + d.target.id; diff --git a/graphSub.html b/graphSub.html index 409795c..90d99e3 100644 --- a/graphSub.html +++ b/graphSub.html @@ -32,20 +32,31 @@ \ No newline at end of file From 9f0fe1e8968f7a7321a930b5cef90676e5a97cf8 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Sun, 21 Jun 2015 20:31:24 +0100 Subject: [PATCH 06/73] debug phase --- graphSub.html | 148 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 102 insertions(+), 46 deletions(-) diff --git a/graphSub.html b/graphSub.html index 90d99e3..79d751b 100644 --- a/graphSub.html +++ b/graphSub.html @@ -33,9 +33,9 @@ From a0765621030426cc9c1cd937d25824ea0fa45513 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Mon, 22 Jun 2015 03:40:43 +0100 Subject: [PATCH 07/73] a few minor bug fixes, layout not rendering correctly but nodes visible --- graphSub.html | 62 +- static/css/base.css | 3836 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 3869 insertions(+), 29 deletions(-) create mode 100644 static/css/base.css diff --git a/graphSub.html b/graphSub.html index 79d751b..a5447b8 100644 --- a/graphSub.html +++ b/graphSub.html @@ -5,7 +5,6 @@ graphSub - Animating Changes in Force Diagram @@ -32,6 +31,7 @@ diff --git a/static/css/base.css b/static/css/base.css new file mode 100644 index 0000000..9d22be2 --- /dev/null +++ b/static/css/base.css @@ -0,0 +1,3836 @@ +/*! Copyright jQuery Foundation and other contributors + * Includes: + * - normalize.css v1.0.1 | MIT License | git.io/normalize + * - Font Awesome - http://fortawesome.github.com/Font-Awesome - CC BY 3.0 + */ + +/* ========================================================================== + HTML5 display definitions + ========================================================================== */ + +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +/* + * Corrects `block` display not defined in IE 6/7/8/9 and Firefox 3. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section, +summary { + display: block; +} + +/* + * Corrects `inline-block` display not defined in IE 6/7/8/9 and Firefox 3. + */ + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +/* + * Prevents modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/* ========================================================================== + Base + ========================================================================== */ + +/* + * 1. Corrects text resizing oddly in IE 6/7 when body `font-size` is set using + * `em` units. + * 2. Prevents iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-size: 100%; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ + -ms-text-size-adjust: 100%; /* 2 */ +} + +/* + * Addresses `font-family` inconsistency between `textarea` and other form + * elements. + */ + +html, +button, +input, +select, +textarea { + font-family: sans-serif; + color: #333; +} + +/* + * Addresses margins handled incorrectly in IE 6/7. + */ + +body { + margin: 0; +} + +::-moz-selection { + background: #b3d4fc; + text-shadow: none; +} + +::selection { + background: #b3d4fc; + text-shadow: none; +} + +.chromeframe { + margin: 0.2em 0; + background: #ccc; + color: #000; + padding: 0.2em 0; +} + +@font-face { + font-family: 'FontAwesome'; + src: url('fonts/fontawesome-webfont.eot?v=3.0.2'); + src: url('fonts/fontawesome-webfont.eot?#iefix&v=3.0.2') format('embedded-opentype'), + url('fonts/fontawesome-webfont.woff?v=3.0.2') format('woff'), + url('fonts/fontawesome-webfont.ttf?v=3.0.2') format('truetype'); + font-weight: normal; + font-style: normal; +} + +/* ========================================================================== + Links + ========================================================================== */ + +/* + * Addresses `outline` inconsistency between Chrome and other browsers. + */ + +a:focus { + outline: thin dotted; +} + +/* + * Improves readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* ========================================================================== + Typography + ========================================================================== */ + +/* + * Addresses font sizes and margins set differently in IE 6/7. + * Addresses font sizes within `section` and `article` in Firefox 4+, Safari 5, + * and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0 0 0.33em; +} + +h2 { + font-size: 1.5em; + margin: 0 0 0.5em; +} + +h3 { + font-size: 1.25em; + margin: 0 0 0.67em; +} + +h4 { + font-size: 1em; + margin: 0 0 1em; +} + +h5 { + font-size: 0.83em; + margin: 0 0 1.33em; +} + +h6 { + font-size: 0.75em; + margin: 0 0 2em; +} + +h1, h2, h3, h4, h5, h6 { + font-weight: 700; + font-family: "klavika-web", "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif !important; +} +/* + * Addresses styling not present in IE 7/8/9, Safari 5, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/* + * Addresses style set to `bolder` in Firefox 3+, Safari 4/5, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +blockquote { + margin: 1em 40px; +} + +/* + * Addresses styling not present in Safari 5 and Chrome. + */ + +dfn { + font-style: italic; +} + +/* + * Addresses styling not present in IE 6/7/8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/* + * Addresses margins set differently in IE 6/7. + */ + +p, +pre { + margin: 1em 0; +} + +/* + * Improves readability of pre-formatted text in all browsers. + */ + +pre, code { + white-space: pre; + white-space: pre-wrap; + word-wrap: break-word; + word-spacing: 0; + font-size: 13px; + line-height: 16px; +} +code { + padding: 0 3px; + background-color: #eee; /* support: IE8 */; + background-color: rgba( 0, 0, 0, .1 ); + border-radius: 3px; +} +pre code { + background-color: transparent; + font-size: 16px; + font-weight: bold; + white-space: pre; + word-wrap: normal; +} + +/* + * Addresses CSS quotes not supported in IE 6/7. + */ + +q { + quotes: none; +} + +/* + * Addresses `quotes` property not supported in Safari 4. + */ + +q:before, +q:after { + content: ''; + content: none; +} + +/* + * Prevents `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* ========================================================================== + Lists + ========================================================================== */ + +/* + * Addresses margins set differently in IE 6/7. + */ + +dl, +menu, +ol, +ul { + margin: 0 0 1em; +} + +dd { + margin: 0 0 0 40px; +} + +/* + * Addresses paddings set differently in IE 6/7. + */ + +menu, +ol, +ul { + padding: 0; +} + +/* + * Corrects list images handled incorrectly in IE 7. + */ + +nav ul, +nav ol { + list-style: none; + list-style-image: none; +} + +/* ========================================================================== + Embedded content + ========================================================================== */ + +/* + * 1. Removes border when inside `a` element in IE 6/7/8/9 and Firefox 3. + * 2. Improves image quality when scaled in IE 7. + */ + +img { + border: 0; /* 1 */ + -ms-interpolation-mode: bicubic; /* 2 */ + vertical-align: middle; + max-width: 100%; +} + +/* ========================================================================== + Figures + ========================================================================== */ + +/* + * Addresses margin not present in IE 6/7/8/9, Safari 5, and Opera 11. + */ + +figure { + margin: 0; +} + +/* ========================================================================== + Forms + ========================================================================== */ + +/* + * Corrects margin displayed oddly in IE 6/7. + */ + +form { + margin: 0; + padding: 10px 0; +} + +/* + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 0; + margin: 0; + padding: 0; +} + +/* + * 1. Corrects color not being inherited in IE 6/7/8/9. + * 2. Corrects text not wrapping in Firefox 3. + * 3. Corrects alignment displayed oddly in IE 6/7. + */ + +legend { + border: 0; /* 1 */ + padding: 0; + white-space: normal; /* 2 */ + *margin-left: -7px; /* 3 */ +} + +/* + * 1. Corrects font size not being inherited in all browsers. + * 2. Addresses margins set differently in IE 6/7, Firefox 3+, Safari 5, + * and Chrome. + * 3. Improves appearance and consistency in all browsers. + */ + +button, +input, +select, +textarea { + font-size: 100%; /* 1 */ + margin: 0; /* 2 */ + vertical-align: baseline; /* 3 */ + *vertical-align: middle; /* 3 */ +} + +/* + * Addresses Firefox 3+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +button, +input { + line-height: normal; +} + +/* + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Corrects inability to style clickable `input` types in iOS. + * 3. Improves usability and consistency of cursor style between image-type + * `input` and others. + * 4. Removes inner spacing in IE 7 without affecting normal text inputs. + * Known issue: inner spacing remains in IE 6. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ + *overflow: visible; /* 4 */ +} + +/* + * Re-set default cursor for disabled elements. + */ + +button[disabled], +input[disabled] { + cursor: default; +} + +/* + * 1. Addresses box sizing set to content-box in IE 8/9. + * 2. Removes excess padding in IE 8/9. + * 3. Removes excess padding in IE 7. + * Known issue: excess padding remains in IE 6. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ + *height: 13px; /* 3 */ + *width: 13px; /* 3 */ +} + +/* + * 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome. + * 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; + box-sizing: content-box; +} + +/* + * Removes inner padding and search cancel button in Safari 5 and Chrome + * on OS X. + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* + * Removes inner padding and border in Firefox 3+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/* + * 1. Removes default vertical scrollbar in IE 6/7/8/9. + * 2. Improves readability and alignment in all browsers. + */ + +textarea { + overflow: auto; /* 1 */ + vertical-align: top; /* 2 */ + min-height: 150px; + resize: vertical; +} + +#content input[type="text"], +#content input[type="email"], +#content textarea { + color: #666; + + width: 70%; + min-width: 300px; + + margin: 5px 0 10px 0; + padding: 8px 12px; + + background: rgba(245,245,245,0.37); + + border: 1px solid rgba(192,192,192,0.49); + border-radius: 2px; + + box-shadow: inset 0 1px 3px rgba(0,0,0,0.17); +} + +/* + * 1. :-moz-placeholder has been deprecated in favor of ::-moz-placeholder. + * 2. Using :placeholder for completeness. + */ +::-webkit-input-placeholder { + color: #9A1B1E; +} +:-moz-placeholder { /* 1 */ + color: #9A1B1E; +} +::-moz-placeholder { + color: #9A1B1E; +} +:-ms-placeholder { + color: #9A1B1E; +} +:placeholder { /* 2 */ + color: #9A1B1E; +} + +#content input:focus, +#content input[type="text"]:focus, +#content input[type="email"]:focus, +#content textarea:focus { + outline: none; + + color: #333; + background: #FFF; + + border: 1px solid #B24926; + + box-shadow: 0px 0px 6px rgba(23,138,156,0.5), + inset 0px 1px 3px rgba(0,0,0,0.2); +} + +/** + * Radio Buttons + */ + +.radio { + margin: 15px 0; +} + +#content .radio ul { + margin: 0; + padding: 0; + float: left; +} + +#content .radio ul li { + margin: 0; + padding: 0; + background: none; + list-style-type: none; +} + +.radio label { + margin: 5px 0; +} + +input[type=radio] { + margin: 0 5px 0 0; +} + +/** + * Checkboxes + */ + +input[type="checkbox"] { + margin: 0 5px 0 0; +} + +/** + * Submit Buttons + */ + +form input[type="submit"] { + margin: 40px 0; + float: none; +} + +/** + * Top aligned labels + */ + +.top-labels label, +.top-labels .radio label, +.top-labels input[type="text"], +.top-labels input[type="email"], +.top-labels textarea { + display: block; +} + +/** + * Left aligned labels + */ + +.left-labels label { + padding: 5px 0 0 0; + display: block; +} + +.left-labels span { + margin: 0 10px 0 0; + min-width: 100px; + + float: left; + + text-align: left; +} + +.left-labels .radio span { + padding-top: 5px; +} + +.left-labels .radio { + display: block; +} + +.left-labels .radio li label { + margin: 0; + padding: 0 0 5px 0; + + border: 0; +} + +/** + * Label descriptions + */ + +label .field-description { + font-size: 0.8em; +} + +/* ========================================================================== + Tables + ========================================================================== */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + +#content table { + margin: 1em 2em; +} + +#content thead tr { + border-bottom: 2px solid #666; +} + +#content tbody tr { + border-bottom: 1px solid #666; +} + +#content tbody tr:hover { + background-color: #eee; +} + +#content th { + font-family: "klavika-web", "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif; +} + +#content th, +#content td { + padding: .5em; +} + +/* ========================================================================== + Font Awesome + ========================================================================== */ + +[class^="icon-"], +[class*=" icon-"] { + font-weight: normal; + font-style: normal; + text-decoration: inherit; + -webkit-font-smoothing: antialiased; + + /* sprites.less reset */ + display: inline; + width: auto; + height: auto; + line-height: normal; + vertical-align: baseline; + background-image: none; + background-position: 0% 0%; + background-repeat: repeat; + margin-top: 0; +} + +/* more sprites.less reset*/ +.icon-white, +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], +.dropdown-menu > li > a:hover > [class^="icon-"], +.dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > .active > a > [class^="icon-"], +.dropdown-menu > .active > a > [class*=" icon-"], +.dropdown-submenu:hover > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"] { + background-image: none; +} +[class^="icon-"]:before, +[class*=" icon-"]:before { + text-decoration: inherit; + display: inline-block; + speak: none; +} +/* makes sure icons active on rollover in links */ +a [class^="icon-"], +a [class*=" icon-"] { + display: inline-block; +} +/* makes the font 33% larger relative to the icon container */ +.icon-large:before { + vertical-align: -10%; + font-size: 1.3333333333333333em; +} +.btn [class^="icon-"], +.nav [class^="icon-"], +.btn [class*=" icon-"], +.nav [class*=" icon-"] { + display: inline; + /* keeps button heights with and without icons the same */ + +} +.btn [class^="icon-"].icon-large, +.nav [class^="icon-"].icon-large, +.btn [class*=" icon-"].icon-large, +.nav [class*=" icon-"].icon-large { + line-height: .9em; +} +.btn [class^="icon-"].icon-spin, +.nav [class^="icon-"].icon-spin, +.btn [class*=" icon-"].icon-spin, +.nav [class*=" icon-"].icon-spin { + display: inline-block; +} +.nav-tabs [class^="icon-"], +.nav-pills [class^="icon-"], +.nav-tabs [class*=" icon-"], +.nav-pills [class*=" icon-"] { + /* keeps button heights with and without icons the same */ + +} +.nav-tabs [class^="icon-"], +.nav-pills [class^="icon-"], +.nav-tabs [class*=" icon-"], +.nav-pills [class*=" icon-"], +.nav-tabs [class^="icon-"].icon-large, +.nav-pills [class^="icon-"].icon-large, +.nav-tabs [class*=" icon-"].icon-large, +.nav-pills [class*=" icon-"].icon-large { + line-height: .9em; +} +li [class^="icon-"], +.nav li [class^="icon-"], +li [class*=" icon-"], +.nav li [class*=" icon-"] { + display: inline-block; + width: 1.25em; + text-align: center; +} +li [class^="icon-"].icon-large, +.nav li [class^="icon-"].icon-large, +li [class*=" icon-"].icon-large, +.nav li [class*=" icon-"].icon-large { + /* increased font size for icon-large */ + + width: 1.5625em; +} +ul.icons { + list-style-type: none; + text-indent: -0.75em; +} +ul.icons li [class^="icon-"], +ul.icons li [class*=" icon-"] { + width: .75em; +} +.icon-muted { + color: #eeeeee; +} +.icon-border { + border: solid 1px #eeeeee; + padding: .2em .25em .15em; + border-radius: 3px; +} +.icon-2x { + font-size: 2em; +} +.icon-2x.icon-border { + border-width: 2px; + border-radius: 4px; +} +.icon-3x { + font-size: 3em; +} +.icon-3x.icon-border { + border-width: 3px; + border-radius: 5px; +} +.icon-4x { + font-size: 4em; +} +.icon-4x.icon-border { + border-width: 4px; + border-radius: 6px; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +[class^="icon-"].pull-left, +[class*=" icon-"].pull-left { + margin-right: .3em; +} +[class^="icon-"].pull-right, +[class*=" icon-"].pull-right { + margin-left: .3em; +} +.btn [class^="icon-"].pull-left.icon-2x, +.btn [class*=" icon-"].pull-left.icon-2x, +.btn [class^="icon-"].pull-right.icon-2x, +.btn [class*=" icon-"].pull-right.icon-2x { + margin-top: .18em; +} +.btn [class^="icon-"].icon-spin.icon-large, +.btn [class*=" icon-"].icon-spin.icon-large { + line-height: .8em; +} +.btn.btn-small [class^="icon-"].pull-left.icon-2x, +.btn.btn-small [class*=" icon-"].pull-left.icon-2x, +.btn.btn-small [class^="icon-"].pull-right.icon-2x, +.btn.btn-small [class*=" icon-"].pull-right.icon-2x { + margin-top: .25em; +} +.btn.btn-large [class^="icon-"], +.btn.btn-large [class*=" icon-"] { + margin-top: 0; +} +.btn.btn-large [class^="icon-"].pull-left.icon-2x, +.btn.btn-large [class*=" icon-"].pull-left.icon-2x, +.btn.btn-large [class^="icon-"].pull-right.icon-2x, +.btn.btn-large [class*=" icon-"].pull-right.icon-2x { + margin-top: .05em; +} +.btn.btn-large [class^="icon-"].pull-left.icon-2x, +.btn.btn-large [class*=" icon-"].pull-left.icon-2x { + margin-right: .2em; +} +.btn.btn-large [class^="icon-"].pull-right.icon-2x, +.btn.btn-large [class*=" icon-"].pull-right.icon-2x { + margin-left: .2em; +} +.icon-spin { + display: inline-block; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + -webkit-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} +@-webkit-keyframes spin { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(359deg); } +} +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(359deg); } +} +@-moz-document url-prefix() { + .icon-spin { + height: .9em; + } + .btn .icon-spin { + height: auto; + } + .icon-spin.icon-large { + height: 1.25em; + } + .btn .icon-spin.icon-large { + height: .75em; + } +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.icon-glass:before { content: "\f000"; } +.icon-music:before { content: "\f001"; } +.icon-search:before { content: "\f002"; } +.icon-envelope:before { content: "\f003"; } +.icon-heart:before { content: "\f004"; } +.icon-star:before { content: "\f005"; } +.icon-star-empty:before { content: "\f006"; } +.icon-user:before { content: "\f007"; } +.icon-film:before { content: "\f008"; } +.icon-th-large:before { content: "\f009"; } +.icon-th:before { content: "\f00a"; } +.icon-th-list:before { content: "\f00b"; } +.icon-ok:before { content: "\f00c"; } +.icon-remove:before { content: "\f00d"; } +.icon-zoom-in:before { content: "\f00e"; } + +.icon-zoom-out:before { content: "\f010"; } +.icon-off:before { content: "\f011"; } +.icon-signal:before { content: "\f012"; } +.icon-cog:before { content: "\f013"; } +.icon-trash:before { content: "\f014"; } +.icon-home:before { content: "\f015"; } +.icon-file:before { content: "\f016"; } +.icon-time:before { content: "\f017"; } +.icon-road:before { content: "\f018"; } +.icon-download-alt:before { content: "\f019"; } +.icon-download:before { content: "\f01a"; } +.icon-upload:before { content: "\f01b"; } +.icon-inbox:before { content: "\f01c"; } +.icon-play-circle:before { content: "\f01d"; } +.icon-repeat:before { content: "\f01e"; } + +/* \f020 doesn't work in Safari. all shifted one down */ +.icon-refresh:before { content: "\f021"; } +.icon-list-alt:before { content: "\f022"; } +.icon-lock:before { content: "\f023"; } +.icon-flag:before { content: "\f024"; } +.icon-headphones:before { content: "\f025"; } +.icon-volume-off:before { content: "\f026"; } +.icon-volume-down:before { content: "\f027"; } +.icon-volume-up:before { content: "\f028"; } +.icon-qrcode:before { content: "\f029"; } +.icon-barcode:before { content: "\f02a"; } +.icon-tag:before { content: "\f02b"; } +.icon-tags:before { content: "\f02c"; } +.icon-book:before { content: "\f02d"; } +.icon-bookmark:before { content: "\f02e"; } +.icon-print:before { content: "\f02f"; } + +.icon-camera:before { content: "\f030"; } +.icon-font:before { content: "\f031"; } +.icon-bold:before { content: "\f032"; } +.icon-italic:before { content: "\f033"; } +.icon-text-height:before { content: "\f034"; } +.icon-text-width:before { content: "\f035"; } +.icon-align-left:before { content: "\f036"; } +.icon-align-center:before { content: "\f037"; } +.icon-align-right:before { content: "\f038"; } +.icon-align-justify:before { content: "\f039"; } +.icon-list:before { content: "\f03a"; } +.icon-indent-left:before { content: "\f03b"; } +.icon-indent-right:before { content: "\f03c"; } +.icon-facetime-video:before { content: "\f03d"; } +.icon-picture:before { content: "\f03e"; } + +.icon-pencil:before { content: "\f040"; } +.icon-map-marker:before { content: "\f041"; } +.icon-adjust:before { content: "\f042"; } +.icon-tint:before { content: "\f043"; } +.icon-edit:before { content: "\f044"; } +.icon-share:before { content: "\f045"; } +.icon-check:before { content: "\f046"; } +.icon-move:before { content: "\f047"; } +.icon-step-backward:before { content: "\f048"; } +.icon-fast-backward:before { content: "\f049"; } +.icon-backward:before { content: "\f04a"; } +.icon-play:before { content: "\f04b"; } +.icon-pause:before { content: "\f04c"; } +.icon-stop:before { content: "\f04d"; } +.icon-forward:before { content: "\f04e"; } + +.icon-fast-forward:before { content: "\f050"; } +.icon-step-forward:before { content: "\f051"; } +.icon-eject:before { content: "\f052"; } +.icon-chevron-left:before { content: "\f053"; } +.icon-chevron-right:before { content: "\f054"; } +.icon-plus-sign:before { content: "\f055"; } +.icon-minus-sign:before { content: "\f056"; } +.icon-remove-sign:before { content: "\f057"; } +.icon-ok-sign:before { content: "\f058"; } +.icon-question-sign:before { content: "\f059"; } +.icon-info-sign:before { content: "\f05a"; } +.icon-screenshot:before { content: "\f05b"; } +.icon-remove-circle:before { content: "\f05c"; } +.icon-ok-circle:before { content: "\f05d"; } +.icon-ban-circle:before { content: "\f05e"; } + +.icon-arrow-left:before { content: "\f060"; } +.icon-arrow-right:before { content: "\f061"; } +.icon-arrow-up:before { content: "\f062"; } +.icon-arrow-down:before { content: "\f063"; } +.icon-share-alt:before { content: "\f064"; } +.icon-resize-full:before { content: "\f065"; } +.icon-resize-small:before { content: "\f066"; } +.icon-plus:before { content: "\f067"; } +.icon-minus:before { content: "\f068"; } +.icon-asterisk:before { content: "\f069"; } +.icon-exclamation-sign:before { content: "\f06a"; } +.icon-gift:before { content: "\f06b"; } +.icon-leaf:before { content: "\f06c"; } +.icon-fire:before { content: "\f06d"; } +.icon-eye-open:before { content: "\f06e"; } + +.icon-eye-close:before { content: "\f070"; } +.icon-warning-sign:before { content: "\f071"; } +.icon-plane:before { content: "\f072"; } +.icon-calendar:before { content: "\f073"; } +.icon-random:before { content: "\f074"; } +.icon-comment:before { content: "\f075"; } +.icon-magnet:before { content: "\f076"; } +.icon-chevron-up:before { content: "\f077"; } +.icon-chevron-down:before { content: "\f078"; } +.icon-retweet:before { content: "\f079"; } +.icon-shopping-cart:before { content: "\f07a"; } +.icon-folder-close:before { content: "\f07b"; } +.icon-folder-open:before { content: "\f07c"; } +.icon-resize-vertical:before { content: "\f07d"; } +.icon-resize-horizontal:before { content: "\f07e"; } + +.icon-bar-chart:before { content: "\f080"; } +.icon-twitter-sign:before { content: "\f081"; } +.icon-facebook-sign:before { content: "\f082"; } +.icon-camera-retro:before { content: "\f083"; } +.icon-key:before { content: "\f084"; } +.icon-cogs:before { content: "\f085"; } +.icon-comments:before { content: "\f086"; } +.icon-thumbs-up:before { content: "\f087"; } +.icon-thumbs-down:before { content: "\f088"; } +.icon-star-half:before { content: "\f089"; } +.icon-heart-empty:before { content: "\f08a"; } +.icon-signout:before { content: "\f08b"; } +.icon-linkedin-sign:before { content: "\f08c"; } +.icon-pushpin:before { content: "\f08d"; } +.icon-external-link:before { content: "\f08e"; } + +.icon-signin:before { content: "\f090"; } +.icon-trophy:before { content: "\f091"; } +.icon-github-sign:before { content: "\f092"; } +.icon-upload-alt:before { content: "\f093"; } +.icon-lemon:before { content: "\f094"; } +.icon-phone:before { content: "\f095"; } +.icon-check-empty:before { content: "\f096"; } +.icon-bookmark-empty:before { content: "\f097"; } +.icon-phone-sign:before { content: "\f098"; } +.icon-twitter:before { content: "\f099"; } +.icon-facebook:before { content: "\f09a"; } +.icon-github:before { content: "\f09b"; } +.icon-unlock:before { content: "\f09c"; } +.icon-credit-card:before { content: "\f09d"; } +.icon-rss:before { content: "\f09e"; } + +.icon-hdd:before { content: "\f0a0"; } +.icon-bullhorn:before { content: "\f0a1"; } +.icon-bell:before { content: "\f0a2"; } +.icon-certificate:before { content: "\f0a3"; } +.icon-hand-right:before { content: "\f0a4"; } +.icon-hand-left:before { content: "\f0a5"; } +.icon-hand-up:before { content: "\f0a6"; } +.icon-hand-down:before { content: "\f0a7"; } +.icon-circle-arrow-left:before { content: "\f0a8"; } +.icon-circle-arrow-right:before { content: "\f0a9"; } +.icon-circle-arrow-up:before { content: "\f0aa"; } +.icon-circle-arrow-down:before { content: "\f0ab"; } +.icon-globe:before { content: "\f0ac"; } +.icon-wrench:before { content: "\f0ad"; } +.icon-tasks:before { content: "\f0ae"; } + +.icon-filter:before { content: "\f0b0"; } +.icon-briefcase:before { content: "\f0b1"; } +.icon-fullscreen:before { content: "\f0b2"; } + +.icon-group:before { content: "\f0c0"; } +.icon-link:before { content: "\f0c1"; } +.icon-cloud:before { content: "\f0c2"; } +.icon-beaker:before { content: "\f0c3"; } +.icon-cut:before { content: "\f0c4"; } +.icon-copy:before { content: "\f0c5"; } +.icon-paper-clip:before { content: "\f0c6"; } +.icon-save:before { content: "\f0c7"; } +.icon-sign-blank:before { content: "\f0c8"; } +.icon-reorder:before { content: "\f0c9"; } +.icon-list-ul:before { content: "\f0ca"; } +.icon-list-ol:before { content: "\f0cb"; } +.icon-strikethrough:before { content: "\f0cc"; } +.icon-underline:before { content: "\f0cd"; } +.icon-table:before { content: "\f0ce"; } + +.icon-magic:before { content: "\f0d0"; } +.icon-truck:before { content: "\f0d1"; } +.icon-pinterest:before { content: "\f0d2"; } +.icon-pinterest-sign:before { content: "\f0d3"; } +.icon-google-plus-sign:before { content: "\f0d4"; } +.icon-google-plus:before { content: "\f0d5"; } +.icon-money:before { content: "\f0d6"; } +.icon-caret-down:before { content: "\f0d7"; } +.icon-caret-up:before { content: "\f0d8"; } +.icon-caret-left:before { content: "\f0d9"; } +.icon-caret-right:before { content: "\f0da"; } +.icon-columns:before { content: "\f0db"; } +.icon-sort:before { content: "\f0dc"; } +.icon-sort-down:before { content: "\f0dd"; } +.icon-sort-up:before { content: "\f0de"; } + +.icon-envelope-alt:before { content: "\f0e0"; } +.icon-linkedin:before { content: "\f0e1"; } +.icon-undo:before { content: "\f0e2"; } +.icon-legal:before { content: "\f0e3"; } +.icon-dashboard:before { content: "\f0e4"; } +.icon-comment-alt:before { content: "\f0e5"; } +.icon-comments-alt:before { content: "\f0e6"; } +.icon-bolt:before { content: "\f0e7"; } +.icon-sitemap:before { content: "\f0e8"; } +.icon-umbrella:before { content: "\f0e9"; } +.icon-paste:before { content: "\f0ea"; } +.icon-lightbulb:before { content: "\f0eb"; } +.icon-exchange:before { content: "\f0ec"; } +.icon-cloud-download:before { content: "\f0ed"; } +.icon-cloud-upload:before { content: "\f0ee"; } + +.icon-user-md:before { content: "\f0f0"; } +.icon-stethoscope:before { content: "\f0f1"; } +.icon-suitcase:before { content: "\f0f2"; } +.icon-bell-alt:before { content: "\f0f3"; } +.icon-coffee:before { content: "\f0f4"; } +.icon-food:before { content: "\f0f5"; } +.icon-file-alt:before { content: "\f0f6"; } +.icon-building:before { content: "\f0f7"; } +.icon-hospital:before { content: "\f0f8"; } +.icon-ambulance:before { content: "\f0f9"; } +.icon-medkit:before { content: "\f0fa"; } +.icon-fighter-jet:before { content: "\f0fb"; } +.icon-beer:before { content: "\f0fc"; } +.icon-h-sign:before { content: "\f0fd"; } +.icon-plus-sign-alt:before { content: "\f0fe"; } + +.icon-double-angle-left:before { content: "\f100"; } +.icon-double-angle-right:before { content: "\f101"; } +.icon-double-angle-up:before { content: "\f102"; } +.icon-double-angle-down:before { content: "\f103"; } +.icon-angle-left:before { content: "\f104"; } +.icon-angle-right:before { content: "\f105"; } +.icon-angle-up:before { content: "\f106"; } +.icon-angle-down:before { content: "\f107"; } +.icon-desktop:before { content: "\f108"; } +.icon-laptop:before { content: "\f109"; } +.icon-tablet:before { content: "\f10a"; } +.icon-mobile-phone:before { content: "\f10b"; } +.icon-circle-blank:before { content: "\f10c"; } +.icon-quote-left:before { content: "\f10d"; } +.icon-quote-right:before { content: "\f10e"; } + +.icon-spinner:before { content: "\f110"; } +.icon-circle:before { content: "\f111"; } +.icon-reply:before { content: "\f112"; } +.icon-github-alt:before { content: "\f113"; } +.icon-folder-close-alt:before { content: "\f114"; } +.icon-folder-open-alt:before { content: "\f115"; } + +/* Manual Font Awesome Styles */ +[class^="icon-"]::before, [class^="icon-"]::after, +[class*=" icon-"]::before, [class*=" icon-"]::after { + font-family: FontAwesome, "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +#content ul li[class^="icon-"], +#content ul li[class*=" icon-"] { + background: none; + padding-left: 0; +} + +h2 [class^="icon-"], +h2 [class*=" icon-"], +h3 [class^="icon-"], +h3 [class*=" icon-"] { + margin-right: 7px; +} + +/* Global Structure + ========================================================================== */ + +body { + -webkit-font-smoothing: antialiased; + color: #333; + font: 15px/22.5px "Helvetica Neue", HelveticaNeue, Helvetica, Arial, sans-serif; +} + +iframe { + border: 1px solid #bfbfbf; + padding: 1px; +} + +#container { + background: #0769AD; + margin: 0 auto; + padding: 0 20px; + +} + +.jquery-ui #container { + background: #B24926; +} + +.jquery-mobile #container { + background: #108040; +} + +.sizzlejs #container { + background: #9A1B1E; +} + +.qunitjs #container { + background: #390F39; +} + +.jquery-foundation #container { + background: #333; +} + +.jquery-learn #container { + background: url(../images/bg-body-learn.jpg) no-repeat center top #000; +} + +#content-wrapper { + background-color: #fff; + box-shadow: -3px 0 5px -3px rgba(1, 1, 1, 0.87), 3px 0 5px -3px rgba(1, 1, 1, 0.87); + padding: 20px 0; + border-top: 1px solid #333; + border-radius: 0 0 10px 10px; + position: relative; +} +.no-boxshadow #content-wrapper { + border: 1px solid #333; +} + +.constrain { + max-width: 1240px; + margin: 0 auto; + padding: 0 20px; +} + +.lte8 .constrain { + max-width: 1198px; /* Accomodate for padding + 1px border */ +} + +#content { + float: left; + width: 71%; +} + +.content-right #content { + float: right; +} + +.content-full #content { + width: 100%; + padding-left: 10%; + padding-right: 10%; +} + +.content-full.full-width #content { + padding-left: 0; + padding-right: 0; +} + +#sidebar, +.sidebar-left, +.sidebar-right { + padding: 20px; + width: 29%; +} + +#sidebar, +.sidebar-right { + float: right; + margin-right: -25px; + position: relative; + -webkit-border-image: -webkit-linear-gradient(#ffffff, #e7e7e7 15%, #e7e7e7 85%, #ffffff); + border-image: linear-gradient(#ffffff, #e7e7e7 15%, #e7e7e7 85%, #ffffff); + box-shadow: inset 15px 0 5px -16px #e7e7e7; + background-image: -webkit-radial-gradient(left, #f2f2f2, #ffffff 80%); + background-image: radial-gradient(left, #f2f2f2, #ffffff 80%); + border: 0; + border-left: 1px solid #efefef; +} + + +.content-right #sidebar, +.sidebar-left { + float: left; + border-left: 0; + border-right: 1px solid #e7e7e7; + margin: -20px 0 0 -25px; + -webkit-border-image: -webkit-linear-gradient(#ffffff, #e7e7e7 15%, #e7e7e7 85%, #ffffff); + border-image: linear-gradient(#ffffff, #e7e7e7 15%, #e7e7e7 85%, #ffffff); + box-shadow: inset 15px 0 5px -16px #e7e7e7; + background-image: -webkit-radial-gradient(right, #f2f2f2, #ffffff 80%); + background-image: radial-gradient(right, #f2f2f2, #ffffff 80%); +} + +.entry-summary p { + margin: 0; +} + + +/* Global Nav + ========================================================================== */ + +#global-nav { + background: url(../images/jq-global-nav.png) repeat-x 0 bottom #1b1b1b; +} + +#global-nav nav { + height: 34px; +} + +#global-nav nav ul { + text-align: left; + display: inline; + float: left; + margin: 0; + list-style: none; + border-right: 1px solid rgba(255, 255, 255, 0.0976562); + border-left: 1px solid rgba(0, 0, 0, 0.347656); +} + +.tinynav-container { display: none } +.tinynav { display: none } + +#global-nav nav ul.links { + float: right; +} + +#global-nav nav ul li { + font: bold 13px/17px "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif; + display: inline-block; + float: left; + position: relative; + top: 1px; + cursor: pointer; + transition: all 0.2s; + text-shadow: 0 0px 2px #000; + border-left: 1px solid rgba(255, 255, 255, 0.0976562); + border-right: 1px solid rgba(0, 0, 0, 0.347656); +} +.ie #global-nav nav ul li { + top: 2px; +} + +#global-nav nav ul li:hover { + background: url(../images/bg-footer-noise.jpg) #000; + color: #fff; +} + +#global-nav nav ul li i { + height: 1em; +} + +#global-nav nav ul li a { + color: #e6e6e6; + font-weight: normal; + font-style: normal; + text-decoration: none; + display: block; + padding: 8px 12px; +} + +#global-nav nav ul li ul { + padding: 0; + position: absolute; + top: 32px; + left: -2px; + width: 120px; + display: none; + opacity: 0; + visibility: hidden; + transition: opacity 0.2s; + box-shadow: 0 4px 5px rgba(0, 0, 0, 0.4); + z-index: 400; +} + +#global-nav nav ul li ul.wide { + width: 260px; +} + +#global-nav nav ul li ul li { + background: url(../images/bg-footer-noise.jpg) #000; + display: block; + color: #fff; + float: none; +} + +#global-nav nav ul li ul li:hover { background: #000; } +#global-nav nav ul li:hover ul { + display: block; + opacity: 1; + visibility: visible; +} + +#global-nav nav ul.projects li.project { + width: 42px; + padding: 0; + height: 33px; + text-indent: -9999px; + background: url(../images/jq-nav-icons.png) -6px 0; + z-index: 10; +} + +#global-nav nav ul.projects li.project a { + display: block; + height: 33px; +} + +#global-nav nav ul.projects li.jquery-ui { + background-position: -57px 0px; +} + +#global-nav nav ul.projects li.jquery-mobile { + background-position: -107px 0px; +} + +#global-nav nav ul.projects li.sizzlejs { + background-position: -155px 0px; +} + +#global-nav nav ul.projects li.qunitjs { + background-position: -204px 0px; +} + +.jquery #global-nav nav ul.projects li.jquery { + background-position: 0 bottom; + width: 52px; + position: relative; + margin-top:1px; + border: none; +} + +.jquery #global-nav nav ul.projects { + border-left: none; +} + +.jquery #global-nav nav ul.projects li.jquery-ui { + border-left: none; + background-position: -59px 0; +} + +.jquery-ui #global-nav nav ul.projects li.jquery-ui { + background-position: -50px bottom; + width: 52px; + position: relative; + margin-top:1px; + border: none; +} + +.jquery-ui #global-nav nav ul.projects li.jquery { + border-right: none; + background-position: -2px 0; +} + +.jquery-ui #global-nav nav ul.projects li.jquery-mobile { + border-left: none; +} + +.jquery-mobile #global-nav nav ul.projects li.jquery-mobile { + background-position: -100px bottom; + width: 52px; + position: relative; + margin-top:1px; + border: none; +} + +.jquery-mobile #global-nav nav ul.projects li.jquery-ui { + border-right: none; + background-position: -53px 0; +} + +.jquery-mobile #global-nav nav ul.projects li.jquery-mobile { + border-right: none; +} + +.jquery-mobile #global-nav nav ul.projects li.sizzlejs{ + border-left: none; + background-position: -157px 0; +} + + +.sizzlejs #global-nav nav ul.projects li.jquery-mobile { + border-right: none; + background-position: -102px 0; +} + +.sizzlejs #global-nav nav ul.projects li.sizzlejs { + background-position: -148px bottom; + width: 52px; + position: relative; + margin-top:1px; + border: none; +} + +.sizzlejs #global-nav nav ul.projects li.qunitjs{ + border-left: none; + background-position: -206px 0; +} + + +.qunitjs #global-nav nav ul.projects li.sizzlejs { + border-right: none; +} + +.qunitjs #global-nav nav ul.projects li.qunitjs { + background-position: -202px bottom; + width: 52px; + position: relative; + margin-top:1px; + border: none; +} + +.qunitjs #global-nav nav ul.projects { + border-right: none; +} + +#container, +footer { + border-top: 1px solid #7ACEF4; +} + +.jquery-ui #container, +.jquery-ui footer { + border-top-color: #FAA523; +} + +.jquery-mobile #container, +.jquery-mobile footer { + border-top-color: #3EB249; +} + +.sizzlejs #container, +.sizzlejs footer { + border-top-color: #FAA523; +} + +.qunitjs #container, +.qunitjs footer { + border-top-color: #9C3493; +} + +.jquery-learn #container, +.jquery-learn footer { + border-top-color: #333; +} + +/* Brand Colors for General Use + ========================================================================== */ +.color.black { background-color: #333; } +.color.primary-blue { background-color: #0769AD; } +.color.secondary-blue { background-color: #7ACEF4; } +.color.navy-blue { background-color: #131B28; } +.color.primary-orange { background-color: #FAA523; } +.color.secondary-orange { background-color: #B24926; } +.color.primary-green { background-color: #3EB249; } +.color.secondary-green { background-color: #108040; } +.color.sizzle-orange { background-color: #FAA523; } +.color.sizzle-red { background-color: #9A1B1E; } +.color.qunit-primary-purple { background-color: #9C3493; } +.color.qunit-secondary-purple { background-color: #390F39; } +.color.globalize-primary-aqua { background-color: #009B93; } +.color.globalize-secondary-aqua { background-color: #41586B; } + +/* Logo & Navigation + ========================================================================== */ + +#logo-events { + clear: both; + padding: 20px 0; +} + +h2.logo { + float: left; + margin: 20px 0 0 0; + width: 243px; +} + +h2.logo a { + float: left; + display: block; + height: 66px; + overflow: hidden; + text-indent: -1000px; +} + +.jquery h2.logo a, +.jquery-learn h2.logo a { + width: 243px; + background: url(../images/logo-jquery.png) no-repeat; +} + +.jquery-ui h2.logo a { + width: 253px; + background: url(../images/logo-jquery-ui.png) no-repeat; +} + +.jquery-mobile h2.logo a { + width: 268px; + background: url(../images/logo-jquery-mobile.png) no-repeat; +} + +.sizzlejs h2.logo a { + width: 243px; + background: url(../images/logo-sizzle.png) no-repeat; +} + +.qunitjs h2.logo a { + width: 243px; + background: url(../images/logo-qunit.png) no-repeat; +} + +.jquery-foundation h2.logo a { + width: 243px; + background: url(../images/logo-jquery-foundation.png) no-repeat; +} + +.jquery-events.jquery-foundation h2.logo a { + width: 243px; + background: url(../images/logo-jquery-events.png) no-repeat; +} + +.logo.small { + height: 30px; + background: url('../images/projectlogosfull-small.png') no-repeat; +} + +.jquery.logo.small { + width:109px; + background-position: -0px 0px; +} +.jquery-foundation.logo.small { + width: 109px; + background-position: -109px 0px; +} +.jquery-events.logo.small { + width: 109px; + background-position: -219px 0px; +} +.jqueryui.logo.small { + width: 114px; + background-position: -327px 0px; +} +.jquery-mobile.logo.small { + width: 122px; + background-position: -442px 0px; +} +.qunitjs.logo.small { + width: 105px; + background-position: -564px 0px; +} +.sizzlejs.logo.small { + width: 105px; + background-position: -669px 0px; +} + +#logo-events aside { + float: right; +} + +nav#main { + background-color: rgba(0, 0, 0, 0.18); + border-radius: 10px 10px 0 0; + border-right: 1px solid rgba(2, 2, 2, 0.28); + border-left: 1px solid rgba(2, 2, 2, 0.28); + border-top: 1px solid rgba(250, 250, 250, 0.27); + box-shadow: rgba(255,255,255,0.3) 0 1px 0, rgba(0,0,0,0.3) 0 -1px 0; + box-shadow: 0 0 5px rgba(1, 1, 1, 0.7); +} + +.jquery-ui nav#main, +.sizzlejs nav#main { + background-color: rgba(12, 12, 12, 0.06); +} +.qunitjs nav#main { + background-color: rgba(156, 52, 147, 0.5); +} +.jquery-learn nav#main { + background-color: rgba(0, 0, 0, 0.4); +} + +.jquery-foundation nav#main { + background-color: rgba(102, 102, 102, 0.1); +} + +.no-boxshadow nav#main { + border-top: 1px solid #333; + border-left: 1px solid #333; + border-right: 1px solid #333; +} + +nav#main ul { + margin: 0; + float: left; + width: 70%; + padding-top: 10px; + padding-bottom: 10px; +} + +nav#main li { + float: left; + font: normal normal 16px "klavika-web", "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif; + margin-right: 2px; +} + +nav#main li a { + color: #fff; + text-decoration: none; + padding: 6px 10px; + display: block; + border: 1px solid transparent; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.76); +} + +nav#main li a:hover, +nav#main li.current a, +nav#main .searchform { + background: none; + box-shadow: inset 0 0 5px rgba(0,0,0, 0.4), rgba(255,255,255,0.1) 0 1px 0; + border-radius: 4px; + border: 1px solid rgba(0,0,0,0.25); + color: #fff; + text-shadow: rgba(0, 0, 0, 0.796875) 0px -1px 0px, rgba(255, 255, 255, 0.296875) 0px 0px 10px; +} + +nav#main .searchform { + float: right; + width: 28%; + margin-top: 12px; + margin-bottom: 12px; + padding: 0; + border-radius: 20px; + position: relative; +} + +nav#main .searchform input { + text-decoration: none; + font: 12px/12px "Lucida Grande", Lucida, Verdana, sans-serif; + padding: 5px 10px; + margin: 0; + background-color: transparent; + border-style: none; + color: #fff; + line-height: 1.3; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.76); + width: 85%; + box-shadow: none; +} + +nav#main .searchform input:focus { + outline: none; +} + +.no-boxshadow nav#main .searchform { + border: 1px solid #333; +} + +.no-boxshadow nav#main .searchform input { + background: #fff; + color: #333; +} + +/* + * 1. :-moz-placeholder has been deprecated in favor of ::-moz-placeholder. + * 2. Using :placeholder for completeness. + */ +nav#main .searchform input::-webkit-input-placeholder { + color: #fff; +} +nav#main .searchform input:-moz-placeholder { /* 1 */ + color: #fff; +} +nav#main .searchform input::-moz-placeholder { + color: #fff; +} +nav#main .searchform input:-ms-input-placeholder { + color: #fff; +} +nav#main .searchform input:placeholder { /* 2 */ + color: #fff; +} + +nav#main .searchform .icon-search { + position: absolute; + right: 10px; + top: 3px; + bottom: 3px; + border-width: 0; + border-left: 1px solid rgba(7, 7, 7, 0.65); + background-color: transparent; + padding: 0 0 0 7px; + opacity: 0.33; + color: #fff; +} + +#broadcast { + height: 100px; +} + +/* Typography & Global Styles + ========================================================================== */ + +#content a { + text-decoration: underline; +} + +#content a:hover { + text-decoration: none; +} + +#sidebar a { + text-decoration: none; +} + +#sidebar a:hover { + text-decoration: underline; +} + +p { + margin-bottom: 15px; + margin-top: 0; +} + +b, strong { + font-weight: bold; + color: #1a1a1a; +} + +em, i { + color: #6d6d6d; + font-style: italic; +} + +hr { + background-image: url(../images/gauze.png); + height: .75em; + border: none; + margin: .75em 0; +} + +#content code a { + text-decoration: none; +} + +pre strong, +pre b { + color: #fff; + font-weight: bold; +} + +#content blockquote { + margin: 20px 0; +} + +#content blockquote p { + font: italic normal 23px/26px "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif; + color: #828282; + margin-left: 0; + margin-bottom: 0; + padding: 20px 30px; + position: relative; + text-shadow: 0 1px 0 #ffffff; + background-color: #f2f2f2; +} + +#content ol, +#content ul { + margin: 0 0 20px 20px; +} + +#content ul ul { + margin-bottom: 0; +} + +#content ul li { + padding-bottom: 5px; + padding-top: 5px; + padding-left: 20px; + line-height: 20px; + list-style-type: none; + background: url(../images/bullet.png) no-repeat 0 10px; +} + +#content ul.block-grid li { + background: none; +} + +#content ol { + counter-reset: li; /* Initiate a counter */ +} + +#content ol > li { + position: relative; /* Give each list item a left margin to make room for the numbers */ + list-style: none; + padding-left: 10px; + margin-right: 0; + margin-top: 5px; + margin-left: 30px; +} +#content ol > li:before { + content: counter(li); /* Use the counter as content */ + counter-increment: li; /* Increment the counter by 1 */ + /* Position and style the number */ + position: absolute; + top: 1px; + left: -25px; + box-sizing: border-box; + width: 20px; + /* Some space between the number and the content in browsers that support + generated content but not positioning it */ + color: #fff; + text-align: center; + background-color: #ababab; + height: 19px; + width: 19px; + padding-top: 0px; + font: bold 11px/19px "klavika-web", "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif; + border-radius: 12px; +} + +.lt-ie8 #content ol, +.lt-ie7 #content ol { + margin-left: 20px; +} + +.lt-ie8 #content ol li, +.lt-ie7 #content ol li { + margin-left: 30px; + list-style-type: decimal; + padding-left: 0px; +} + +#content img.full, +#content figure.full { + display: block; + width: 100%; + max-width: 100%; +} + +.lt-ie8 #content figure img { + position: relative; +} + +.lt-ie7 #content figure.full, +.lt-ie8 #content figure.full { + width: 99%; +} + +#content img.full, +#content img.left, +#content img.right, +#banner img.full { + box-shadow: 0 0 5px 1px rgba(0, 0, 0, 0.20); +} + +#content img.noborder, +#content figure.noborder { + box-shadow: none; + border: none; + background: none; +} + +#content img.full, +#content img.left, +#content img.right, +#content figure.full, +#content figure.left, +#content figure.right { + margin-bottom: 20px; + float: left; +} + +#content img.right, +#content figure.right { + float: right; + margin-left: 15px; +} + +.lt-ie8 #content img.right, +.lt-ie8 #content figure.right, +.lt-ie7 #content img.right, +.lt-ie7 #content figure.right { + float: left; + margin-left: 0px; + margin-right: 15px; +} + +#content img.left, +#content figure.left { + margin-right: 15px; +} + + +#content figure img { + margin: 0px !important; + margin-bottom: 0px !important; +} + +#content figcaption { + box-shadow: 0px 0px 5px 1px rgba(0, 0, 0, 0.20); + font: italic 700 12px/20px "klavika-web", "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif; + padding-left: 10px; + padding-right: 10px; + padding-top: 5px; + padding-bottom: 5px; + color: #737272; + clear: both; + margin-top: -10px; + background-color: #f2f2f2; +} + +#content figure.noborder figcaption { + box-shadow: none; + background: none; + text-align: center; +} + +#content .embed, +#content .embed_media { + position: relative; + padding-bottom: 56.25%; /* 16/9 ratio */ + height: 0; + overflow: hidden; + box-shadow: 0px 0px 5px 1px rgba(0, 0, 0, 0.20); + margin-bottom: 20px; +} + +#portfolio.media #banner .embed { + margin-bottom: 40px; +} + +.embed iframe, +.embed_media iframe, +.embed object, +.embed_media object, +.embed embed, +.embed_media embed { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +#content h1 { + font-size: 36px; + line-height: 36px; +} + +.content-full #content h1 { + text-align: center; +} + +#content h2 { + font-size: 24px; + line-height: 24px; + color: #333; + margin-bottom: 10px; +} + +#content h3 { + font-size: 20px; + line-height: 20px; + color: #666; +} + +#content h1.block, +#content h2.block { + padding: 10px 2%; + background: url(../images/gauze.png) #ececec; + text-shadow: 0 1px 0 #ffffff; +} + +p.author { + color: #ababab; + font-family: "klavika-web", "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif; + font-weight: 700; + margin-top: -20px; +} + +p.author a { + color: #ababab; +} + +.meta { + padding: 2%; + padding-bottom: .5%; + margin-bottom: 20px; + font: 700 "klavika-web", "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif; + color: #666; + background: url(../images-foundation/gauze.png) #f0f0f0; + text-shadow: 0 1px 0 #ffffff; +} + +#banner-large-image { + text-align: center; + margin-bottom: 30px; + +} + +#banner-large-image .vertically-centered-black-bg { + height: 50%; + width: 100%; + margin-top: 24%; + display: block; + background-color: rgba(0, 0, 0, 0.68); + position: absolute; + padding-top: 3.5%; +} + +#banner-large-image h1, #banner-large-image h2 { + font: bold 60px/60px "klavika-web", "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif; + margin-bottom: 0; + color: #fff; + text-shadow: 0 0 4px rgba(0, 0, 0, 0.85); +} + +#banner-large-image p { + color: #CCCCCC; + font: 700 normal 24px/36px "klavika-web", "Helvetica Neue", sans-serif; +} + +#banner-secondary { + background-image: url(../images/dark-grey-tile.png); + margin: -20px -25px 15px; + padding: 20px; +} + +#banner-secondary h1, +#banner-secondary h2 { + margin-bottom: 0; + color: #fff; + text-shadow: 0 0 4px rgba(0, 0, 0, 0.85); +} + +#banner-secondary h1 { + font-size: 48px; + line-height: 54px; +} + +#banner-secondary h2 { + font-size: 36px; + line-height: 42px; +} + +#banner-secondary p { + color: #ccc; + font: 22px/26px "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif; + padding-left: 15%; + padding-right: 15%; +} + +#banner-secondary a, +#banner-secondary a:hover { + color: #7ACEF4; +} + +#banner-secondary em, +#banner-secondary i { + color: #fff; +} + +#banner-secondary.large-banner { + text-align: center; + padding-top: 30px; + padding-bottom: 30px; +} + +#banner-secondary.large-banner h1, +#banner-secondary.large-banner h2 { + margin-bottom: 10px; +} + +#banner-secondary.large-banner h1 { + font-size: 60px; + line-height: 60px; +} + +#banner-secondary.large-banner h2 { + font-size: 48px; + line-height: 48px; +} + +#banner-secondary.large-banner h3 { + font-size: 36px; + line-height: 36px; +} + +.center-txt { + text-align: center !important; +} + +.callout-block { + background-image: url(../images/gauze.png); + padding: 20px; +} + +/* Buttons + ========================================================================== */ + +a.button, +#content a.button, +.button, +input[type="submit"] { + border-radius: 5px; + border: 1px solid #999; + box-shadow: + 0 0 5px rgba(0, 0, 0, 0.28), + inset 0 1px 0 rgba(255, 255, 255, 0.45), + inset 0px -1px 0px rgba(255, 255, 255, 0.45), + inset 1px 0px 0px rgba(255, 255, 255, 0.45), + inset -1px 1px 0px rgba(255, 255, 255, 0.45); + text-decoration: none; + color: #fff !important; + text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.35); + padding: 8px 15px; + font: bold 16px/16px "klavika-web", "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif; + transition: all 0.2s; + background-color: #d18f4f; + float: left; +} + +a.button:hover, +#content a.button:hover, +.button:hover, +input[type="submit"]:hover { + background-color: #cc8540; +} + +a.button.large, +#content a.button.large, +button.large, +input[type="submit"].large { + font-size: 20px; + padding: 12px 20px; +} + +a.button.dark, +#content a.button.dark, +.button.dark, +input[type="submit"].dark { + background-color: #666; +} + +a.button.dark:hover, +#content a.button.dark:hover, +.button.dark:hover, +input[type="submit"].dark:hover { + background-color: #424141; +} + +/* Sidebar + ========================================================================== */ + +#sidebar h3 { + font: 20px/18px; + background-image: -webkit-linear-gradient(left, #efefef, #f3f3f3); + background-image: linear-gradient(to right, #efefef, #f3f3f3); + margin-left: -20px; + margin-right: -20px; + padding: 12px 20px; + text-shadow: 0 1px 0 #ffffff; +} + +#sidebar li { + padding: 5px 0 5px 20px; + list-style-type: none; + background: url(../images/bullet.png) no-repeat 0 12px; + text-shadow: 0 1px 0 #ffffff; +} + +#sidebar li a { + color: #4d4d4d; + text-decoration: none; + display: block; +} + +#sidebar nav#secondary li { + background-image: none; + padding-left: 0; +} + +#sidebar nav#secondary li.current { + background-color: #eee; + margin-left: -35px; + margin-right: -20px; + padding-left: 35px; + font-weight: bold; +} + +/* == Footer + ========================================================================== */ + +footer { + background: url(../images/bg-footer-noise.jpg) repeat; + margin-top: -20px; + padding-top: 40px; +} + +footer.simple { + padding-top: 45px; + padding-bottom: 10px; +} + +footer a, +footer strong { + color: #fff; + text-decoration: none; +} + +footer .download { + text-align: center; + color: #fff; + padding: 10px 2% 15px 2%; + line-height: 140%; +} + +footer .download strong { margin-right: 10px; } + +footer .download > span { white-space: nowrap; } + +footer .download a { margin: 0 10px; } + +footer .download a em { + font-style: normal; + color: #aaa; +} + +footer .download a:hover { border-bottom: solid 1px #888; } + +footer .footer-icon-links li { + width: 22%; + margin-left: 11%; + float: left; +} + +footer .footer-icon-links li a { + display: block; + line-height: inherit; + font-size: 18px; + float: left; + position: relative; + width: auto; + text-align: left; + padding-left: 10px; +} + +footer .footer-icon-links li a:before { + position: absolute; + left: -35px; + top: 10px; + font-size: 2em; + color: #4d4d4d; + text-shadow: 0 -1px 0 #000000; +} + +footer .footer-icon-links li small { + display: block; + font-size: 14px; + color: #777; + line-height: 120%; +} + +footer .footer-icon-links li:hover a:before { + color: #d1d1d1; +} + +.multiplebgs.cssgradients footer { + background-image: -webkit-linear-gradient(rgba(0,0,0,0.3), rgba(0,0,0,0.0)), url(../images/bg-footer-noise.jpg); /* Chrome 10+, Saf6 */ + background-image: linear-gradient(to bottom, rgba(0,0,0,.3), rgba(0,0,0,0)), url(../images/bg-footer-noise.jpg); /* Firefox 16+, IE 10+, Opera 12.50+ */ + background-repeat: repeat-x, repeat; + background-size: 100px 15px, 140px 140px; +} + +.no-multiplebgs footer, .no-cssgradients footer { + background-image: url(../images/bg-footer-noise.jpg); + background-repeat: repeat; +} + +footer h3 { + color: #777; + letter-spacing: normal; + text-transform: uppercase; + text-shadow: #000 0 1px 0; + border: solid 1px #000; + text-rendering: optimizeLegibility; + border-bottom: none; + border-radius: 4px 4px 0 0; + position: relative; + text-align: center; + height: 10px; + margin-top: 20px; + font-size: 16px; +} + +footer h3 span { + display: inline-block; + padding: 3px 10px; + position: relative; + top: -0.8em; + background: url(../images/bg-footer-noise.jpg) repeat #212121; + z-index: 1; +} + +footer h3:after { + content: ""; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + border: solid 1px #333; + border-bottom: none; + border-radius: 4px 4px 0 0; +} + +.footer-site-links { + float: right; + padding: 10px 0 0 0; + width: 58%; + text-align: right; +} + +footer p.copyright { + margin: 10px 0 0 0; + float: left; + width: 40%; + font-size: 11px; + line-height: 130%; + color: #777; +} + +footer p.copyright a { + color: #aaa; +} + +footer p.copyright a:hover { + color: #fff; +} + +footer p.copyright span.sponsor-line { + display: block; + font-size: 10px; + margin-top: 1em; +} + +footer p.copyright a.mt-link { + background: url(../images/logo-mediatemple.png) left top no-repeat; + padding-left: 31px; +} + +footer p.copyright a.mc-link { + background: url(../images/logo-maxcdn.png) left top no-repeat; + padding-left: 24px; + padding-top: 2px; + padding-bottom: 2px; +} + +footer p.copyright a.wp-link { + background: url(../images/logo-wordpress.png) left top no-repeat; + padding-left: 19px; + padding-top: 1px; + display: inline-block; + height: 16px; +} + +.footer-site-links li { + position: relative; + background: none; + width: auto; + height: auto; + line-height: 20px; + margin: 0 0 10px 20px; + font-size: 13px; +} + +.footer-site-links li:first-child { + margin-left: 0; +} + +.footer-site-links li a { + position: relative; + color: #aaa; + display: block; + padding-left: 30px; + width: auto; + line-height: inherit; +} + +.footer-site-links li a:before { + position: absolute; + font-size: 1.5em; + color: #4d4d4d; + text-shadow: 0 -1px 0 #000000; + left: 2px; +} + +.footer-site-links li:hover a, +.footer-site-links li:hover a:before { + color: #e6e6e6; +} + +.footer-site-links li { + display: inline-block; +} + +footer ul li { + list-style: none; + padding: 0; + margin: 0; + line-height: 30px; +} + +footer #legal { + margin-top: 1em; + border-top: solid 1px #333; + box-shadow: #000 0 -1px 0; +} + +footer .books li { + float: left; + width: 30%; + min-width: 95px; + margin-left: 2.8%; + margin-bottom: 15px; + line-height: 130%; + font-size: 11px; + text-align: center; +} + +footer .books li:first-child { + margin-left: 2%; +} + +footer .books li a img { + display: block; + border-radius: 5px; + border: solid 1px rgba(255,255,255,0.2); + width: 92px; + height: 114px; + margin: 0 auto 5px; +} + +footer .books li a:hover img { + border-color: #fff; +} + +footer .books li a cite { + display: block; + font-style: normal; + font-size: 9px; + line-height: 1.5em; + color: #aaa; +} + + + +/* General Styles + ========================================================================== */ + +#content .entry-title a { + text-decoration: none; +} + +.entry-meta { + color: #999; + font-size: 12px; +} + +.toc-linked { + position: relative; +} + +.toc-linked .toc-link { + position: absolute; + left: -1em; + text-decoration: none; + opacity: 0; +} +/* TODO: Remove (https://github.com/jquery/jquery-wp-content/issues/143) */ +#content .toc-linked .toc-link { + text-decoration: none; +} + +.toc-linked:hover .toc-link { + opacity: 1; +} + +.post-heirarchy { + margin-bottom: 0.75em; +} + +/* Listing Pages (categories, searches, etc.) + ========================================================================== */ + +.listing .hentry { + padding: 10px 20px; + margin: 15px 0; + border: 1px solid rgba( 0, 0, 0, 0.2 ); + border-radius: 5px; + background-color: #eee; + position: relative; +} + +.listing #content .entry-title { + font-size: 1.3em; + margin-bottom: 0; + text-shadow: 0 1px 1px #fff; +} + +.listing .entry-meta { + float: right; +} + +.listing .entry-meta .category { + padding: 4px; + background-color: #ddd; + border-radius: 5px; +} + +.listing #content .entry-meta .category a { + color: #888; + text-decoration: none; +} + +.pagination { + text-align: center; + margin-top: 2em; +} + +.page-numbers { + padding: 0 10px; +} + + + +/* API Sites +========================================================================== */ + +.entry { + margin: 15px 0; +} + +.entry-wrapper { + border: 1px solid #CCC; + border-top: 0; + padding: 10px; + border-radius: 0 0 5px 5px; +} + +#content .section-title { + background: #333; + border: 1px solid #111; + padding: 8px 15px; + font-size: 16px; + color: white; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.5); + letter-spacing: 0; + border-radius: 5px 5px 0 0; + font-weight: normal; + margin-bottom: 0; + overflow: hidden; +} + +.returns { + float: right; + font-style: italic; +} + +.api-item .returns { + font-size: 16px; + color: #333; + font-weight: normal; +} + +.api-item .version-details { + display: block; + padding: 0.5em; + margin: 1em 0; + background: #fff3a5; + border-radius: 5px; +} + +#content .signatures { + background: #eee; + border: 1px solid #ccc; + margin: 0 auto 15px; + max-width: 750px; + border-radius: 3px; + color: #333; + text-shadow: 0 1px 0 #fff; +} + +#content .signatures li { + list-style: none; + background: none; + margin: 0; + padding: 10px; +} + +#content .signatures > li { + padding-bottom: 0; +} + +#content .signature > ul { + margin: 0; +} + +.signatures h4 { + font-size: 16px; + letter-spacing: 0; + padding: 8px 10px; + margin: -10px -10px 0; + color: #fff; + text-shadow: 0 1px 0 #444; +} + +.signature:first-child h4 { + border-radius: 3px 3px 0 0; +} + +#content .signature h4 a { + color: inherit; + text-decoration: none; +} + +.signature h4 .icon-link { + margin-right: 0.5em; +} + +.signature .event-properties { + margin: 15px 0 0 0; +} + +.argument { + margin-top: 1em; +} + +#options, #methods, #extension-points, #events, #quick-nav { + border: 1px solid #CCC; + margin: 0 15px 15px; + padding: 10px; + overflow: auto; +} + +#options header h2, #methods header h2, #extension-points header h2, #events header h2, #quick-nav h2 { + background: #cccccc; /* Old browsers */ + background: -webkit-linear-gradient(top, #ffffff 0%,#eeeeee 17%,#cccccc 100%); /* Chrome10+,Safari5.1+ */ + background: linear-gradient(to bottom, #ffffff 0%,#eeeeee 17%,#cccccc 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#cccccc',GradientType=0 ); /* IE6-9 */ + margin: -10px -10px 10px -10px; + padding: 10px; +} + +#quick-nav h2 a { + float: right; + font-size: 80%; + padding-left: 10px; +} + +.quick-nav-section { + width: 33%; + float: left; +} + +#methods .api-item li, +#extension-points .api-item li, +#events .api-item li { + margin-bottom: 1em; +} + +#methods .api-item li ul, +#extension-points .api-item li ul, +#events .api-item li ul { + list-style: none; +} + +.version-details { + font-weight: bold; +} + +.section-title .version-details, +.name .version-details { + float: right; + clear: right; + font-size: 14px; + color: #fff; +} + +.api-item { + padding: 20px 10px; +} +.signature li, +.api-item { + border-top: 1px solid #CCC; +} + +.signature li:first-child, +.api-item.first-item { + border-top: none; + padding-top: 10px; +} + +.option-type { + font-size: 16px; + font-weight: normal; + color: #333; + float: right; +} + +#options .default { + text-align: right; + font-size: 13px; + margin-top: -10px; +} + +.desc { + font-size: 16px; + padding: 5px 15px 0; + color: #666; + font-style: italic; +} + +.desc strong { + color: #444; + font-style: normal; +} + +.entry-summary p { + margin: 0; +} + +.warning, .note { + padding: 0.5em 1em; + margin: 1em; + border-radius: 5px; +} + +.warning { + background: #fff3a5; +} + +.note { + background: #428bca; + color: #fff; +} + +.note a { + color: #fff; +} + +/* Media Queries + ========================================================================== */ + +@media only screen and (max-width: 1100px) { + +} + +@media only screen and (max-width: 940px) { + +} + +@media only screen and (max-width: 860px) { + +} + +@media only screen and (max-width: 768px) { + #global-nav ul.projects li.toggle-projects { + display: none; + } + + #sidebar, + .content-right #sidebar { + width: auto; + float: none; + clear: both; + margin: 0; + border-top: 1px solid #e7e7e7; + border-left: none; + border-image: none; + box-shadow: none; + background-image: none; + background-image: none; + background-image: none; + background-image: none; + background-image: none; + background-image: none; + } + + .content-full.full-width #content, + .content-right #content, + .content-left #content { + padding-left: 2%; + padding-right: 2%; + } + + #content { + width: 100%; + float: none; + clear: both; + } + + #banner-secondary { + margin-left: -15px; + margin-right: -15px; + } + + footer p.copyright, + footer ul.footer-site-links { + width: 100%; + text-align: center; + margin: 0 0 10px 0; + } +} + +@media only screen and (max-width: 600px) { + #global-nav ul.projects { + display: none; + } + + #global-nav nav ul.links { + float: left; + } + + #global-nav nav ul.links li { + font-size: 12px; + } + + #logo-events { + padding-top: 20px; + padding-bottom: 10px; + } + + #logo-events aside { + display: inline-block; + position: relative; + left: 50%; + margin-left: -200px; + float: none; + padding: 10px 0; + } + + #logo-events h2.logo { + float: none; + margin-left: auto; + margin-right: auto; + } + + nav#main { + background-color: rgba(0, 0, 0, 0.0); + border-radius: 10px 10px 0 0; + border-right: none; + border-left: none; + border-top: none; + box-shadow: none; + padding-top: 10px; + } + + nav#main .searchform { + display: block; + float: none; + width: 100%; + margin: 15px auto; + clear:both; + } + + nav#main ul{ + width: auto !important; + text-align: left !important; + float: none; + margin: 0px; + padding: 0px; + } + + nav#main ul li, nav#main ul li a { + display: block; + text-align: left !important; + float: left; + margin-right: 0px; + padding: 0 4px 4px 0; + } + + + nav#main li a:hover, + nav#main li.current a { + background: none; + box-shadow: none; + border-radius: 4px; + border: 1px solid rgba(0,0,0,0.0); + } + + nav#main li a { + font-size: 14px; + } + + #content-wrapper { + border-top-left-radius: 10px; + border-top-right-radius: 10px; + } + + #banner-secondary { + border-top-left-radius: 9px; + border-top-right-radius: 9px; + margin-left: -10px; + margin-right: -10px; + } + + #banner-secondary h2 { + font-size: 35px; + line-height: 35px; + } + + #content h1 { + font-size: 26px; + line-height: 26px; + } + + #banner-secondary.large-banner h1, + #banner-secondary.large-banner h2 { + font-size: 36px; + line-height: 36px; + } + + #banner-secondary.large-banner p { + font-size: 22px; + padding: 0; + } + + footer .books li { + clear: both; + margin-bottom: 10px; + float: none; + margin-left: auto !important; + margin-right: auto; + text-align: center; + } + + footer .books li span { + display: block; + margin-left: auto; + margin-right: auto; + } +} + +@media only screen and (max-width: 480px) { + + #global-nav { + display: none; + } + + #logo-events aside { + width: 300px; + margin-left: -150px; + } + + #container { + border-top: none !important; + } + + .tinynav-container { + display: block; + } + + #menu-top { + display: none; + } + + .tinynav { + display: block; + width: 100%; + margin: 0 auto 15px; + position: relative; + top: 6px; + left: 0px; + } + + nav#main { + margin-top: 15px; + padding-top: 0; + } + + nav#main .searchform { + display: block; + float: none; + width: 100%; + margin: 15px auto; + } + + nav#main ul li, nav#main ul li a { + float: none; + padding: 6px 0px 6px 8px; + } + + .constrain, + #container { + padding-left: 10px; + padding-right: 10px; + } + + .content-full #content, + .content-full.full-width #content, + .content-right #content, + .content-left #content { + padding-left: 0; + padding-right: 0; + } + + #content-wrapper { + padding-left: 25px; + padding-right: 25px; + } + + #content pre { + margin-left: -25px; + margin-right: -25px; + } + + #content img.left, + #content figure.left, + #content img.right, + #content figure.right { + display: block; + width: 100%; + max-width: 100%; + margin-left: 0; + margin-right: 0; + } + + #banner-secondary { + margin-left: -25px; + margin-right: -25px; + } + + footer .footer-icon-links li a:before { + display: none; + } + + footer .footer-icon-links li:first-child { + margin-left: 0; + } + + footer .download > span { + white-space: normal; + } +} + +@media only screen and (-webkit-device-pixel-ratio: 2){ + .jquery h2.logo a { + background: url(../images/logo-jquery@2x.png) no-repeat; + background-size: 243px 66px; + } + + .jquery-ui h2.logo a { + background: url(../images/logo-jquery-ui@2x.png) no-repeat; + background-size: 253px 66px; + } + + .jquery-mobile h2.logo a { + background: url(../images/logo-jquery-mobile@2x.png) no-repeat; + background-size: 268px 66px; + } + + .sizzlejs h2.logo a { + background: url(../images/logo-sizzle@2x.png) no-repeat; + background-size: 243px 66px; + } + + .qunitjs h2.logo a { + background: url(../images/logo-qunit@2x.png) no-repeat; + background-size: 243px 66px; + } + + .jquery-foundation h2.logo a { + background: url(../images/logo-jquery-foundation@2x.png) no-repeat; + background-size: 243px 66px; + } + + .jquery-events.jquery-foundation h2.logo a { + background: url(../images/logo-jquery-events@2x.png) no-repeat; + background-size: 243px 66px; + } +} + +@media only screen and (-webkit-min-device-pixel-ratio: 1.5), + only screen and (min-resolution: 144dpi) { + +} + + /* Helper classes + ========================================================================== */ + +.ir { + background-color: transparent; + border: 0; + overflow: hidden; + *text-indent: -9999px; +} + +.ir:before { + content: ""; + display: block; + width: 0; + height: 100%; +} + +.hidden { + display: none !important; + visibility: hidden; +} + +.visuallyhidden { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} + +.visuallyhidden.focusable:active, +.visuallyhidden.focusable:focus { + clip: auto; + height: auto; + margin: 0; + overflow: visible; + position: static; + width: auto; +} + +.invisible { + visibility: hidden; +} + +.clearfix:before, +.clearfix:after { + content: " "; + display: table; +} + +.clearfix:after { + clear: both; +} + +.clearfix { + *zoom: 1; +} + +/* Print styles + ========================================================================== */ + +@media print { + * { + background: transparent !important; + color: #000 !important; /* Black prints faster: h5bp.com/s */ + box-shadow:none !important; + text-shadow: none !important; + } + + a, + a:visited { + text-decoration: underline; + } + + a[href]:after { + content: " (" attr(href) ")"; + } + + abbr[title]:after { + content: " (" attr(title) ")"; + } + + /* + * Don't show links for images, or javascript/internal links + */ + + .ir a:after, + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + + thead { + display: table-header-group; /* h5bp.com/t */ + } + + tr, + img { + page-break-inside: avoid; + } + + img { + max-width: 100% !important; + } + + @page { + margin: 0.5cm; + } + + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + + h2, + h3 { + page-break-after: avoid; + } +} + +/* The Grid ---------------------- +Based on Zurb Foundation's Grid +*/ +.row { width: 1240px; max-width: 100%; min-width: 768px; margin: 0 auto; } +.row .row { width: auto; max-width: none; min-width: 0; margin: 0 -25px; } +.row.collapse .column, .row.collapse .columns { padding: 0; } +.row .row { width: auto; max-width: none; min-width: 0; margin: 0 -25px; } +.row .row.collapse { margin: 0; } + +.column, .columns { float: left; min-height: 1px; padding: 0 25px; position: relative; } +.column.centered, .columns.centered { float: none; margin: 0 auto; } + +[class*="column"] + [class*="column"]:last-child { float: right; } + +[class*="column"] + [class*="column"].end { float: left; } + +.one, .row .one { width: 8.33333%; } + +.two, .row .two { width: 16.66667%; } + +.three, .row .three { width: 25%; } + +.four, .row .four { width: 33.33333%; } + +.five, .row .five { width: 41.66667%; } + +.six, .row .six { width: 50%; } + +.seven, .row .seven { width: 58.33333%; } + +.eight, .row .eight { width: 66.66667%; } + +.nine, .row .nine { width: 75%; } + +.ten, .row .ten { width: 83.33333%; } + +.eleven, .row .eleven { width: 91.66667%; } + +.twelve, .row .twelve { width: 100%; } + +.row .offset-by-one { margin-left: 8.33333%; } + +.row .offset-by-two { margin-left: 16.66667%; } + +.row .offset-by-three { margin-left: 25%; } + +.row .offset-by-four { margin-left: 33.33333%; } + +.row .offset-by-five { margin-left: 41.66667%; } + +.row .offset-by-six { margin-left: 50%; } + +.row .offset-by-seven { margin-left: 58.33333%; } + +.row .offset-by-eight { margin-left: 66.66667%; } + +.row .offset-by-nine { margin-left: 75%; } + +.row .offset-by-ten { margin-left: 83.33333%; } + +.push-two { left: 16.66667%; } + +.pull-two { right: 16.66667%; } + +.push-three { left: 25%; } + +.pull-three { right: 25%; } + +.push-four { left: 33.33333%; } + +.pull-four { right: 33.33333%; } + +.push-five { left: 41.66667%; } + +.pull-five { right: 41.66667%; } + +.push-six { left: 50%; } + +.pull-six { right: 50%; } + +.push-seven { left: 58.33333%; } + +.pull-seven { right: 58.33333%; } + +.push-eight { left: 66.66667%; } + +.pull-eight { right: 66.66667%; } + +.push-nine { left: 75%; } + +.pull-nine { right: 75%; } + +.push-ten { left: 83.33333%; } + +.pull-ten { right: 83.33333%; } + +img, object, embed { max-width: 100%; height: auto; } + +object, embed { height: 100%; } + +img { -ms-interpolation-mode: bicubic; } + +#map_canvas img, .map_canvas img { max-width: none!important; } + +/* Nicolas Gallagher's micro clearfix */ +.row { *zoom: 1; } +.row:before, .row:after { content: ""; display: table; } +.row:after { clear: both; } + +/* Mobile Grid and Overrides ---------------------- */ +@media only screen and (max-width: 767px) { + .row { width: auto; min-width: 0; margin-left: 0 !important; margin-right: 0 !important; } + .column, .columns { width: auto !important; float: none; padding-left: 0 !important; padding-right: 0 !important; + } + .column:last-child, .columns:last-child { float: none; } + [class*="column"] + [class*="column"]:last-child { float: none; } + .column:before, .columns:before, .column:after, .columns:after { content: ""; display: table; } + .column:after, .columns:after { clear: both; } + .offset-by-one, .offset-by-two, .offset-by-three, .offset-by-four, .offset-by-five, .offset-by-six, .offset-by-seven, .offset-by-eight, .offset-by-nine, .offset-by-ten { margin-left: 0 !important; } + .push-two, .push-three, .push-four, .push-five, .push-six, .push-seven, .push-eight, .push-nine, .push-ten { left: auto; } + .pull-two, .pull-three, .pull-four, .pull-five, .pull-six, .pull-seven, .pull-eight, .pull-nine, .pull-ten { right: auto; } + /* Mobile 4-column Grid */ + .row .mobile-one { width: 25% !important; float: left; padding: 0 25px; } + .row .mobile-one:last-child { float: right; } + .row .mobile-one.end { float: left; } + .row.collapse .mobile-one { padding: 0; } + .row .mobile-two { width: 50% !important; float: left; padding: 0 25px; } + .row .mobile-two:last-child { float: right; } + .row .mobile-two.end { float: left; } + .row.collapse .mobile-two { padding: 0; } + .row .mobile-three { width: 75% !important; float: left; padding: 0 25px; } + .row .mobile-three:last-child { float: right; } + .row .mobile-three.end { float: left; } + .row.collapse .mobile-three { padding: 0; } + .row .mobile-four { width: 100% !important; float: left; padding: 0 25px; } + .row .mobile-four:last-child { float: right; } + .row .mobile-four.end { float: left; } + .row.collapse .mobile-four { padding: 0; } + .push-one-mobile { left: 25%; } + .pull-one-mobile { right: 25%; } + .push-two-mobile { left: 50%; } + .pull-two-mobile { right: 50%; } + .push-three-mobile { left: 75%; } + .pull-three-mobile { right: 75%; } +} + + +/* Block Grids ---------------------- */ +/* These are 2-up, 3-up, 4-up and 5-up ULs, suited +for repeating blocks of content. Add 'mobile' to +them to switch them just like the layout grid +(one item per line) on phones + +For IE7/8 compatibility block-grid items need to be +the same height. You can optionally uncomment the +lines below to support arbitrary height, but know +that IE7/8 do not support :nth-child. +-------------------------------------------------- */ +.block-grid, #content .block-grid { display: block; overflow: hidden; padding: 0; } +.block-grid > li, #content .block-grid > li { display: block; height: auto; float: left; } +.block-grid.one-up, #content .block-grid.one-up { margin: 0; } +.block-grid.one-up > li, #content .block-grid.one-up > li { width: 100%; padding: 0 0 15px; } +.block-grid.two-up, #content .block-grid.two-up { margin: 0 -15px; } +.block-grid.two-up > li, #content .block-grid.two-up > li { width: 50%; padding: 0 15px 15px; } +.block-grid.two-up > li:nth-child(2n+1), #content .block-grid.two-up > li:nth-child(2n+1) { clear: both; } +.block-grid.three-up, #content .block-grid.three-up { margin: 0 -12px; } +.block-grid.three-up > li, #content .block-grid.three-up > li { width: 33.33%; padding: 0 12px 12px; } +.block-grid.three-up > li:nth-child(3n+1), #content .block-grid.three-up > li:nth-child(3n+1) { clear: both; } +.block-grid.four-up, #content .block-grid.four-up { margin: 0 -10px; } +.block-grid.four-up > li, #content .block-grid.four-up > li { width: 25%; padding: 0 10px 10px; } +.block-grid.four-up > li:nth-child(4n+1), #content .block-grid.four-up > li:nth-child(4n+1) { clear: both; } +.block-grid.five-up, #content .block-grid.five-up { margin: 0 -8px; } +.block-grid.five-up > li, #content .block-grid.five-up > li { width: 20%; padding: 0 8px 8px; } +.block-grid.five-up > li:nth-child(5n+1), #content .block-grid.five-up > li:nth-child(5n+1) { clear: both; } + +/* Mobile Block Grids */ +@media only screen and (max-width: 767px) { + .block-grid.mobile > li { float: none !important; width: 100% !important; margin-left: 0 !important; } + .block-grid > li { clear: none !important; } + .block-grid.mobile-two-up > li { width: 50% !important; } + .block-grid.mobile-two-up > li:nth-child(2n+1) { clear: both; } + .block-grid.mobile-three-up > li { width: 33.33% !important; } + .block-grid.mobile-three-up > li:nth-child(3n+1) { clear: both !important; } + .block-grid.mobile-four-up > li { width: 25% !important; } + .block-grid.mobile-four-up > li:nth-child(4n+1) { clear: both; } + .block-grid.mobile-five-up > li:nth-child(5n+1) { clear: both; } +} + +/* + ColorBox Core Style: + The following CSS is consistent between example themes and should not be altered. +*/ +#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;} +#cboxOverlay{position:fixed; width:100%; height:100%;} +#cboxMiddleLeft, #cboxBottomLeft{clear:left;} +#cboxContent{position:relative;} +#cboxLoadedContent{overflow:auto;} +#cboxTitle{margin:0;} +#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;} +#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;} +.cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none;} +.cboxIframe{width:100%; height:100%; display:block; border:0;} +#colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box;} + +/* + User Style: + Change the following styles to modify the appearance of ColorBox. They are + ordered & tabbed in a way that represents the nesting of the generated HTML. +*/ +#cboxOverlay{background:url(../images/colorbox/overlay.png) repeat 0 0;} +#cboxTopLeft{width:21px; height:21px; background:url(../images/colorbox/controls.png) no-repeat -101px 0;} +#cboxTopRight{width:21px; height:21px; background:url(../images/colorbox/controls.png) no-repeat -130px 0;} +#cboxBottomLeft{width:21px; height:21px; background:url(../images/colorbox/controls.png) no-repeat -101px -29px;} +#cboxBottomRight{width:21px; height:21px; background:url(../images/colorbox/controls.png) no-repeat -130px -29px;} +#cboxMiddleLeft{width:21px; background:url(../images/colorbox/controls.png) left top repeat-y;} +#cboxMiddleRight{width:21px; background:url(../images/colorbox/controls.png) right top repeat-y;} +#cboxTopCenter{height:21px; background:url(../images/colorbox/border.png) 0 0 repeat-x;} +#cboxBottomCenter{height:21px; background:url(../images/colorbox/border.png) 0 -29px repeat-x;} +#cboxContent{background:#fff; overflow:hidden;} +.cboxIframe{background:#fff;} +#cboxError{padding:50px; border:1px solid #ccc;} +#cboxLoadedContent{margin-bottom:28px;} +#cboxTitle{position:absolute; bottom:4px; left:0; text-align:center; width:100%; color:#949494;} +#cboxCurrent{position:absolute; bottom:4px; left:58px; color:#949494;} +#cboxSlideshow{position:absolute; bottom:4px; right:30px; color:#0092ef;} +#cboxPrevious{position:absolute; bottom:0; left:0; background:url(../images/colorbox/controls.png) no-repeat -75px 0; width:25px; height:25px; text-indent:-9999px;} +#cboxPrevious:hover{background-position:-75px -25px;} +#cboxNext{position:absolute; bottom:0; left:27px; background:url(../images/colorbox/controls.png) no-repeat -50px 0; width:25px; height:25px; text-indent:-9999px;} +#cboxNext:hover{background-position:-50px -25px;} +#cboxLoadingOverlay{background:url(../images/colorbox/loading_background.png) no-repeat center center;} +#cboxLoadingGraphic{background:url(../images/colorbox/loading.gif) no-repeat center center;} +#cboxClose{position:absolute; bottom:0; right:0; background:url(../images/colorbox/controls.png) no-repeat -25px 0; width:25px; height:25px; text-indent:-9999px;} +#cboxClose:hover{background-position:-25px -25px;} + +/* + The following fixes a problem where IE7 and IE8 replace a PNG's alpha transparency with a black fill + when an alpha filter (opacity change) is set on the element or ancestor element. This style is not applied to or needed in IE9. + See: http://jacklmoore.com/notes/ie-transparency-problems/ +*/ +.cboxIE #cboxTopLeft, +.cboxIE #cboxTopCenter, +.cboxIE #cboxTopRight, +.cboxIE #cboxBottomLeft, +.cboxIE #cboxBottomCenter, +.cboxIE #cboxBottomRight, +.cboxIE #cboxMiddleLeft, +.cboxIE #cboxMiddleRight { + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#00FFFFFF,endColorstr=#00FFFFFF); +} + + +/* Syntax Highlighting ---------------------- */ + +pre, code { + font-family: "source-code-pro", Consolas, monospace !important; + word-spacing: 0; +} +pre code { + display: block; padding: 0.5em; + color: #333; + background: #f8f8ff +} + +pre .comment, +pre .template_comment, +pre .diff .header, +pre .javadoc { + color: #998; + font-style: italic +} + +pre .keyword, +pre .css .rule .keyword, +pre .winutils, +pre .javascript .title, +pre .nginx .title, +pre .subst, +pre .request, +pre .status { + color: #333; + font-weight: bold +} + +pre .number, +pre .hexcolor, +pre .ruby .constant { + color: #099; +} + +pre .string, +pre .tag .value, +pre .phpdoc, +pre .tex .formula { + color: #d14 +} + +pre .title, +pre .id { + color: #900; + font-weight: bold +} + +pre .javascript .title, +pre .lisp .title, +pre .clojure .title, +pre .subst { + font-weight: normal +} + +pre .class .title, +pre .haskell .type, +pre .vhdl .literal, +pre .tex .command { + color: #458; + font-weight: bold +} + +pre .tag, +pre .tag .title, +pre .rules .property, +pre .django .tag .keyword { + color: #000080; + font-weight: normal +} + +pre .attribute, +pre .variable, +pre .lisp .body { + color: #008080 +} + +pre .regexp { + color: #009926 +} + +pre .class { + color: #458; + font-weight: bold +} + +pre .symbol, +pre .ruby .symbol .string, +pre .lisp .keyword, +pre .tex .special, +pre .prompt { + color: #990073 +} + +pre .built_in, +pre .lisp .title, +pre .clojure .built_in { + color: #0086b3 +} + +pre .preprocessor, +pre .pi, +pre .doctype, +pre .shebang, +pre .cdata { + color: #999; + font-weight: bold +} + +pre .deletion { + background: #fdd +} + +pre .addition { + background: #dfd +} + +pre .diff .change { + background: #0086b3 +} + +pre .chunk { + color: #aaa +} + +.syntaxhighlighter a, +.syntaxhighlighter div, +.syntaxhighlighter pre, +.syntaxhighlighter code, +.syntaxhighlighter table, +.syntaxhighlighter table td, +.syntaxhighlighter table tr, +.syntaxhighlighter table tbody, +.syntaxhighlighter table thead, +.syntaxhighlighter table caption, +.syntaxhighlighter textarea { + border-radius: 0 0 0 0 !important; + background: none !important; + bottom: auto !important; + float: none !important; + height: auto !important; + left: auto !important; + line-height: 1.1em !important; + margin: 0 !important; + outline: 0 !important; + overflow: visible !important; + padding: 0 !important; + position: static !important; + right: auto !important; + text-align: left !important; + top: auto !important; + vertical-align: baseline !important; + width: auto !important; + box-sizing: content-box !important; + font-family: "source-code-pro", Consolas, monospace !important; + font-weight: normal !important; + font-style: normal !important; + font-size: 1em !important; + min-height: inherit !important; + min-height: auto !important; +} +.syntaxhighlighter { + width: 100% !important; + margin: 1em 0 1em 0 !important; + padding: 1em 0; + position: relative !important; + overflow: auto !important; + font-size: 1em !important; + background: #eee; +} +.syntaxhighlighter.source { + overflow: hidden !important; +} +.syntaxhighlighter .line { + white-space: pre !important; +} +.syntaxhighlighter table { + width: 100% !important; +} +.syntaxhighlighter table caption { + text-align: left !important; + padding: .5em 0 0.5em 1em !important; +} +.syntaxhighlighter table td.code { + width: 100% !important; +} +.syntaxhighlighter table td.code .container { + position: relative !important; +} +.syntaxhighlighter table td.code .container textarea { + box-sizing: border-box !important; + position: absolute !important; + left: 0 !important; + top: 0 !important; + width: 100% !important; + height: 100% !important; + border: none !important; + background: white !important; + padding-left: 1em !important; + overflow: hidden !important; + white-space: pre !important; +} +.syntaxhighlighter table td.gutter .line { + text-align: right !important; + padding: 0 0.5em 0 1em !important; +} +.syntaxhighlighter table td.code .line { + padding: 0 0.5em !important; +} +.syntaxhighlighter.nogutter td.code .container textarea, +.syntaxhighlighter.nogutter td.code .line { + padding-left: 1em !important; +} + +.syntaxhighlighter table td.gutter { + border-right: 2px solid #999; +} + +.syntaxhighlighter { + border-radius: 5px; +} + +#content .syntaxhighlighter tr { + border-bottom: none; +} From 69b1fca4eec6dcefbc69719eb9179bdd299f3e94 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Tue, 23 Jun 2015 02:50:15 +0100 Subject: [PATCH 08/73] looking for bug with bad px/py values, error seems to be only restricted to the first two nodes in the nodes array --- data/fm.json | 28 +++++++-------- graphSub.html | 96 +++++++++++++++++++++++++++++-------------------- miserables.html | 10 +++--- 3 files changed, 77 insertions(+), 57 deletions(-) diff --git a/data/fm.json b/data/fm.json index 54d2508..cff0357 100644 --- a/data/fm.json +++ b/data/fm.json @@ -1,19 +1,19 @@ { "nodes":[ - {"name":"a"}, - {"name":"b"}, - {"name":"c"}, - {"name":"d"}, - {"name":"e"}, - {"name":"f"}, - {"name":"g"}, - {"name":"h"}, - {"name":"i"}, - {"name":"j"}, - {"name":"k"}, - {"name":"l"}, - {"name":"m"}, - {"name":"n"} + {"name":"a", "group":1}, + {"name":"b", "group":2}, + {"name":"c", "group":3}, + {"name":"d", "group":4}, + {"name":"e", "group":5}, + {"name":"f", "group":6}, + {"name":"g", "group":7}, + {"name":"h", "group":1}, + {"name":"i", "group":2}, + {"name":"j", "group":3}, + {"name":"k", "group":4}, + {"name":"l", "group":5}, + {"name":"m", "group":6}, + {"name":"n", "group":7} ], "links":[ {"source":0,"target":1,"value":1}, diff --git a/graphSub.html b/graphSub.html index a5447b8..4909e63 100644 --- a/graphSub.html +++ b/graphSub.html @@ -43,34 +43,21 @@ }; } - d3.json("data/miserables.json", function(error, graph) { + d3.json("data/fm.json", function(error, graph) { if (error) throw error; // Code layout uses the functional/module pattern // See p52 of Crockfords book function chart(elementName) { - var width = 960, // default width - height = 450, // default height - color = d3.scale.category10(), - force = d3.layout.force(), - nodes = force.nodes(), - links = force.links(), - vis, - runOnceFlag = true; - - vis = d3.select(elementName) - .append("svg:svg") - .attr("width", width) - .attr("height", height) - .attr("id", "svg") - .attr("pointer-events", "all") - .attr("viewBox", "0 0 " + width + " " + height) - .attr("perserveAspectRatio", "xMinYMid") - .append('svg:g'); - if (runOnceFlag) { - clickHandler(graph.nodes[0], 0); - runOnceFlag = false; - }; + // because of the way the network is created, nodes are created first, and links second, + // so the lines were on top of the nodes, this just reorders the DOM to put the svg:g on top + function keepNodesOnTop() { + $(".nodeStrokeClass").each(function( index ) { + var gnode = this.parentNode; + gnode.parentNode.appendChild(gnode); + }); + } + function width(value) { if (!arguments.length) return width; @@ -87,14 +74,22 @@ // add nodes to the layout function addNode(nodeObj){ nodes.push(nodeObj); + console.log('addnode',nodes); update(); + console.log('addnode',nodes); + console.log('******'); + console.log(nodes); }; function addLink(source, target, value){ + console.log(nodes); var link = {"source": findNode(source), "target": findNode(target), "value": value}; + console.log(nodes); links.push(link); - //console.log(link); + console.log(nodes); + console.log('######'); update(); + keepNodesOnTop(); }; // look for the node in the d3 layout @@ -137,10 +132,8 @@ currentIndex; // initialize - console.log('datum.name', datum.name); currentIndex = findNodeIndex(datum.name, graph.nodes); // index of the node - console.log('currentIndex', currentIndex); - + if (currentIndex === undefined) throw error; toVisit.push(currentIndex); // next node to find @@ -169,9 +162,7 @@ }; count = count + 1; }; - console.log('subNodes', subNodes); - console.log('subLinks', subLinks); - + return { 'subNodes': subNodes, 'subLinks': subLinks @@ -180,12 +171,10 @@ function clickHandler(d, i){ // clear the nodes and links array - console.log('layout nodes', nodes); - console.log('layout links', links); - + removeAllNodes(); removeAllLinks(); - console.log('layout links', links); + var link, source, target; @@ -196,18 +185,48 @@ for (var i = 0; i < subNet.subNodes.length; i++) { addNode(graph.nodes[subNet.subNodes[i]]) }; + + keepNodesOnTop(); + console.log('from clickHandler', nodes); + // then add the links for (var i = 0; i < subNet.subLinks.length; i++) { link = subNet.subLinks[i]; + // get objects from JSON data source = graph.nodes[link.sourceIndex]; target = graph.nodes[link.targetIndex]; - +// console.log(link, source.name, target.name); addLink(source.name, target.name, 1); - + }; }; + var width = 960, // default width + height = 450, // default height + color = d3.scale.category10(), + force = d3.layout.force(), + nodes = force.nodes(), + links = force.links(), + vis, + runOnceFlag = true; + + vis = d3.select(elementName) + .append("svg:svg") + .attr("width", width) + .attr("height", height) + .attr("id", "svg") + .attr("pointer-events", "all") + .attr("viewBox", "0 0 " + width + " " + height) + .attr("perserveAspectRatio", "xMinYMid") + .append('svg:g'); + + + if (runOnceFlag) { + clickHandler(graph.nodes[0], 0); + runOnceFlag = false; + }; + function update() { var link = vis.selectAll("line") .data(links, function (d) { @@ -279,9 +298,8 @@ }); // Restart the force layout. - force.gravity(.01) - .charge(-80000) - .friction(0) + force + .charge(-120) .linkDistance( function(d) { return d.group * 10 } ) .size([width, height]) .start(); diff --git a/miserables.html b/miserables.html index 486cdc6..deafd76 100644 --- a/miserables.html +++ b/miserables.html @@ -34,15 +34,16 @@ d3.json("data/miserables.json", function(error, graph) { force .nodes(graph.nodes) - .links(graph.links) + .links([]) .start(); - + //graph.links + /* var link = svg.selectAll(".link") .data(graph.links) .enter().append("line") .attr("class", "link") .style("stroke-width", function(d) { return Math.sqrt(d.value); }); - + */ var node = svg.selectAll(".node") .data(graph.nodes) .enter().append("circle") @@ -55,11 +56,12 @@ .text(function(d) { return d.name; }); force.on("tick", function() { + /* 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("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }); }); From f0620fe0188032bfa6ed2cc06582d538ed95202e Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Wed, 24 Jun 2015 13:00:50 +0100 Subject: [PATCH 09/73] sub section now working, nodes will re-render epending on which node is clicked --- cool-blue.html | 156 ++++++++++++++++++++++++++++++++++++++++++++++ dynamicForce.html | 19 +++--- error | 150 ++++++++++++++++++++++++++++++++++++++++++++ graphSub.html | 92 +++++++++++++++------------ 4 files changed, 366 insertions(+), 51 deletions(-) create mode 100644 cool-blue.html create mode 100644 error diff --git a/cool-blue.html b/cool-blue.html new file mode 100644 index 0000000..53613e1 --- /dev/null +++ b/cool-blue.html @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dynamicForce.html b/dynamicForce.html index 750b06c..30d442b 100644 --- a/dynamicForce.html +++ b/dynamicForce.html @@ -161,7 +161,6 @@ node.exit().remove(); force.on("tick", function () { - node.attr("transform", function (d) { return "translate(" + d.x + "," + d.y + ")"; }); @@ -169,15 +168,15 @@ 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; - }); + .attr("y1", function (d) { + return d.source.y; + }) + .attr("x2", function (d) { + return d.target.x; + }) + .attr("y2", function (d) { + return d.target.y; + }); }); // Restart the force layout. diff --git a/error b/error new file mode 100644 index 0000000..6c8a9f9 --- /dev/null +++ b/error @@ -0,0 +1,150 @@ + + + + + + + graphSub + Animating Changes in Force Diagram + + + + + + + + + \ No newline at end of file diff --git a/graphSub.html b/graphSub.html index 4909e63..a23306e 100644 --- a/graphSub.html +++ b/graphSub.html @@ -6,9 +6,8 @@ graphSub Animating Changes in Force Diagram - + - - - - - - - - - \ No newline at end of file diff --git a/error b/error deleted file mode 100644 index 6c8a9f9..0000000 --- a/error +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - - graphSub - Animating Changes in Force Diagram - - - - - - - - - \ No newline at end of file diff --git a/graphSub.html b/graphSub.html index a23306e..f50a5cd 100644 --- a/graphSub.html +++ b/graphSub.html @@ -42,7 +42,7 @@ }; } - d3.json("data/miserables.json", function(error, graph) { + d3.json("data/fm.json", function(error, graph) { if (error) throw error; // Code layout uses the functional/module pattern // See p52 of Crockfords book @@ -72,11 +72,7 @@ // add nodes to the layout var addNode = function(nodeObj){ nodes.push(nodeObj); - //console.log('addnode',nodes); - update(); - //console.log('addnode',nodes); - //console.log('******'); - //console.log(nodes); + update(); }; var addLink = function(source, target, value){ @@ -178,7 +174,8 @@ target; // get the subNet values - var subNet = getSubNetwork(d, 1); + var subNet = getSubNetwork(d, 2); + //console.log // add the nodes one at a time for (var i = 0; i < subNet.subNodes.length; i++) { addNode(graph.nodes[subNet.subNodes[i]]) @@ -194,7 +191,7 @@ // get objects from JSON data source = graph.nodes[link.sourceIndex]; target = graph.nodes[link.targetIndex]; - addLink(source.name, target.name, 1); + addLink(source.name, target.name, 2); }; }; @@ -273,7 +270,6 @@ force.on("tick", function () { node.attr("transform", function (d) { - console.log(d); return "translate(" + d.x + "," + d.y + ")"; }); @@ -293,8 +289,10 @@ // Restart the force layout. force - .charge(-120) - .linkDistance( function(d) { return d.value * 100 } ) + .gravity(.02) + .charge(-8000) + .friction(0.1) + .linkDistance( function(d) { return d.value * 10 } ) .size([width, height]) .start(); }; @@ -309,6 +307,7 @@ console.log(nodes); console.log(links); var c = {"source": findNode('Napoleon'), "target": findNode('Myriel'), value: 1} + //var c = {"source": findNode('a'), "target": findNode('b'), value: 1} links.push(c); update(); From 60b0736134f04c856721216ebc520d9616200548 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Thu, 25 Jun 2015 14:37:47 +0100 Subject: [PATCH 11/73] new subnet extractor using recursive method, in working order --- data/fm.json | 14 +++++------ graphSub.html | 66 +++++++++++++++++++++++++++++++++++---------------- 2 files changed, 53 insertions(+), 27 deletions(-) diff --git a/data/fm.json b/data/fm.json index cff0357..4b34291 100644 --- a/data/fm.json +++ b/data/fm.json @@ -17,20 +17,20 @@ ], "links":[ {"source":0,"target":1,"value":1}, + {"source":0,"target":5,"value":1}, + {"source":0,"target":6,"value":1}, + {"source":0,"target":7,"value":1}, + {"source":1,"target":5,"value":1}, + {"source":1,"target":6,"value":1}, + {"source":1,"target":7,"value":1}, {"source":2,"target":3,"value":1}, {"source":4,"target":5,"value":1}, {"source":7,"target":8,"value":1}, {"source":9,"target":10,"value":1}, {"source":11,"target":12,"value":1}, - {"source":0,"target":5,"value":1}, - {"source":1,"target":5,"value":1}, - {"source":0,"target":6,"value":1}, - {"source":1,"target":6,"value":1}, - {"source":0,"target":7,"value":1}, - {"source":1,"target":7,"value":1}, {"source":2,"target":8,"value":1}, - {"source":3,"target":8,"value":1}, {"source":2,"target":9,"value":1}, + {"source":3,"target":8,"value":1}, {"source":3,"target":9,"value":1}, {"source":4,"target":11,"value":1}, {"source":5,"target":11,"value":1}, diff --git a/graphSub.html b/graphSub.html index f50a5cd..c14f5c6 100644 --- a/graphSub.html +++ b/graphSub.html @@ -42,7 +42,7 @@ }; } - d3.json("data/fm.json", function(error, graph) { + d3.json("data/miserables.json", function(error, graph) { if (error) throw error; // Code layout uses the functional/module pattern // See p52 of Crockfords book @@ -81,9 +81,9 @@ //console.log(nodes); links.push(link); //console.log(nodes); - //console.log('######'); + //onsole.log('######'); update(); - keepNodesOnTop(); + }; // look for the node in the d3 layout @@ -113,6 +113,29 @@ }; }; + var rn = []; + var rl = [] + var nodesVisited = function(currentIndex, hops){ + //console.log('index', currentIndex, 'hops', hops); + rn.xpush(currentIndex); + + if (hops === 0) { + return rn; + }; + + for (var i = 0; i < graph.links.length; i++) { + + if (currentIndex === graph.links[i].source) { + rl.xpush(JSON.stringify(graph.links[i])); + nodesVisited(graph.links[i].target, hops - 1) + }; + if (currentIndex === graph.links[i].target) { + rl.xpush(JSON.stringify(graph.links[i])); + nodesVisited(graph.links[i].source, hops - 1) + }; + }; + }; + var getSubNetwork = function(datum, hops){ // return all the nodes within the number of 'hops' // initialise variable. @@ -153,7 +176,9 @@ toVisit.xpush(graph.links[i].source); subNodes.xpush(graph.links[i].source); }; + //console.log('currentIndex->', currentIndex, 'count->', count, 'toVisit->', toVisit, 'result->', subNodes, subLinks); }; + count = count + 1; }; @@ -175,22 +200,24 @@ // get the subNet values var subNet = getSubNetwork(d, 2); - //console.log + + rn = [], + rl = []; + var index = findNodeIndex(d.name, graph.nodes); + nodesVisited(index, 1); + console.log(rn, rl); // add the nodes one at a time - for (var i = 0; i < subNet.subNodes.length; i++) { - addNode(graph.nodes[subNet.subNodes[i]]) + for (var i = 0; i < rn.length; i++) { + addNode(graph.nodes[rn[i]]) }; - - keepNodesOnTop(); - console.log('from clickHandler', nodes); - + // then add the links - for (var i = 0; i < subNet.subLinks.length; i++) { - link = subNet.subLinks[i]; + for (var i = 0; i < rl.length; i++) { + link = JSON.parse(rl[i]); // get objects from JSON data - source = graph.nodes[link.sourceIndex]; - target = graph.nodes[link.targetIndex]; + source = graph.nodes[link.source]; + target = graph.nodes[link.target]; addLink(source.name, target.name, 2); }; @@ -223,7 +250,8 @@ return d.source.name + "-" + d.target.name; }); - link.enter().append("line") + //link.enter().append("line") + link.enter().insert("line", "g") .attr("id", function (d) { return d.source.name + "-" + d.target.name; }) @@ -255,7 +283,7 @@ }) .attr("class", "nodeStrokeClass") .attr("fill", function(d) { return color(d.group); }) - .on('click', clickHandler); + .on('dblclick', clickHandler); nodeEnter.append("svg:text") .attr("class", "textClass") @@ -289,10 +317,8 @@ // Restart the force layout. force - .gravity(.02) - .charge(-8000) - .friction(0.1) - .linkDistance( function(d) { return d.value * 10 } ) + .charge(-800) + .linkDistance(30) .size([width, height]) .start(); }; From 539b7095fbb4c3be1fd5c021dabfd9b00b1533d3 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Thu, 25 Jun 2015 15:18:50 +0100 Subject: [PATCH 12/73] cleanup of code - WORKING CODE --- graphSub.html | 128 ++++++++++++-------------------------------------- 1 file changed, 29 insertions(+), 99 deletions(-) diff --git a/graphSub.html b/graphSub.html index c14f5c6..1d21c60 100644 --- a/graphSub.html +++ b/graphSub.html @@ -42,21 +42,11 @@ }; } - d3.json("data/miserables.json", function(error, graph) { + d3.json("data/fm.json", function(error, graph) { if (error) throw error; - // Code layout uses the functional/module pattern - // See p52 of Crockfords book + function chart(elementName) { - // because of the way the network is created, nodes are created first, and links second, - // so the lines were on top of the nodes, this just reorders the DOM to put the svg:g on top - var keepNodesOnTop = function() { - $(".nodeStrokeClass").each(function( index ) { - var gnode = this.parentNode; - gnode.parentNode.appendChild(gnode); - }); - }; - var width = function(value) { if (!arguments.length) return width; width = value; @@ -70,18 +60,15 @@ }; // add nodes to the layout - var addNode = function(nodeObj){ - nodes.push(nodeObj); + var addNode = function(node){ + nodes.push(node); update(); }; + // add link to the layout var addLink = function(source, target, value){ - //console.log(nodes); var link = {"source": findNode(source), "target": findNode(target), "value": value}; - //console.log(nodes); links.push(link); - //console.log(nodes); - //onsole.log('######'); update(); }; @@ -113,109 +100,51 @@ }; }; - var rn = []; - var rl = [] var nodesVisited = function(currentIndex, hops){ - //console.log('index', currentIndex, 'hops', hops); - rn.xpush(currentIndex); - + // links stored as JSON objects, easy to compare + subNetNodes.xpush(currentIndex); + if (hops === 0) { - return rn; + return; }; for (var i = 0; i < graph.links.length; i++) { if (currentIndex === graph.links[i].source) { - rl.xpush(JSON.stringify(graph.links[i])); + subNetLinks.xpush(JSON.stringify(graph.links[i])); nodesVisited(graph.links[i].target, hops - 1) }; if (currentIndex === graph.links[i].target) { - rl.xpush(JSON.stringify(graph.links[i])); + subNetLinks.xpush(JSON.stringify(graph.links[i])); nodesVisited(graph.links[i].source, hops - 1) }; }; }; - var getSubNetwork = function(datum, hops){ - // return all the nodes within the number of 'hops' - // initialise variable. - - // chosen to return indice values rarther than actual object - // to avoid hidden references to objects tainting the layout data - var count = 0, - toVisit = [], // nodes Indices to look for - subNodes = [],// list of node indices - subLinks = [],// list of source target indices - currentIndex; - - // initialize - currentIndex = findNodeIndex(datum.name, graph.nodes); // index of the node - - if (currentIndex === undefined) throw error; - - toVisit.push(currentIndex); // next node to find - subNodes.push(currentIndex); // nodes in the sub network - - // working with raw data from JSON file - while((count < hops) || (toVisit.length === 0)){ - currentIndex = toVisit.pop(toVisit); - - for (var i = 0; i < graph.links.length; i++) { - // collect links that 'currentIndex' points to - if(graph.links[i].source === currentIndex){ - - subLinks.xpush({sourceIndex: currentIndex, targetIndex: graph.links[i].target}); - toVisit.xpush(graph.links[i].target); - subNodes.xpush(graph.links[i].target); - }; - - // collect the links that point to 'currentIndex' - if(graph.links[i].target === currentIndex){ - - subLinks.xpush({sourceIndex: graph.links[i].source, targetIndex: currentIndex}); - toVisit.xpush(graph.links[i].source); - subNodes.xpush(graph.links[i].source); - }; - //console.log('currentIndex->', currentIndex, 'count->', count, 'toVisit->', toVisit, 'result->', subNodes, subLinks); - }; - - count = count + 1; - }; - - return { - 'subNodes': subNodes, - 'subLinks': subLinks - }; - }; - var clickHandler = function(d, i){ - // clear the nodes and links array - + // init removeAllNodes(); removeAllLinks(); + subNetNodes = [], + subNetLinks = []; var link, source, target; - // get the subNet values - var subNet = getSubNetwork(d, 2); - - rn = [], - rl = []; var index = findNodeIndex(d.name, graph.nodes); - nodesVisited(index, 1); - console.log(rn, rl); - // add the nodes one at a time - for (var i = 0; i < rn.length; i++) { - addNode(graph.nodes[rn[i]]) + nodesVisited(index, 2); + console.log(subNetNodes, subNetLinks); + + // add the nodes incrementaly + for (var i = 0; i < subNetNodes.length; i++) { + addNode(graph.nodes[subNetNodes[i]]) }; - // then add the links - for (var i = 0; i < rl.length; i++) { - link = JSON.parse(rl[i]); + // add links incrementaly + for (var i = 0; i < subNetLinks.length; i++) { + link = JSON.parse(subNetLinks[i]); - // get objects from JSON data source = graph.nodes[link.source]; target = graph.nodes[link.target]; addLink(source.name, target.name, 2); @@ -230,6 +159,8 @@ nodes = force.nodes(), links = force.links(), vis, + subNetNodes = [], + subNetLinks = [], runOnceFlag = true; vis = d3.select(elementName) @@ -250,7 +181,6 @@ return d.source.name + "-" + d.target.name; }); - //link.enter().append("line") link.enter().insert("line", "g") .attr("id", function (d) { return d.source.name + "-" + d.target.name; @@ -326,14 +256,14 @@ if (runOnceFlag) { var a = graph.nodes[0]; var b = graph.nodes[1] + nodes.push(a); update(); nodes.push(b); update(); - console.log(nodes); - console.log(links); - var c = {"source": findNode('Napoleon'), "target": findNode('Myriel'), value: 1} - //var c = {"source": findNode('a'), "target": findNode('b'), value: 1} + + //var c = {"source": findNode('Napoleon'), "target": findNode('Myriel'), value: 1} + var c = {"source": findNode('a'), "target": findNode('b'), value: 1} links.push(c); update(); From c067146e854cd426996c83ff4e35993358805326 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Fri, 26 Jun 2015 15:42:55 +0100 Subject: [PATCH 13/73] removed epdate after every node addition, all nodes added at once and rendered at once. same with links --- graphSub.html | 54 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/graphSub.html b/graphSub.html index 1d21c60..74519af 100644 --- a/graphSub.html +++ b/graphSub.html @@ -61,15 +61,19 @@ // add nodes to the layout var addNode = function(node){ + //node.fixed = true; + //node.x = 100; + //node.y = 100; + console.table(node); nodes.push(node); - update(); + //update(); }; // add link to the layout var addLink = function(source, target, value){ var link = {"source": findNode(source), "target": findNode(target), "value": value}; links.push(link); - update(); + //update(); }; @@ -100,7 +104,7 @@ }; }; - var nodesVisited = function(currentIndex, hops){ + var subNet = function(currentIndex, hops){ // links stored as JSON objects, easy to compare subNetNodes.xpush(currentIndex); @@ -112,11 +116,11 @@ if (currentIndex === graph.links[i].source) { subNetLinks.xpush(JSON.stringify(graph.links[i])); - nodesVisited(graph.links[i].target, hops - 1) + subNet(graph.links[i].target, hops - 1) }; if (currentIndex === graph.links[i].target) { subNetLinks.xpush(JSON.stringify(graph.links[i])); - nodesVisited(graph.links[i].source, hops - 1) + subNet(graph.links[i].source, hops - 1) }; }; }; @@ -132,15 +136,27 @@ source, target; - var index = findNodeIndex(d.name, graph.nodes); - nodesVisited(index, 2); - console.log(subNetNodes, subNetLinks); + subNet(findNodeIndex(d.name, graph.nodes), 3); + console.log(graph.nodes[subNetNodes[0]]); // add the nodes incrementaly for (var i = 0; i < subNetNodes.length; i++) { + //if (i === 0) {}; addNode(graph.nodes[subNetNodes[i]]) }; - +/* + nodes.forEach(function(n) { + if(n.name === d.name) { + n.fixed = true; + n.x = width/2; + n.y = height/2; + }else{ + n.fixed = false + }; + + }); +*/ + //update(); // add links incrementaly for (var i = 0; i < subNetLinks.length; i++) { link = JSON.parse(subNetLinks[i]); @@ -150,6 +166,8 @@ addLink(source.name, target.name, 2); }; + update(); + //console.log(nodes); }; var width = 960, // default width @@ -174,14 +192,16 @@ .append('svg:g'); var update = function() { - force.start(); - var link = vis.selectAll("line") .data(links, function (d) { return d.source.name + "-" + d.target.name; }); link.enter().insert("line", "g") + .transition() + .delay(function (d, i) { + return i*100; + }) .attr("id", function (d) { return d.source.name + "-" + d.target.name; }) @@ -202,18 +222,20 @@ return d.name; }); - var nodeEnter = node.enter().append("g") + var nodeEnter = node.enter() + .append("g") .attr("class", "node") .call(force.drag); - nodeEnter.append("svg:circle") + nodeEnter + .append("svg:circle") .attr("r", 12) .attr("id", function (d) { return "Node;" + d.name; }) .attr("class", "nodeStrokeClass") .attr("fill", function(d) { return color(d.group); }) - .on('dblclick', clickHandler); + .on('click', clickHandler); nodeEnter.append("svg:text") .attr("class", "textClass") @@ -245,6 +267,10 @@ }); }); + force.on("end", function () { + console.log(d3.event); + }); + // Restart the force layout. force .charge(-800) From 2b252c38d8839173e47d09a2c0010d2127bbcdeb Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Sun, 28 Jun 2015 18:03:02 +0100 Subject: [PATCH 14/73] minor experiments --- graphSub.html | 52 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/graphSub.html b/graphSub.html index 74519af..2e59447 100644 --- a/graphSub.html +++ b/graphSub.html @@ -59,12 +59,19 @@ return chart; // enable chaining }; + var resize = function() { + var svg = d3.select(elementName).append("svg"); + width = window.innerWidth, height = window.innerHeight; + vis.attr("width", width).attr("height", height); + force.size([width, height]).resume(); + } + // add nodes to the layout var addNode = function(node){ //node.fixed = true; - //node.x = 100; - //node.y = 100; - console.table(node); + //node.x = width/2; + //node.y = height/2; + //console.table(node); nodes.push(node); //update(); }; @@ -126,11 +133,13 @@ }; var clickHandler = function(d, i){ + console.log(d3.event, this); // init removeAllNodes(); removeAllLinks(); subNetNodes = [], subNetLinks = []; + clikedNode = this; var link, source, @@ -144,19 +153,8 @@ //if (i === 0) {}; addNode(graph.nodes[subNetNodes[i]]) }; -/* - nodes.forEach(function(n) { - if(n.name === d.name) { - n.fixed = true; - n.x = width/2; - n.y = height/2; - }else{ - n.fixed = false - }; - - }); -*/ - //update(); + + // add links incrementaly for (var i = 0; i < subNetLinks.length; i++) { link = JSON.parse(subNetLinks[i]); @@ -167,9 +165,12 @@ }; update(); + //force.resume(); //console.log(nodes); }; + d3.select(window).on("resize", resize) + var width = 960, // default width height = 450, // default height color = d3.scale.category10(), @@ -179,7 +180,8 @@ vis, subNetNodes = [], subNetLinks = [], - runOnceFlag = true; + runOnceFlag = true, + clikedNode; vis = d3.select(elementName) .append("svg:svg") @@ -189,7 +191,12 @@ .attr("pointer-events", "all") .attr("viewBox", "0 0 " + width + " " + height) .attr("perserveAspectRatio", "xMinYMid") - .append('svg:g'); + .on("click", mouseclick) + .append('svg:g'); + + function mouseclick() { + console.log(d3.mouse(this)); + } var update = function() { var link = vis.selectAll("line") @@ -249,6 +256,8 @@ force.on("tick", function () { + //node.attr("cx", function(d) { return d.x; }) + // .attr("cy", function(d) { return d.y; }); node.attr("transform", function (d) { return "translate(" + d.x + "," + d.y + ")"; }); @@ -268,13 +277,16 @@ }); force.on("end", function () { - console.log(d3.event); + d3.select(clikedNode) + .transition() + .delay(1000) + .attr("r", 50); }); // Restart the force layout. force .charge(-800) - .linkDistance(30) + .linkDistance(20) .size([width, height]) .start(); }; From 2aa0c58d811ec35dff7f8f11178d8d53284c75b8 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Tue, 30 Jun 2015 01:26:01 +0100 Subject: [PATCH 15/73] centrering nodes for stability --- graphSub.html | 142 ++++++++++++++++++++++---------------------------- 1 file changed, 63 insertions(+), 79 deletions(-) diff --git a/graphSub.html b/graphSub.html index 2e59447..5b61544 100644 --- a/graphSub.html +++ b/graphSub.html @@ -8,6 +8,7 @@ Animating Changes in Force Diagram + - - - - - - - - - - \ No newline at end of file From 87ca761af6331b336fd5e9144bc810b6c0d26961 Mon Sep 17 00:00:00 2001 From: Imran Nazir Date: Sat, 4 Jul 2015 00:36:24 +0100 Subject: [PATCH 20/73] cleanup --- miserables.html | 70 ------------------------------------------------- 1 file changed, 70 deletions(-) delete mode 100644 miserables.html diff --git a/miserables.html b/miserables.html deleted file mode 100644 index deafd76..0000000 --- a/miserables.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - From 72f86d8a8b94cfedc4fed0d9af47b2039323a913 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Sat, 4 Jul 2015 00:58:54 +0100 Subject: [PATCH 21/73] working baseline --- graphSub.html | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/graphSub.html b/graphSub.html index 150178b..8752693 100644 --- a/graphSub.html +++ b/graphSub.html @@ -41,7 +41,7 @@ }; } - d3.json("miserables.json", function(error, graph) { + d3.json("data/miserables.json", function(error, graph) { if (error) throw error; function chart(elementName) { @@ -139,7 +139,7 @@ target; // extract subnet around 'd' with all nodes up to 2 hops away - subNet(findNodeIndex(d.name, graph.nodes), 1); + subNet(findNodeIndex(d.name, graph.nodes), 2); // setting the initial positions of the nodes // subNetNodes.forEach(function(d, i, array){ // var angle = Math.random*Math.PI*2; @@ -268,9 +268,9 @@ // Restart the force layout. force .size([width, height]) - .charge(-250) + .charge(-1120) .gravity(0.6) - .linkDistance(100) + .linkDistance(30) .start(); // @@ -285,11 +285,11 @@ // d.target.y += k; // }); - var kx = .4 * e.alpha, ky = 1.4 * e.alpha; - subNetLinks.forEach(function(d, i) { - d.target.x += (d.source.x - d.target.x) * kx; - d.target.y += (d.source.y + 80 - d.target.y) * ky; - }); + // var kx = .4 * e.alpha, ky = 1.4 * e.alpha; + // subNetLinks.forEach(function(d, i) { + // d.target.x += (d.source.x - d.target.x) * kx; + // d.target.y += (d.source.y + 80 - d.target.y) * ky; + // }); node.attr("transform", function (d) { //console.log('**', d); From 739d092d055453822f546875cbc01fd9f39a39fe Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Sat, 4 Jul 2015 23:19:52 +0100 Subject: [PATCH 22/73] initial version --- graphSub.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/graphSub.html b/graphSub.html index 8752693..22edd75 100644 --- a/graphSub.html +++ b/graphSub.html @@ -20,11 +20,11 @@ stroke-width: 2px; } .textClass { - stroke: #323232; - font-family: "Lucida Grande", "Droid Sans", Arial, Helvetica, sans-serif; + stroke: #23232; + font-family: "Arial", "Liberation Sans", Arial, Helvetica, sans-serif; font-weight: normal; - stroke-width: .5; - font-size: 14px; + stroke-width: .1; + font-size: 18px; } From ea50f32a828b29466c1136179658bcba93102fef Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Tue, 7 Jul 2015 02:12:42 +0100 Subject: [PATCH 23/73] made labels clickable --- graphSub.html | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/graphSub.html b/graphSub.html index 8752693..35bbf1e 100644 --- a/graphSub.html +++ b/graphSub.html @@ -129,6 +129,7 @@ }; var clickHandler = function(d, i){ + console.log(d); // init removeAllNodes(); // clears force.nodes() removeAllLinks(); // clears force.links() @@ -235,6 +236,9 @@ .attr("opacity", 0) .call(force.drag); + nodeEnter + .on('click', clickHandler) + nodeEnter .transition() .duration(3000) @@ -243,17 +247,16 @@ nodeEnter .append("svg:circle") - .attr("r", 10) + .attr("r", 1) .attr("id", function (d) { return "Node;" + d.name; }) .attr("class", "nodeStrokeClass") - .attr("fill", function(d) { return color(d.group); }) - .on('click', clickHandler); + .attr("fill", function(d) { return color(d.group); }); nodeEnter.append("svg:text") .attr("class", "textClass") - .attr("x", 14) + .attr("x", 1) .attr("y", ".31em") .attr("opacity", 0) .text(function (d) { From 017e16a8f4c60563c3435dd9f8e8268254107cec Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Tue, 7 Jul 2015 02:20:29 +0100 Subject: [PATCH 24/73] working clickable nodes --- graphSub.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphSub.html b/graphSub.html index 35bbf1e..9d41ea5 100644 --- a/graphSub.html +++ b/graphSub.html @@ -24,7 +24,7 @@ font-family: "Lucida Grande", "Droid Sans", Arial, Helvetica, sans-serif; font-weight: normal; stroke-width: .5; - font-size: 14px; + font-size: 15px; } From a79f8a562cb46ef6a44f493198d4eb4aff356975 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Tue, 7 Jul 2015 16:55:52 +0100 Subject: [PATCH 25/73] no changes --- graphSub.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/graphSub.html b/graphSub.html index a07b776..136248f 100644 --- a/graphSub.html +++ b/graphSub.html @@ -32,6 +32,10 @@ - @@ -47,7 +47,7 @@ }; } - d3.json("data/fm.json", function(error, graph) { + d3.json("data/miserables.json", function(error, graph) { if (error) throw error; function chart(elementName) { @@ -334,7 +334,7 @@ // join var anchorNode = vis.selectAll("g.anchorNode") .data(labelAnchors, function(d, i){ - return d.node.name + i; + return d.node.label.name + i; }); // enter @@ -346,20 +346,21 @@ // enter anchorNodeEnter .append("svg:circle") - .attr("r", 10) + .attr("r", 0) .style("fill", "#FFF"); // enter anchorNodeEnter .append("svg:text") .text(function(d, i) { - return i % 2 == 0 ? "" : d.node.name + return i % 2 == 0 ? "" : d.node.label.name }) .style("fill", "#555") .style("font-family", "Arial") .style("font-size", 12); - + // exit + anchorNode.exit().remove(); // Restart the force layout. force @@ -373,7 +374,7 @@ force2 .size([width, height]) .gravity(0) - .linkDistance(20) + .linkDistance(0) .linkStrength(8) .charge(-100) .start(); @@ -395,41 +396,37 @@ var updateNode = function() { this.attr("transform", function(d) { + //console.log('line 398',d.x, d.y); return "translate(" + d.x + "," + d.y + ")"; }); } - // console.log('------------------'); - // console.log(node); - // console.log(anchorNode); - // console.log('------------------'); - force.on("tick", function() { force2.start(); //--------- node.call(updateNode); - + anchorNode.each(function(d, i) { - //console.log(d); + if(i % 2 == 0) { - d.x = d.node.x; - d.y = d.node.y; + d.x = d.node.label.x; + d.y = d.node.label.y; } else { + // get the bounding box var b = this.childNodes[1].getBBox(); - var diffX = d.x - d.node.x; - var diffY = d.y - d.node.y; + var diffX = d.x - d.node.label.x; + var diffY = d.y - d.node.label.y; var dist = Math.sqrt(diffX * diffX + diffY * diffY); var shiftX = b.width * (diffX - dist) / (dist * 2); - if (!shiftX) { - console.log(d); - force.stop(); - }; shiftX = Math.max(-b.width, Math.min(0, shiftX)); + var shiftY = 5; + + // move the label of the current anchor this.childNodes[1].setAttribute("transform", "translate(" + shiftX + "," + shiftY + ")"); } }); From 1df0bd7688acee8b86ca4b56023f68c49653447f Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Sun, 12 Jul 2015 17:48:35 +0100 Subject: [PATCH 33/73] made floating labels clickable, graph also initialises correctly --- graphSub.html | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/graphSub.html b/graphSub.html index 42136c9..bdb167e 100644 --- a/graphSub.html +++ b/graphSub.html @@ -165,6 +165,14 @@ }; var clickHandler = function(d, i){ + console.log(d); + var nodeName; + + if (d.hasOwnProperty('node')) { + nodeName = d.node.label.name; + } else { + nodeName = d.name; + }; // graph refreshed onces after nodes is added then after links // prevents wild variations in graph render. @@ -182,7 +190,7 @@ // first the nodes and anchors // extract subnet around 'd' with all nodes up to 2 hops away - subNet(findNodeIndex(d.name, graph.nodes), 2); + subNet(findNodeIndex(nodeName, graph.nodes), 1); createAnchors(); update(); @@ -302,7 +310,7 @@ // enter nodeEnter .append("svg:circle") - .attr("r", 5) + .attr("r", 0) .attr("id", function (d) { return "Node;" + d.name; }) @@ -342,6 +350,9 @@ .enter() .append("svg:g") .attr("class", "anchorNode"); + + anchorNodeEnter + .on('click', clickHandler) // enter anchorNodeEnter @@ -365,8 +376,8 @@ // Restart the force layout. force .size([width, height]) - .charge(-1120) - .gravity(0.6) + .charge(-3000) + .gravity(1) .linkDistance(30) .start(); @@ -439,16 +450,9 @@ }; if (runOnceFlag) { - var a = graph.nodes[0]; - var b = graph.nodes[1]; - - //console.log(subNetNodes, subNetLinks); - subNetNodes.push(a); - subNetNodes.push(b); - - var c = {"source":0,"target":1,"value":1}; - subNetLinks.push(c); - update(); + // initialise the display + subNet(0, 1) + clickHandler(subNetNodes[0]); runOnceFlag = false; }; }; From 876dbac0d31cca63392ca5714ba23258f5656373 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Sun, 12 Jul 2015 17:52:34 +0100 Subject: [PATCH 34/73] made changes to sample data in fm.json --- data/fm.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/data/fm.json b/data/fm.json index 4b34291..f2e78c5 100644 --- a/data/fm.json +++ b/data/fm.json @@ -1,19 +1,19 @@ { "nodes":[ - {"name":"a", "group":1}, - {"name":"b", "group":2}, - {"name":"c", "group":3}, - {"name":"d", "group":4}, - {"name":"e", "group":5}, - {"name":"f", "group":6}, - {"name":"g", "group":7}, - {"name":"h", "group":1}, - {"name":"i", "group":2}, - {"name":"j", "group":3}, - {"name":"k", "group":4}, - {"name":"l", "group":5}, - {"name":"m", "group":6}, - {"name":"n", "group":7} + {"name":"a-asdasdasd", "group":1}, + {"name":"b-dfgdfgdfg", "group":2}, + {"name":"c-hjfghjfgj", "group":3}, + {"name":"d-sthdfhdfg", "group":4}, + {"name":"e-vbncvbvcb", "group":5}, + {"name":"f-qwerqwere", "group":6}, + {"name":"g-xfgxfgdff", "group":7}, + {"name":"h-sdfghdfhd", "group":1}, + {"name":"i-arsargfas", "group":2}, + {"name":"j-hdgfhdgfh", "group":3}, + {"name":"k-asefasdfd", "group":4}, + {"name":"l-sthsdhgsd", "group":5}, + {"name":"m-awsefraea", "group":6}, + {"name":"n-rtyhrthyt", "group":7} ], "links":[ {"source":0,"target":1,"value":1}, From 35548f6b4ef840d8faa95d2e74bc40eebaf6e5cd Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Mon, 13 Jul 2015 02:23:14 +0100 Subject: [PATCH 35/73] added some code for paths and arrows --- graphSub.html | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/graphSub.html b/graphSub.html index bdb167e..bf5bf17 100644 --- a/graphSub.html +++ b/graphSub.html @@ -34,6 +34,8 @@ + +
+ + +
- \ No newline at end of file + From 0d811b25f46518e5690f7b0766c63cc19672f779 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Sat, 18 Jul 2015 16:50:44 +0100 Subject: [PATCH 51/73] first working draft complete --- graphSub.html | 49 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/graphSub.html b/graphSub.html index a302a1e..ca599b7 100644 --- a/graphSub.html +++ b/graphSub.html @@ -7,8 +7,9 @@ graphSub Animating Changes in Force Diagram - - + + + - - -
- - -
- - - diff --git a/index.html b/index.html new file mode 100644 index 0000000..01e5771 --- /dev/null +++ b/index.html @@ -0,0 +1,50 @@ + + + + + + + graphSub + Animating Changes in Force Diagram + + + + + + + +
+ + +
+ + + diff --git a/static/js/graphSub.js b/static/js/graphSub.js index e7e0bb4..3e4183e 100644 --- a/static/js/graphSub.js +++ b/static/js/graphSub.js @@ -20,154 +20,458 @@ if (!('xpush' in Array.prototype)) { }; }; -d3.grapSub = function () { +d3.grapSub = function() { var config = { width: 1000, - height: 500 + height: 500, + hops: 2 }; function chart(selection) { + selection.each(function (d, i) { + + var current_selection = this; - var data = { - }; + var model = {}; - var controller = { - - init: function (argument) { - data.color = d3.scale.category10(); - data.force = d3.layout.force(); - data.force2 = d3.layout.force(); - data.subNetNodes = force.nodes(); - data.subNetLinks = force.links(); - data.linkStrings = []; - data.labelAnchors = force2.nodes(); - data.labelAnchorLinks =force2.links(); - - view.init(); - }; + var controller = { + + init: function() { + model.graph = d; + model.color = d3.scale.category10(); + model.force = d3.layout.force(); + model.force2 = d3.layout.force(); + model.subNetNodes = model.force.nodes(); + model.subNetLinks = model.force.links(); + model.linkStrings = []; + model.labelAnchors = model.force2.nodes(); + model.labelAnchorLinks = model.force2.links(); + + // setup search-box data + model.nodeNames = []; + for (var i = 0; i < model.graph.nodes.length; i++) { + model.nodeNames.push({'label': model.graph.nodes[i].name, 'value': i+''}); + }; + + view.init(); - // add link to the layout - addLink: function(source, target, value){ - var link = {"source": findNode(source), "target": findNode(target), "value": value}; - data.subNetLinks.push(link); - }; + controller.getSubnet(0, 1) + this.click(model.subNetNodes[0]); + }, - // look for the node in the d3 layout - findNode: function(name) { - for (var i in data.graph.nodes) { - if (data.graph.nodes[i]["name"] === name) return data.graph.nodes[i]; - }; - }; + // add link to the layout + addLink: function(source, target, value){ + var link = {"source": this.findNode(source), "target": this.findNode(target), "value": value}; + model.subNetLinks.push(link); + }, - // remove all links from the layout - removeAllLinks: function(linkArray) { - linkArray.splice(0, linkArray.length); - }; + // look for the node in the d3 layout + findNode: function(name) { + for (var i in model.graph.nodes) { + if (model.graph.nodes[i]["name"] === name) return model.graph.nodes[i]; + }; + }, - // remove all node from the layout - removeAllNodes: function(nodeArray) { - nodeArray.splice(0, nodeArray.length); - }; + // remove all links from the layout + removeAllLinks: function(linkArray) { + linkArray.splice(0, linkArray.length); + }, - findNodeIndex: function(name, nodes) { - for (var i = 0; i < nodes.length; i++) { - if (nodes[i].name == name) { - return i; - } - }; - }; - - }; + // remove all node from the layout + removeAllNodes: function(nodeArray) { + nodeArray.splice(0, nodeArray.length); + }, - var view = { - - init: function () { - d3.select(window).on("resize", this.resize) + findNodeIndex: function(name, nodes) { + for (var i = 0; i < nodes.length; i++) { + if (nodes[i].name == name) { + return i; + } + }; + }, + + createAnchors: function(){ + for (var i = 0; i < model.subNetNodes.length; i++) { + // one node is anchor to the force1 node + var n = { + label : model.subNetNodes[i] + }; + + model.labelAnchors.push({ + node : n + }); + model.labelAnchors.push({ + node : n + }); + }; + }, + + createAnchorLinks: function(){ + for (var i = 0; i < model.subNetNodes.length; i++) { + // join nodes in pairs + model.labelAnchorLinks.push({ + source : i * 2, + target : i * 2 + 1, + weight : 1 + }); + }; + }, + + getSubnet: function(currentIndex, hops){ + // links stored as JSON objects, easy to compare + // operates on the data loaded from the JSON + var n = model.graph.nodes[currentIndex]; + + model.subNetNodes.xpush(n); + + if (hops === 0) { + return; + }; + + for (var i = 0; i < model.graph.links.length; i++) { + + if (currentIndex === model.graph.links[i].source) { + model.linkStrings.xpush(JSON.stringify(model.graph.links[i])); + this.getSubnet(model.graph.links[i].target, hops - 1) + }; + if (currentIndex === model.graph.links[i].target) { + model.linkStrings.xpush(JSON.stringify(model.graph.links[i])); + this.getSubnet(model.graph.links[i].source, hops - 1) + }; + }; + }, + + click: function(d){ + //console.log(d); + var nodeName; + + if (d.hasOwnProperty('node')) { + // the callback route + nodeName = d.node.label.name; + } else { + nodeName = d.name; + }; + + $("#search").val(nodeName); + + // graph refreshed onces after nodes is added then after links + // prevents wild variations in graph render. + model.linkStrings = []; // var to ensure links no repeated + console.log(this, d); + this.removeAllNodes(model.subNetNodes); // clears force.nodes() + this.removeAllLinks(model.subNetLinks); // clears force.links() + + this.removeAllNodes(model.labelAnchors); + this.removeAllLinks(model.labelAnchorLinks); + + var link, + source, + target; + + // first the nodes and anchors + // extract subnet around 'd' with all nodes up to 2 hops away + this.getSubnet(this.findNodeIndex(nodeName, model.graph.nodes), 2); + this.createAnchors(); + + view.render(); + + + // now the links and anchor links + // add links incrementaly + for (var i = 0; i < model.linkStrings.length; i++) { + link = JSON.parse(model.linkStrings[i]); + + source = model.graph.nodes[link.source]; + target = model.graph.nodes[link.target]; + this.addLink(source.name, target.name, 2); + + }; + + this.createAnchorLinks(); + + view.render(); + } - data.vis = d3.select(config.element) - .append("svg:svg") - .attr("width", config.width) - .attr("height", config.height) - .attr("id", "svg") - .attr("pointer-events", "all") - .attr("viewBox", "0 0 " + 1000 + " " + 500) - .attr("perserveAspectRatio", "xMinYMid") - .append('svg:g'); - - // Per-type markers, as they don't inherit styles. - data.vis.insert("defs") - .selectAll("marker") - .data(["suit", "licensing", "resolved"]) - .enter() - .append("marker") - .attr("id", function(d) { return d; }) - .attr("viewBox", "0 -5 10 10") - .attr("refX", 15) - .attr("refY", -0.5) - .attr("markerWidth", 6) - .attr("markerHeight", 6) - .attr("orient", "auto") - .append("path") - .attr("d", "M0,-5L10,0L0,5"); - } + }; - resize: function() { - config.width = window.innerWidth; - config.height = window.innerHeight; + var view = { - vis.attr("width", config.width) - .attr("height", config.height); + init: function () { + d3.select(window).on("resize", this.resize) + + model.vis = d3.select(current_selection) + .append("svg:svg") + .attr("width", config.width) + .attr("height", config.height) + .attr("id", "svg") + .attr("pointer-events", "all") + .attr("viewBox", "0 0 " + 1000 + " " + 500) + .attr("perserveAspectRatio", "xMinYMid") + .append('svg:g'); - force.size([config.width, config.height]).resume(); - }; + //Per-type markers, as they don't inherit styles. + model.vis.insert("defs") + .selectAll("marker") + .data(["suit", "licensing", "resolved"]) + .enter() + .append("marker") + .attr("id", function(d) { return d; }) + .attr("viewBox", "0 -5 10 10") + .attr("refX", 15) + .attr("refY", -0.5) + .attr("markerWidth", 6) + .attr("markerHeight", 6) + .attr("orient", "auto") + .append("path") + .attr("d", "M0,-5L10,0L0,5"); - }; + // clear search box + $("#search").val(''); - // make it all go - controller.init(); + // bind search values do the search box + $("#search").autocomplete({ + source: model.nodeNames, + + select: function(event, ui) { + event.preventDefault(); + //console.log(+ui.item.value); + controller.click(model.graph.nodes[+ui.item.value], +ui.item.value); + $("#search").val(ui.item.label); + }, + + focus: function(event, ui) { + event.preventDefault(); + $("#search").val(ui.item.label); + } + }); + }, - }; + resize: function() { + config.width = window.innerWidth; + config.height = window.innerHeight; + + vis.attr("width", config.width).attr("height", config.height); - var width = function(value) { - if (!arguments.length) return config.width; - config.width = value; - return chart; // enable chaining - }; + force.size([config.width, config.height]).resume(); + }, - var height = function(value) { - if (!arguments.length) return config.height; - config.height = value; - return chart; // enable chaining - }; + render: function() { - var element = function(value) { - if (!arguments.length) return config.element; - config.element = value; - return chart; // enable chaining + // join + var link = model.vis.selectAll("line") + .data(model.subNetLinks, function (d) { + return d.source.name + "-" + d.target.name; + }); + + // enter + link.enter().insert("line", "g") + .attr("id", function (d) { + return d.source.name + "-" + d.target + .name; + }) + .attr("stroke-width", function (d) { + return d.value / 10; + }) + .attr("class", "link") + .attr("marker-end", "url(#suit)"); + + // update + link.append("title") + .text(function (d) { + return d.value; + }); + + // exit + link.exit().remove(); + + // join + var node = model.vis.selectAll("g.node") + .data(model.subNetNodes, function (d) { + return d.name; + }); + + // enter + var nodeEnter = node.enter() + .append("g") + .attr("class", "node"); + + + // enter + nodeEnter + .append("svg:circle") + .attr("r", 5) + .attr("id", function (d) { + return "Node;" + d.name; + }) + .attr("class", "nodeStrokeClass") + .attr("fill", function(d) { return model.color(d.group); }); + + // exit + node.exit().remove(); + + // Force2 labels + + // join + var anchorLink = model.vis.selectAll("line.anchorLink") + .data(model.labelAnchorLinks);//.enter().append("svg:line").attr("class", "anchorLink").style("stroke", "#999"); + + // join + var anchorNode = model.vis.selectAll("g.anchorNode") + .data(model.labelAnchors, function(d, i){ + return d.node.label.name + i; + }); + + // enter + var anchorNodeEnter = anchorNode + .enter() + .append("svg:g") + .attr("class", "anchorNode"); + + anchorNodeEnter + .on('click', function(d){controller.click(d);}, false) + + // enter + anchorNodeEnter + .append("svg:circle") + .attr("r", 0) + .style("fill", "#FFF"); + + // enter + anchorNodeEnter + .append("svg:text") + .text(function(d, i) { + return i % 2 == 0 ? "" : d.node.label.name + }) + .style("fill", "#555") + .style("font-family", "Arial") + .style("font-size", 12); + + // exit + anchorNode.exit().remove(); + + // Restart the force layout. + model.force + .size([config.width, config.height]) + .charge(-3000) + .gravity(1) + .linkDistance(50) + .start(); + + // restart the labels force layout + model.force2 + .size([config.width, config.height]) + .gravity(0) + .linkDistance(0) + .linkStrength(8) + .charge(-100) + .start(); + + //console.log('selection', anchorNode); + //console.log('force datum', force2.nodes()); + + var updateLink = function() { + this.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; + }); + } + + var updateNode = function() { + this.attr("transform", function(d) { + //console.log('line 398',d.x, d.y); + return "translate(" + d.x + "," + d.y + ")"; + }); + } + + model.force.on("tick", function() { + + model.force2.start(); + + //--------- + node.call(updateNode); + + anchorNode.each(function(d, i) { + + if(i % 2 == 0) { + d.x = d.node.label.x; + d.y = d.node.label.y; + } else { + // get the bounding box + var b = this.childNodes[1].getBBox(); + + var diffX = d.x - d.node.label.x; + var diffY = d.y - d.node.label.y; + + var dist = Math.sqrt(diffX * diffX + diffY * diffY); + + var shiftX = b.width * (diffX - dist) / (dist * 2); + shiftX = Math.max(-b.width, Math.min(0, shiftX)); + + var shiftY = 5; + + // move the label of the current anchor + this.childNodes[1].setAttribute("transform", "translate(" + shiftX + "," + shiftY + ")"); + } + }); + anchorNode.call(updateNode); + + link.call(updateLink); + + anchorLink.call(updateLink); + }); + /// + } + + } + + // make it all go + controller.init(); + }); + + }; - var graph = function(value) { - if (!arguments.length) return data.graph; - data.graph = value; + chart.width = function(value) { + if (!arguments.length) return config.width; + config.width = value; return chart; // enable chaining - }; + }; + + chart.height = function(value) { + if (!arguments.length) return config.height; + config.height = value; + return chart; // enable chaining + }; + + chart.hops = function(value) { + if (!arguments.length) return config.hops; + config.hops = value; + return chart; // enable chaining + }; - return chart; + return chart; + +}; -}() /*----------------------------------------------------------------------------*/ + d3.json("data/miserables.json", function(error, graph) { if (error) throw error; // Parse JSON into the correct format if needed var chart = d3.grapSub() - .width() - .height() - .element() - .graph(graph); + .width(760) + .height(500); - d3.call(chart) -}; + d3.select("body") + .datum(graph) + .call(chart); +}); From 179f4d82343021cf3ee433215eba88e6bf98fd33 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Sun, 26 Jul 2015 23:52:30 +0100 Subject: [PATCH 57/73] fixed typo --- static/js/graphSub.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/js/graphSub.js b/static/js/graphSub.js index 3e4183e..79e2e9b 100644 --- a/static/js/graphSub.js +++ b/static/js/graphSub.js @@ -20,7 +20,7 @@ if (!('xpush' in Array.prototype)) { }; }; -d3.grapSub = function() { +d3.graphSub = function() { var config = { width: 1000, @@ -466,7 +466,7 @@ d3.json("data/miserables.json", function(error, graph) { // Parse JSON into the correct format if needed - var chart = d3.grapSub() + var chart = d3.graphSub() .width(760) .height(500); From a7bff8eb736cc5dc820fbb2277f022a6698a226e Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Mon, 27 Jul 2015 14:35:19 +0100 Subject: [PATCH 58/73] add line gradients to the DOM for the node links, also experimented with the size of the node arrows --- index.html | 3 +-- static/js/graphSub.js | 39 +++++++++++++++++++++++++++++++++------ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/index.html b/index.html index 01e5771..37b32e2 100644 --- a/index.html +++ b/index.html @@ -12,8 +12,7 @@ @@ -44,6 +54,8 @@
+
+
diff --git a/static/js/graphSub.js b/static/js/graphSub.js index d093146..3198935 100644 --- a/static/js/graphSub.js +++ b/static/js/graphSub.js @@ -1,4 +1,4 @@ -/* test graph - mothers are on the left hand side */ +/* test data in data/fm.json */ /* (a)---------(b) (c)---------(d) | | | | | @@ -40,7 +40,6 @@ d3.graphSub = function() { init: function() { model.graph = d; - model.color = d3.scale.category10(); model.force = d3.layout.force(); model.force2 = d3.layout.force(); model.subNetNodes = model.force.nodes(); @@ -57,10 +56,18 @@ d3.graphSub = function() { view.init(); - controller.getSubnet(0, 1) + this.getSubnet(0, 1) this.click(model.subNetNodes[0]); }, + graphNodes: function () { + return model.graph.nodes; + }, + + graphLinks: function () { + return model.graph.links; + }, + // add link to the layout addLink: function(source, target, value){ var link = {"source": this.findNode(source), "target": this.findNode(target), "value": value}; @@ -195,18 +202,20 @@ d3.graphSub = function() { view.render(); - console.log(JSON.stringify(model.subNetNodes)); - console.log(JSON.stringify(model.subNetLinks)); + // console.log(JSON.stringify(model.subNetNodes)); + // console.log(JSON.stringify(model.subNetLinks)); } }; var view = { - + init: function () { d3.select(window).on("resize", this.resize) + + this.color = d3.scale.category10(); - model.viz = d3.select(current_selection) + this.viz = d3.select(current_selection) .append("svg:svg") .attr("width", config.width) .attr("height", config.height) @@ -217,7 +226,7 @@ d3.graphSub = function() { .append('svg:g'); //Per-type markers, as they don't inherit styles. - model.viz.insert("defs") + this.viz.insert("defs") .selectAll("marker") .data(["suit", "licensing", "resolved"]) .enter() @@ -267,7 +276,7 @@ d3.graphSub = function() { select: function(event, ui) { event.preventDefault(); //console.log(+ui.item.value); - controller.click(model.graph.nodes[+ui.item.value], +ui.item.value); + controller.click(controller.graphNodes()[+ui.item.value], +ui.item.value); $("#search").val(ui.item.label); }, @@ -279,18 +288,16 @@ d3.graphSub = function() { }, resize: function() { - config.width = window.innerWidth; - config.height = window.innerHeight; + x = window.innerWidth || e.clientWidth || g.clientWidth; + y = window.innerHeight|| e.clientHeight|| g.clientHeight; - model.viz.attr("width", config.width).attr("height", config.height); - - model.force.size([config.width, config.height]).resume(); + d3.select("svg").attr("width", x).attr("height", y); }, render: function() { // join - var link = model.viz.selectAll("line") + var link = view.viz.selectAll("line") .data(model.subNetLinks, function (d) { return d.source.name + "-" + d.target.name; }); @@ -319,7 +326,7 @@ d3.graphSub = function() { link.exit().remove(); // join - var node = model.viz.selectAll("g.node") + var node = this.viz.selectAll("g.node") .data(model.subNetNodes, function (d) { return d.name; }); @@ -338,7 +345,7 @@ d3.graphSub = function() { return "Node;" + d.name; }) .attr("class", "nodeStrokeClass") - .attr("fill", function(d) { return model.color(d.group); }); + .attr("fill", function(d) { return view.color(d.group); }); // exit node.exit().remove(); @@ -346,11 +353,11 @@ d3.graphSub = function() { // Force2 labels // join - var anchorLink = model.viz.selectAll("line.anchorLink") - .data(model.labelAnchorLinks).enter().append("svg:line").attr("class", "anchorLink").style("stroke", "#999"); + var anchorLink = this.viz.selectAll("line.anchorLink") + .data(model.labelAnchorLinks);//.enter().append("svg:line").attr("class", "anchorLink").style("stroke", "#999"); // join - var anchorNode = model.viz.selectAll("g.anchorNode") + var anchorNode = this.viz.selectAll("g.anchorNode") .data(model.labelAnchors, function(d, i){ //console.log(d.node.label.name + d.type); return d.node.label.name + d.type; @@ -368,7 +375,7 @@ d3.graphSub = function() { // enter anchorNodeEnter .append("svg:circle") - .attr("r", 3) + .attr("r", 0) .style("fill", "red"); // enter @@ -398,13 +405,12 @@ d3.graphSub = function() { .attr("height", textElem.height) .attr("y", textElem.y) .attr("x", textElem.x) - .attr("fill", "red") + .attr("fill", function(d) { return view.color(d.node.label.group); }) .attr("opacity", "0.3"); }; }; }); - // exit @@ -522,9 +528,15 @@ d3.graphSub = function() { }; -/*----------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- +The code example below: +1. loads the JSON data. +2. Sets the width to 760px. +3. Set the height to 500px. +4. Attaches the cahrt to the DOM element with id #chart +*/ -d3.json("data/ramzaneh.json", function(error, graph) { +d3.json("data/miserables.json", function(error, graph) { if (error) throw error; // Parse JSON into the correct format if needed @@ -532,23 +544,10 @@ d3.json("data/ramzaneh.json", function(error, graph) { var chart = d3.graphSub() .width(760) .height(500) - .hops(1); - console.log(graph); - - var data = g2j4d3(graph); - - d3.select("body") - .datum(data) - .call(chart); -}); - -// d3.json("data/ramzaneh.json", function(error, graph) { -// if (error) throw error; - - // Parse JSON into the correct format if needed - + .hops(2); //console.log(graph); - // var data = g2j4d3(graph); -//}); - + d3.select("#chart") + .datum(graph) + .call(chart); +}); \ No newline at end of file From 198a6e04b8f2801000b0b0ceaf20f5b17cd746e5 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Mon, 10 Aug 2015 14:19:36 +0100 Subject: [PATCH 68/73] linear gradiens cant be seen on tablets, changes links to lines instead --- index.html | 6 +++--- static/js/graphSub.js | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/index.html b/index.html index 7439173..f2451b7 100644 --- a/index.html +++ b/index.html @@ -12,7 +12,7 @@ diff --git a/static/js/graphSub.js b/static/js/graphSub.js index 3198935..b1c1324 100644 --- a/static/js/graphSub.js +++ b/static/js/graphSub.js @@ -311,10 +311,11 @@ d3.graphSub = function() { .attr("stroke-width", function (d) { return d.value / 10; }) - .attr("stroke", "url(#linearGradient)") + .attr("stroke", "grey") + .attr("opacity", "0.5") .attr("class", "link") .attr("marker-end", "url(#suit)"); - //.attr("class", "link") + //.attr("stroke", "url(#linearGradient)") // update link.append("title") From 086777b54d1152f59fac82af17cc3b94c6c21a2c Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Wed, 12 Aug 2015 23:52:00 +0100 Subject: [PATCH 69/73] minor changes --- static/js/graphSub.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/static/js/graphSub.js b/static/js/graphSub.js index b1c1324..dad5820 100644 --- a/static/js/graphSub.js +++ b/static/js/graphSub.js @@ -240,7 +240,7 @@ d3.graphSub = function() { .attr("orient", "auto") .append("path") .attr("d", "M0,-1L5,0L0,1"); - //"M0,-5L10,0L0,5" + //.attr("M0,-5L10,0L0,5"); // linear gradient for the lines d3.select("defs") @@ -386,7 +386,7 @@ d3.graphSub = function() { return i % 2 == 0 ? "" : d.node.label.name }) .attr("class", "textClass") - .style("fill", "#555") + .style("fill", "black") .style("font-family", "Arial") .style("font-size", 20); @@ -401,7 +401,7 @@ d3.graphSub = function() { //console.log(textElem); if (this.childNodes.length === 2) { d3.select(this) - .insert("rect") + .insert("rect", "text") .attr("width", textElem.width) .attr("height", textElem.height) .attr("y", textElem.y) From f8986402892f85615edee93f2cec725603b460d0 Mon Sep 17 00:00:00 2001 From: Imran Nazir Date: Mon, 17 Aug 2015 23:21:56 +0100 Subject: [PATCH 70/73] updated file to match project page --- README.md | 55 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 46ca22c..9d9b74e 100644 --- a/README.md +++ b/README.md @@ -8,16 +8,51 @@ -graphSub is a re-usable D3 force directed graph for displaying -subsets of a much larger graph. This has the benefits of presenting -a graph which is easier to understand and navigable whilst still -giving access to the entire dataset. +graphSub is a re-usable force directed chart for displaying connected data. Written in Javascript with the [d3js](http://d3js.org) library. It has some cool features rolled in. -Featues include: -* None over lapping labels. -* You can configure how wide the subset is. -* Clickable nodes which redraw the graph centered on the clicked node. -* Smooth transitions which fade in/out only the new nodes and links. +### Featues include: +* Display graph subsets. Given a data-set with 1000+ nodes, displaying all nodes at once can clutter your screen. With graphSub you can display only a subset of your data-set whilst being able to navigate through the entire data-set with mouse clicks. +* The search box feature allows you to quickly locate the node that you are interested in. +* None over-lapping labels means that node labels do not obscure each other. +* Works on touch screens. +* The responsive chart resizes upon a browser resize. +* The code uses an MVC architecture, making future development easier to manage. +* More features to be added.... + +### Instructions: + +The following code can be found at the end of static/js/graphsub.js please modify it to suit your needs. +Your data must follow the format given in the example data-set. This can be found in /data/miserables.json +More information on d3s' force layouts can be found [here](https://github.com/mbostock/d3/wiki/Force-Layout#force). + + + /*----------------------------------------------------------------------------` + The code example below: + 1. Loads the JSON data. + 2. Sets the width to 760px. + 3. Set the height to 500px. + 4. Displays all nodes within 2 hops of the selected node. + 5. Attaches the chart to the DOM element with id #chart + */ + + d3.json("data/miserables.json", function(error, graph) { + if (error) throw error; + + // Parse JSON into the correct format if needed + + var chart = d3.graphSub() + .width(760) + .height(500) + .hops(2); + + d3.select("#chart") + .datum(graph) + .call(chart); + }); + +Want to contribute a bug fix or enhancement; then feel free to clone the repository and make a pull request. + +****A working example can be found [here](http://bl.ocks.org/TimeBandit/6460e2ba3792385b2754).**** Example bl.ock.s used in the development of this graph: @@ -33,4 +68,4 @@ Example bl.ock.s used in the development of this graph: [General Update Pattern, III](http://bl.ocks.org/mbostock/3808234) -[Animating Changes in Force Diagram](http://bl.ocks.org/ericcoopey/6c602d7cb14b25c179a4) \ No newline at end of file +[Animating Changes in Force Diagram](http://bl.ocks.org/ericcoopey/6c602d7cb14b25c179a4) From 7e8ea139b457b0433934e78787003509e098eef8 Mon Sep 17 00:00:00 2001 From: imran_nazir Date: Wed, 2 Sep 2015 22:37:06 +0100 Subject: [PATCH 71/73] code wrapped in an IIFE to prevent polution of global namespace --- static/js/graphSub.js | 1088 +++++++++++++++++++++-------------------- 1 file changed, 553 insertions(+), 535 deletions(-) diff --git a/static/js/graphSub.js b/static/js/graphSub.js index dad5820..0d3d4a5 100644 --- a/static/js/graphSub.js +++ b/static/js/graphSub.js @@ -1,533 +1,551 @@ -/* test data in data/fm.json */ -/* - (a)---------(b) (c)---------(d) - | | | | | -(e)---(f)(g)(h)---------(i)(j)---(k) - | | - (l)------------------------(m) - | - (n) -*/ - -// add a method conditionaly -if (!('xpush' in Array.prototype)) { - // push value to array only if not already present - Array.prototype.xpush = function(value){ - if(this.indexOf(value) === -1){ - this.push(value); - } - return this; - }; -}; - -d3.graphSub = function() { - - var config = { - width: 1000, - height: 500, - hops: 2 - }; - - function chart(selection) { - selection.each(function (d, i) { - - // DOM to which to attach the vizualization - var current_selection = this; - - var model = {}; - - var controller = { - - init: function() { - model.graph = d; - model.force = d3.layout.force(); - model.force2 = d3.layout.force(); - model.subNetNodes = model.force.nodes(); - model.subNetLinks = model.force.links(); - model.linkStrings = []; - model.labelAnchors = model.force2.nodes(); - model.labelAnchorLinks = model.force2.links(); - - // setup search-box data - model.nodeNames = []; - for (var i = 0; i < model.graph.nodes.length; i++) { - model.nodeNames.push({'label': model.graph.nodes[i].name, 'value': i+''}); - }; - - view.init(); - - this.getSubnet(0, 1) - this.click(model.subNetNodes[0]); - }, - - graphNodes: function () { - return model.graph.nodes; - }, - - graphLinks: function () { - return model.graph.links; - }, - - // add link to the layout - addLink: function(source, target, value){ - var link = {"source": this.findNode(source), "target": this.findNode(target), "value": value}; - model.subNetLinks.push(link); - }, - - // look for the node in the d3 layout - findNode: function(name) { - for (var i in model.graph.nodes) { - if (model.graph.nodes[i]["name"] === name) return model.graph.nodes[i]; - }; - }, - - // remove all links from the layout - removeAllLinks: function(linkArray) { - linkArray.splice(0, linkArray.length); - }, - - // remove all node from the layout - removeAllNodes: function(nodeArray) { - nodeArray.splice(0, nodeArray.length); - }, - - findNodeIndex: function(name, nodes) { - for (var i = 0; i < nodes.length; i++) { - if (nodes[i].name == name) { - return i; - } - }; - }, - - createAnchors: function(){ - for (var i = 0; i < model.subNetNodes.length; i++) { - // one node is anchor to the force1 node - var n = { - label : model.subNetNodes[i] - }; - - model.labelAnchors.push({ - node : n, - type: "tail" - }); - model.labelAnchors.push({ - node : n, - type: "head" - }); - }; - }, - - createAnchorLinks: function(){ - for (var i = 0; i < model.subNetNodes.length; i++) { - // nodes are connected in pairs - model.labelAnchorLinks.push({ - source : i * 2, - target : i * 2 + 1, - weight : 1 - }); - }; - }, - - getSubnet: function(currentIndex, hops){ - // links stored as JSON objects, easy to compare - // operates on the data loaded from the JSON - var n = model.graph.nodes[currentIndex]; - - model.subNetNodes.xpush(n); - - if (hops === 0) { - return; - }; - - for (var i = 0; i < model.graph.links.length; i++) { - - if (currentIndex === model.graph.links[i].source) { - model.linkStrings.xpush(JSON.stringify(model.graph.links[i])); - this.getSubnet(model.graph.links[i].target, hops - 1) - }; - if (currentIndex === model.graph.links[i].target) { - model.linkStrings.xpush(JSON.stringify(model.graph.links[i])); - this.getSubnet(model.graph.links[i].source, hops - 1) - }; - }; - }, - - click: function(d){ - //console.log(d); - var nodeName; - - if (d.hasOwnProperty('node')) { - // the callback route - nodeName = d.node.label.name; - } else { - nodeName = d.name; - }; - - $("#search").val(nodeName); - - // graph refreshed onces after nodes is added then after links - // prevents wild variations in graph render. - model.linkStrings = []; // var to ensure links no repeated - - this.removeAllNodes(model.subNetNodes); // clears force.nodes() - this.removeAllLinks(model.subNetLinks); // clears force.links() - - this.removeAllNodes(model.labelAnchors); - this.removeAllLinks(model.labelAnchorLinks); - - var link, - source, - target; - - // first the nodes and anchors - // extract subnet around 'd' with all nodes up to 2 hops away - this.getSubnet(this.findNodeIndex(nodeName, model.graph.nodes), config.hops); - this.createAnchors(); - - view.render(); - - - // now the links and anchor links - // add links incrementaly - for (var i = 0; i < model.linkStrings.length; i++) { - link = JSON.parse(model.linkStrings[i]); - - source = model.graph.nodes[link.source]; - target = model.graph.nodes[link.target]; - this.addLink(source.name, target.name, 2); - - }; - - this.createAnchorLinks(); - - view.render(); - - // console.log(JSON.stringify(model.subNetNodes)); - // console.log(JSON.stringify(model.subNetLinks)); - } - - }; - - var view = { - - init: function () { - d3.select(window).on("resize", this.resize) - - this.color = d3.scale.category10(); - - this.viz = d3.select(current_selection) - .append("svg:svg") - .attr("width", config.width) - .attr("height", config.height) - .attr("id", "svg") - .attr("pointer-events", "all") - .attr("viewBox", "0 0 " + 1000 + " " + 500) - .attr("perserveAspectRatio", "xMinYMid") - .append('svg:g'); - - //Per-type markers, as they don't inherit styles. - this.viz.insert("defs") - .selectAll("marker") - .data(["suit", "licensing", "resolved"]) - .enter() - .append("marker") - .attr("id", function(d) { return d; }) - .attr("viewBox", "0 -5 10 10") - .attr("refX", 5) - .attr("refY", 0) - .attr("markerWidth", 6) - .attr("markerHeight", 6) - .attr("orient", "auto") - .append("path") - .attr("d", "M0,-1L5,0L0,1"); - //.attr("M0,-5L10,0L0,5"); - - // linear gradient for the lines - d3.select("defs") - .insert("linearGradient") - .attr("id", "linearGradient") - .attr("x1", "0%") - .attr("y1", "0%") - .attr("x2", "100%") - .attr("y2", "100%") - .attr("spreadMethod", "pad"); - - d3.select("linearGradient") - .insert("stop") - .attr("offset", "0%") - .attr("stop-color", "grey") - .attr("stop-opacity", "0"); - - d3.select("linearGradient") - .insert("stop") - .attr("offset", "100%") - .attr("stop-color", "grey") - .attr("stop-opacity", "1"); - - // female D54A5C - // male A2C1D5 - // clear search box - $("#search").val(''); - - // bind search values do the search box - $("#search").autocomplete({ - source: model.nodeNames, - - select: function(event, ui) { - event.preventDefault(); - //console.log(+ui.item.value); - controller.click(controller.graphNodes()[+ui.item.value], +ui.item.value); - $("#search").val(ui.item.label); - }, - - focus: function(event, ui) { - event.preventDefault(); - $("#search").val(ui.item.label); - } - }); - }, - - resize: function() { - x = window.innerWidth || e.clientWidth || g.clientWidth; - y = window.innerHeight|| e.clientHeight|| g.clientHeight; - - d3.select("svg").attr("width", x).attr("height", y); - }, - - render: function() { - - // join - var link = view.viz.selectAll("line") - .data(model.subNetLinks, function (d) { - return d.source.name + "-" + d.target.name; - }); - - // enter - link.enter().insert("line", "g") - .attr("id", function (d) { - return d.source.name + "-" + d.target - .name; - }) - .attr("stroke-width", function (d) { - return d.value / 10; - }) - .attr("stroke", "grey") - .attr("opacity", "0.5") - .attr("class", "link") - .attr("marker-end", "url(#suit)"); - //.attr("stroke", "url(#linearGradient)") - - // update - link.append("title") - .text(function (d) { - return d.value; - }); - - // exit - link.exit().remove(); - - // join - var node = this.viz.selectAll("g.node") - .data(model.subNetNodes, function (d) { - return d.name; - }); - - // enter - var nodeEnter = node.enter() - .append("g") - .attr("class", "node"); - - - // enter - nodeEnter - .append("svg:circle") - .attr("r", 0) - .attr("id", function (d) { - return "Node;" + d.name; - }) - .attr("class", "nodeStrokeClass") - .attr("fill", function(d) { return view.color(d.group); }); - - // exit - node.exit().remove(); - - // Force2 labels - - // join - var anchorLink = this.viz.selectAll("line.anchorLink") - .data(model.labelAnchorLinks);//.enter().append("svg:line").attr("class", "anchorLink").style("stroke", "#999"); - - // join - var anchorNode = this.viz.selectAll("g.anchorNode") - .data(model.labelAnchors, function(d, i){ - //console.log(d.node.label.name + d.type); - return d.node.label.name + d.type; - }); - - // enter - var anchorNodeEnter = anchorNode - .enter() - .append("svg:g") - .attr("class", "anchorNode"); - - anchorNodeEnter - .on('click', function(d){controller.click(d);}, false) - - // enter - anchorNodeEnter - .append("svg:circle") - .attr("r", 0) - .style("fill", "red"); - - // enter - anchorNodeEnter - .append("svg:text") - .text(function(d, i) { - return i % 2 == 0 ? "" : d.node.label.name - }) - .attr("class", "textClass") - .style("fill", "black") - .style("font-family", "Arial") - .style("font-size", 20); - - // add coloured box around text - anchorNode.each(function(d, i) { - if(i % 2 != 0){ - // prevents two rects being added - // due to render being called twice in - // click func. - //console.log(this.childNodes[2]); - var textElem = this.childNodes[1].getBBox(); - //console.log(textElem); - if (this.childNodes.length === 2) { - d3.select(this) - .insert("rect", "text") - .attr("width", textElem.width) - .attr("height", textElem.height) - .attr("y", textElem.y) - .attr("x", textElem.x) - .attr("fill", function(d) { return view.color(d.node.label.group); }) - .attr("opacity", "0.3"); - }; - - }; - }); - - - // exit - anchorNode.exit().remove(); - - // Restart the force layout. - model.force - .size([config.width, config.height]) - .charge(-3000) - .gravity(1) - .linkDistance(50) - .start(); - - // restart the labels force layout - model.force2 - .size([config.width, config.height]) - .gravity(0) - .linkDistance(0) - .linkStrength(8) - .charge(-200) - .start(); - - //console.log('selection', anchorNode); - //console.log('force datum', force2.nodes()); - - var updateLink = function() { - this.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; - }); - } - - var updateNode = function() { - this.attr("transform", function(d) { - //console.log('line 398',d.x, d.y); - return "translate(" + d.x + "," + d.y + ")"; - }); - } - - model.force.on("tick", function() { - - model.force2.start(); - - //--------- - node.call(updateNode); - - anchorNode.each(function(d, i) { - - if(i % 2 == 0) { - - d.x = d.node.label.x; - d.y = d.node.label.y; - } else { - // get the bounding box - var b = this.childNodes[1].getBBox(); - - var diffX = d.x - d.node.label.x; - var diffY = d.y - d.node.label.y; - - var dist = Math.sqrt(diffX * diffX + diffY * diffY); - - var shiftX = b.width * (diffX - dist) / (dist * 2); - shiftX = Math.max(-b.width, Math.min(0, shiftX)); - - var shiftY = 5; - - // move the label of the current anchor - this.childNodes[1].setAttribute("transform", "translate(" + shiftX + "," + shiftY + ")"); - // move the coloured box of the current anchor - this.childNodes[2].setAttribute("transform", "translate(" + shiftX + "," + shiftY + ")"); - } - }); - anchorNode.call(updateNode); - - link.call(updateLink); - - anchorLink.call(updateLink); - }); - /// +(function() { + /* test data in data/fm.json */ + /* + (a)---------(b) (c)---------(d) + | | | | | + (e)---(f)(g)(h)---------(i)(j)---(k) + | | + (l)------------------------(m) + | + (n) + */ + + // add a method conditionaly + if (!('xpush' in Array.prototype)) { + // push value to array only if not already present + Array.prototype.xpush = function(value) { + if (this.indexOf(value) === -1) { + this.push(value); } + return this; + }; + }; - } + d3.graphSub = function() { + + var config = { + width: 1000, + height: 500, + hops: 2 + }; + + function chart(selection) { + selection.each(function(d, i) { + + // DOM to which to attach the vizualization + var current_selection = this; + + var model = {}; + + var controller = { + + init: function() { + model.graph = d; + model.force = d3.layout.force(); + model.force2 = d3.layout.force(); + model.subNetNodes = model.force.nodes(); + model.subNetLinks = model.force.links(); + model.linkStrings = []; + model.labelAnchors = model.force2.nodes(); + model.labelAnchorLinks = model.force2.links(); + + // setup search-box data + model.nodeNames = []; + for (var i = 0; i < model.graph.nodes.length; i++) { + model.nodeNames.push({ + 'label': model.graph.nodes[i].name, + 'value': i + '' + }); + }; + + view.init(); + + this.getSubnet(0, 1) + this.click(model.subNetNodes[0]); + }, + + graphNodes: function() { + return model.graph.nodes; + }, + + graphLinks: function() { + return model.graph.links; + }, + + // add link to the layout + addLink: function(source, target, value) { + var link = { + "source": this.findNode(source), + "target": this.findNode(target), + "value": value + }; + model.subNetLinks.push(link); + }, + + // look for the node in the d3 layout + findNode: function(name) { + for (var i in model.graph.nodes) { + if (model.graph.nodes[i]["name"] === name) return model.graph.nodes[i]; + }; + }, + + // remove all links from the layout + removeAllLinks: function(linkArray) { + linkArray.splice(0, linkArray.length); + }, + + // remove all node from the layout + removeAllNodes: function(nodeArray) { + nodeArray.splice(0, nodeArray.length); + }, + + findNodeIndex: function(name, nodes) { + for (var i = 0; i < nodes.length; i++) { + if (nodes[i].name == name) { + return i; + } + }; + }, + + createAnchors: function() { + for (var i = 0; i < model.subNetNodes.length; i++) { + // one node is anchor to the force1 node + var n = { + label: model.subNetNodes[i] + }; + + model.labelAnchors.push({ + node: n, + type: "tail" + }); + model.labelAnchors.push({ + node: n, + type: "head" + }); + }; + }, + + createAnchorLinks: function() { + for (var i = 0; i < model.subNetNodes.length; i++) { + // nodes are connected in pairs + model.labelAnchorLinks.push({ + source: i * 2, + target: i * 2 + 1, + weight: 1 + }); + }; + }, + + getSubnet: function(currentIndex, hops) { + // links stored as JSON objects, easy to compare + // operates on the data loaded from the JSON + var n = model.graph.nodes[currentIndex]; + + model.subNetNodes.xpush(n); + + if (hops === 0) { + return; + }; + + for (var i = 0; i < model.graph.links.length; i++) { + + if (currentIndex === model.graph.links[i].source) { + model.linkStrings.xpush(JSON.stringify(model.graph.links[i])); + this.getSubnet(model.graph.links[i].target, hops - 1) + }; + if (currentIndex === model.graph.links[i].target) { + model.linkStrings.xpush(JSON.stringify(model.graph.links[i])); + this.getSubnet(model.graph.links[i].source, hops - 1) + }; + }; + }, + + click: function(d) { + //console.log(d); + var nodeName; + + if (d.hasOwnProperty('node')) { + // the callback route + nodeName = d.node.label.name; + } else { + nodeName = d.name; + }; + + $("#search").val(nodeName); + + // graph refreshed onces after nodes is added then after links + // prevents wild variations in graph render. + model.linkStrings = []; // var to ensure links no repeated + + this.removeAllNodes(model.subNetNodes); // clears force.nodes() + this.removeAllLinks(model.subNetLinks); // clears force.links() + + this.removeAllNodes(model.labelAnchors); + this.removeAllLinks(model.labelAnchorLinks); + + var link, + source, + target; + + // first the nodes and anchors + // extract subnet around 'd' with all nodes up to 2 hops away + this.getSubnet(this.findNodeIndex(nodeName, model.graph.nodes), config.hops); + this.createAnchors(); + + view.render(); + + + // now the links and anchor links + // add links incrementaly + for (var i = 0; i < model.linkStrings.length; i++) { + link = JSON.parse(model.linkStrings[i]); + + source = model.graph.nodes[link.source]; + target = model.graph.nodes[link.target]; + this.addLink(source.name, target.name, 2); + + }; + + this.createAnchorLinks(); + + view.render(); + + // console.log(JSON.stringify(model.subNetNodes)); + // console.log(JSON.stringify(model.subNetLinks)); + } + + }; + + var view = { + + init: function() { + d3.select(window).on("resize", this.resize) + + this.color = d3.scale.category10(); + + this.viz = d3.select(current_selection) + .append("svg:svg") + .attr("width", config.width) + .attr("height", config.height) + .attr("id", "svg") + .call(d3.behavior.zoom()) + .attr("pointer-events", "all") + .attr("viewBox", "0 0 " + 1000 + " " + 500) + .attr("perserveAspectRatio", "xMinYMid") + .append('svg:g'); + + //Per-type markers, as they don't inherit styles. + this.viz.insert("defs") + .selectAll("marker") + .data(["suit", "licensing", "resolved"]) + .enter() + .append("marker") + .attr("id", function(d) { + return d; + }) + .attr("viewBox", "0 -5 10 10") + .attr("refX", 5) + .attr("refY", 0) + .attr("markerWidth", 6) + .attr("markerHeight", 6) + .attr("orient", "auto") + .append("path") + .attr("d", "M0,-1L5,0L0,1"); + //.attr("M0,-5L10,0L0,5"); + + // linear gradient for the lines + d3.select("defs") + .insert("linearGradient") + .attr("id", "linearGradient") + .attr("x1", "0%") + .attr("y1", "0%") + .attr("x2", "100%") + .attr("y2", "100%") + .attr("spreadMethod", "pad"); + + d3.select("linearGradient") + .insert("stop") + .attr("offset", "0%") + .attr("stop-color", "grey") + .attr("stop-opacity", "0"); + + d3.select("linearGradient") + .insert("stop") + .attr("offset", "100%") + .attr("stop-color", "grey") + .attr("stop-opacity", "1"); + + // female D54A5C + // male A2C1D5 + // clear search box + $("#search").val(''); + + // bind search values do the search box + $("#search").autocomplete({ + source: model.nodeNames, + + select: function(event, ui) { + event.preventDefault(); + //console.log(+ui.item.value); + controller.click(controller.graphNodes()[+ui.item.value], +ui.item.value); + $("#search").val(ui.item.label); + }, + + focus: function(event, ui) { + event.preventDefault(); + $("#search").val(ui.item.label); + } + }); + }, + + resize: function() { + x = window.innerWidth || e.clientWidth || g.clientWidth; + y = window.innerHeight || e.clientHeight || g.clientHeight; + + d3.select("svg").attr("width", x).attr("height", y); + }, + + render: function() { + + // join + var link = view.viz.selectAll("line") + .data(model.subNetLinks, function(d) { + return d.source.name + "-" + d.target.name; + }); + + // enter + link.enter().insert("line", "g") + .attr("id", function(d) { + return d.source.name + "-" + d.target + .name; + }) + .attr("stroke-width", function(d) { + return d.value / 10; + }) + .attr("stroke", "grey") + .attr("opacity", "0.5") + .attr("class", "link") + .attr("marker-end", "url(#suit)"); + //.attr("stroke", "url(#linearGradient)") + + // update + link.append("title") + .text(function(d) { + return d.value; + }); + + // exit + link.exit().remove(); + + // join + var node = this.viz.selectAll("g.node") + .data(model.subNetNodes, function(d) { + return d.name; + }); + + // enter + var nodeEnter = node.enter() + .append("g") + .attr("class", "node"); + + + // enter + nodeEnter + .append("svg:circle") + .attr("r", 0) + .attr("id", function(d) { + return "Node;" + d.name; + }) + .attr("class", "nodeStrokeClass") + .attr("fill", function(d) { + return view.color(d.group); + }); + + // exit + node.exit().remove(); + + // Force2 labels + + // join + var anchorLink = this.viz.selectAll("line.anchorLink") + .data(model.labelAnchorLinks); //.enter().append("svg:line").attr("class", "anchorLink").style("stroke", "#999"); + + // join + var anchorNode = this.viz.selectAll("g.anchorNode") + .data(model.labelAnchors, function(d, i) { + //console.log(d.node.label.name + d.type); + return d.node.label.name + d.type; + }); + + // enter + var anchorNodeEnter = anchorNode + .enter() + .append("svg:g") + .attr("class", "anchorNode"); + + anchorNodeEnter + .on('click', function(d) { + controller.click(d); + }, false) + + // enter + anchorNodeEnter + .append("svg:circle") + .attr("r", 0) + .style("fill", "red"); + + // enter + anchorNodeEnter + .append("svg:text") + .text(function(d, i) { + return i % 2 == 0 ? "" : d.node.label.name + }) + .attr("class", "textClass") + .style("fill", "black") + .style("font-family", "Arial") + .style("font-size", 20); + + // add coloured box around text + anchorNode.each(function(d, i) { + if (i % 2 != 0) { + // prevents two rects being added + // due to render being called twice in + // click func. + //console.log(this.childNodes[2]); + var textElem = this.childNodes[1].getBBox(); + //console.log(textElem); + if (this.childNodes.length === 2) { + d3.select(this) + .insert("rect", "text") + .attr("width", textElem.width) + .attr("height", textElem.height) + .attr("y", textElem.y) + .attr("x", textElem.x) + .attr("fill", function(d) { + return view.color(d.node.label.group); + }) + .attr("opacity", "0.3"); + }; + + }; + }); + + + // exit + anchorNode.exit().remove(); + + // Restart the force layout. + model.force + .size([config.width, config.height]) + .charge(-3000) + .gravity(1) + .linkDistance(50) + .start(); + + // restart the labels force layout + model.force2 + .size([config.width, config.height]) + .gravity(0) + .linkDistance(0) + .linkStrength(8) + .charge(-200) + .start(); + + //console.log('selection', anchorNode); + //console.log('force datum', force2.nodes()); + + var updateLink = function() { + this.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; + }); + } + + var updateNode = function() { + this.attr("transform", function(d) { + //console.log('line 398',d.x, d.y); + return "translate(" + d.x + "," + d.y + ")"; + }); + } + + model.force.on("tick", function() { + + model.force2.start(); + + //--------- + node.call(updateNode); + + anchorNode.each(function(d, i) { + + if (i % 2 == 0) { + + d.x = d.node.label.x; + d.y = d.node.label.y; + } else { + // get the bounding box + var b = this.childNodes[1].getBBox(); + + var diffX = d.x - d.node.label.x; + var diffY = d.y - d.node.label.y; + + var dist = Math.sqrt(diffX * diffX + diffY * diffY); + + var shiftX = b.width * (diffX - dist) / (dist * 2); + shiftX = Math.max(-b.width, Math.min(0, shiftX)); + + var shiftY = 5; + + // move the label of the current anchor + this.childNodes[1].setAttribute("transform", "translate(" + shiftX + "," + shiftY + ")"); + // move the coloured box of the current anchor + this.childNodes[2].setAttribute("transform", "translate(" + shiftX + "," + shiftY + ")"); + } + }); + anchorNode.call(updateNode); + + link.call(updateLink); + + anchorLink.call(updateLink); + }); + /// + } + + } + + // make it all go + controller.init(); + }); - // make it all go - controller.init(); - }); - - }; + }; - chart.width = function(value) { - if (!arguments.length) return config.width; - config.width = value; - return chart; // enable chaining - }; + chart.width = function(value) { + if (!arguments.length) return config.width; + config.width = value; + return chart; // enable chaining + }; - chart.height = function(value) { - if (!arguments.length) return config.height; - config.height = value; - return chart; // enable chaining - }; + chart.height = function(value) { + if (!arguments.length) return config.height; + config.height = value; + return chart; // enable chaining + }; - chart.hops = function(value) { - if (!arguments.length) return config.hops; - config.hops = value; - return chart; // enable chaining - }; + chart.hops = function(value) { + if (!arguments.length) return config.hops; + config.hops = value; + return chart; // enable chaining + }; - return chart; + return chart; -}; + }; +})(); /*---------------------------------------------------------------------------- The code example below: @@ -538,17 +556,17 @@ The code example below: */ d3.json("data/miserables.json", function(error, graph) { - if (error) throw error; - - // Parse JSON into the correct format if needed - - var chart = d3.graphSub() - .width(760) - .height(500) - .hops(2); - //console.log(graph); - - d3.select("#chart") - .datum(graph) - .call(chart); -}); \ No newline at end of file + if (error) throw error; + + // Parse JSON into the correct format if needed + + var chart = d3.graphSub() + .width(760) + .height(500) + .hops(2); + //console.log(graph); + + d3.select("#chart") + .datum(graph) + .call(chart); +}); From 22ec3b62c524bd032bf674936f5df6b7658f4c40 Mon Sep 17 00:00:00 2001 From: Imran Nazir Date: Fri, 29 Apr 2016 18:45:45 +0100 Subject: [PATCH 72/73] block.ord demo not working --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d9b74e..1b16062 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ More information on d3s' force layouts can be found [here](https://github.com/mb Want to contribute a bug fix or enhancement; then feel free to clone the repository and make a pull request. -****A working example can be found [here](http://bl.ocks.org/TimeBandit/6460e2ba3792385b2754).**** +****A working example can be seen by downloading the repo and opening index.html**** Example bl.ock.s used in the development of this graph: From d23bbe06c304288425b102497c234332bed671bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imr=C4=81n=20Nazir?= Date: Mon, 19 Jul 2021 08:51:06 +0100 Subject: [PATCH 73/73] Update underscore-min.js --- static/js/underscore-min.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/static/js/underscore-min.js b/static/js/underscore-min.js index 4db9729..542fe3c 100644 --- a/static/js/underscore-min.js +++ b/static/js/underscore-min.js @@ -1,7 +1,6 @@ -// Underscore.js 1.5.0 -// http://underscorejs.org -// (c) 2009-2011 Jeremy Ashkenas, DocumentCloud Inc. -// (c) 2011-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +!function(n,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define("underscore",r):(n="undefined"!=typeof globalThis?globalThis:n||self,function(){var t=n._,e=n._=r();e.noConflict=function(){return n._=t,e}}())}(this,(function(){ +// Underscore.js 1.13.1 +// https://underscorejs.org +// (c) 2009-2021 Jeremy Ashkenas, Julian Gonggrijp, and DocumentCloud and Investigative Reporters & Editors // Underscore may be freely distributed under the MIT license. -!function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,v=e.reduce,h=e.reduceRight,d=e.filter,g=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,_=Object.keys,w=i.bind,j=function(n){return n instanceof j?n:this instanceof j?(this._wrapped=n,void 0):new j(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=j),exports._=j):n._=j,j.VERSION="1.5.0";var A=j.each=j.forEach=function(n,t,e){if(null!=n)if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a in n)if(j.has(n,a)&&t.call(e,n[a],a,n)===r)return};j.map=j.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e.push(t.call(r,n,u,i))}),e)};var E="Reduce of empty array with no initial value";j.reduce=j.foldl=j.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduce===v)return e&&(t=j.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(E);return r},j.reduceRight=j.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduceRight===h)return e&&(t=j.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=j.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(E);return r},j.find=j.detect=function(n,t,r){var e;return O(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},j.filter=j.select=function(n,t,r){var e=[];return null==n?e:d&&n.filter===d?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&e.push(n)}),e)},j.reject=function(n,t,r){return j.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},j.every=j.all=function(n,t,e){t||(t=j.identity);var u=!0;return null==n?u:g&&n.every===g?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var O=j.some=j.any=function(n,t,e){t||(t=j.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};j.contains=j.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:O(n,function(n){return n===t})},j.invoke=function(n,t){var r=o.call(arguments,2),e=j.isFunction(t);return j.map(n,function(n){return(e?t:n[t]).apply(n,r)})},j.pluck=function(n,t){return j.map(n,function(n){return n[t]})},j.where=function(n,t,r){return j.isEmpty(t)?r?void 0:[]:j[r?"find":"filter"](n,function(n){for(var r in t)if(t[r]!==n[r])return!1;return!0})},j.findWhere=function(n,t){return j.where(n,t,!0)},j.max=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.max.apply(Math,n);if(!t&&j.isEmpty(n))return-1/0;var e={computed:-1/0,value:-1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;a>e.computed&&(e={value:n,computed:a})}),e.value},j.min=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.min.apply(Math,n);if(!t&&j.isEmpty(n))return 1/0;var e={computed:1/0,value:1/0};return A(n,function(n,u,i){var a=t?t.call(r,n,u,i):n;ae||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.indexi;){var o=i+a>>>1;r.call(e,n[o])=0})})},j.difference=function(n){var t=c.apply(e,o.call(arguments,1));return j.filter(n,function(n){return!j.contains(t,n)})},j.zip=function(){return j.unzip.apply(j,o.call(arguments))},j.unzip=function(){for(var n=j.max(j.pluck(arguments,"length").concat(0)),t=new Array(n),r=0;n>r;r++)t[r]=j.pluck(arguments,""+r);return t},j.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},j.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=j.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},j.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},j.range=function(n,t,r){arguments.length<=1&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=new Array(e);e>u;)i[u++]=n,n+=r;return i};var M=function(){};j.bind=function(n,t){var r,e;if(w&&n.bind===w)return w.apply(n,o.call(arguments,1));if(!j.isFunction(n))throw new TypeError;return r=o.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(o.call(arguments)));M.prototype=n.prototype;var u=new M;M.prototype=null;var i=n.apply(u,r.concat(o.call(arguments)));return Object(i)===i?i:u}},j.partial=function(n){var t=o.call(arguments,1);return function(){return n.apply(this,t.concat(o.call(arguments)))}},j.bindAll=function(n){var t=o.call(arguments,1);if(0===t.length)throw new Error("bindAll must be passed function names");return A(t,function(t){n[t]=j.bind(n[t],n)}),n},j.memoize=function(n,t){var r={};return t||(t=j.identity),function(){var e=t.apply(this,arguments);return j.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},j.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},j.defer=function(n){return j.delay.apply(j,[n,1].concat(o.call(arguments,1)))},j.throttle=function(n,t,r){var e,u,i,a=null,o=0;r||(r={});var c=function(){o=new Date,a=null,i=n.apply(e,u)};return function(){var l=new Date;o||r.leading!==!1||(o=l);var f=t-(l-o);return e=this,u=arguments,0>=f?(clearTimeout(a),a=null,o=l,i=n.apply(e,u)):a||r.trailing===!1||(a=setTimeout(c,f)),i}},j.debounce=function(n,t,r){var e,u=null;return function(){var i=this,a=arguments,o=function(){u=null,r||(e=n.apply(i,a))},c=r&&!u;return clearTimeout(u),u=setTimeout(o,t),c&&(e=n.apply(i,a)),e}},j.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},j.wrap=function(n,t){return function(){var r=[n];return a.apply(r,arguments),t.apply(this,r)}},j.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},j.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},j.keys=_||function(n){if(n!==Object(n))throw new TypeError("Invalid object");var t=[];for(var r in n)j.has(n,r)&&t.push(r);return t},j.values=function(n){var t=[];for(var r in n)j.has(n,r)&&t.push(n[r]);return t},j.pairs=function(n){var t=[];for(var r in n)j.has(n,r)&&t.push([r,n[r]]);return t},j.invert=function(n){var t={};for(var r in n)j.has(n,r)&&(t[n[r]]=r);return t},j.functions=j.methods=function(n){var t=[];for(var r in n)j.isFunction(n[r])&&t.push(r);return t.sort()},j.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},j.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},j.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)j.contains(r,u)||(t[u]=n[u]);return t},j.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]===void 0&&(n[r]=t[r])}),n},j.clone=function(n){return j.isObject(n)?j.isArray(n)?n.slice():j.extend({},n):n},j.tap=function(n,t){return t(n),n};var S=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof j&&(n=n._wrapped),t instanceof j&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==String(t);case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;var a=n.constructor,o=t.constructor;if(a!==o&&!(j.isFunction(a)&&a instanceof a&&j.isFunction(o)&&o instanceof o))return!1;r.push(n),e.push(t);var c=0,f=!0;if("[object Array]"==u){if(c=n.length,f=c==t.length)for(;c--&&(f=S(n[c],t[c],r,e)););}else{for(var s in n)if(j.has(n,s)&&(c++,!(f=j.has(t,s)&&S(n[s],t[s],r,e))))break;if(f){for(s in t)if(j.has(t,s)&&!c--)break;f=!c}}return r.pop(),e.pop(),f};j.isEqual=function(n,t){return S(n,t,[],[])},j.isEmpty=function(n){if(null==n)return!0;if(j.isArray(n)||j.isString(n))return 0===n.length;for(var t in n)if(j.has(n,t))return!1;return!0},j.isElement=function(n){return!(!n||1!==n.nodeType)},j.isArray=x||function(n){return"[object Array]"==l.call(n)},j.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){j["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),j.isArguments(arguments)||(j.isArguments=function(n){return!(!n||!j.has(n,"callee"))}),"function"!=typeof/./&&(j.isFunction=function(n){return"function"==typeof n}),j.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},j.isNaN=function(n){return j.isNumber(n)&&n!=+n},j.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},j.isNull=function(n){return null===n},j.isUndefined=function(n){return n===void 0},j.has=function(n,t){return f.call(n,t)},j.noConflict=function(){return n._=t,this},j.identity=function(n){return n},j.times=function(n,t,r){for(var e=Array(Math.max(0,n)),u=0;n>u;u++)e[u]=t.call(r,u);return e},j.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))};var I={escape:{"&":"&","<":"<",">":">",'"':""","'":"'","/":"/"}};I.unescape=j.invert(I.escape);var T={escape:new RegExp("["+j.keys(I.escape).join("")+"]","g"),unescape:new RegExp("("+j.keys(I.unescape).join("|")+")","g")};j.each(["escape","unescape"],function(n){j[n]=function(t){return null==t?"":(""+t).replace(T[n],function(t){return I[n][t]})}}),j.result=function(n,t){if(null==n)return void 0;var r=n[t];return j.isFunction(r)?r.call(n):r},j.mixin=function(n){A(j.functions(n),function(t){var r=j[t]=n[t];j.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),D.call(this,r.apply(j,n))}})};var N=0;j.uniqueId=function(n){var t=++N+"";return n?n+t:t},j.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var q=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},z=/\\|'|\r|\n|\t|\u2028|\u2029/g;j.template=function(n,t,r){var e;r=j.defaults({},r,j.templateSettings);var u=new RegExp([(r.escape||q).source,(r.interpolate||q).source,(r.evaluate||q).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(z,function(n){return"\\"+B[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=new Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,j);var c=function(n){return e.call(this,n,j)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},j.chain=function(n){return j(n).chain()};var D=function(n){return this._chain?j(n).chain():n};j.mixin(j),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];j.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],D.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];j.prototype[n]=function(){return D.call(this,t.apply(this._wrapped,arguments))}}),j.extend(j.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}})}.call(this); -//# sourceMappingURL=underscore-min.map \ No newline at end of file +var n="1.13.1",r="object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global||Function("return this")()||{},t=Array.prototype,e=Object.prototype,u="undefined"!=typeof Symbol?Symbol.prototype:null,o=t.push,i=t.slice,a=e.toString,f=e.hasOwnProperty,c="undefined"!=typeof ArrayBuffer,l="undefined"!=typeof DataView,s=Array.isArray,p=Object.keys,v=Object.create,h=c&&ArrayBuffer.isView,y=isNaN,d=isFinite,g=!{toString:null}.propertyIsEnumerable("toString"),b=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"],m=Math.pow(2,53)-1;function j(n,r){return r=null==r?n.length-1:+r,function(){for(var t=Math.max(arguments.length-r,0),e=Array(t),u=0;u=0&&t<=m}}function J(n){return function(r){return null==r?void 0:r[n]}}var G=J("byteLength"),H=K(G),Q=/\[object ((I|Ui)nt(8|16|32)|Float(32|64)|Uint8Clamped|Big(I|Ui)nt64)Array\]/;var X=c?function(n){return h?h(n)&&!q(n):H(n)&&Q.test(a.call(n))}:C(!1),Y=J("length");function Z(n,r){r=function(n){for(var r={},t=n.length,e=0;e":">",'"':""","'":"'","`":"`"},Cn=Ln($n),Kn=Ln(_n($n)),Jn=tn.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g},Gn=/(.)^/,Hn={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},Qn=/\\|'|\r|\n|\u2028|\u2029/g;function Xn(n){return"\\"+Hn[n]}var Yn=/^\s*(\w|\$)+\s*$/;var Zn=0;function nr(n,r,t,e,u){if(!(e instanceof r))return n.apply(t,u);var o=Mn(n.prototype),i=n.apply(o,u);return _(i)?i:o}var rr=j((function(n,r){var t=rr.placeholder,e=function(){for(var u=0,o=r.length,i=Array(o),a=0;a1)ur(a,r-1,t,e),u=e.length;else for(var f=0,c=a.length;f0&&(t=r.apply(this,arguments)),n<=1&&(r=null),t}}var lr=rr(cr,2);function sr(n,r,t){r=qn(r,t);for(var e,u=nn(n),o=0,i=u.length;o0?0:u-1;o>=0&&o0?a=o>=0?o:Math.max(o+f,a):f=o>=0?Math.min(o+1,f):o+f+1;else if(t&&o&&f)return e[o=t(e,u)]===u?o:-1;if(u!=u)return(o=r(i.call(e,a,f),$))>=0?o+a:-1;for(o=n>0?a:f-1;o>=0&&o0?0:i-1;for(u||(e=r[o?o[a]:a],a+=n);a>=0&&a=3;return r(n,Fn(t,u,4),e,o)}}var Ar=wr(1),xr=wr(-1);function Sr(n,r,t){var e=[];return r=qn(r,t),jr(n,(function(n,t,u){r(n,t,u)&&e.push(n)})),e}function Or(n,r,t){r=qn(r,t);for(var e=!er(n)&&nn(n),u=(e||n).length,o=0;o=0}var Br=j((function(n,r,t){var e,u;return D(r)?u=r:(r=Nn(r),e=r.slice(0,-1),r=r[r.length-1]),_r(n,(function(n){var o=u;if(!o){if(e&&e.length&&(n=In(n,e)),null==n)return;o=n[r]}return null==o?o:o.apply(n,t)}))}));function Nr(n,r){return _r(n,Rn(r))}function Ir(n,r,t){var e,u,o=-1/0,i=-1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=er(n)?n:jn(n)).length;ao&&(o=e);else r=qn(r,t),jr(n,(function(n,t,e){((u=r(n,t,e))>i||u===-1/0&&o===-1/0)&&(o=n,i=u)}));return o}function Tr(n,r,t){if(null==r||t)return er(n)||(n=jn(n)),n[Wn(n.length-1)];var e=er(n)?En(n):jn(n),u=Y(e);r=Math.max(Math.min(r,u),0);for(var o=u-1,i=0;i1&&(e=Fn(e,r[1])),r=an(n)):(e=qr,r=ur(r,!1,!1),n=Object(n));for(var u=0,o=r.length;u1&&(t=r[1])):(r=_r(ur(r,!1,!1),String),e=function(n,t){return!Er(r,t)}),Ur(n,e,t)}));function zr(n,r,t){return i.call(n,0,Math.max(0,n.length-(null==r||t?1:r)))}function Lr(n,r,t){return null==n||n.length<1?null==r||t?void 0:[]:null==r||t?n[0]:zr(n,n.length-r)}function $r(n,r,t){return i.call(n,null==r||t?1:r)}var Cr=j((function(n,r){return r=ur(r,!0,!0),Sr(n,(function(n){return!Er(r,n)}))})),Kr=j((function(n,r){return Cr(n,r)}));function Jr(n,r,t,e){A(r)||(e=t,t=r,r=!1),null!=t&&(t=qn(t,e));for(var u=[],o=[],i=0,a=Y(n);ir?(e&&(clearTimeout(e),e=null),a=c,i=n.apply(u,o),e||(u=o=null)):e||!1===t.trailing||(e=setTimeout(f,l)),i};return c.cancel=function(){clearTimeout(e),a=0,e=u=o=null},c},debounce:function(n,r,t){var e,u,o,i,a,f=function(){var c=zn()-u;r>c?e=setTimeout(f,r-c):(e=null,t||(i=n.apply(a,o)),e||(o=a=null))},c=j((function(c){return a=this,o=c,u=zn(),e||(e=setTimeout(f,r),t&&(i=n.apply(a,o))),i}));return c.cancel=function(){clearTimeout(e),e=o=a=null},c},wrap:function(n,r){return rr(r,n)},negate:fr,compose:function(){var n=arguments,r=n.length-1;return function(){for(var t=r,e=n[r].apply(this,arguments);t--;)e=n[t].call(this,e);return e}},after:function(n,r){return function(){if(--n<1)return r.apply(this,arguments)}},before:cr,once:lr,findKey:sr,findIndex:vr,findLastIndex:hr,sortedIndex:yr,indexOf:gr,lastIndexOf:br,find:mr,detect:mr,findWhere:function(n,r){return mr(n,Dn(r))},each:jr,forEach:jr,map:_r,collect:_r,reduce:Ar,foldl:Ar,inject:Ar,reduceRight:xr,foldr:xr,filter:Sr,select:Sr,reject:function(n,r,t){return Sr(n,fr(qn(r)),t)},every:Or,all:Or,some:Mr,any:Mr,contains:Er,includes:Er,include:Er,invoke:Br,pluck:Nr,where:function(n,r){return Sr(n,Dn(r))},max:Ir,min:function(n,r,t){var e,u,o=1/0,i=1/0;if(null==r||"number"==typeof r&&"object"!=typeof n[0]&&null!=n)for(var a=0,f=(n=er(n)?n:jn(n)).length;ae||void 0===t)return 1;if(t