D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
cbuie
Full window
Github gist
KmeansCluster
Built with
blockbuilder.org
<!DOCTYPE html> <head> <meta charset="utf-8"> <script src="https://d3js.org/d3.v3.min.js"></script> <style> body { margin:0; position:fixed; top:0; right:0; bottom:0; left:0; } .input{ width: 100%; padding: 12px 20px; margin: 8px 0; display: inline-block; border: 1px solid #64d7f1; border-radius: 4px; box-sizing: border-box; } .input{ width: 100%; background-color: #ffffff; color: black; padding: 14px 20px; margin: 10px 0; border: 2; border-radius: 4px; } .button { position: relative; background-color: #32b0ea; border: none; font-size: 14px; border-radius: 6px; color: #FFFFFF; padding: 10px; width: 120px; text-align: center; -webkit-transition-duration: 0.4s; /* Safari */ transition-duration: 0.4s; text-decoration: none; overflow: hidden; cursor: pointer; } .button:after { content: ""; background: #f1f1f1; display: block; position: absolute; padding-top: 300%; padding-left: 350%; margin-left: -20px !important; margin-top: -120%; opacity: 0; transition: all 0.8s } .button:active:after { padding: 0; margin: 0; opacity: 1; transition: 0s } </style> </head> <body> <div id="kmeans"> <div> <svg> </svg> </div> <div><button class=button id="step">Iterate</button> <!-- <button class=button id="restart" disabled>Restart</button> --> <button class=button id="reset">Start Over</button></div> </div> <fieldset style="display: inline; margin: .8em 0 1em 0; border: 1px solid #ffffff; padding: .5em"> <div> <label for="N">N (the number of node):</label> <input class=input type="number" id="N" min="2" max="1000" value="500"></div> <div> <label for="K">K (the number of cluster):</label> <input class=input type="number" id="K" min="2" max="50" value="5"> </div> </fieldset> <script> var flag = false; // var WIDTH = d3.select("#kmeans")[0][0].offsetWidth - 20; // var HEIGHT = Math.max(300, WIDTH * .7); var WIDTH = 800; var HEIGHT = 400; var svg = d3.select("#kmeans svg") .attr('width', WIDTH) .attr('height', HEIGHT) .style('padding', '10px') .style('background', '#ffffff') .style('cursor', 'pointer') .on('click', function() { d3.event.preventDefault(); step(); }); d3.selectAll("#kmeans button") .style('padding', '.5em .8em'); d3.selectAll("#kmeans label") .style('display', 'inline-block') .style('width', '15em'); var lineg = svg.append('g'); var dotg = svg.append('g'); var centerg = svg.append('g'); d3.select("#step") .on('click', function() { step(); draw(); }); d3.select("#restart") .on('click', function() { restart(); draw(); }); d3.select("#reset") .on('click', function() { init(); draw(); }); var groups = [], dots = []; function step() { d3.select("#restart").attr("disabled", null); if (flag) { moveCenter(); draw(); } else { updateGroups(); draw(); } flag = !flag; } function init() { d3.select("#restart").attr("disabled", "disabled"); var N = parseInt(d3.select('#N')[0][0].value, 10); var K = parseInt(d3.select('#K')[0][0].value, 10); groups = []; for (var i = 0; i < K; i++) { var g = { dots: [], color: 'hsl(' + (i * 360 / K) + ',100%,50%)', center: { x: Math.random() * WIDTH, y: Math.random() * HEIGHT }, init: { center: {} } }; g.init.center = { x: g.center.x, y: g.center.y }; groups.push(g); } dots = []; flag = false; for (i = 0; i < N; i++) { var dot ={ x: Math.random() * WIDTH, y: Math.random() * HEIGHT, group: undefined }; dot.init = { x: dot.x, y: dot.y, group: dot.group }; dots.push(dot); } } function restart() { flag = false; d3.select("#restart").attr("disabled", "disabled"); groups.forEach(function(g) { g.dots = []; g.center.x = g.init.center.x; g.center.y = g.init.center.y; }); for (var i = 0; i < dots.length; i++) { var dot = dots[i]; dots[i] = { x: dot.init.x, y: dot.init.y, group: undefined, init: dot.init }; } } function draw() { var circles = dotg.selectAll('circle') .data(dots); circles.enter() .append('circle'); circles.exit().remove(); circles .transition() .duration(500) .attr('cx', function(d) { return d.x; }) .attr('cy', function(d) { return d.y; }) .attr('fill', function(d) { return d.group ? d.group.color : '#a1a4af'; }) .attr('r', 4); if (dots[0].group) { var l = lineg.selectAll('line') .data(dots); var updateLine = function(lines) { lines .attr('x1', function(d) { return d.x; }) .attr('y1', function(d) { return d.y; }) .attr('x2', function(d) { return d.group.center.x; }) .attr('y2', function(d) { return d.group.center.y; }) .attr('stroke', function(d) { return d.group.color; }); }; updateLine(l.enter().append('line')); updateLine(l.transition().duration(500)); l.exit().remove(); } else { lineg.selectAll('line').remove(); } var c = centerg.selectAll('path') .data(groups); var updateCenters = function(centers) { centers .attr('transform', function(d) { return "translate(" + d.center.x + "," + d.center.y + ") rotate(0)";}) .attr('fill', function(d,i) { return d.color; }) .attr('stroke', '#000000'); }; c.exit().remove(); updateCenters(c.enter() .append('path') .attr('d', d3.svg.symbol().type('circle').size(function(d) { return (10 * 10); })) .attr('stroke', '#ffffff')); updateCenters(c .transition() .duration(500));} function moveCenter() { groups.forEach(function(group, i) { if (group.dots.length == 0) return; // get center of gravity var x = 0, y = 0; group.dots.forEach(function(dot) { x += dot.x; y += dot.y; }); group.center = { x: x / group.dots.length, y: y / group.dots.length }; }); } function updateGroups() { groups.forEach(function(g) { g.dots = []; }); dots.forEach(function(dot) { // find the nearest group var min = Infinity; var group; groups.forEach(function(g) { var d = Math.pow(g.center.x - dot.x, 2) + Math.pow(g.center.y - dot.y, 2); if (d < min) { min = d; group = g; } }); // update group group.dots.push(dot); dot.group = group; }); } init(); draw(); </script> </body>
https://d3js.org/d3.v3.min.js