If then else HTML/CSV file - javascript

I am currently building an organisation chart for my company using an html code (pasted below) build by the genius Mr Bostock. The code is calling a .csv file (flare.csv) where I am organizing my data (3 different columns: Employee Name/Employee span of control (5 ranges)/Employee Salary (6 ranges)).
I want to know if it is possible to change the color of the dots/circles on the diagram depending on the two parameters Span of control and Salary (Ranges).
Maybe a diagram for Span of control and another one for Salary.
Let s say if the Span of control of that employee is between 1 and 3 (Flare.csv file) then his circle on the chart will be yellow.
Thank you in advance for your answers.
Cheers,
Alex
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.node circle {
fill: #999;
}
.node text {
font: 12px sans-serif;
}
.node--internal circle {
fill: #555;
}
.node--internal text {
text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
}
.link {
fill: none;
stroke: #555;
stroke-opacity: 0.4;
stroke-width: 1.5px;
}
</style>
<svg width="960" height="900"></svg>
<script src="d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + (height / 2 + 20) + ")");
var stratify = d3.stratify()
.parentId(function(d) { return d.id.substring(0, d.id.lastIndexOf(".")); });
var cluster = d3.cluster()
.size([360, width / 2 - 120]);
d3.csv("flare.csv", function(error, data) {
if (error) throw error;
var root = stratify(data)
.sort(function(a, b) { return a.height - b.height || a.id.localeCompare(b.id); });
cluster(root);
var link = g.selectAll(".link")
.data(root.descendants().slice(1))
.enter().append("path")
.attr("class", "link")
.attr("d", function(d) {
return "M" + project(d.x, d.y)
+ "C" + project(d.x, (d.y + d.parent.y) / 2)
+ " " + project(d.parent.x, (d.y + d.parent.y) / 2)
+ " " + project(d.parent.x, d.parent.y);
});
var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
.attr("transform", function(d) { return "translate(" + project(d.x, d.y) + ")"; });
node.append("circle")
.attr("r", 2.5);
node.append("text")
.attr("dy", "0.31em")
.attr("x", function(d) { return d.x < 180 === !d.children ? 6 : -6; })
.style("text-anchor", function(d) { return d.x < 180 === !d.children ? "start" : "end"; })
.attr("transform", function(d) { return "rotate(" + (d.x < 180 ? d.x - 90 : d.x + 90) + ")"; })
.text(function(d) { return d.id.substring(d.id.lastIndexOf(".") + 1); });
});
function project(x, y) {
var angle = (x - 90) / 180 * Math.PI, radius = y;
return [radius * Math.cos(angle), radius * Math.sin(angle)];
}
</script>

Related

HTML input range slider is affecting the wrong D3 chart

