Public
Edited
Dec 4, 2023
Insert cell
Insert cell
{
let a = 0.2;
let circles = layout(a);
const context = DOM.context2d(width, height);

const timer = d3.timer(() => {
context.save();
context.clearRect(0, 0, width, height);
context.translate(width / 2, height / 2);
context.rotate(Math.sin(Date.now() / 10000));
context.translate(-width / 2, -height / 2);
context.beginPath();
for (let i = 0; i < n; ++i) {
let move = true;
d3.pairs(circles, (
{x: x1, y: y1, r: r1, a: a1},
{x: x2, y: y2, r: r2, a: a2}
) => {
const ai = (i * 2) / n * Math.PI;
context[move ? (move = false, "moveTo") : "lineTo"](...point(x1, y1, r1, a1 + ai));
context.lineTo(...point(x2, y2, r2, a2 + ai));
});
d3.pairs(circles.slice().reverse(), (
{x: x1, y: y1, r: r1, a: a1},
{x: x2, y: y2, r: r2, a: a2}
) => {
const ai = (i * 2 + 1) / n * Math.PI;
context.lineTo(...point(x1, y1, r1, a1 + ai));
context.lineTo(...point(x2, y2, r2, a2 + ai));
});
context.closePath();
}
context.fill();
context.restore();
});

const interval = d3.interval(() => {
d3.transition().duration(4000).tween("circles", () => {
const i = d3.interpolate(circles, layout(a = -a));
return t => circles = i(t);
});
}, 5000, d3.now() - 4000);

invalidation.then(() => timer.stop());
invalidation.then(() => interval.stop());

return context.canvas;
}
Insert cell
function layout(a) {
let x = width / 2;
let y = height / 2;
let r = Math.min(width, height) / 2;
let dr = r / 6.5;
const circles = [];
while (r > 0) {
circles.push({x, y, r, a});
const t = Math.random() * 2 * Math.PI;
const s = Math.sqrt(Math.random() * dr * dr / 4);
x += Math.cos(t) * s;
y += Math.sin(t) * s;
r -= dr;
a = -a;
}
return circles;
}
Insert cell
point = (cx, cy, r, a) => ([cx + r * Math.cos(a), cy + r * Math.sin(a)])
Insert cell
n = 80
Insert cell
height = Math.min(640, width)
Insert cell
d3 = require("d3@5")
Insert cell
loadAndParseGPX = async () => {
// Access the contents of the GPX file
const gpxContent = await fieldStudy1.text();

// Parse the GPX data
const gpxData = parse(gpxContent);

// Extract information from the parsed GPX data
const trackPoints = gpxData.tracks.flatMap(track => track.segments.flatMap(segment => segment.points));

return trackPoints;
};

Insert cell
loadAndParseGPX().then(trackPoints => {
trackPoints.forEach(point => {
console.log(`Latitude: ${point.lat}, Longitude: ${point.lon}`);
});

});
Insert cell
fieldStudy1 = FileAttachment("2023-09-20 field study@1.gpx")
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