xxxxxxxxxx
199
let flowField = [];
let particles = [];
let numParticles = 500;
let scl = 20; // Scale of each cell in the flow field
let noiseScale = 0.05; // Scale for Perlin noise
let flowStrength = 1; // Adjustable flow strength
let showArt = false; // Flag to control when to show the art
let titleAlpha = 0; // Alpha for title fade-in
let transitionTime = 5000; // 5 seconds
let startTime;
let artLoaded = false;
let waveRadius = 0; // Radius of the ripple effect
let waveMaxRadius = 100; // Maximum radius of the ripple effect
let waveCenter;
let backgroundColor;
// Example dataset: array of river flow points with fictional values
const dataset = [
{ x: 100, y: 150, flow_rate: 10 },
{ x: 150, y: 200, flow_rate: 12 },
{ x: 200, y: 250, flow_rate: 15 },
{ x: 100, y: 160, flow_rate: 9 },
{ x: 150, y: 210, flow_rate: 11 },
{ x: 200, y: 260, flow_rate: 14 },
];
function setup() {
createCanvas(800, 600);
cols = width / scl;
rows = height / scl;
flowField = Array.from({ length: cols * rows }, () => createVector());
// Initialize particles
for (let i = 0; i < numParticles; i++) {
particles.push({
pos: createVector(random(width), random(height)),
vel: createVector(),
lifetime: random(200, 500)
});
}
noStroke();
colorMode(HSB, 360, 100, 100, 100);
// Set initial background color
backgroundColor = color(0, 50, 100); // Oceanic blue background
startTime = millis(); // Record start time
processData(); // Process the dataset
// Set initial wave center
waveCenter = createVector(width / 2, height / 2);
}
function draw() {
if (showArt) {
// Display the interactive art
background(backgroundColor); // Oceanic blue background
// Update flow field with Perlin noise
updateFlowField();
// Update and draw particles
for (let particle of particles) {
let x = floor(particle.pos.x / scl);
let y = floor(particle.pos.y / scl);
let index = x + y * cols;
if (index >= 0 && index < flowField.length) {
let force = flowField[index];
particle.vel.add(force);
particle.vel.limit(2);
particle.pos.add(particle.vel);
// Visualize particle with color based on its position
let age = map(particle.lifetime, 0, 500, 0, 100);
let colorHue = map(particle.pos.x, 0, width, 180, 240); // Oceanic color based on x position
let fadeColor = color(colorHue, 100, 100, age);
fill(fadeColor);
ellipse(particle.pos.x, particle.pos.y, 4);
particle.lifetime -= 1;
// Reset particle if it goes off screen or its lifetime ends
if (particle.lifetime <= 0 || particle.pos.x < 0 || particle.pos.x > width || particle.pos.y < 0 || particle.pos.y > height) {
particle.pos.set(random(width), random(height));
particle.vel.set(0);
particle.lifetime = random(200, 500);
}
}
}
} else {
// Display the trailer with animated title
background(0);
let elapsedTime = millis() - startTime;
if (elapsedTime < transitionTime) {
titleAlpha = map(elapsedTime, 0, transitionTime, 0, 255);
// Create a ripple effect when the cursor is over the trailer
let d = dist(mouseX, mouseY, width / 2, height / 2);
if (d < waveMaxRadius) {
waveRadius = map(d, 0, waveMaxRadius, waveMaxRadius, 0);
} else {
waveRadius = 0;
}
// Draw ripple effect
noFill();
stroke(255, 255, 255, 100);
strokeWeight(2);
ellipse(width / 2, height / 2, waveRadius * 2);
} else {
titleAlpha = 255;
if (!artLoaded) {
artLoaded = true;
showArt = true;
}
}
fill(255, 255, 255, titleAlpha);
textSize(50);
textAlign(CENTER, CENTER);
textFont('Georgia');
text('River Flow Visualization', width / 2, height / 2);
if (elapsedTime < transitionTime) {
let progress = map(elapsedTime, 0, transitionTime, 0, 1);
let wave = sin(progress * TWO_PI * 2) * 10;
textSize(50 + wave);
}
}
}
function updateFlowField() {
let yoff = millis() * 0.0001;
for (let y = 0; y < rows; y++) {
let xoff = 0;
for (let x = 0; x < cols; x++) {
let index = x + y * cols;
let angle = noise(xoff, yoff) * TWO_PI * 2;
let v = p5.Vector.fromAngle(angle);
v.mult(map(noise(xoff, yoff), 0, 1, 0, flowStrength));
flowField[index] = v;
xoff += noiseScale;
}
yoff += noiseScale;
}
}
function processData() {
// Ensure dataset is defined and valid
if (!dataset || !Array.isArray(dataset)) {
console.error('Dataset is not defined or is not an array.');
return;
}
for (let row of dataset) {
let x = row.x;
let y = row.y;
let flowRate = row.flow_rate;
// Adjust flow field based on flowRate
let col = floor(x / scl);
let rowIdx = floor(y / scl);
let index = col + rowIdx * cols;
if (index >= 0 && index < flowField.length) {
let angle = map(flowRate, 0, 15, 0, TWO_PI);
let v = p5.Vector.fromAngle(angle);
v.mult(map(flowRate, 0, 15, 0, flowStrength));
flowField[index] = v;
}
}
}
function keyPressed() {
if (key === ' ') {
if (isLooping()) {
noLoop();
} else {
loop();
}
} else if (key === 'F') {
// Increase flow strength
flowStrength += 0.1;
} else if (key === 'S') {
// Decrease flow strength
flowStrength = max(0, flowStrength - 0.1);
}
}
function mouseMoved() {
if (!showArt) {
// Adjust ripple effect based on mouse position during the trailer
waveCenter.set(mouseX, mouseY);
}
}