Emily Zhou –– Final Project

Hi there, my final project is 900 x 450 px but WordPress cuts it off at 600 px width so here is the zip file to see the full thing: moon-exp.zip

Instructions: Click the stars to traverse the timeline of humanity’s exploration of the moon.

Details: Each click should reveal a key event in moon exploration in chronological order. The representation of the moon should slowly fill as time passes. After revealing all 26 events, the stars should be connected as one single constellation.

final project

var starX = [245, 260, 295, 325, 325, 365, 410, 400, 380, 390, 360, 355, 335, 
             265, 240, 205, 185, 170, 85, 95, 50, 60, 55, 65, 100, 120, 140];
var starY = [40, 32, 60, 85, 85, 100, 225, 275, 290, 305, 355, 370, 352, 385, 
             395, 382, 385, 380, 340, 325, 275, 250, 230, 140, 110, 100, 70];
var starD = [10, 6, 4, 10, 10, 6, 10, 4, 5, 8, 5, 4, 8, 6, 
             10, 4, 6, 5, 10, 5, 4, 6, 10, 5, 8, 4, 5];
var time = ["1609", "1610", "1610", "1645", "1647", "1651", "1753", "1824", "1920", "1959", 
            "1961", "1964", "1966", "1967", "1968", "1969", "1969", "1972", "1976", 
            "1990", "1994", "1998", "2007", "2007", "2008", "2009"];
var data = ["Hans Lippershey invented the telescope.",
            "Galileo Galilei made the first telescopic observation of the moon.",
            "Thomas Harriot and Galileo Galilei drew the first telescopic representation of the moon.",
            "Michael Florent van Langren made the first map of the moon.",
            "Johannes Hevelius published the first treatise devoted to the moon.",
            "Giovanni Battista Riccioli named craters after philosophers and astronomers.",
            "Roger Joseph Boscovich proved the moon has no atmosphere.",
            "Franz von Gruithuisen thought craters were formed by meteor strikes.",
            "Robert Goddard suggested sending rockets to the moon.",
            "Soviet spacecraft Luna 2 reached the moon, impacting near the crater Autolycus.",
            "President John F. Kennedy proposed a manned lunar program.",
            "NASA's Ranger 7 produced the first close-up TV pictures of the lunar surface.",
            "Soviet spacecraft Luna 9 made the first soft landing on the moon.",
            "NASA's Lunar Orbiter missions completed photographic mapping of the moon.",
            "NASA's Apollo 8 made the first manned flight to the moon, circling it 10 times before returning to Earth.",
            "Apollo 11 mission made the first landing on the moon and returned samples.",
            "Apollo 12 made first precision landing on the the moon.",
            "Apollo 17 made the last manned landing of the Apollo Program.",
            "Soviet Luna 24 returned the last sample to be returned from the moon (to date).",
            "NASA's Galileo spacecraft obtained multispectral images of the western limb and part of the far side of the moon.",
            "NASA's Clementine mission conducted multispectral mapping of the moon.",
            "NASA's Lunar Prospector mission launched.",
            "Japanese SELENE (Kaguya) spacecraft launched.",
            "Chinese Chang'e 1 lunar orbiter launched.",
            "Indian Chandrayaan 1 moon orbiter launched.",
            "NASA's Lunar Reconnaissance Orbiter launched"]
var newData = [];
var newTime = [];

var speed = 100; // typing speed
var maxCharacters = 65; // max characters per line
var spacing = 15; // spacing between lines
var clicks = 0; // click count
var next = 0; // to evaluate when next star is clicked

var starClickIndices = []; // index values of clicked stars
var clear1 = []; // stores handles for text either appearing or intercepting
var clear2 = []; // stores handles for text either appearing or intercepting
var toClearOne = true; // used to differentiate between clear1 and clear2

