xxxxxxxxxx
112
let data;
let bubbles = []; // Holds artist bubbles
function preload() {
data = loadTable("ArtistStreams.csv", "csv", "header"); // Load CSV file
}
function setup() {
createCanvas(600, 600);
let maxStream = 0; // Keep maximum stream count
// Extract and sort the data
let artistData = [];
for (let i = 0; i < data.getRowCount(); i++) {
let artist = data.getString(i, "Artist");
let streams = parseFloat(data.getString(i, "Streams")); // Convert stream count from string to float
artistData.push({ artist, streams }); // Add artist and streams to the artistData array
}
// Sort the data in descending order based on streams
artistData.sort((a, b) => b.streams - a.streams);
// Calculate maximum streams for normalization
maxStream = artistData[0].streams;
// Create bubbles for all artists in the data
for (let i = 0; i < artistData.length; i++) {
let artist = artistData[i].artist;
let streams = artistData[i].streams;
bubbles.push(new Bubble(artist, streams, i, artistData.length, maxStream));
}
}
function draw() {
background(30); // Set background color
translate(300, 300); // origin to center
// Draw central circle with total streams
let totalStreams = bubbles.reduce((sum, bubble) => sum + bubble.streams, 0);
fill(100, 100, 200, 100);
noStroke();
ellipse(0, 0, 200, 200);
fill(255);
textAlign(CENTER, CENTER);
textSize(20);
text("Total Streams\n" + nf(totalStreams, 0, 1) + "K", 0, 0);
// Draw bubbles
for (let bubble of bubbles) {
bubble.move(); // Update the position/size of the bubble
bubble.display();
}
}
// Bubble class
class Bubble {
constructor(artist, streams, index, total, maxStream) {
this.artist = artist;
this.streams = streams;
this.angle = map(index, 0, total, 0, TWO_PI); // Calculate angle position on the circle
this.radius = 250; // Adjust radius to fit within the smaller canvas
this.x = this.radius * cos(this.angle); // Calculate x position based on angle
this.y = this.radius * sin(this.angle); // Calculate y position based on angle
this.diameter = 0;
// Target diameter based on the stream count, scaled to the maximum stream count
this.targetDiameter = map(this.streams, 0, maxStream, 50, 200);
this.diameter = this.targetDiameter * 0.8;
// Set color from red to blue based on position in the sorted array
this.color = lerpColor(
color(255, 0, 0, 150),
color(0, 0, 255, 150),
index / total
); // Gradient from red to blue
}
move() {
// Update the bubble's size
if (this.diameter < this.targetDiameter) {
this.diameter += 2; // Increase size by 2 units per frame
if (this.diameter > this.targetDiameter) {
this.diameter = this.targetDiameter; // Ensure it doesn't overshoot
}
} else if (this.diameter > this.targetDiameter) {
this.diameter -= 2; // Decrease size by 2 units per frame
if (this.diameter < this.targetDiameter) {
this.diameter = this.targetDiameter; // Ensure it doesn't undershoot
}
}
}
// Display bubble on canvas
display() {
let mouseOnBubble =
dist(mouseX - 300, mouseY - 300, this.x, this.y) < this.diameter / 2; // Check if mouse is on top of bubble
if (mouseOnBubble) {
// If mouse is on bubble, highlight and show artist details
fill(255, 255, 0, 150); // Highlight color
ellipse(this.x, this.y, this.diameter + 10, this.diameter + 10);
fill(255);
textAlign(CENTER, CENTER);
textSize(14);
text(this.artist + "\n" + nf(this.streams, 0, 1) + "K", this.x, this.y); // Display artist name and streams
} else {
// Draw bubble normally
fill(this.color);
ellipse(this.x, this.y, this.diameter, this.diameter); // Artist bubble
}
}
}