xxxxxxxxxx
// this dataset was loaded using the Harvard Art Museum's API (https://harvardartmuseums.org/collections/api)
// data processing python notebook: https://github.com/cynthia9chen/acrylic-color/blob/main/data_cleaning.ipynb
// more information:
// size of circles represent number of pageviews
// painting coordinates are determined using the UMAP (Uniform Manifold Approximation and Projection) method
let width
let height
let xborder_left
let xborder_right = 30
let yborder = 100
let paintings = [];
let num_paintings;
let currentHover;
let textCenter = 220;
function preload() {
// load data
coordinates = loadTable('coordinates.csv', 'csv').getRows();
color_comp = loadTable('color_comp.csv', 'csv').getRows();
desc = loadTable('desc.csv', 'csv', 'header').getRows();
// load fonts
// marcellus = loadFont('marcellus.ttf');
// medium = loadFont('medium.ttf');
abadi = loadFont('abadi_extralight.otf');
outfit = loadFont('outfit.ttf');
}
function setup() {
// noLoop()
createCanvas(windowWidth, windowHeight);
width = windowWidth
height = windowHeight
xborder_left = 440/1440*width
textCenter = xborder_left/2+10
noStroke();
num_paintings = coordinates.length
// set up Painting objects
for (let i = 0; i < num_paintings; i++) {
coord = coordinates[i]['arr']
x = coord[0]
y = coord[1]
scaled_x = xborder_left + (width-(xborder_left+xborder_right))*x
scaled_y = yborder/2 + (height-yborder)*y
colors = color_comp[i]['arr']
// painting_tmp = new Painting([scaled_x, scaled_y], colors);
display = true
painting_tmp = new Painting([scaled_x, scaled_y], colors, display, desc[i]['obj']);
paintings.push(painting_tmp);
}
}
function draw() {
background(41, 50, 64);
textFont(outfit)
textSize(windowWidth/39)
noStroke()
fill(220)
textAlign(CENTER)
text('Color in Acrylic Works', textCenter, height/2.8-40)
// textSize(windowWidth/50)
// textFont(outfit)
// text('Paintings', textCenter, height/4+30)
textFont(abadi)
textSize(windowWidth/45)
text('at the Harvard Art Museums', textCenter, height/2.8 + 5)
textFont(abadi)
textSize(windowWidth/68)
text('Every circle represents one artwork.', textCenter, height*2/3-125)
// textFont(abadi)
// textSize(windowWidth/60)
// text('Hover over a circle to learn more.', textCenter, height*3/4 + 5)
// text('Click to see image of artwork.', textCenter, height*3/4+40)
paintings[25].show_sample(); // good ones: 110
let i = 0;
let highlight_ind;
let mouse_over = false;
while (i < num_paintings && !mouse_over) {
let p = paintings[i]
mouse_over = dist(p.coord[0], p.coord[1], mouseX, mouseY) <= p.radius/2
if (mouse_over) {
highlight_ind = i;
currentHover = i
}
i++;
}
// hovering over painting
if (mouse_over) {
for (let j = 0; j < num_paintings; j++) {
if (j != highlight_ind) {
paintings[j].show();
}
paintings[highlight_ind].show(highlight = true);
}
}
// no hover
else {
for (let i = 0; i < num_paintings; i++) {
paintings[i].show();
}
currentHover = -1
}
// saveCanvas('paintings', 'png');
}
class Painting {
constructor (coord, colors, display, d) {
this.coord = coord;
this.colors = colors;
this.display = display;
this.title = d['title']
this.artist = d['artist']
this.views = d['views']
this.date = d['date']
this.radius = windowWidth/105*log(d['views'])
}
// displays a single painting circle
show(highlight = false, sample = false) {
let x = this.coord[0]
let y = this.coord[1]
let r = this.radius
if (highlight) {
// display description
drawTextBox(x, y, this.radius, this.title, this.artist, this.date)
}
for (let i = this.colors.length/2 - 1; i >= 0; i--) {
let color_hex = color(this.colors[i*2])
if (highlight) {
color_hex.setAlpha(255);
fill(color_hex)
}
else{
color_hex.setAlpha(155);
fill(color_hex)
}
noStroke()
circle(x, y, r);
r -= int(this.colors[i*2+1])*(this.radius/100)
}
if (highlight) {
noFill()
noStroke()
circle(x, y, this.radius);
}
}
// shows sample circle for legend
show_sample() {
x = textCenter-115
y = height/2+90
let temp = this.radius
this.radius = this.radius*(120/this.radius)
let r = this.radius
for (let i = this.colors.length/2 - 1; i >= 0; i--) {
let color_hex = color(this.colors[i*2])
color_hex.setAlpha(255);
fill(color_hex)
noStroke()
circle(x, y, r);
r -= int(this.colors[i*2+1])*(this.radius/100)
textFont(abadi)
fill(200)
textSize(windowWidth/78)
text(this.colors[i*2], x+this.radius/2+width/16.5, y + (i-1.3)*35)
textFont(abadi)
text(this.colors[i*2+1] +"\%", x+this.radius/2+width/8, y + (i-1.3)*35)
fill(color_hex)
stroke(200)
strokeWeight(0.8)
rect(x+this.radius/2+width/10.5, y + (i-1.3)*35 - 14, 15, 15)
}
stroke(200)
strokeWeight(1.3)
line(x+this.radius/2+10, y, x+this.radius/2+30, y,)
line(x+this.radius/2+30, y - 60, x+this.radius/2+30, y + 60)
line(x+this.radius/2+30, y - 60, x+this.radius/2+40, y - 60)
line(x+this.radius/2+30, y + 60, x+this.radius/2+40, y + 60)
textAlign(LEFT)
this.radius = temp
}
}
// function to draw text box on hover
function drawTextBox(x, y, radius, title, artist, date) {
let endx;
let endy;
let line_len = max(23, radius*2/3)
let rectx;
let recty;
rect_width = max(250, 10*title.length, 10*artist.length);
rect_height = 115
rect_corner = 20
if (x < width/2 && y < height/2) {
endx = x + line_len
endy = y + line_len
rectx = endx - 10
recty = endy - 10
}
if (x < width/2 && y >= height/2) {
endx = x + line_len
endy = y - line_len
rectx = endx - 10
recty = endy - rect_height + 10
}
if (x >= width/2 && y >= height/2) {
endx = x - line_len
endy = y - line_len
rectx = endx - rect_width + 10
recty = endy - rect_height + 10
}
if (x >= width/2 && y < height/2) {
endx = x - line_len
endy = y + line_len
rectx = endx - rect_width + 10
recty = endy - 10
}
// text description box
stroke(220)
strokeWeight(2)
line(x, y, endx, endy)
fill(51, 60, 74)
strokeWeight(0.5)
rect(rectx, recty, rect_width, rect_height, rect_corner)
textFont(outfit)
textSize(19)
noStroke()
fill(220)
textAlign(CENTER)
text("\"" + title + "\"", rectx + rect_width/2, recty + 40)
textFont(abadi)
text(artist, rectx + rect_width/2, recty + 65)
if (artist == '') {
text('Artist Unknown', rectx + rect_width/2, recty + 65)
}
text(date, rectx + rect_width/2, recty + 90)
textFont(abadi)
}
function mouseClicked() {
if (currentHover != -1) {
window.open(desc[currentHover]['obj']['url']);
}
}