I have two D3 edge bundle charts, one on top of the other (CSS grid). For the top chart (id: edgeB) I have a div input style slider that changes the tension (amount of curve) of the node lines. It should affect the top chart only. Currently, the slider associated with the top chart is affecting the bottom most chart (id: edgeBTwo). I've tried including the correct div id but it seems to have no effect. I'm thinking that it is affecting the most recently created D3 chart but I'm not sure how to change this behavior.
Here is all of my code.
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="icon" type="globe_icon.png">
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'></script>
<style type="text/css">
body {
padding: 90px;
margin: 0px;
height: 100%;
}
html,
.grid-container {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto auto;
background-color: #ffffff;
padding: 10px;
grid-row-gap: 10px;
}
.grid-item1 {
background-color: rgb(255, 255, 255);
border: 5px solid rgba(255, 0, 0, 0.8);
padding: 15px;
font-size: 12px;
text-align: left;
grid-row-gap: 10px;
font: 8pt "Helvetica Neue", Arial, Helvetica, sans-serif;
}
.grid-item2 {
background-color: rgb(255, 255, 255);
border: 5px solid rgba(234, 0, 255, 0.8);
padding: 15px;
font-size: 12px;
text-align: left;
grid-row-gap: 10px;
font: 8pt "Helvetica Neue", Arial, Helvetica, sans-serif;
}
.wrapword {
white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
white-space: -webkit-pre-wrap; /* Chrome & Safari */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
white-space: pre-wrap; /* CSS3 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
word-break: break-all;
white-space: normal;
}
path.arc {
cursor: move;
fill: #000000;
}
.node {
font: 300 9 "Helvetica Neue", Helvetica, Arial, sans-serif;
fill: rgb(0, 0, 0);
}
.node:hover {
fill: rgb(132, 236, 255);
}
.node:hover,
.node--source,
.node--target {
font-weight: 700;
}
.link {
fill: none;
stroke: #1f77b4;
stroke-opacity: .5;
pointer-events: none;
}
.link.source, .link.target {
stroke-opacity: .8;
stroke-width: 2px;
}
.node.target {
fill: #d62728 !important;
}
.link.source {
stroke: #d62728;
}
.node.source {
fill: #00ff40;
}
.link.target {
stroke: #00ff40;
}
</style>
</head>
<body>
<div class="grid-container"></div>
<div class="grid-item1" id="edgeB">
<div id="edgeB" style="position:absolute;bottom: 2%;;font-size:16px;">Tension: <input style="position:relative;top:3px;" type="range" min="0" max="100" value="85"></div>
<script type="text/javascript" src="//d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="packages.js"></script>
<script>
(function chart1(){
color = d3.scale.category10();
var w = 700,
h = 700,
rx = w / 2.1,
ry = h / 2.1,
m0,
rotate = 0
pi = Math.PI;
var splines = [];
var cluster = d3.layout.cluster()
.size([360, ry - 180])
.sort(function(a, b) {
return d3.ascending(a.key, b.key);
});
var bundle = d3.layout.bundle();
var line = d3.svg.line.radial()
.interpolate("bundle")
.tension(.8)
.radius(function(d) {
return d.y;
})
.angle(function(d) {
return d.x / 180 * Math.PI;
});
// Chrome 15 bug: <http://code.google.com/p/chromium/issues/detail?id=98951>
var div = d3.select("#edgeB")
.style("width", w + "px")
.style("height", w + "px")
.style("position", "relative");
var svg = div.append("svg:svg")
.attr("width", 700)
.attr("height", 700)
.append("svg:g")
.attr("transform", "translate(" + rx + "," + ry + ")");
svg.append("svg:path")
.attr("class", "arc")
.attr("d", d3.svg.arc().outerRadius(ry - 180).innerRadius(0).startAngle(0).endAngle(2 * Math.PI))
.on("mousedown", mousedown);
d3.json("flare_year.json", function(classes) {
var nodes = cluster.nodes(packages.root(classes)),
links = packages.imports(nodes),
splines = bundle(links);
var path = svg.selectAll("path.link")
.data(links)
.enter().append("svg:path")
.attr("class", function(d) {
return "link source-" + d.source.key + " target-" + d.target.key;
})
.attr("d", function(d, i) {
return line(splines[i]);
});
var groupData = svg.selectAll("g.group")
.data(nodes.filter(function(d) {
return (d.key == '1970-1979' || d.key == '1980-1989' || d.key == '1990-1999' || d.key == '2000-2009' || d.key == '2010-2019') && d.children;
}))
.enter().append("group")
.attr("class", "group");
var groupArc = d3.svg.arc()
.innerRadius(ry - 177)
.outerRadius(ry - 157)
.startAngle(function(d) {
return (findStartAngle(d.__data__.children) - 2.3) * pi / 180;
})
.endAngle(function(d) {
return (findEndAngle(d.__data__.children) + 2.3) * pi / 180;
});
svg.selectAll("g.arc")
.data(groupData[0])
.enter().append("svg:path")
.attr("d", groupArc)
.attr("class", "groupArc")
.attr("id", function(d, i) {console.log(d.__data__.key); return d.__data__.key;})
.style("fill", function(d, i) {return color(i);})
.style("fill-opacity", 0.5)
.each(function(d,i) {
var firstArcSection = /(^.+?)L/;
var newArc = firstArcSection.exec( d3.select(this).attr("d") )[1];
newArc = newArc.replace(/,/g , " ");
svg.append("path")
.attr("class", "hiddenArcs")
.attr("id", "hidden"+d.__data__.key)
.attr("d", newArc)
.style("fill", "none");
});
svg.selectAll(".arcText")
.data(groupData[0])
.enter().append("text")
.attr("class", "arcText")
.attr("dy", 12)
.append("textPath")
.attr("startOffset","50%")
.style("text-anchor","middle")
.attr("xlink:href",function(d,i){return "#hidden" + d.__data__.key;})
.text(function(d){return d.__data__.key;});
svg.selectAll("g.node")
.data(nodes.filter(function(n) {
return !n.children;
}))
.enter().append("svg:g")
.attr("class", "node")
.attr("id", function(d) {
return "node-" + d.key;
})
.attr("transform", function(d) {
return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")";
})
.append("svg:text")
.attr("dx", function(d) {
return d.x < 180 ? 25 : -25;
})
.attr("dy", ".31em")
.attr("text-anchor", function(d) {
return d.x < 180 ? "start" : "end";
})
.attr("transform", function(d) {
return d.x < 180 ? null : "rotate(180)";
})
.text(function(d) {
return d.key.replace(/_/g, ' ');
})
.on("mouseover", mouseover)
.on("mouseout", mouseout);
d3.select("input[type=range]").on("change", function() {
line.tension(this.value / 100);
path.attr("d", function(d, i) {
return line(splines[i]);
});
});
});
d3.select(window)
.on("mousemove", mousemove)
.on("mouseup", mouseup);
function mouse(e) {
return [e.pageX - rx, e.pageY - ry];
}
function mousedown() {
m0 = mouse(d3.event);
d3.event.preventDefault();
}
function mousemove() {
if (m0) {
var m1 = mouse(d3.event),
dm = Math.atan2(cross(m0, m1), dot(m0, m1)) * 180 / Math.PI;
div.style("-webkit-transform", "translate3d(0," + (ry - rx) + "px,0)rotate3d(0,0,0," + dm + "deg)translate3d(0," + (rx - ry) + "px,0)");
}
}
function mouseup() {
if (m0) {
var m1 = mouse(d3.event),
dm = Math.atan2(cross(m0, m1), dot(m0, m1)) * 180 / Math.PI;
rotate += dm;
if (rotate > 360) rotate -= 360;
else if (rotate < 0) rotate += 360;
m0 = null;
div.style("-webkit-transform", "rotate3d(0,0,0,0deg)");
svg.attr("transform", "translate(" + rx + "," + ry + ")rotate(" + rotate + ")")
.selectAll("g.node text")
.attr("dx", function(d) { return (d.x + rotate) % 360 < 180 ? 25 : -25; })
.attr("text-anchor", function(d) { return (d.x + rotate) % 360 < 180 ? "start" : "end"; })
.attr("transform", function(d) { return (d.x + rotate) % 360 < 180 ? null : "rotate(180)"; });
}
}
function mouseover(d) {
svg.selectAll("path.link.target-" + d.key)
.classed("target", true)
.each(updateNodes("source", true));
svg.selectAll("path.link.source-" + d.key)
.classed("source", true)
.each(updateNodes("target", true));
}
function mouseout(d) {
svg.selectAll("path.link.source-" + d.key)
.classed("source", false)
.each(updateNodes("target", false));
svg.selectAll("path.link.target-" + d.key)
.classed("target", false)
.each(updateNodes("source", false));
}
function updateNodes(name, value) {
return function(d) {
if (value) this.parentNode.appendChild(this);
svg.select("#node-" + d[name].key).classed(name, value);
};
}
function cross(a, b) {
return a[0] * b[1] - a[1] * b[0];
}
function dot(a, b) {
return a[0] * b[0] + a[1] * b[1];
}
function findStartAngle(children) {
var min = children[0].x;
children.forEach(function(d) {
if (d.x < min)
min = d.x;
});
return min;
}
function findEndAngle(children) {
var max = children[0].x;
children.forEach(function(d) {
if (d.x > max)
max = d.x;
});
return max;
}}())
</script>
</div>
<div class="grid-item2" id="edgeBTwo">
<script type="text/javascript" src="//d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="packages.js"></script>
<script>
(function chart2(){
color = d3.scale.category10();
var w = 700,
h = 700,
rx = w / 2.1,
ry = h / 2.1,
m0,
rotate = 0
pi = Math.PI;
var splines = [];
var cluster = d3.layout.cluster()
.size([360, ry - 180])
.sort(function(a, b) {
return d3.ascending(a.key, b.key);
});
var bundle = d3.layout.bundle();
var line = d3.svg.line.radial()
.interpolate("bundle")
.tension(.8)
.radius(function(d) {
return d.y;
})
.angle(function(d) {
return d.x / 180 * Math.PI;
});
// Chrome 15 bug: <http://code.google.com/p/chromium/issues/detail?id=98951>
var div = d3.select("#edgeBTwo")
.style("width", w + "px")
.style("height", w + "px")
.style("position", "relative");
var svg = div.append("svg:svg")
.attr("width", 700)
.attr("height", 700)
.append("svg:g")
.attr("transform", "translate(" + rx + "," + ry + ")");
svg.append("svg:path")
.attr("class", "arc")
.attr("d", d3.svg.arc().outerRadius(ry - 180).innerRadius(0).startAngle(0).endAngle(2 * Math.PI))
.on("mousedown", mousedown);
d3.json("flare_test.json", function(classes) {
var nodes = cluster.nodes(packages.root(classes)),
links = packages.imports(nodes),
splines = bundle(links);
var path = svg.selectAll("path.link")
.data(links)
.enter().append("svg:path")
.attr("class", function(d) {
return "link source-" + d.source.key + " target-" + d.target.key;
})
.attr("d", function(d, i) {
return line(splines[i]);
});
var groupData = svg.selectAll("g.group")
.data(nodes.filter(function(d) {
return (d.key == '1970-1979' || d.key == 'Low' || d.key == 'Medium' || d.key == 'High') && d.children;
}))
.enter().append("group")
.attr("class", "group");
var groupArc = d3.svg.arc()
.innerRadius(ry - 177)
.outerRadius(ry - 157)
.startAngle(function(d) {
return (findStartAngle(d.__data__.children) - 2.3) * pi / 180;
})
.endAngle(function(d) {
return (findEndAngle(d.__data__.children) + 2.3) * pi / 180;
});
svg.selectAll("g.arc")
.data(groupData[0])
.enter().append("svg:path")
.attr("d", groupArc)
.attr("class", "groupArc")
.attr("id", function(d, i) {console.log(d.__data__.key); return d.__data__.key;})
.style("fill", function(d, i) {return color(i);})
.style("fill-opacity", 0.5)
.each(function(d,i) {
var firstArcSection = /(^.+?)L/;
var newArc = firstArcSection.exec( d3.select(this).attr("d") )[1];
newArc = newArc.replace(/,/g , " ");
svg.append("path")
.attr("class", "hiddenArcs")
.attr("id", "hidden"+d.__data__.key)
.attr("d", newArc)
.style("fill", "none");
});
svg.selectAll(".arcText")
.data(groupData[0])
.enter().append("text")
.attr("class", "arcText")
.attr("dy", 12)
.append("textPath")
.attr("startOffset","50%")
.style("text-anchor","middle")
.attr("xlink:href",function(d,i){return "#hidden" + d.__data__.key;})
.text(function(d){return d.__data__.key;});
svg.selectAll("g.node")
.data(nodes.filter(function(n) {
return !n.children;
}))
.enter().append("svg:g")
.attr("class", "node")
.attr("id", function(d) {
return "node-" + d.key;
})
.attr("transform", function(d) {
return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")";
})
.append("svg:text")
.attr("dx", function(d) {
return d.x < 180 ? 25 : -25;
})
.attr("dy", ".31em")
.attr("text-anchor", function(d) {
return d.x < 180 ? "start" : "end";
})
.attr("transform", function(d) {
return d.x < 180 ? null : "rotate(180)";
})
.text(function(d) {
return d.key.replace(/_/g, ' ');
})
.on("mouseover", mouseover)
.on("mouseout", mouseout);
d3.select("input[type=range]").on("change", function() {
line.tension(this.value / 100);
path.attr("d", function(d, i) {
return line(splines[i]);
});
});
});
d3.select(window)
.on("mousemove", mousemove)
.on("mouseup", mouseup);
function mouse(e) {
return [e.pageX - rx, e.pageY - ry];
}
function mousedown() {
m0 = mouse(d3.event);
d3.event.preventDefault();
}
function mousemove() {
if (m0) {
var m1 = mouse(d3.event),
dm = Math.atan2(cross(m0, m1), dot(m0, m1)) * 180 / Math.PI;
div.style("-webkit-transform", "translate3d(0," + (ry - rx) + "px,0)rotate3d(0,0,0," + dm + "deg)translate3d(0," + (rx - ry) + "px,0)");
}
}
function mouseup() {
if (m0) {
var m1 = mouse(d3.event),
dm = Math.atan2(cross(m0, m1), dot(m0, m1)) * 180 / Math.PI;
rotate += dm;
if (rotate > 360) rotate -= 360;
else if (rotate < 0) rotate += 360;
m0 = null;
div.style("-webkit-transform", "rotate3d(0,0,0,0deg)");
svg.attr("transform", "translate(" + rx + "," + ry + ")rotate(" + rotate + ")")
.selectAll("g.node text")
.attr("dx", function(d) { return (d.x + rotate) % 360 < 180 ? 25 : -25; })
.attr("text-anchor", function(d) { return (d.x + rotate) % 360 < 180 ? "start" : "end"; })
.attr("transform", function(d) { return (d.x + rotate) % 360 < 180 ? null : "rotate(180)"; });
}
}
function mouseover(d) {
svg.selectAll("path.link.target-" + d.key)
.classed("target", true)
.each(updateNodes("source", true));
svg.selectAll("path.link.source-" + d.key)
.classed("source", true)
.each(updateNodes("target", true));
}
function mouseout(d) {
svg.selectAll("path.link.source-" + d.key)
.classed("source", false)
.each(updateNodes("target", false));
svg.selectAll("path.link.target-" + d.key)
.classed("target", false)
.each(updateNodes("source", false));
}
function updateNodes(name, value) {
return function(d) {
if (value) this.parentNode.appendChild(this);
svg.select("#node-" + d[name].key).classed(name, value);
};
}
function cross(a, b) {
return a[0] * b[1] - a[1] * b[0];
}
function dot(a, b) {
return a[0] * b[0] + a[1] * b[1];
}
function findStartAngle(children) {
var min = children[0].x;
children.forEach(function(d) {
if (d.x < min)
min = d.x;
});
return min;
}
function findEndAngle(children) {
var max = children[0].x;
children.forEach(function(d) {
if (d.x > max)
max = d.x;
});
return max;
}}());
</script>
</div>
</body>
</html>
Here is my packages.js file and both data files needed to run the above code:
packages.js
(function() {
packages = {
// Lazily construct the package hierarchy from class names.
root: function(classes) {
var map = {};
function find(name, data) {
var node = map[name], i;
if (!node) {
node = map[name] = data || {name: name, children: []};
if (name.length) {
node.parent = find(name.substring(0, i = name.lastIndexOf(".")));
node.parent.children.push(node);
node.key = name.substring(i + 1);
}
}
return node;
}
classes.forEach(function(d) {
find(d.name, d);
});
return map[""];
},
// Return a list of imports for the given array of nodes.
imports: function(nodes) {
var map = {},
imports = [];
// Compute a map from name to node.
nodes.forEach(function(d) {
map[d.name] = d;
});
// For each import, construct a link from the source to target node.
nodes.forEach(function(d) {
if (d.imports) d.imports.forEach(function(i) {
imports.push({source: map[d.name], target: map[i]});
});
});
return imports;
}
};
})();
flare_year.json
[
{
"name": "root.2010-2019.A",
"imports": [
"root.1990-1999.B",
]
},
{
"name": "root.1990-1999.B",
"imports": [
"root.2010-2019.A",
]
}
]
flare_test.json
[
{
"name": "root.High.A",
"imports": [
"root.Medium.F",
]
},
{
"name": "root.Medium.F",
"imports": [
"root.High.A",
]
}
]
It was a simple issue but took me some time to figure out.
What you are doing wrong is that you are assigning the onChange Event Handler on (input[type="range"]) in chart1 and again assigning it in chart2 on the same node. Event Listener assigned later will always be called.
You need to have seperate inputs for range and corresponding handlers or if you want to assign a same handler, add a dropdown to select which chart to change and get value of that dropdown in the event handler.
Your fixed code below:
(function() {
packages = {
// Lazily construct the package hierarchy from class names.
root: function(classes) {
var map = {};
function find(name, data) {
var node = map[name],
i;
if (!node) {
node = map[name] = data || {
name: name,
children: []
};
if (name.length) {
node.parent = find(name.substring(0, i = name.lastIndexOf(".")));
node.parent.children.push(node);
node.key = name.substring(i + 1);
}
}
return node;
}
classes.forEach(function(d) {
find(d.name, d);
});
return map[""];
},
// Return a list of imports for the given array of nodes.
imports: function(nodes) {
var map = {},
imports = [];
// Compute a map from name to node.
nodes.forEach(function(d) {
map[d.name] = d;
});
// For each import, construct a link from the source to target node.
nodes.forEach(function(d) {
if (d.imports) d.imports.forEach(function(i) {
imports.push({
source: map[d.name],
target: map[i]
});
});
});
return imports;
}
};
})();
(function chart1() {
color = d3.scale.category10();
let w = 700,
h = 700,
rx = w / 2.1,
ry = h / 2.1,
m0,
rotate = 0
pi = Math.PI;
let splines = [];
let cluster = d3.layout.cluster()
.size([360, ry - 180])
.sort(function(a, b) {
return d3.ascending(a.key, b.key);
});
let bundle = d3.layout.bundle();
let line = d3.svg.line.radial()
.interpolate("bundle")
.tension(.8)
.radius(function(d) {
return d.y;
})
.angle(function(d) {
return d.x / 180 * Math.PI;
});
// Chrome 15 bug: <http://code.google.com/p/chromium/issues/detail?id=98951>
let div = d3.select("#edgeB")
.style("width", w + "px")
.style("height", w + "px")
.style("position", "relative");
let svg = div.append("svg:svg")
.attr("width", 700)
.attr("height", 700)
.append("svg:g")
.attr("transform", "translate(" + rx + "," + ry + ")");
svg.append("svg:path")
.attr("class", "arc")
.attr("d", d3.svg.arc().outerRadius(ry - 180).innerRadius(0).startAngle(0).endAngle(2 * Math.PI))
.on("mousedown", mousedown);
{
let classes = [{
"name": "root.2010-2019.A",
"imports": [
"root.1990-1999.B",
]
},
{
"name": "root.1990-1999.B",
"imports": [
"root.2010-2019.A",
]
}
];
let nodes = cluster.nodes(packages.root(classes)),
links = packages.imports(nodes),
splines = bundle(links);
let path = svg.selectAll("path.link")
.data(links)
.enter().append("svg:path")
.attr("class", function(d) {
return "link source-" + d.source.key + " target-" + d.target.key;
})
.attr("d", function(d, i) {
return line(splines[i]);
});
let groupData = svg.selectAll("g.group")
.data(nodes.filter(function(d) {
return (d.key == '1970-1979' || d.key == '1980-1989' || d.key == '1990-1999' || d.key == '2000-2009' || d.key == '2010-2019') && d.children;
}))
.enter().append("group")
.attr("class", "group");
let groupArc = d3.svg.arc()
.innerRadius(ry - 177)
.outerRadius(ry - 157)
.startAngle(function(d) {
return (findStartAngle(d.__data__.children) - 2.3) * pi / 180;
})
.endAngle(function(d) {
return (findEndAngle(d.__data__.children) + 2.3) * pi / 180;
});
svg.selectAll("g.arc")
.data(groupData[0])
.enter().append("svg:path")
.attr("d", groupArc)
.attr("class", "groupArc")
.attr("id", function(d, i) {
console.log(d.__data__.key);
return d.__data__.key;
})
.style("fill", function(d, i) {
return color(i);
})
.style("fill-opacity", 0.5)
.each(function(d, i) {
let firstArcSection = /(^.+?)L/;
let newArc = firstArcSection.exec(d3.select(this).attr("d"))[1];
newArc = newArc.replace(/,/g, " ");
svg.append("path")
.attr("class", "hiddenArcs")
.attr("id", "hidden" + d.__data__.key)
.attr("d", newArc)
.style("fill", "none");
});
svg.selectAll(".arcText")
.data(groupData[0])
.enter().append("text")
.attr("class", "arcText")
.attr("dy", 12)
.append("textPath")
.attr("startOffset", "50%")
.style("text-anchor", "middle")
.attr("xlink:href", function(d, i) {
return "#hidden" + d.__data__.key;
})
.text(function(d) {
return d.__data__.key;
});
svg.selectAll("g.node")
.data(nodes.filter(function(n) {
return !n.children;
}))
.enter().append("svg:g")
.attr("class", "node")
.attr("id", function(d) {
return "node-" + d.key;
})
.attr("transform", function(d) {
return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")";
})
.append("svg:text")
.attr("dx", function(d) {
return d.x < 180 ? 25 : -25;
})
.attr("dy", ".31em")
.attr("text-anchor", function(d) {
return d.x < 180 ? "start" : "end";
})
.attr("transform", function(d) {
return d.x < 180 ? null : "rotate(180)";
})
.text(function(d) {
return d.key.replace(/_/g, ' ');
})
.on("mouseover", mouseover)
.on("mouseout", mouseout);
d3.select("input[type=range]").on("change", function() {
console.log(line);
line.tension(this.value / 100);
path.attr("d", function(d, i) {
return line(splines[i]);
});
});
};
d3.select(window)
.on("mousemove", mousemove)
.on("mouseup", mouseup);
function mouse(e) {
return [e.pageX - rx, e.pageY - ry];
}
function mousedown() {
m0 = mouse(d3.event);
d3.event.preventDefault();
}
function mousemove() {
if (m0) {
var m1 = mouse(d3.event),
dm = Math.atan2(cross(m0, m1), dot(m0, m1)) * 180 / Math.PI;
div.style("-webkit-transform", "translate3d(0," + (ry - rx) + "px,0)rotate3d(0,0,0," + dm + "deg)translate3d(0," + (rx - ry) + "px,0)");
}
}
function mouseup() {
if (m0) {
var m1 = mouse(d3.event),
dm = Math.atan2(cross(m0, m1), dot(m0, m1)) * 180 / Math.PI;
rotate += dm;
if (rotate > 360) rotate -= 360;
else if (rotate < 0) rotate += 360;
m0 = null;
div.style("-webkit-transform", "rotate3d(0,0,0,0deg)");
svg.attr("transform", "translate(" + rx + "," + ry + ")rotate(" + rotate + ")")
.selectAll("g.node text")
.attr("dx", function(d) {
return (d.x + rotate) % 360 < 180 ? 25 : -25;
})
.attr("text-anchor", function(d) {
return (d.x + rotate) % 360 < 180 ? "start" : "end";
})
.attr("transform", function(d) {
return (d.x + rotate) % 360 < 180 ? null : "rotate(180)";
});
}
}
function mouseover(d) {
svg.selectAll("path.link.target-" + d.key)
.classed("target", true)
.each(updateNodes("source", true));
svg.selectAll("path.link.source-" + d.key)
.classed("source", true)
.each(updateNodes("target", true));
}
function mouseout(d) {
svg.selectAll("path.link.source-" + d.key)
.classed("source", false)
.each(updateNodes("target", false));
svg.selectAll("path.link.target-" + d.key)
.classed("target", false)
.each(updateNodes("source", false));
}
function updateNodes(name, value) {
return function(d) {
if (value) this.parentNode.appendChild(this);
svg.select("#node-" + d[name].key).classed(name, value);
};
}
function cross(a, b) {
return a[0] * b[1] - a[1] * b[0];
}
function dot(a, b) {
return a[0] * b[0] + a[1] * b[1];
}
function findStartAngle(children) {
var min = children[0].x;
children.forEach(function(d) {
if (d.x < min)
min = d.x;
});
return min;
}
function findEndAngle(children) {
var max = children[0].x;
children.forEach(function(d) {
if (d.x > max)
max = d.x;
});
return max;
}
}());
(function chart2() {
color = d3.scale.category10();
var w = 700,
h = 700,
rx = w / 2.1,
ry = h / 2.1,
m0,
rotate = 0
pi = Math.PI;
var splines = [];
var cluster = d3.layout.cluster()
.size([360, ry - 180])
.sort(function(a, b) {
return d3.ascending(a.key, b.key);
});
var bundle = d3.layout.bundle();
var line = d3.svg.line.radial()
.interpolate("bundle")
.tension(.8)
.radius(function(d) {
return d.y;
})
.angle(function(d) {
return d.x / 180 * Math.PI;
});
// Chrome 15 bug: <http://code.google.com/p/chromium/issues/detail?id=98951>
var div = d3.select("#edgeBTwo")
.style("width", w + "px")
.style("height", w + "px")
.style("position", "relative");
var svg = div.append("svg:svg")
.attr("width", 700)
.attr("height", 700)
.append("svg:g")
.attr("transform", "translate(" + rx + "," + ry + ")");
svg.append("svg:path")
.attr("class", "arc")
.attr("d", d3.svg.arc().outerRadius(ry - 180).innerRadius(0).startAngle(0).endAngle(2 * Math.PI))
.on("mousedown", mousedown);
{
let classes = [
{
"name": "root.High.A",
"imports": [
"root.Medium.F",
]
},
{
"name": "root.Medium.F",
"imports": [
"root.High.A",
]
}
];
var nodes = cluster.nodes(packages.root(classes)),
links = packages.imports(nodes),
splines = bundle(links);
var path = svg.selectAll("path.link")
.data(links)
.enter().append("svg:path")
.attr("class", function(d) {
return "link source-" + d.source.key + " target-" + d.target.key;
})
.attr("d", function(d, i) {
return line(splines[i]);
});
var groupData = svg.selectAll("g.group")
.data(nodes.filter(function(d) {
return (d.key == '1970-1979' || d.key == 'Low' || d.key == 'Medium' || d.key == 'High') && d.children;
}))
.enter().append("group")
.attr("class", "group");
var groupArc = d3.svg.arc()
.innerRadius(ry - 177)
.outerRadius(ry - 157)
.startAngle(function(d) {
return (findStartAngle(d.__data__.children) - 2.3) * pi / 180;
})
.endAngle(function(d) {
return (findEndAngle(d.__data__.children) + 2.3) * pi / 180;
});
svg.selectAll("g.arc")
.data(groupData[0])
.enter().append("svg:path")
.attr("d", groupArc)
.attr("class", "groupArc")
.attr("id", function(d, i) {
console.log(d.__data__.key);
return d.__data__.key;
})
.style("fill", function(d, i) {
return color(i);
})
.style("fill-opacity", 0.5)
.each(function(d, i) {
var firstArcSection = /(^.+?)L/;
var newArc = firstArcSection.exec(d3.select(this).attr("d"))[1];
newArc = newArc.replace(/,/g, " ");
svg.append("path")
.attr("class", "hiddenArcs")
.attr("id", "hidden" + d.__data__.key)
.attr("d", newArc)
.style("fill", "none");
});
svg.selectAll(".arcText")
.data(groupData[0])
.enter().append("text")
.attr("class", "arcText")
.attr("dy", 12)
.append("textPath")
.attr("startOffset", "50%")
.style("text-anchor", "middle")
.attr("xlink:href", function(d, i) {
return "#hidden" + d.__data__.key;
})
.text(function(d) {
return d.__data__.key;
});
svg.selectAll("g.node")
.data(nodes.filter(function(n) {
return !n.children;
}))
.enter().append("svg:g")
.attr("class", "node")
.attr("id", function(d) {
return "node-" + d.key;
})
.attr("transform", function(d) {
return "rotate(" + (d.x - 90) + ")translate(" + d.y + ")";
})
.append("svg:text")
.attr("dx", function(d) {
return d.x < 180 ? 25 : -25;
})
.attr("dy", ".31em")
.attr("text-anchor", function(d) {
return d.x < 180 ? "start" : "end";
})
.attr("transform", function(d) {
return d.x < 180 ? null : "rotate(180)";
})
.text(function(d) {
return d.key.replace(/_/g, ' ');
})
.on("mouseover", mouseover)
.on("mouseout", mouseout);
d3.select("input#inputEdgesec").on("change", function() {
line.tension(this.value / 100);
path.attr("d", function(d, i) {
return line(splines[i]);
});
});
};
d3.select(window)
.on("mousemove", mousemove)
.on("mouseup", mouseup);
function mouse(e) {
return [e.pageX - rx, e.pageY - ry];
}
function mousedown() {
m0 = mouse(d3.event);
d3.event.preventDefault();
}
function mousemove() {
if (m0) {
var m1 = mouse(d3.event),
dm = Math.atan2(cross(m0, m1), dot(m0, m1)) * 180 / Math.PI;
div.style("-webkit-transform", "translate3d(0," + (ry - rx) + "px,0)rotate3d(0,0,0," + dm + "deg)translate3d(0," + (rx - ry) + "px,0)");
}
}
function mouseup() {
if (m0) {
var m1 = mouse(d3.event),
dm = Math.atan2(cross(m0, m1), dot(m0, m1)) * 180 / Math.PI;
rotate += dm;
if (rotate > 360) rotate -= 360;
else if (rotate < 0) rotate += 360;
m0 = null;
div.style("-webkit-transform", "rotate3d(0,0,0,0deg)");
svg.attr("transform", "translate(" + rx + "," + ry + ")rotate(" + rotate + ")")
.selectAll("g.node text")
.attr("dx", function(d) {
return (d.x + rotate) % 360 < 180 ? 25 : -25;
})
.attr("text-anchor", function(d) {
return (d.x + rotate) % 360 < 180 ? "start" : "end";
})
.attr("transform", function(d) {
return (d.x + rotate) % 360 < 180 ? null : "rotate(180)";
});
}
}
function mouseover(d) {
svg.selectAll("path.link.target-" + d.key)
.classed("target", true)
.each(updateNodes("source", true));
svg.selectAll("path.link.source-" + d.key)
.classed("source", true)
.each(updateNodes("target", true));
}
function mouseout(d) {
svg.selectAll("path.link.source-" + d.key)
.classed("source", false)
.each(updateNodes("target", false));
svg.selectAll("path.link.target-" + d.key)
.classed("target", false)
.each(updateNodes("source", false));
}
function updateNodes(name, value) {
return function(d) {
if (value) this.parentNode.appendChild(this);
svg.select("#node-" + d[name].key).classed(name, value);
};
}
function cross(a, b) {
return a[0] * b[1] - a[1] * b[0];
}
function dot(a, b) {
return a[0] * b[0] + a[1] * b[1];
}
function findStartAngle(children) {
var min = children[0].x;
children.forEach(function(d) {
if (d.x < min)
min = d.x;
});
return min;
}
function findEndAngle(children) {
var max = children[0].x;
children.forEach(function(d) {
if (d.x > max)
max = d.x;
});
return max;
}
}());
body {
padding: 90px;
margin: 0px;
height: 100%;
}
html,
.grid-container {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto auto;
background-color: #ffffff;
padding: 10px;
grid-row-gap: 10px;
}
.grid-item1 {
background-color: rgb(255, 255, 255);
border: 5px solid rgba(255, 0, 0, 0.8);
padding: 15px;
font-size: 12px;
text-align: left;
grid-row-gap: 10px;
font: 8pt "Helvetica Neue", Arial, Helvetica, sans-serif;
}
.grid-item2 {
background-color: rgb(255, 255, 255);
border: 5px solid rgba(234, 0, 255, 0.8);
padding: 15px;
font-size: 12px;
text-align: left;
grid-row-gap: 10px;
font: 8pt "Helvetica Neue", Arial, Helvetica, sans-serif;
}
.wrapword {
white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
white-space: -webkit-pre-wrap; /* Chrome & Safari */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
white-space: pre-wrap; /* CSS3 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
word-break: break-all;
white-space: normal;
}
path.arc {
cursor: move;
fill: #000000;
}
.node {
font: 300 9 "Helvetica Neue", Helvetica, Arial, sans-serif;
fill: rgb(0, 0, 0);
}
.node:hover {
fill: rgb(132, 236, 255);
}
.node:hover,
.node--source,
.node--target {
font-weight: 700;
}
.link {
fill: none;
stroke: #1f77b4;
stroke-opacity: .5;
pointer-events: none;
}
.link.source, .link.target {
stroke-opacity: .8;
stroke-width: 2px;
}
.node.target {
fill: #d62728 !important;
}
.link.source {
stroke: #d62728;
}
.node.source {
fill: #00ff40;
}
.link.target {
stroke: #00ff40;
}
.sliderContainer
{
display:flex;
flex-direction:column;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="icon" type="globe_icon.png">
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'></script>
</head>
<body>
<div class="grid-container"></div>
<div class="grid-item1" id="edgeB">
<div id="edgeB" style="position:absolute;bottom: 2%;;font-size:16px;"><div class="sliderContainer">Tension: <input style="position:relative;top:3px;" type="range" min="0" max="100" value="85"> Tension for second <input id="inputEdgesec" style="position:relative;top:3px;" type="range" min="0" max="100" value="85">
</div>
</div>
<script type="text/javascript" src="//d3js.org/d3.v3.min.js"></script>
</script>
</div>
<div class="grid-item2" id="edgeBTwo">
</div>
<script type="text/javascript" src="//d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="packages.js"></script>
</body>
</html>

Links overlapping with the image in directional force layout

In my directional force layout codepen I am using icons rather than circles; currently, the links are overlapping with the image/icon. I want the links to end just before the image. However I see in d3noob's example the link starts/end after the circle, it does not overlap with the circle.
I tweaked the following return statement but not able to fix it properly.
function tick() {
link.attr("d", function(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return ( "M" + d.source.x + "," + d.source.y +
"A" + dr + "," + dr + " 0 0,1 " +
d.target.x + "," + d.target.y );
});
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
The mathematical way to avoid this, without playing with the elements' order, is computing an offset, so the links start and end at the nodes' edges.
In your case, we first get the angle between the two nodes:
var angle = Math.atan2(dx, dy);
Then we compute the offset:
var offsetX = radius * Math.cos(angle);
var offsetY = radius * Math.sin(angle);
And finally use that value in the d attribute:
return ("M" + (d.source.x + offsetX) + "," + (d.source.y + offsetY) +
"A" + dr + "," + dr + " 0 0,1 " + (d.target.x - offsetX) +
"," + (d.target.y - offsetY)
);
Here is the code with that change:
var width = 500,
height = 400,
radius = 8;
var fill = d3.scale.category20();
var links = [{ source: "FH", target: "TP" }];
var nodes = [
{ id: "FH", x: 100, y: 110 },
{ id: "TP", x: 200, y: 110 },
{ id: "GW", x: 200, y: 110 },
{ id: "DB", x: 100, y: 110 }
]
var map = {}
nodes.forEach(function(d,i){
map[d.id] = i;
})
links.forEach(function(d) {
d.source = map[d.source];
d.target = map[d.target];
})
var force = d3.layout
.force()
.size([width, height])
.nodes(nodes)
.links(links)
.linkDistance(150)
.charge(-500)
.on("tick", tick);
var svg = d3
.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var arrows = svg
.append("svg:defs")
.selectAll("marker")
.data(["arrow"])
.enter()
.append("marker")
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 10)
.attr("refY", 0)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("path")
.attr("d", "M0,-5L10,0L0,5");
svg
.append("rect")
.attr("width", width)
.attr("height", height);
var nodes = force.nodes(),
links = force.links(),
node = svg.selectAll(".node"),
link = svg.selectAll(".link");
restart();
function tick() {
link.attr("d", function(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y;
var angle = Math.atan2(dy, dx);
var offsetX = radius * Math.cos(angle);
var offsetY = radius * Math.sin(angle);
dr = Math.sqrt(dx * dx + dy * dy);
return (
"M" +
(d.source.x + offsetX) +
"," +
(d.source.y + offsetY) +
"A" +
dr +
"," +
dr +
" 0 0,1 " +
(d.target.x - offsetX) +
"," +
(d.target.y - offsetY)
);
});
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
function restart() {
link = link.data(links);
link
.enter()
.append("path")
.attr("class", "link")
.attr("marker-end", "url(#arrow)");
link.exit().remove();
node = node.data(nodes);
node
.enter()
.insert("g")
.attr("class", "node")
.call(force.drag);
node
.append("image")
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("x", -8)
.attr("y", -8)
.attr("width", 16)
.attr("height", 16);
node
.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) {
return d.id;
});
node.exit().remove();
force.start();
}
#nodeConsole {
width: 80%;
height: 1px;
font-family: courier new;
padding: 1px;
border: 3px solid gray;
margin-top: 1px;
overflow: autao;
}
#linkedNodes {
width: 80%;
font-family: courier new;
padding: 10px;
}
#srcNodes {
width: 40%;
font-family: courier new;
padding: 8px;
}
#targetNodes {
width: 40%;
font-family: courier new;
padding: 8px;
}
rect {
fill: none;
pointer-events: all;
}
.node {
fill: #000;
}
.cursor {
fill: none;
stroke: brown;
pointer-events: none;
}
.link {
stroke: #999;
}
.node text {
pointer-events: none;
font: 10px sans-serif;
}
path.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
In the restart() function draw the links before the nodes and use an image that has no internal transparency.
function restart() {
link = link.data(links);
link
.enter()
.append("path")
.attr("class", "link")
.attr("marker-end", "url(#arrow)");
link.exit().remove();
node = node.data(nodes);
node
.enter()
.insert("g")
.attr("class", "node")
.call(force.drag);
node
.append("image")
.attr("xlink:href", "https://github.com/favicon.ico")
.attr("x", -8)
.attr("y", -8)
.attr("width", 16)
.attr("height", 16);
node
.append("text")
.attr("dx", 12)
.attr("dy", ".35em")
.text(function(d) {
return d.id;
});
node.exit().remove();
force.start();
}

D3 zoomable circle packing with Bar Chart (Bar chart zoom)

I have done basic things in D3 so I don't have deep knowledge about it.
I have created the zoomable circle packing chart with bar chart.
Here is the code:
var xr, yr, xaxis, yaxis, bar, bg;
var svg = d3.select("svg"),
margin = 20,
width = +svg.attr("width") - margin.left - margin.right,
height = +svg.attr("height") - margin.top - margin.bottom;
diameter = +svg.attr("width"),
g = svg.append("g").attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")");
var color = d3.scaleLinear()
.domain([-1, 5])
.range(["hsl(152,80%,80%)", "hsl(228,30%,40%)"])
.interpolate(d3.interpolateHcl);
var pack = d3.pack()
.size([diameter - margin, diameter - margin])
.padding(2);
d3.json("occupation.json", function(error, root) {
if (error) throw error;
root = d3.hierarchy(root)
.sum(function(d) {
return d.size;
})
.sort(function(a, b) {
return b.value - a.value;
});
var focus = root,
nodes = pack(root).descendants(),
view;
var circle = g.selectAll("circle")
.data(nodes.filter(function(d) {
return d.height > 0
}))
.enter().append("circle")
.attr("class", function(d) {
return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root";
})
.style("fill", function(d) {
return d.children ? color(d.depth) : null;
})
.on("click", function(d) {
if (focus !== d) {
if (d.children) {
zoom(d), d3.event.stopPropagation();
} else {
var nextMonthVal = prompt("Please enter target value you want to set");
if (nextMonthVal) {
alert("You have set the target of Rs. " + nextMonthVal + " for next Month");
}
}
}
});
var leaf = g.selectAll(".bars")
.data(nodes.filter(function(d) {
return d.height == 1
}))
.enter()
.append("g")
.attr("x", 0)
.attr("y", 0)
.attr("height", function(d) {
return d.x + d.r
})
.attr("width", function(d) {
return d.y + d.r
})
.attr("class", "bars")
.each(function(d) {
drawBarData(this, this.__data__, d);
})
var text = g.selectAll(".label")
.data(nodes.filter(function(d) {
return d.height > 0
}))
.enter().append("text")
.attr("class", "label")
.style("fill-opacity", function(d) {
return d.parent === root ? 1 : 0;
})
.style("display", function(d) {
return d.parent === root ? "inline" : "none";
})
.text(function(d) {
return d.data.name + " " + d.data.size + " Rs.";
});
var node = g.selectAll("circle,.bars,.label");
svg
.style("background", color(-1))
.on("click", function() {
zoom(root);
});
zoomTo([root.x, root.y, root.r * 2 + margin]);
function zoom(d) {
var focus0 = focus;
focus = d;
var transition = d3.transition()
.duration(d3.event.altKey ? 7500 : 750)
.tween("zoom", function(d) {
var i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2 + margin]);
return function(t) {
zoomTo(i(t), focus);
};
});
transition.selectAll(".label")
.filter(function(d) {
return d.parent === focus || this.style.display === "inline";
})
.style("fill-opacity", function(d) {
return d.parent === focus ? 1 : 0;
})
.on("start", function(d) {
if (d.parent === focus) this.style.display = "inline";
})
.on("end", function(d) {
if (d.parent !== focus) this.style.display = "none";
});
}
function zoomTo(v, focus) {
var k = diameter / v[2];
view = v;
node.attr("transform", function(d) {
return "translate(" + (d.x - v[0]) * k + "," + (d.y - v[1]) * k + ")";
});
circle.attr("r", function(d) {
return d.r * k;
});
if (focus && focus.height == 1) {
var data2 = focus.children.map(function(d) {
return d.data
})
var data1 = []
rectwidth = focus.r,
rectheight = focus.r;
barsize = data2.length;
maxDataPoint = d3.max(data2, function(d) {
return d.size
});
var linearScale = d3.scaleLinear()
.domain([0, maxDataPoint])
.range([0, rectheight]);
for (var i = 0; i < data2.length; i++) {
data1.push({
name: data2[i].name,
size: linearScale(data2[i].size)
})
}
bg.attr("transform", function(d) {
console.log(d);
return "translate(" + (d.x - v[0]) * k + "," + (d.y - v[1]) * k + ")";
})
bar.attr("x", function(d, i) {
console.log("D ::: >", d);
return i * (rectwidth / data1.length);
})
.attr("y", function(d) {
return rectheight - d.size;
})
.attr("width", focus.r / data1.length - 2)
.attr("height", function(d) {
return d.size;
});
}
}
function drawBarData(ele, data, d) {
if (!data && !data.parent)
return;
var data2 = data.children.map(function(e) {
return e.data
})
var data1 = []
rectwidth = d.r,
rectheight = d.r;
barsize = data2.length;
maxDataPoint = d3.max(data2, function(d) {
return d.size
});
var linearScale = d3.scaleLinear()
.domain([0, maxDataPoint])
.range([0, rectheight]);
for (var i = 0; i < data2.length; i++) {
data1.push({
name: data2[i].name,
size: linearScale(data2[i].size)
})
}
bg = d3.select(ele).attr("transform", "translate(" + 0 + "," + 0 + ")").append("g")
.attr("class", "chart-wrapper")
.attr("transform", function(d) {
console.log('BG ::: >>>', d);
return "translate(" + -d.r / 2 + "," + -d.r / 2 + ")";
});
bar = bg.selectAll(".bar")
.data(data1)
.enter()
.append('rect')
.attr("class", "bar")
.attr("x", function(d, i) {
return i * (rectwidth / data1.length);
})
.attr("y", function(d) {
return rectheight - d.size;
})
.attr("width", d.r / data1.length - 2)
.attr("height", function(d) {
return d.size;
});
}
});
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}
a {
color: #00B7FF;
}
.container {
width: 400px;
}
.node {
cursor: pointer;
}
.node:hover {
border: #000;
border-width: 1.5px;
}
.node--leaf {
color: white;
}
.label {
font: 11px "Helvetica Neue", Helvetica, Arial, sans-serif;
text-align: center;
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff, 0 -1px 0 #fff;
}
.label,
.node--root {
pointer-events: none;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="960" height="960"></svg>
(not enough room for json - refer to plunkr)
I've placed the bar chart as per my understanding. But I also want barchart to be zoomed on the focus of each node. I am not getting any idea how to do it.
Please help me if anyone having idea or solution.

Fit the d3js graph in a simple html page

I am trying to use the example from here, and my files are as follows:
index.html
<!DOCTYPE html>
<html>
<head>
<title>Test Page</title>
<meta charset="utf-8">
<style>
.node circle {
fill: #999;
}
.node text {
font: 10px sans-serif;
}
.node--internal circle {
fill: #555;
}
.node--internal text {
text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
}
.link {
fill: none;
stroke: #555;
stroke-opacity: 0.4;
stroke-width: 1.5px;
}
html, body {
height: 100%;
}
html {
display: table;
margin: auto;
}
body {
display: table-cell;
vertical-align: middle;
}
</style>
</head>
<body>
<svg width="960" height="2000"></svg>
<script src="d3.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
g = svg.append("g").attr("transform", "translate(40,0)");
var tree = d3.cluster()
.size([height, width - 160]);
var stratify = d3.stratify()
.parentId(function(d) { return d.id.substring(0, d.id.lastIndexOf(".")); });
d3.csv("test.csv", function(error, data) {
if (error) throw error;
var root = stratify(data)
.sort(function(a, b) { return (a.height - b.height) || a.id.localeCompare(b.id); });
tree(root);
var link = g.selectAll(".link")
.data(root.descendants().slice(1))
.enter().append("path")
.attr("class", "link")
.attr("d", function(d) {
return "M" + d.y + "," + d.x
+ "C" + (d.parent.y + 100) + "," + d.x
+ " " + (d.parent.y + 100) + "," + d.parent.x
+ " " + d.parent.y + "," + d.parent.x;
});
var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
node.append("circle")
.attr("r", 2.5);
node.append("text")
.attr("dy", 3)
.attr("x", function(d) { return d.children ? -8 : 8; })
.style("text-anchor", function(d) { return d.children ? "end" : "start"; })
.text(function(d) { return d.id.substring(d.id.lastIndexOf(".") + 1); });
});
</script>
</body>
</html>
and test.csv
id
country
country.USA
country.Canada
country.Russia
country.China
country.India
country.England
country.USA.Wisconsin
country.USA.Wisconsin.Madison
country.USA.Washington DC
country.Canada.Toronto
country.Canada.Ottawa
country.Russia.St Petersburg
country.India.Karnataka
country.India.Maharashtra
country.India.Delhi
country.India.Karnataka.Bangalore
country.India.Karnataka.Bangalore.city
country.India.Karnataka.Bangalore.rural
country.India.Karnataka.Mysore
country.India.Karnataka.Mangalore
country.India.Maharashtra.Mumbai
country.India.Maharashtra.Pune
The resulting output is cutting off the first node, i.e. instead of country, it is displaying just ountry as highlighted in the screenshot below:
How to resolve this? This is just a sample, I have actual csv with the name of the nodes of length 10 Characters. How to auto-adjust the final output.
Your line with the g defined in it, you probably just want to increase the x translation.
g = svg.append("g").attr("transform", "translate(40,0)");
becomes
g = svg.append("g").attr("transform", "translate(60,0)");
This moves the group which contains the entire visualization over some additional pixels. If you want to get clever about it you could actually measure the length of the string "country" and translate by that amount. For example:
const countryText = g.append("g")
.attr("class", "node") //apply all the same classes to ensure css rules match
.append("text")
.text("country");
const width = countryText.node().getComputedTextLength()
g.attr("transform", `translate(${width}, 0)`);
Server Side: A word of warning about measuring strings though. This is only supported in an environment with a browser, which can make server side rendering (or automated tests that use something like Node) very difficult to work with.
If you look at Bostock's code, you can see that he's appending everything to a group, which is being translated 40 pixels to the right:
g = svg.append("g").attr("transform", "translate(40,0)");
Solution: translate more than that:
g = svg.append("g").attr("transform", "translate(50,0)");
Here is your updated bl.ocks: https://bl.ocks.org/anonymous/c873ba1afc1d58a1ea5a13a093468d39

How to make a node of a D3 force directed graph stay at the place after we drag it there

i have a force directed graph where i can show some relationship among some numbers.And we can drag the nodes after releasing the nodes the nodes will come back to the original position.but here i want that i will drag the nodes. Upto here i am able drag all the nodes to some position and the are not coming back to the original position,but i want also the links with them ...
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}
#licensing {
fill: green;
}
.link.licensing {
stroke: green;
}
.link.resolved {
stroke-dasharray: 0, 2 1;
}
circle {
fill: #ccc;
stroke: #333;
stroke-width: 1.5px;
cursor: pointer;
}
text {
font: 10px sans-serif;
pointer-events: none;
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var links = [];
var nodes = {};
// Compute the distinct nodes from the links.
var width = 960, height = 500;
var svg = d3.select("body").append("svg").attr("width", width).attr(
"height", height);
// Per-type markers, as they don't inherit styles.
svg.append("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",
-1.5).attr("markerWidth", 6).attr("markerHeight", 6)
.attr("orient", "auto").append("path").attr("d",
"M0,-5L10,0L0,5");
d3.json(
"test.json",
function(error, directed) {
links=directed.links;
links.forEach(function(link) {
link.source = nodes[link.source]
|| (nodes[link.source] = {
name : link.source
});
link.target = nodes[link.target]
|| (nodes[link.target] = {
name : link.target
});
});
var force = d3.layout.force().nodes(
d3.values(nodes)).links(links).size(
[ width, height ]).linkDistance(60).charge(
-300).on("tick", tick).start();
var path = svg.append("g").selectAll("path").data(
force.links()).enter().append("path").attr(
"class", function(d) {
return "link " + d.type;
}).attr("marker-end", function(d) {
return "url(#" + d.type + ")";
});
var circle = svg.append("g").selectAll("circle")
.data(force.nodes()).enter().append(
"circle").attr("r", 6).call(d3.behavior.drag().origin(function(d) {
return d;
}).on("drag", function(d) {
d.x = d3.event.x, d.y = d3.event.y;
d3.select(this).attr("cx", d.x).attr("cy", d.y);
link.filter(function(l) {
return l.source === d;
}).attr("x1", d.x).attr("y1", d.y);
link.filter(function(l) {
return l.target === d;
}).attr("x2", d.x).attr("y2", d.y);
}));
circle.append("title").text(function(d){
return d.name;
});
var text = svg.append("g").selectAll("text").data(
force.nodes()).enter().append("text").attr(
"x", 8).attr("y", ".31em").text(
function(d) {
return d.name;
});
//selection is happening
var selected = circle.filter(function(d) {
return d.name;
});
selected.each(function(d) {
// d contains the data for the node and this is the circle element
console.log(d.name);
});
var drag = d3.behavior.drag()
.on("drag", function(d,i) {
d.x += d3.event.dx
d.y += d3.event.dy
d3.select(this).attr("transform", function(d,i){
return "translate(" + d.x + "," + d.y + ")";
})
});
var circle = svg.append("g").selectAll("circle")
.data(force.nodes()).enter().append(
"circle").attr("r", 6).on("click",
clickfn).call(drag);
var clickfn = function(circle) {
alert();
}
// Use elliptical arc path segments to doubly-encode directionality.
function tick() {
path.attr("d", linkArc);
circle.attr("transform", transform);
text.attr("transform", transform);
}
function linkArc(d) {
var dx = d.target.x - d.source.x, dy = d.target.y
- d.source.y, dr = Math.sqrt(dx * dx
+ dy * dy);
return "M" + d.source.x + "," + d.source.y
+ "A" + dr + "," + dr + " 0 0,1 "
+ d.target.x + "," + d.target.y;
}
function transform(d) {
return "translate(" + d.x + "," + d.y + ")";
}
});
</script>
this is the test.json
{"links":[{"source":"9804500485","target":"9804086391","type":"licensing"},{"source":"9804500485","target":"8420697490","type":"resolved"},{"source":"9804086391","target":"9804056963","type":"licensing"},{"source":"8420697490","target":"9804086391","type":"suit"},{"source":"9804086391","target":"9874525986","type":"licensing"},{"source":"9804500485","target":"9806895472","type":"resolved"},{"source":"8420697490","target":"9836444045","type":"licensing"},{"source":"9836444045","target":"9804500485","type":"licensing"},{"source":"9804500485","target":"9874525986","type":"licensing"},{"source":"9836444045","target":"9804086391","type":"suit"}]}

Categories