Published
Edited
Mar 24, 2021
2 forks
Importers
40 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
circles = {
replay; // triggers a re-rendering using the button above

// Create your svg
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height);

// Add circles, and transition their radius with a delay based on their index in the array
const circles = svg
.selectAll("circle")
.data(circle_data)
.join("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.style("opacity", .2)
.transition()
.delay((d, i) => i * 10)
.attr("r", d => d.r);
return svg.node();
}
Insert cell
Insert cell
Insert cell
// Rewrite our code above to return a function
render = () => {
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height);

// Add a white background rectangle
svg
.append("rect")
.attr("width", width)
.attr("height", height)
.attr("fill", "white")
.attr("stroke", "none");

// Add the circles (don't set the radius yet)
const circles = svg
.selectAll("circle")
.data(circle_data)
.join("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.style("opacity", .2);

// Return a function that takes in t and returns the node
return t => {
circles.attr("r", d => d.r * t); // Set the radius based on t, which will go from 0 to 1
return svg.node();
};
}
Insert cell
Insert cell
{
await visibility(); // wait until the cell is visible
const draw = render(); // return the drawing function from the render() method
return renderGif(invalidation, draw, 1000, { preview: draw(0), pause: 1000 }); // render the gif
}
Insert cell
Insert cell
// Rewrite our code above to return a function
delay_render = () => {
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height);

// Add a white background rectangle
svg
.append("rect")
.attr("width", width)
.attr("height", height)
.attr("fill", "white")
.attr("stroke", "none");

// Add the circles
const circles = svg
.selectAll("circle")
.data(circle_data)
.join("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.style("opacity", .2);

// Return a function that takes in t and returns the node
return t => {
const total_duration = 1500; // total time of the animation
const circle_duration = 500; // how long for each circle to go from 0 to d.r
const delay = 10; // how long to wait based on the index
circles.attr("r", (d, i) => {
const circle_delay = delay * i; // how long to wait for this particular circle
const time_elapsed = t * total_duration; // how much time (in ms) has passed
const eligible_time = time_elapsed - circle_delay; // time passed after the delay
const r = (d.r * eligible_time) / circle_duration; // proportion of radius to display
return r > d.r ? d.r : r; // if the calculated radius is greater than d.r, return d.r
});
return svg.node();
};
}
Insert cell
{
await visibility(); // wait until the cell is visible
const draw = delay_render(); // return the drawing function from the render() method
return renderGif(invalidation, draw, 1500, { preview: draw(0), pause: 1000 }); // render the gif
}
Insert cell
Insert cell
md`## Appendix`
Insert cell
d3 = require("d3")
Insert cell
_ = require('lodash')
Insert cell
height = 500
Insert cell
import { Button, Range } from "@observablehq/inputs"
Insert cell
circle_data = _.range(100).map(d => ({
x: Math.random() * width,
y: Math.random() * height,
r: Math.random() * 100
}))
Insert cell
html`<style>
p code, h2 code, li code{
color: #c30771;
}

.underline {
text-decoration:underline;
font-weight:bold;
}
</style>`
Insert cell
import { renderGif } from '@mootari/gif'
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more