Skip to content

Instantly share code, notes, and snippets.

@vasturiano
Last active October 22, 2017 04:13
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save vasturiano/5086628299fa6c1bae0094f93d112634 to your computer and use it in GitHub Desktop.
ForceMagnetic based Hierarchical Orbits

Simulation of multiple particles orbitting around each other in a hierarchical system (e.g. sun > planet > moon).

Uses D3's force plugin forceMagnetic to connect particles to their moving gravitational centers via magnetic/electrostatic links. These magnetic attraction forces simulate the mechanics of gravity. Each link holds its own gravitational constant to exaggerate the amplitude and velocity of the orbits relative to each other, which would be otherwise impossible in a system with a single constant.

Compare with the forceLink version.

<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/4.7.0/d3.min.js"></script>
<script src="//unpkg.com/d3-force-magnetic"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<svg id="canvas">
<g id="trails"></g>
<g id="bodies"></g>
</svg>
<script>
const width = window.innerWidth, height = window.innerHeight;
const au = Math.min(width, height) / 4; // Astronomical unit
const gravity = 0.3, // Regulates mechanics speed
bodies = [
{ id: 'sun', mass: 1000, r: 20 },
{ id: 'planet', mass: 10, r: 8, x: 0, y: -au, vx: Math.sqrt(1000 * gravity / au), vy: 0 }, // vx set to orbital speed: sqrt(GM/d)
{ id: 'moon', mass: 0, r: 2, x: 0, y: -au * 1.5, vx: 1.1 * Math.sqrt(10 * (gravity * 500) / (au * 0.5)), vy: 0 }
],
links = [
{ source: 'planet', target: 'sun', attraction: gravity },
{ source: 'moon', target: 'planet', attraction: gravity * 500 } // Higher attraction = more revolutions
];
d3.forceSimulation()
.alphaDecay(0)
.velocityDecay(0)
.nodes(bodies)
.force("gravitate-around", d3.forceMagnetic()
.id(d => d.id)
.charge(node => node.mass)
.strength(link => link.attraction || 0.1)
.links(links)
)
.on("tick", ticked);
// Add orbit trails
d3.timer(() => {
d3.selectAll('g.trail')
.append('circle')
.attr('r', 1.5)
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.transition().duration(5000)
.style('opacity', 0)
.remove();
});
// Size canvas
d3.select('#canvas')
.attr('width', width)
.attr('height', height)
.attr('viewBox', `${-width/2} ${-height/2} ${width} ${height}`);
//
function ticked() {
var body = d3.select('#bodies').selectAll('.body')
.data(bodies);
body.exit().remove();
body.merge(
body.enter().append('circle')
.attr('class', 'body')
.attr('id', d => d.id)
.attr('r', d => d.r)
)
.attr('cx', d => d.x)
.attr('cy', d => d.y);
// Add trail elements
var trails = d3.select('#trails').selectAll('.trail')
.data(bodies);
trails.exit().remove();
trails.enter().append('g').attr('class', 'trail');
}
</script>
</body>
body {
text-align: center;
font-family: Sans-serif;
margin: 0;
}
#sun {
fill: #ff4e2d;
}
#planet {
fill: #203390;
}
#moon {
fill: slategrey;
}
#trails circle {
fill: darkgrey;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment