Public
Edited
Mar 31
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// A simple Particle class
class MintParticle {
constructor(p5, position) {
this.p5 = p5;
this.acceleration = this.p5.createVector(0, 0.1);
this.velocity = this.p5.createVector(this.p5.random(-1.8, 1.8), this.p5.random(-1, 0)); // Spread wide
this.position = position.copy();
this.lifespan = 255 * 1.5;

let cycleMintTrillion = mintingIcpPerSec * icpXdrRate;
let icpMint = mintingIcpPerSec;

if (toggleIcp) {
this.particleInterval = 1000 / icpMint; // When icpToggle is True
} else {
this.particleInterval = 1000 / cycleMintTrillion; // When icpToggle is False
}

this.lastParticleTime = 0; // Time the particle was last produced
}

run() {
this.update();
this.display();
this.generateParticles(); // Call for particle generation
}

// Control logic for particle generation
generateParticles() {
let currentTime = this.p5.millis();
// Generates a particle every X seconds
if (currentTime - this.lastParticleTime > this.particleInterval) {
this.lastParticleTime = currentTime; // Last generation time updated
return new MintParticle(this.p5, this.position); // Return new particles
}
return null; // Returns null if it is not yet time to generate
}

// Methods to update position
update() {
this.velocity.add(this.acceleration);
this.position.add(this.velocity);
this.lifespan -= 1;
}

// Drawing Methods
display() {
this.p5.stroke(200, this.lifespan);
this.p5.strokeWeight(2);
this.p5.fill(40,10,255, this.lifespan);
this.p5.ellipse(this.position.x, this.position.y, 16, 16);
}

// Methods to check if particles are dead
isDead() {
return this.lifespan < 0;
}
}
Insert cell
class MintParticleSystem {
constructor(p5, position) {
this.p5 = p5;
this.origin = position.copy();
this.particles = [];
this.particleGenerator = new MintParticle(this.p5, this.origin); // Particle for generation management
}

addParticle() {
let newParticle = this.particleGenerator.generateParticles(); // Check if it is possible to generate
if (newParticle !== null) {
this.particles.push(newParticle); // Added only when new particles are generated
}
}

run() {
this.particles = this.particles.filter(particle => {
particle.run();
return !particle.isDead();
});
}
}
Insert cell
// A simple Particle class
class BurnParticle {
constructor(p5, position) {
this.p5 = p5;
this.acceleration = this.p5.createVector(0, 0.03);
this.velocity = this.p5.createVector(this.p5.random(-1, 1), this.p5.random(-5, -5)); // Spread wide
this.position = position.copy();
this.lifespan = 255 * 0.6;

let cycleBurnRate = fetchCycleBurnRateForImage.valueNow;
let cycleBurnTrillion = cycleBurnRate / 1000000000000;
let icpBurn = cycleBurnTrillion / icpXdrRate;
if (toggleIcp) {
this.particleInterval = 1000 / icpBurn; // When icpToggle is True
} else {
this.particleInterval = 1000 / cycleBurnTrillion; // When icpToggle is False
}
this.lastParticleTime = 0; // Time the particle was last produced
}

run() {
this.update();
this.display();
this.generateParticles(); // Call for particle generation
}

// Control logic for particle generation
generateParticles() {
let currentTime = this.p5.millis();
// Generates a particle every X seconds
if (currentTime - this.lastParticleTime > this.particleInterval) {
this.lastParticleTime = currentTime; // Last generation time updated
return new BurnParticle(this.p5, this.position); // Return new particles
}
return null; // Returns null if it is not yet time to generate
}

// Methods to update position
update() {
this.velocity.add(this.acceleration);
this.position.add(this.velocity);
this.lifespan -= 1;
}

// Drawing Methods
display() {
this.p5.stroke(200, this.lifespan);
this.p5.strokeWeight(2);
this.p5.fill(225,25,25, this.lifespan);
this.p5.ellipse(this.position.x, this.position.y, 16, 16);
}

// Methods to check if particles are dead
isDead() {
return this.lifespan < 0;
}
}

Insert cell
class BurnParticleSystem {
constructor(p5, position) {
this.p5 = p5;
this.origin = position.copy();
this.particles = [];
this.particleGenerator = new BurnParticle(this.p5, this.origin); // Particle for generation management
}

addParticle() {
let newParticle = this.particleGenerator.generateParticles(); // Check if it is possible to generate
if (newParticle !== null) {
this.particles.push(newParticle); // Added only when new particles are generated
}
}

run() {
this.particles = this.particles.filter(particle => {
particle.run();
return !particle.isDead();
});
}
}

