nothing to read here..
forked from dwoltjer's block: Force-Directed Scatterplot
xxxxxxxxxx
<meta charset="utf-8">
<style>
body {
font: 14px sans-serif;
}
path,
.xaxis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
path,
.yaxis line {
fill: none;
stroke: none;
shape-rendering: crispEdges;
}
.dot {
stroke: #000;
stroke-opacity: .7;
fill-opacity: .7;
}
/*start gridlines*/
.grid .tick {
stroke: lightgrey;
opacity: 0.7;
}
.grid path {
stroke-width: 0;
}
/* end gridlines */
#controls {
font-size: 14px;
position: absolute;
top: 20px;
left: 80px;
}
input {
margin: 4px 4px 0;
}
div.tooltip {
position: absolute;
text-align: center;
width: 150px;
height: 30px;
padding: 5px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
</style>
<body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
padding = 1, // separation between nodes
radius = 6;
var formatAsPercentage = d3.format("%");
var formatAsPercentageOneDec = d3.format(",.1%");
var formatAsInteger = d3.format("0");
var x = d3.scale.linear() // transformatie van range naar pixels
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x) // uitrekken schaal, labels en punten
.orient("bottom") // positie as labels
.tickFormat(function(d, i) {
if (d == 0) { return "variabel" ;}
else { return d + " jaar" ;}
});
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5)
.tickFormat(formatAsPercentage);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var controls = d3.select("body").append("label")
.attr("id", "controls");
var checkbox = controls.append("input")
.attr("id", "collisiondetection")
.attr("type", "checkbox")
.attr("checked", "true");
controls.append("span")
.text("...");
var checkbox2 = controls.append("input")
.attr("id", "changexvar")
.attr("type", "button");
controls.append("span")
.text("Wissel marktwaarde / looptijd");
d3.csv("data_tsv2.csv", function(error, data) {
var xVar = "looptijd",
yVar = "rente";
data.forEach(function(d) {
d[xVar] = +d[xVar];
d[yVar] = +d[yVar];
});
var force = d3.layout.force()
.nodes(data)
.size([width, height])
.on("tick", tick)
.charge(-5)
.gravity(0)
.chargeDistance(20);
//x.domain(d3.extent(data, function(d) { return d[xVar]; })).nice();
x.domain([-2,32]);
//y.domain(d3.extent(data, function(d) { return d[yVar]; })).nice();
y.domain([0, d3.max(data, function(d) { return d[yVar]; }) * 1.2])
// Set initial positions
data.forEach(function(d) {
//d.x = x(d[xVar]);
//d.y = y(d[yVar]);
//d.x = x(-1);
//d.y = y(-1);
d.color = color(d.bank);
d.radius = radius;
});
svg.append("g")
.attr("class", "xaxis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("id", "x-as")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text("looptijd");
svg.append("g")
.attr("class", "yaxis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("rente")
svg.append("g")
.attr("class", "grid")
.call(yAxis
.tickSize(-width, 0, 0)
.tickFormat("")
)
var node = svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", radius)
.attr("cx", function(d) { return x(d[xVar]); })
.attr("cy", function(d) { return y(d[yVar]); })
.style("fill", function(d) { return d.color; })
.attr("data-bank", function (d) {
return d.bank;
})
.style("opacity", 1)
.on("mouseover", function(d) {
div.transition()
.duration(200)
.style("opacity", .9);
div
.html("<strong>" + d.bank + "</strong>, " +
d.looptijd + " jaar, " + formatAsPercentageOneDec(d.rente) +
",</br>NHG = " + d.nhg + ", MWtm = " + formatAsPercentage(d.mw_tm))
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY) - 50 + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color)
.on("click", function (d) {
node.filter(function () {
return this.dataset.bank === d;
})
.transition().duration(750)
.style("opacity", function () {
console.log(this.style.opacity);
return (parseInt(this.style.opacity)) ? 0 : 1;
});
});
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
d3.select("#collisiondetection").on("change", function() {
force.resume();
});
///////////////////////
d3.select("#changexvar").on("click", function() {
if (xVar == "looptijd") {
xVar = "mw_tm";
d3.select('#x-as')
.text("% van de marktwaarde");
x.domain([0.5,1.2]); // herschalen van de punten
xAxis.tickFormat(formatAsPercentage);
svg.select(".xaxis")
.transition().duration(1000).ease("sin-in-out") // https://github.com/mbostock/d3/wiki/Transitions#wiki-d3_ease
.call(xAxis);
} else {
xVar = "looptijd";
d3.select('#x-as').text("looptijd");
x.domain([-2,32]);
xAxis.tickFormat(function(d, i) {
if (d == 0) { return "variabel" ;}
else { return d + " jaar" ;}
})
svg.select(".xaxis")
.transition().duration(1000).ease("sin-in-out") // https://github.com/mbostock/d3/wiki/Transitions#wiki-d3_ease
.call(xAxis);
};
force.resume();
});
force.start();
function tick(e) {
node.each(moveTowardDataPosition(e.alpha));
if (checkbox.node().checked) node.each(collide(e.alpha));
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
function moveTowardDataPosition(alpha) {
return function(d) {
d.x += (x(d[xVar]) - d.x) * 0.1 * alpha;
d.y += (y(d[yVar]) - d.y) * 0.1 * alpha;
};
}
// Resolve collisions between nodes.
function collide(alpha) {
var quadtree = d3.geom.quadtree(data);
return function(d) {
var r = d.radius + radius + padding,
nx1 = d.x - r,
nx2 = d.x + r,
ny1 = d.y - r,
ny2 = d.y + r;
quadtree.visit(function(quad, x1, y1, x2, y2) {
if (quad.point && (quad.point !== d)) {
var x = d.x - quad.point.x,
y = d.y - quad.point.y,
l = Math.sqrt(x * x + y * y),
r = d.radius + quad.point.radius + (d.color !== quad.point.color) * padding;
if (l < r) {
l = (l - r) / l * alpha;
d.x -= x *= l;
d.y -= y *= l;
quad.point.x += x;
quad.point.y += y;
}
}
return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
});
};
}
});
</script>
Modified http://d3js.org/d3.v3.min.js to a secure url
https://d3js.org/d3.v3.min.js