Public
Edited
Sep 21, 2023
1 fork
24 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function earth_venus_anim() {
let w = width < 700 ? width : 700;
let h = w;
let div = d3
.create('div')
.style('width', `${w}px`)
.style('height', `${h + 30}px`);

let running = true;
let interval_id;
let controls = div
.append('div')
.style('width', `${300}px`)
.style('height', `${30}px`);
let start_stop_button = controls
.append('div')
.style('display', 'inline-block')
.append('button')
.on('click', function() {
if (running) {
running = false;
clearInterval(interval_id);
d3.select(this).html('start');
} else {
running = true;
start();
d3.select(this).html('stop');
}
})
.html('stop');
controls
.append('div')
.style('display', 'inline-block')
.append('button')
.on('click', setup)
.html('reset');

let container = div
.append('div')
.style('position', 'relative')
.style('width', `${w}px`)
.style('height', `${h}px`);
let pad = 10;
let canvas = container
.append('canvas')
.attr('width', w)
.attr('height', h)
.style('position', 'absolute')
.style('top', 0)
.style('left', 0);
let context = canvas.node().getContext('2d');
let svg = container
.append('svg')
.attr('width', w)
.attr('height', h)
.style('position', 'absolute')
.style('top', 0)
.style('left', 0);

let bb = 1;
let xmin = -bb;
let xmax = bb;
let ymin = -bb;
let ymax = bb;
let xScale = d3
.scaleLinear()
.domain([xmin, xmax])
.range([pad, w - pad]);
let yScale = d3
.scaleLinear()
.domain([ymin, ymax])
.range([h - pad, pad]);
let rScale = d3
.scaleLinear()
.domain([0, xmax - xmin])
.range([0, w - 2 * pad]);

let T, earth, venus, connect;
function setup() {
if (running) {
running = false;
clearInterval(interval_id);
start_stop_button.html('start');
}
context.clearRect(0, 0, w, h);
T = 0;
context.beginPath();
context.lineWidth = 2;
context.strokeStyle = "rgba(0,0,0, 1)";
context.moveTo(xScale(1), yScale(0));
context.arc(xScale(0), yScale(0), rScale(1), 0, 2 * Math.PI);
context.stroke();
context.closePath();

context.beginPath();
context.lineWidth = 2;
context.strokeStyle = "rgba(0,0,0, 1)";
context.moveTo(xScale(0) + oscale * rScale(vr), yScale(0));
context.ellipse(
xScale(0),
yScale(0),
oscale * rScale(vr),
rScale(vr),
0,
0,
2 * Math.PI
);
context.stroke();
context.closePath();

context.beginPath();
context.lineWidth = 1;
context.moveTo(xScale(1), yScale(0));
context.lineTo(xScale(vr), yScale(0));
context.strokeStyle = "rgba(0,0,0, 0.1)";
context.stroke();
context.closePath();

svg.selectAll('line').remove();
connect = svg
.append('line')
.style('stroke', 'black')
.style('stroke-width', '2');
svg.selectAll('circle').remove();
earth = svg
.append('circle')
.attr('id', 'earth')
.attr('cx', xScale(1))
.attr('cy', yScale(0))
.attr('r', rScale(0.025))
.attr('fill', 'blue');
venus = svg
.append('circle')
.attr('id', 'venus')
.attr('cx', xScale(0) + oscale * rScale(vr))
.attr('cy', yScale(0))
.attr('r', rScale(0.015))
.attr('fill', 'red');
svg
.append('circle')
.attr('cx', xScale(0))
.attr('cy', yScale(0))
.attr('r', rScale(0.1))
.attr('fill', function() {
if (math.evaluate(vspeed) == 1) {
return 'black';
} else {
return '#efef00';
}
})
.attr('stroke-width', 3)
.attr('stroke', function() {
if (math.evaluate(vspeed) == 1) {
return 'black';
} else {
return '#dd0';
}
});
}

function start() {
let t = T;
let s = math.evaluate(vspeed);
let step = Math.PI / 400;
running = true;
interval_id = setInterval(function() {
if (running) {
let ep = earth_position(t);
let vp = venus_position(s, t);
earth.attr('cx', xScale(ep[0])).attr('cy', yScale(ep[1]));
venus.attr('cx', xScale(vp[0])).attr('cy', yScale(vp[1]));
connect
.attr('x1', xScale(ep[0]))
.attr('y1', yScale(ep[1]))
.attr('x2', xScale(vp[0]))
.attr('y2', yScale(vp[1]));
context.beginPath();
context.lineWidth = 1;
context.strokeStyle = "rgba(0,0,0, 0.1)";
context.moveTo(xScale(ep[0]), yScale(ep[1]));
context.lineTo(xScale(vp[0]), yScale(vp[1]));
context.stroke();
context.closePath();
t = t + step;
T = t;
}
}, 20);
}

setup();
start();
start_stop_button.text('stop');
return div.node();
}
Insert cell
function earth_position(t) {
return [Math.cos(2*Math.PI*t), Math.sin(2*Math.PI*t)]
}
Insert cell
oscale = {
if (math.evaluate(vspeed) == 1) {
return 0.85;
} else {
return 1;
}
}
Insert cell
function venus_position(s, t) {
return [
oscale * vr * Math.cos(2 * Math.PI * t * s),
vr * Math.sin(2 * Math.PI * t * s)
];
}
Insert cell
Insert cell
import { Range, Text } from "@observablehq/inputs"
Insert cell
math = require('mathjs@7.6.0')
Insert cell
d3 = require('d3-selection@2', 'd3-scale@3', 'd3-shape@2')
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more