class SolarSystem {
run({svg, height, width, timer}) {
const radius = planetSize;
this._bodies = [
new Body({radius, translationRadius: 0, translationPeriodInSecs: 0, color: '#ffe942'}),
new Body({radius, translationRadius: 35, translationPeriodInSecs: 88, color: '#8a8781'}),
new Body({radius, translationRadius: 67, translationPeriodInSecs: 225, color: '#edce8c'}),
new Body({radius, translationRadius: 92, translationPeriodInSecs: 365, color: '#5279c7'}),
new Body({radius, translationRadius: 141, translationPeriodInSecs: 687, color: '#d9721e'}),
new Body({radius, translationRadius: 483, translationPeriodInSecs: 4300, color: '#91543c'}),
new Body({radius, translationRadius: 890, translationPeriodInSecs: 11000, color: '#87794c'}),
new Body({radius, translationRadius: 1784, translationPeriodInSecs: 31000, color: '#7d9cb0'}),
]
const orbitsContainer = svg.append("g");
this.renderOrbits({orbitsContainer, height, width});
const bodiesContainer = svg.append("g");
this.renderBodies({bodiesContainer, height, width, timer});
}
renderOrbits({orbitsContainer, height, width}) {
const scaleFactor = this.getDistanceScaleFactor({height, width});
const data = this._bodies.map(body => {
const radius = body.getTranslationRadius();
return {r: radius * scaleFactor};
});
const offsetY = height / 2;
const offsetX = width / 2;
const circle = orbitsContainer.selectAll("circle").data(data);
circle.enter().append("circle")
.attr("r", row => row.r)
.attr("cx", row => offsetX)
.attr("cy", row => offsetY)
.attr("fill", 'none')
.attr("stroke", "white")
.attr("stroke-opacity", "0.5")
.attr("stroke-dasharray", "1 4");
}
getDistanceScaleFactor({height, width}) {
// Scale radius to fit on screen
const maxTranslationRadius = Math.max(
...this._bodies.map(body => body.getTranslationRadius())
);
// Multiply by 0.9 to add some margin
return Math.min(height, width)*0.9 / (2.0 * maxTranslationRadius);
}
renderBodies(params) {
const {bodiesContainer, height, width, timer} = params;
const scaleFactor = this.getDistanceScaleFactor({height, width});
// Scale time so that 1 min elapsed is a full orbit of the slowest planet.
const maxPeriod = Math.max(
...this._bodies.map(body => body.getPeriod())
);
const periodScaleFactor = maxPeriod / 10000.0;
const offsetY = height / 2;
const offsetX = width / 2;
const data = this._bodies.map(body => {
const {x, y} = body.getPosition(timer * periodScaleFactor);
const radius = body.getRadius();
const pixelY = y * scaleFactor + offsetY;
const pixelX = x * scaleFactor + offsetX;
return {r: body.getRadius(), cx: pixelX, cy: pixelY, color: body.getColor()};
});
const circle = bodiesContainer.selectAll("circle").data(data);
// Adding new circles
circle.enter().append("circle")
.attr("r", row => row.r)
.attr("cx", row => row.cx)
.attr("cy", row => row.cy)
.attr("fill", row => row.color);
// Updating
circle.transition()
.attr("cx", row => row.cx)
.attr("cy", row => row.cy);
}
};