var imgNames = ["walter.jpg", "clint.jpg", "snake.jpg"];
var activeHotspot = null;
var tooltip = "".concat("Press space to change to the next image.\n",
"Press any other key to toggle the hotspots.\n",
"Click and drag hotspots to move or scale them.");
for (let i = 0; i < imgNames.length; i++) {
let newImg = loadImage(imgNames[i]);
createCanvas(windowWidth, windowHeight);
let img = imgs[imgIndex];
for (let i = 0; i < 4; i++) {
hotspots.push(new Hotspot());
for (let i = 0; i < spawnCount; i++) {
staticPoints.push(new p5.Vector(int(random(img.width)), int(random(img.height))));
let img = imgs[imgIndex];
translate(width/2-img.width/2, height/2-img.height/2);
let currentPoints = staticPoints.slice();
for (let i = 0; i < hotspots.length; i++) {
currentPoints = currentPoints.concat(hotspots[i].points);
for (let i = 0; i < currentPoints.length; i++) {
let x = currentPoints[i].x;
let y = currentPoints[i].y;
if (x < 0 || x > img.width || y < 0 || y > img.height) {
let index = (y*img.width+x)*4;
let r = img.pixels[index];
let g = img.pixels[index+1];
let b = img.pixels[index+2];
let a = img.pixels[index+3];
let closestData = getClosestHotspot(x, y);
if (closestData[0] == null) {
transform.push({x:x, y:y, r:r, g:g, b:b, a:a, closestHotspot:closestData[0], closestDist:closestData[1]});
boundingBox = {xl:1, xr:img.width-1, yt:1, yb:img.height-1};
voronoi.recycle(diagram);
diagram = voronoi.compute(transform, boundingBox);
for (let i = 0; i < diagram.cells.length; i++) {
if (!diagram.cells[i].halfedges.length) {
let closestHotspot = diagram.cells[i].site.closestHotspot;
let closestDist = diagram.cells[i].site.closestDist;
let siteColor = color(diagram.cells[i].site.r, diagram.cells[i].site.g, diagram.cells[i].site.b, diagram.cells[i].site.a);
if (closestDist < closestHotspot.r*falloff) {
for (let j = 0; j < diagram.cells[i].halfedges.length; j++) {
let v = diagram.cells[i].halfedges[j].getStartpoint();
} else if (closestDist < closestHotspot.r) {
strokeWeight(map(closestDist-closestHotspot.r*falloff, 0, closestHotspot.r-closestHotspot.r*falloff, 10, 0));
point(diagram.cells[i].site.x, diagram.cells[i].site.y);
let closestData = getClosestHotspot(mouseX+img.width/2-width/2, mouseY+img.height/2-height/2);
let closestHotspot = closestData[0];
let closestDist = closestData[1];
if (closestHotspot != null) {
if (closestDist < closestHotspot.r-ringThickness*0.5) {
activeHotspot = closestHotspot;
} else if (closestDist < closestHotspot.r+ringThickness*0.5) {
activeHotspot = closestHotspot;
for (let i = 0; i < hotspots.length; i++) {
ellipse(hotspots[i].x, hotspots[i].y, hotspots[i].r*2)
if (activeHotspot != null) {
let d = dist(mouseX+img.width/2-width/2, mouseY+img.height/2-height/2, activeHotspot.x, activeHotspot.y);
if (d < activeHotspot.r+ringThickness*0.5) {
if (d < activeHotspot.r-ringThickness*0.5) {
strokeWeight(activeHotspot.r*2-ringThickness);
point(activeHotspot.x, activeHotspot.y)
strokeWeight(ringThickness);
ellipse(activeHotspot.x, activeHotspot.y, activeHotspot.r*2)
text(tooltip, width/2, 50);
function mouseDragged() {
if (activeHotspot == null) {
let img = imgs[imgIndex];
activeHotspot.x = mouseX+img.width/2-width/2;
activeHotspot.y = mouseY+img.height/2-height/2;
activeHotspot.r = dist(mouseX+img.width/2-width/2, mouseY+img.height/2-height/2, activeHotspot.x, activeHotspot.y);
activeHotspot.getPoints();
if (imgIndex >= imgs.length) {
function initHotspots() {
presetValues = [[365, 230, 210], [300, 130, 150], [175, 315, 200], [500, 340, 170]];
} else if (imgIndex == 1) {
presetValues = [[440, 230, 220], [280, 215, 150], [315, 340, 150], [115, 170, 120]];
} else if (imgIndex == 2) {
presetValues = [[660, 240, 240], [360, 120, 150], [230, 65, 200], [485, 250, 185]];
for (let i = 0; i < hotspots.length; i++) {
if (presetValues != null) {
hotspots[i].x = presetValues[i][0];
hotspots[i].y = presetValues[i][1];
hotspots[i].r = presetValues[i][2];
function getClosestHotspot(x, y) {
let closestHotspot = null;
for (let i = 0; i < hotspots.length; i++) {
let d = dist(x, y, hotspots[i].x, hotspots[i].y);
if (closestDist == null || d < closestDist) {
closestHotspot = hotspots[i];
return [closestHotspot, closestDist];