Skip to content

Instantly share code, notes, and snippets.

@Mbrownshoes
Created March 14, 2018 20:37
Show Gist options
  • Save Mbrownshoes/86c6996626d9ee17e3f7adebd99022e9 to your computer and use it in GitHub Desktop.
Save Mbrownshoes/86c6996626d9ee17e3f7adebd99022e9 to your computer and use it in GitHub Desktop.
ForceMagnetic based Hierarchical Orbits
license: mit

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.

forked from vasturiano's block: ForceMagnetic based Hierarchical Orbits

<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: 6, 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