function setup() {
    createCanvas(900, 450);
    background(255, 255, 255);

    // to match time to new data array
    for (var i = 0; i < time.length; i++) {
    	newTime.push([]);
    	newTime[i].push(time[i]);
    }

    // code to split long text lines 
    for (var i = 0; i < data.length; i++) {
    	newData.push([]);
    	var stringStart = 0;
    	var stringEnd = 0;
    	
    	while (stringEnd < data[i].length) {

    		stringEnd += maxCharacters;

    		var trunc = stringEnd; // index of where to truncate
    		while (data[i].substring(trunc - 1, trunc) != " " & 
    				(stringEnd - trunc <= 10)) {
    			trunc--;
    		}

    		if (data[i].substring(trunc - 1, trunc) == " ") {
    			newData[i].push(data[i].substring(stringStart, trunc));
    			stringStart = trunc;
    			stringEnd = trunc;
    		}
    		else {
    			newData[i].push(data[i].substring(stringStart, stringEnd));
    			stringStart = stringEnd;
    		}
    	}
    }

    // frame
    noFill();
    stroke(220);
    rect(0, 0, width - 1, height - 1);
}

function draw() {
    // moon
    moonChord();

    // constellation lines
    for (var i = 1; i < starClickIndices.length; i++) {
        stroke(220);
        strokeWeight(0.5);
        line(starX[starClickIndices[i]], starY[starClickIndices[i]], 
        	starX[starClickIndices[i - 1]], starY[starClickIndices[i - 1]]);
    }

    if (next != clicks) {

        // erase text
        fill(255);
        noStroke();
        rect(450, 170, 425, 125);

        // code to type text
        if (toClearOne) {
        	for (var i = clear1.length - 1; i >= 0; i--) {
        		clearTimeout(clear1[i]);
        		clear1.pop(i);
        	}
        }
        else {
        	for (var i = clear2.length - 1; i >= 0; i--) {
        		clearTimeout(clear2[i]);
        		clear2.pop(i);
        	}
        }

        toClearOne = ! toClearOne;

	    fill(220);
	    noStroke();

	    if (toClearOne) {
	        typeWriter(newTime[next], 0, 0, 475, 215, clear1);
	        typeWriter(newData[next], 0, 0, 475, 235, clear1);
	    }
	    else {
	        typeWriter(newTime[next], 0, 0, 475, 215, clear2);
	        typeWriter(newData[next], 0, 0, 475, 235, clear2);

	    }
    }

    // stars
    stroke(150);
    fill(150);
    for (i = 0; i < 27; i++) {
        ellipse(starX[i], starY[i], starD[i], starD[i],)
    }

    next = clicks;
}

function mousePressed() {
    for (var i = 0; i < 27; i++) {
        var distance = dist(mouseX, mouseY, starX[i], starY[i]);
        if (distance <= starD[i] / 2 + 2) {

        	var unclicked = true;
        	for (var j = 0; j < starClickIndices.length; j++) {
        		if (starClickIndices[j] == i) unclicked = false;
        	}

        	if (unclicked) {
	            starClickIndices.push(i);
	            clicks++;
	            if (clicks >= data.length) clicks = 0;
	            curStarIndex = i;
	        }
        }
    }
}

// typewriter effect to print text
function typeWriter(info, r, c, x, y, clear) {
    if (r < (info.length)) {

    	c++;
    	if (c > info[r].length) {
    		c = 1;
    		r++;
    	}

        if (r < info.length) {
	        noStroke();
	        textSize(12);
	        text(info[r].substring(0, c), 
	            x, y + (r * spacing));

	        var handle = setTimeout(function() {
		          typeWriter(info, r, c, x, y, clear)
		        }, speed)
	        clear.push(handle);
	    }

    }
}

// continuously draw chords fill moon
function moonChord() {
    stroke(0, 0, 0, 15);

    var angle1 = random(0, 2 * PI);
    var px1 = 225 + 150 * cos(angle1);
    var py1 = 225 + 150 * sin(angle1);

    var angle2 = random(0, 2 * PI);
    var px2 = 225 + 150 * cos(angle2);
    var py2 = 225 + 150 * sin(angle2);

    line(px1, py1, px2, py2);
}

Progression:

Reflection: The hardest part was getting the typewriter text to print like I wanted and coordinating all of the different actions to the mouse click.

Sources:
The representation of the moon was inspired by this example on p5js.org:
https://p5js.org/examples/math-random-chords.html
I referenced this code as a starting point for developing the typewriter text:
https://gist.github.com/mjvo/2dce29799eb75b7ee1a571380f12ef1b

Leave a Reply