var table; var points = []; var tickValueY, tickDistanceY, tickValueX, tickDistanceX, maxKey = 0, maxvalue = 0; var map1 = {}; function preload() { table = loadTable('airlines.csv', 'csv', 'header'); } function setup() { createCanvas(1000, 1000); for (var j = 0; j < table.getRowCount(); j++){ if (table.getString(j, 'Code') === "SFO"){ if (table.getNum(j, 'Year') in map1){ map1[table.getNum(j, 'Year')] = map1[table.getNum(j, 'Year')] + table.getNum(j, 'Cancelled'); } else { map1[table.getNum(j, 'Year')] = table.getNum(j, 'Cancelled'); } } } // find max/min values and keys var minKey = 99999999999999999; // cannot assume that the keys are read in sorted order var minvalue = 99999999999; for (var key in map1) { if (map1[key] > maxvalue){ maxvalue = map1[key]; } if (map1[key] < minvalue){ minvalue = map1[key]; } if (key < minKey){ minKey = key; } if (key > maxKey){ maxKey = key; } } // to get decimal-free scales while (maxvalue % 100 != 0){ maxvalue++; } while (minvalue % 100 != 0){ minvalue--; } while (maxKey %10 != 0){ maxKey++; } while (minKey % 10 != 0){ minKey--; } var rangeVal = maxvalue - minvalue; var rangeKey = maxKey - minKey; tickDistanceY = 850/10; // we want 10 ticks always. the length of the Y axis will not change tickDistanceX = 900/10; // we want 10 ticks always. the length of the X axis will not change tickValueY = rangeVal/10; // each tick will correspond to a multiple of this number tickValueX = rangeKey/10; // each tick will correspond to a multiple of this number console.log(tickDistanceX + ", " + tickValueX); var counter = 0; var startPointY, startPointX; // get values in sorted order var prevX = -1, prevY = -1; for (var i = minKey; i <= maxKey; i++){ if (i in map1){ startPointY = getStartPointY(map1[i]); startPointX = getStartPointX(i); points.push(new Line(startPointX, startPointY, prevX, prevY, i, map1[i])); counter++; prevX = startPointX; prevY = startPointY; } } } function getStartPointY(value){ return 50+(((maxvalue-value)/tickValueY)*tickDistanceY); } function getStartPointX(value){ return 950-(((maxKey-value)/tickValueX)*tickDistanceX); } function draw(){ clear(); // y axis line(50, 50, 50, 900); // x axis line(50, 900, 950, 900); for (var j = 0; j <= 10; j++){ line(48, 50+(tickDistanceY*j), 53, 50+(tickDistanceY*j)); // does not depend on range text(maxvalue-(tickValueY*j), 15, 50+(tickDistanceY*j)); } // adding ticks on x-axis for (var k = 0; k <= 10; k++){ line(950-(tickDistanceX*k), 897, 950-(tickDistanceX*k), 904); // does not depend on range text(maxKey-(tickValueX*k), 935-(tickDistanceX*k), 920); } text("Year", 475, 950); text("Number of Cancelled Flights from SFO", 350, 10); var xcoord, ycoord, year, value, isHover = false; for (var i = 0; i < points.length; i++){ points[i].show(); if (points[i].checkHover() == true){ isHover = true; xcoord = points[i].getxcoord(); ycoord = points[i].getycoord(); year = points[i].getyear(); value = points[i].getvalue(); } } // display hover after ALL lines/points drawn, so the info is not covered by lines if (isHover){ fill('red'); ellipse(xcoord, ycoord, 6); fill(240); rect(xcoord-60, ycoord-40, 80, 30); fill(0); text("(" + year + ", " + value + ")", xcoord-55, ycoord-20); } rotate(PI/2); text("Number of Cancelled Flights", 200, -5); } class Line { constructor(x, y, prevx, prevy, year, value) { this.x = x; this.y = y; // to connect to previous point this.prevx = prevx; this.prevy = prevy; // stored info about the point this.year = year; this.value = value; } show(){ fill(0); ellipse(this.x, this.y, 3); // if not first point if (this.prevx != -1 && this.prevy != -1){ line(this.x, this.y, this.prevx, this.prevy); } } checkHover(){ if (dist(this.x, this.y, mouseX, mouseY) < 6){ return true; } else{ return false; } } getxcoord(){ return this.x; } getycoord(){ return this.y; } getyear(){ return this.year; } getvalue(){ return this.value; } }