Public
Edited
Sep 24, 2023
1 fork
8 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
palette1 = utils.random.pick(palettes)
Insert cell
Insert cell
circleAnimation = {
const width = 1200
const height = 300
const ctx = DOM.context2d(width, height);
const numPoints = 200

// Pick a random palette for start and end data
//const palette1 = utils.random.pick(palettes)
const palette2 = utils.random.pick(palettes)

///////////////////////////////
///////// Create Data /////////
///////////////////////////////
const dataStart = _.range(0, numPoints).map(i => ({
id: i,
x: Math.random()*width,
y: Math.random()*height,
r: Math.abs(utils.random.gaussian() * 15),
fill: utils.random.pick(palette1)
}))

const dataEnd = _.range(0, numPoints).map(i => ({
id: i,
x: Math.random()*width,
y: Math.random()*height,
r: Math.abs(utils.random.gaussian() * 20),
fill: utils.random.pick(palette2)
}))

///////////////////////////////
//////// Draw Function ////////
///////////////////////////////
const draw = (data) => {
ctx.fillStyle = 'black'
ctx.fillRect(0, 0, width, height) // Make sure to clear or fill the rect
for (const { x, y, r, fill } of data ) {
ctx.beginPath()
ctx.arc(x, y, r, 0, 2*Math.PI)
ctx.fillStyle = fill
ctx.fill()
}
}
///////////////////////////////
////////// Animation //////////
///////////////////////////////
const animation = gsap.to(dataStart, {
x: (index) => dataEnd[index].x,
y: (index) => dataEnd[index].y,
fill: (index) => dataEnd[index].fill,
r: (index) => dataEnd[index].r,
duration: 3,
ease: ease,
onUpdate: () => draw(dataStart)
})

animation.pause()

///////////////////////////////
//// Control the animation ////
///////////////////////////////
const play = document.querySelector('#play-circles')
const pause = document.querySelector('#pause-circles')
const restart = document.querySelector('#restart-circles')
const reverse = document.querySelector('#reverse-circles')

play.onclick = () => animation.play()
restart.onclick = () => animation.restart()
pause.onclick = () => animation.pause()
reverse.onclick = () => animation.reverse()

// Draw the initial graph
draw(dataStart)

yield ctx.canvas
}
Insert cell
Insert cell
palette3 = utils.random.pick(palettes) // re-run this cell to update colours
Insert cell
viewof numCircles = Inputs.range([5000, 50000], {value: 20000, step: 5000, label: "Number of circles"})
Insert cell
Insert cell
manyCirclesAnimation = {
const width = 1100
const height = 600
const ctx = DOM.context2d(width, height);
const numPoints = numCircles

// Pick a random palette for start and end data
const palette2 = utils.random.pick(palettes)

///////////////////////////////
///////// Create Data /////////
///////////////////////////////
const dataStart = _.range(0, numPoints).map(i => ({
id: i,
x: Math.random()*width,
y: Math.random()*height,
r: Math.abs(utils.random.gaussian() * 5),
fill: utils.random.pick(palette3)
}))

const dataEnd = _.range(0, numPoints).map(i => ({
id: i,
x: Math.random()*width,
y: Math.random()*height,
r: Math.abs(utils.random.gaussian() * 5),
fill: utils.random.pick(palette2)
}))

///////////////////////////////
//////// Draw Function ////////
///////////////////////////////
const draw = (data) => {
ctx.fillStyle = 'white'
ctx.fillRect(0, 0, width, height) // Make sure to clear or fill the rect
for (const { x, y, r, fill } of data ) {
ctx.beginPath()
ctx.arc(x, y, r, 0, 2*Math.PI)
ctx.fillStyle = fill
ctx.fill()
}
}
///////////////////////////////
////////// Animation //////////
///////////////////////////////
const animation = gsap.to(dataStart, {
x: (index) => dataEnd[index].x,
y: (index) => dataEnd[index].y,
r: (index) => dataEnd[index].r,
fill: (index) => dataEnd[index].fill,
duration: 3,
//stagger: 0.01,
ease: 'bounce',
onUpdate: () => draw(dataStart)
})

animation.pause()

///////////////////////////////
//// Control the animation ////
///////////////////////////////
const play = document.querySelector('#play-many')
const pause = document.querySelector('#pause-many')
const restart = document.querySelector('#restart-many')
const reverse = document.querySelector('#reverse-many')

play.onclick = () => { console.log('playing'); animation.play() }
restart.onclick = () => animation.restart()
pause.onclick = () => animation.pause()
reverse.onclick = () => animation.reverse()

// Draw the initial graph
draw(dataStart)

yield ctx.canvas
}
Insert cell
Insert cell
palette4 = utils.random.pick(palettes) // re-run this cell to update colours
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function getRandomArrangement(dataIn, width, height) {
const dataRandomArrangement = _.range(0, dataIn.length - 1).map(i => ({
name: dataIn[i].name,
x: Math.random()*width,
y: Math.random()*height,
r: Math.abs(utils.random.gaussian() * 5),
fill: dataIn[i].fill,
red: dataIn[i].red,
green: dataIn[i].green,
blue: dataIn[i].blue,
}))
return dataRandomArrangement
}
Insert cell
function getCirclePacking(dataIn, width, height) {
const dataClone = _.cloneDeep([...dataIn])
const circlePacking = d3.packSiblings(dataClone).map(d => ({
x: d.x + width /2,
y: d.y + height / 2,
r: d.r,
fill: d.fill,
red: d.red,
green: d.green,
blue: d.blue,
}))
return circlePacking
}
Insert cell
dataTidy = tidyData(dataSample)
Insert cell
function tidyData(dataIn) {
const radius = 2.5
const data = []
dataIn.forEach(frame => {
frame.colours.forEach(colour => {
data.push({
name: frame.img,
fill: colour,
red: +colour.split(', ')[0].split('(')[1],
green: +colour.split(', ')[1],
blue: +colour.split(', ')[2].split(')')[0],
r: radius
})
})
})
return data
}
Insert cell
dataSample = dataRaw.filter((d, i) => i%5 === 0) // Take every 5th frame; you can change this to experiment.
Insert cell
dataRaw = spiritedAway
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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