D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
almccon
Full window
Github gist
galaxy
Built with
blockbuilder.org
<!DOCTYPE html> <head> <meta charset="utf-8"> <script src="d3.v3.min.js"></script> <script src="d3.slider.js"></script> <link rel="stylesheet" href="d3.slider.css" /> <style> body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0;background:black;color:white;font: 10px sans-serif; } path#spiral1fixed, path#spiral2fixed, path#spiral1, path#spiral2 { fill: none; stroke: #222; //stroke: none; stroke-width: 3px; } path#spiral1fixed, path#spiral2fixed { display: none; } svg { float: left; } </style> </head> <body> <script> var width = 500, height = 300 start = 0 // for the spiral end = 2; // for the spiral var center = { x: width/2, y: height/2}; var dotWidth = d3.min([width,height])/50; // size of dots relative to view var step = dotWidth * 3; // spacing relative to dot size var offset = 42; //initial step var numDots = 7; var numDotsMax = 50; var decay = 1; // to make the dots smaller after each step var centralRatio = 2; // how big the centralDot is relative to other dots var tightness = 1; // how tight the spiral is var rotate = 30; // Initial rotation // for rotating the view in "3d" space var spinAngle = 50; // between -180 and 180 var tiltAngle = 40;//45; // between 0 and 90 var params = { numDots: { value: 7, min: 0, max: numDotsMax, step: 1 }, dotWidth: { // width of dots value: 6, min: 0, max: 100, step: null }, step: { // spacing of dots along arms value: 18, min: 0, max: 100, step: 1 }, offset: { // initial step away from the galactic center value: 42, min: 0, max: 300, step: 1 }, rotate: { // initial rotation of the galaxy on its axis value: 30, min: 0, max: 1800, step: 1 }, spinAngle: { // for rotating the view in "3d" space value: 50, min: 0, max: 90, step: 1 }, tiltAngle: { // for rotating the view in "3d" space value: 40, min: 0, max: 90, step: 1 }, centralRatio: {// how big the centralDot is relative to other dots value: 2, min: 0, max: 5, step: null }, tightness: { // how tight the spiral is value: 1, min: 0, max: 5, step: null }, decay: { // to make the dots smaller after each step value: 1, min: 0, max: 5, step: null } }; // create sliders d3.keys(params).forEach(function(key) { params[key].slider = d3.slider() .axis(d3.svg.axis().ticks(0)) .min(params[key].min) .max(params[key].max) .value(params[key].value) .on("slide", function(evt, value) { console.log("slide",key,value); params[key].value = value; redraw(); }); if (params[key].step) params[key].slider.step(params[key].step); }); var numDotsSlider = d3.slider().axis(d3.svg.axis().ticks(0)).min(0).max(30).step(1).value(numDots); var dotWidthSlider = d3.slider().axis(d3.svg.axis().ticks(0)).min(0).max(100).step(1).value(dotWidth); var stepSlider = d3.slider().axis(d3.svg.axis().ticks(0)).min(0).max(100).step(1).value(step); var offsetSlider = d3.slider().axis(d3.svg.axis().ticks(0)).min(0).max(300).step(1).value(offset); var rotateSlider = d3.slider().axis(d3.svg.axis().ticks(0)).min(0).max(1800).step(1).value(rotate); var spinSlider = d3.slider().axis(d3.svg.axis().ticks(0)).min(0).max(90).step(1).value(spinAngle); var tiltSlider = d3.slider().axis(d3.svg.axis().ticks(0)).min(0).max(90).step(1).value(tiltAngle); var centralSlider = d3.slider().axis(d3.svg.axis().ticks(0)).min(0).max(5).step(null).value(centralRatio); var tightnessSlider = d3.slider().axis(d3.svg.axis().ticks(0)).min(0).max(5).step(null).value(tightness); var decaySlider = d3.slider().axis(d3.svg.axis().ticks(0)).min(0).max(2).step(null).value(decay); var theta = function(r) { return -2*Math.PI*r*params.tightness.value; }; var radius = d3.scale.linear() .domain([start, end]) .range([0, d3.min([width,height])]); var spiralLine1 = d3.svg.line() .x(function(d) { return getGalacticX(d) *(90-spinAngle)/90 // should include cos or sin +(getGalacticY(d)*(tiltAngle)/90); // should include cos or sin }) .y(function(d) { return getGalacticY(d) *(90-tiltAngle)/90; // should include cos or sin }) var spiralLine2 = d3.svg.line() .x(function(d) { return getGalacticX(d, 'left') *(90-spinAngle)/90 // should include cos or sin +(getGalacticY(d, 'left')*(tiltAngle)/90); // should include cos or sin }) .y(function(d) { return getGalacticY(d, 'left') *(90-tiltAngle)/90; // should include cos or sin }) var spiralLineFixed1 = d3.svg.line() .x(function(d) { return getGalacticX(d); }) .y(function(d) { return getGalacticY(d); }) var spiralLineFixed2 = d3.svg.line() .x(function(d) { return getGalacticX(d, 'left'); }) .y(function(d) { return getGalacticY(d, 'left'); }) // GalacticX and GalacticY are relative to a 0,0 at the center of the galaxy getGalacticX = function(d, arm = 'right') { var extraRotation = (arm == 'left') ? 0 : Math.PI; return radius(d)*Math.cos((rotate/180)+extraRotation+theta(d)); } getGalacticY = function(d, arm = 'right') { var extraRotation = (arm == 'left') ? 0 : Math.PI; return radius(d)*Math.sin((rotate/180)+extraRotation+theta(d)); } var values = [...Array(numDotsMax).keys()]; var pieces = d3.range(start, end+0.001, (end-start)/1000); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height); var spiral1 = svg.append("g").selectAll("#spiral1") .data([pieces]) .enter().append("path") .attr("id", "spiral1") .attr("d", spiralLine1) .attr("transform", "translate(" + center.x + "," + center.y +") " ); var spiral2 = svg.append("g").selectAll("#spiral2") .data([pieces]) .enter().append("path") .attr("id", "spiral2") .attr("d", spiralLine2) .attr("transform", "translate(" + center.x + "," + center.y +") " ); var spiral1fixed = svg.append("g").selectAll("#spiral1fixed") .data([pieces]) .enter().append("path") .attr("id", "spiral1fixed") .attr("d", spiralLineFixed1) .attr("transform", "translate(" + center.x + "," + center.y +") " ); var spiral2fixed = svg.append("g").selectAll("#spiral2") .data([pieces]) .enter().append("path") .attr("id", "spiral2fixed") .attr("d", spiralLineFixed2) .attr("transform", "translate(" + center.x + "," + center.y +") " ); // Center dot: var centralDot = svg.append("g") .append("circle") .attr("fill","#ccc") //.attr("fill","none") //.attr("stroke","white") .attr("cx", center.x) .attr("cy", center.y) .attr("r", centralRatio*dotWidth); /* var spiral1Circles = svg.append("g") .selectAll("circle") .attr("class", "circles1") .data(values) .enter() .append("circle") .attr("fill","none") .attr("stroke", function(d,i) { return i < numDots ? "white" : "none"; }) .attr("cx", function(d,i) {return spiral1.node().getPointAtLength(offset+step*i).x;}) .attr("cy", function(d,i) {return spiral1.node().getPointAtLength(offset+step*i).y;}) .attr("r", function(d,i) { var radius = dotWidth - i*decay; return radius > 0 ? radius : 0; }) .attr("transform", "translate(" + center.x + "," + center.y +") " ); var spiral2Circles = svg.append("g") .selectAll("circle") .data(values) .enter() .append("circle") .attr("class", "circles2") .attr("fill","none") .attr("stroke", function(d,i) { return i < numDots ? "white" : "none"; }) .attr("cx", function(d,i) {return spiral2.node().getPointAtLength(offset+step*i).x;}) .attr("cy", function(d,i) {return spiral2.node().getPointAtLength(offset+step*i).y;}) .attr("r", function(d,i) { var radius = dotWidth - i*decay; return radius > 0 ? radius : 0; }) .attr("transform", "translate(" + center.x + "," + center.y +") " ); */ var spiral1CirclesFixed = svg.append("g") .selectAll("circle") .attr("class", "circles1") .data(values) .enter() .append("circle") .attr("fill","none") .attr("stroke", function(d,i) { return i < numDots ? "white" : "none"; }) .attr("cx", function(d,i) { return spiral1fixed.node().getPointAtLength(offset+step*i).x *(90-spinAngle)/90 +(spiral1fixed.node().getPointAtLength(offset+step*i).y*(tiltAngle)/90); }) .attr("cy", function(d,i) { return spiral1fixed.node().getPointAtLength(offset+step*i).y *(90-tiltAngle)/90; }) .attr("r", function(d,i) { var radius = dotWidth - i*decay; return radius > 0 ? radius : 0; }) .attr("transform", "translate(" + center.x + "," + center.y +") " ); var spiral2CirclesFixed = svg.append("g") .selectAll("circle") .data(values) .enter() .append("circle") .attr("class", "circles2") .attr("fill","none") .attr("stroke", function(d,i) { return i < numDots ? "white" : "none"; }) .attr("cx", function(d,i) { return spiral2fixed.node().getPointAtLength(offset+step*i).x *(90-spinAngle)/90 +(spiral2fixed.node().getPointAtLength(offset+step*i).y*(tiltAngle)/90); }) .attr("cy", function(d,i) { return spiral2fixed.node().getPointAtLength(offset+step*i).y *(90-tiltAngle)/90; }) .attr("r", function(d,i) { var radius = dotWidth - i*decay; return radius > 0 ? radius : 0; }) .attr("transform", "translate(" + center.x + "," + center.y +") " ); function redraw() { centralDot.attr("r", centralRatio*dotWidth); spiral1.attr("d", spiralLine1); spiral2.attr("d", spiralLine2); spiral1fixed.attr("d", spiralLineFixed1); spiral2fixed.attr("d", spiralLineFixed2); /* spiral1Circles .attr("stroke", function(d,i) { return i < numDots ? "white" : "none"; }) .attr("r", function(d,i) { var radius = dotWidth - i*decay; return radius > 0 ? radius : 0; }) .attr("cx", function(d,i) {return spiral1.node().getPointAtLength(offset+step*i).x;}) .attr("cy", function(d,i) {return spiral1.node().getPointAtLength(offset+step*i).y;}); spiral2Circles .attr("stroke", function(d,i) { return i < numDots ? "white" : "none"; }) .attr("r", function(d,i) { var radius = dotWidth - i*decay; return radius > 0 ? radius : 0; }) .attr("cx", function(d,i) {return spiral2.node().getPointAtLength(offset+step*i).x;}) .attr("cy", function(d,i) {return spiral2.node().getPointAtLength(offset+step*i).y;}); */ spiral1CirclesFixed .attr("stroke", function(d,i) { return i < numDots ? "white" : "none"; }) .attr("cx", function(d,i) { return spiral1fixed.node().getPointAtLength(offset+step*i).x *(90-spinAngle)/90 +(spiral1fixed.node().getPointAtLength(offset+step*i).y*(tiltAngle)/90); }) .attr("cy", function(d,i) { return spiral1fixed.node().getPointAtLength(offset+step*i).y *(90-tiltAngle)/90; }) .attr("r", function(d,i) { var radius = dotWidth - i*decay; return radius > 0 ? radius : 0; }); spiral2CirclesFixed .attr("stroke", function(d,i) { return i < numDots ? "white" : "none"; }) .attr("cx", function(d,i) { return spiral2fixed.node().getPointAtLength(offset+step*i).x *(90-spinAngle)/90 +(spiral2fixed.node().getPointAtLength(offset+step*i).y*(tiltAngle)/90); }) .attr("cy", function(d,i) { return spiral2fixed.node().getPointAtLength(offset+step*i).y *(90-tiltAngle)/90; }) .attr("r", function(d,i) { var radius = dotWidth - i*decay; return radius > 0 ? radius : 0; }); } numDotsSlider.on("slide", function(evt, value) { numDots = value; redraw(); }); dotWidthSlider.on("slide", function(evt, value) { dotWidth = value; redraw(); }); stepSlider.on("slide", function(evt, value) { step = value; redraw(); }); offsetSlider.on("slide", function(evt, value) { offset = value; redraw(); }); rotateSlider.on("slide", function(evt, value) { rotate = value; redraw(); }); spinSlider.on("slide", function(evt, value) { spinAngle = value; redraw(); }); tiltSlider.on("slide", function(evt, value) { tiltAngle = value; redraw(); }); centralSlider.on("slide", function(evt, value) { centralRatio = value; redraw(); }); tightnessSlider.on("slide", function(evt, value) { tightness = value; redraw(); }); decaySlider.on("slide", function(evt, value) { decay = value; redraw(); }); d3.select("body").append("text").text("numDots").style("width","10%").style("float","left").style("clear","both"); d3.select("body").append("div").call(numDotsSlider).style("width","50%").style("float","left"); d3.select("body").append("text").text("dotWidth").style("width","10%").style("float","left").style("clear","both"); d3.select("body").append("div").call(dotWidthSlider).style("width","50%").style("float","left"); d3.select("body").append("text").text("centerRatio").style("width","10%").style("float","left").style("clear","both"); d3.select("body").append("div").call(centralSlider).style("width","50%").style("float","left"); d3.select("body").append("text").text("step").style("width","10%").style("float","left").style("clear","both"); d3.select("body").append("div").call(stepSlider).style("width","50%").style("float","left"); d3.select("body").append("text").text("decay").style("width","10%").style("float","left").style("clear","both"); d3.select("body").append("div").call(decaySlider).style("width","50%").style("float","left"); d3.select("body").append("text").text("offset").style("width","10%").style("float","left").style("clear","both"); d3.select("body").append("div").call(offsetSlider).style("width","50%").style("float","left"); d3.select("body").append("text").text("tightness").style("width","10%").style("float","left").style("clear","both"); d3.select("body").append("div").call(tightnessSlider).style("width","50%").style("float","left"); d3.select("body").append("text").text("rotate").style("width","10%").style("float","left").style("clear","both"); d3.select("body").append("div").call(rotateSlider).style("width","50%").style("float","left"); d3.select("body").append("text").text("spin").style("width","10%").style("float","left").style("clear","both"); d3.select("body").append("div").call(spinSlider).style("width","50%").style("float","left"); d3.select("body").append("text").text("tilt").style("width","10%").style("float","left").style("clear","both"); d3.select("body").append("div").call(tiltSlider).style("width","50%").style("float","left"); //When I finish with the parameterization: /* d3.keys(params).forEach(function(key) { d3.select("body").append("text").text(key).style("width","10%").style("float","left").style("clear","both"); d3.select("body").append("div").call(params[key].slider).style("width","50%").style("float","left"); }); */ </script> </body>