Insert cell
// Generating count
cycleBurnPerSec = Generators.observe(change => {

// Set the latest value retrieved from the API
let valueSecondsAgo = fetchCycleBurnRateForDigit.valueSecondsAgo; // Use results from other cells
let valueNow = fetchCycleBurnRateForDigit.valueNow; // Use results from other cells

let valueGap = valueNow - valueSecondsAgo;
let loadTimeInterval = 10;

const interval = setInterval(() => {
// Rounding and updating changes in value
valueSecondsAgo += valueGap / loadTimeInterval / 100;

// Rounded to the nearest whole number
const roundedValue = Math.round(valueSecondsAgo);

// Notification of rounded values
change(roundedValue);
}, 10);

// Cleanup when a cell is disabled
return () => clearInterval(interval);
});
Insert cell
fetchCycleBurnRateForDigit = Generators.observe(change => {
let valueSecondsAgo = 0; // Set 0 as initial value
let valueNow = 0; // Current Value
let isFirstFetch = true; // Flag to check if it is the first time or not

const fetchData = async () => {
const response = await fetch("https://ic-api.internetcomputer.org/api/v3/metrics/cycle-burn-rate?step=7200&format=json");
const data = await response.json();
let cycleBurnRate = parseFloat(data.cycle_burn_rate[0][1]);

// Rounded to the nearest whole number.
cycleBurnRate = Math.round(cycleBurnRate);

if (isFirstFetch) {
// First time, valueSecondsAgo is set randomly between 99.9% and 100.1% of valueNow
const randomFactor = 0.999 + Math.random() * 0.002; // Random value between 0.999 and 1.001
valueSecondsAgo = Math.round(cycleBurnRate * randomFactor);
isFirstFetch = false; // Reset the "first" flag
} else {
// Overwrite old value with valueSecondsAgo
valueSecondsAgo = valueNow;
}

// Set new value to valueNow
valueNow = cycleBurnRate;

// Notification of changes
change({ valueNow, valueSecondsAgo });
};

// Initial acquisition
fetchData();

// Perform API requests every millisecond
const interval = setInterval(fetchData, 10000);

// Cleanup when a cell is disabled
return () => clearInterval(interval);
});

Insert cell
// Makes an API request every millisecond and updates its value
fetchCycleBurnRateForImage = Generators.observe(change => {
let valueSecondsAgo = 0; // Set 0 as initial value
let valueNow = 0; // Current Value

const fetchData = async () => {
const response = await fetch("https://ic-api.internetcomputer.org/api/v3/metrics/cycle-burn-rate?step=7200&format=json");
let data = await response.json();
let cycleBurnRate = parseFloat(data.cycle_burn_rate[0][1]);

// Rounded to the nearest whole number.
cycleBurnRate = Math.round(cycleBurnRate);

// Overwrite old value with valueSecondsAgo
valueSecondsAgo = valueNow;

// Set new value to valueNow
valueNow = cycleBurnRate;

// Notification of changes
change({ valueNow, valueSecondsAgo });
};

// Initial acquisition
fetchData();

// Perform API requests every millisecond
const interval = setInterval(fetchData, 120000);

// Cleanup when a cell is disabled
return () => clearInterval(interval);
});

Insert cell
icpXdrRate = Generators.observe(change => {

let icpXdrRate = 6; // Set 6 as the initial value
const fetchData = async () => {
const response = await fetch("https://ic-api.internetcomputer.org/api/v3/icp-xdr-conversion-rates?step=600&format=json");
const data = await response.json();
const newRate = parseFloat(data.icp_xdr_conversion_rates[0][1]);

// To the nearest ten thousandth of a value.
change(newRate / 10000);
};

// Initial acquisition
fetchData();
// API requests are executed every millisecond
const interval = setInterval(fetchData, 600000);
// Cleanup when a cell is disabled
return () => clearInterval(interval);
});

Insert cell
// This cell is copied from https://observablehq.com/@tmcw/p5. Thank you @tmcw.

function* p5(sketch) {
const element = DOM.element('div');

yield element;

const instance = new P5(sketch, element, true);
try {
while (true) {
yield element;
}
} finally {
instance.remove();
}
}
Insert cell
P5 = require('https://unpkg.com/p5@1.2.0/lib/p5.js')
Insert cell
toggleIcp
Insert cell
mintingIcpPerSec = (disbursed_voting_rewards_last_month + node_provider_rewards_last_month) / (days_in_month * 24 * 60 * 60);
Insert cell
Insert cell
// Mar 2025
days_in_month = 31
Insert cell
// Mar 2025
disbursed_voting_rewards_last_month = 617626
Insert cell
// Mar 2025
node_provider_rewards_last_month = 336284
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