|
var width = 960, |
|
height = 700; |
|
|
|
var svg = d3.select("body").append("svg") |
|
.attr("width", width) |
|
.attr("height", height); |
|
|
|
// 150 words per minute to read confortably |
|
var CPM = 150 * 5; // CPM = WPM * 5 |
|
|
|
// I need 'Blocks' to accomodate the full height of my water tank |
|
d3.select(self.frameElement).style("height", height + "px"); |
|
|
|
d3.json("monolog.json", function(error, json) { |
|
if (error) return console.warn(error); |
|
play({ monolog: json.dialogLines }); |
|
}); |
|
|
|
function play(opts) { |
|
|
|
var opts = opts || {}, |
|
doublingTime = opts.doublingTime || 10 * 1000, |
|
tankCapacity = opts.tankCapacity || 4000, |
|
startValue = opts.startValue || 1, |
|
startTime = opts.startTime || new Date("March 28, 2013 00:00:00"), |
|
interval = opts.interval || 100, |
|
headLevel = opts.headLevel || 600, |
|
monolog = opts.monolog || [] |
|
|
|
var currentTime = startTime, |
|
heSays = monolog.shift(); |
|
|
|
updateHero('idle'); |
|
var t = setInterval(timeTick, interval); |
|
|
|
function timeTick() { |
|
|
|
currentTime = new Date(currentTime.getTime() + interval); |
|
|
|
updateClock(currentTime); |
|
|
|
var value = getValue(startValue, doublingTime, currentTime - startTime), |
|
waterLevel = value*height/tankCapacity; |
|
|
|
if (waterLevel > headLevel) { |
|
updateHero('drowning'); |
|
} |
|
|
|
if (heSays && heSays.time * 1000 < currentTime - startTime) { |
|
updateText(heSays.text); |
|
heSays = monolog.shift(); |
|
} |
|
|
|
if (waterLevel > height) { |
|
console.log("Oh! The hero is drowning!") |
|
clearInterval(t); |
|
updateWatertank(headLevel, 3000, 5000) |
|
setTimeout(function() { |
|
updateHero('idle'); |
|
updateText("Pheww... please, don't try this in the real world."); |
|
}, 8000); |
|
} |
|
else { |
|
updateWatertank(waterLevel, interval) |
|
} |
|
} |
|
} |
|
|
|
function getValue(startValue, doublingTime, elapsedMilis) { |
|
return startValue * Math.pow(2, elapsedMilis / doublingTime); |
|
} |
|
|
|
function updateWatertank(waterLevel, duration, delay) { |
|
|
|
delay = delay || 0; |
|
|
|
var waterRectangle = svg.selectAll("rect").data([waterLevel]) |
|
|
|
waterRectangle.enter().append("rect") |
|
.attr("id", "water") |
|
.attr("x", 0) |
|
.attr("width", width) |
|
|
|
waterRectangle |
|
.transition().delay(delay).duration(duration) |
|
.attr("y", function(d) { return height - waterLevel; }) |
|
.attr("height", function(d) { return waterLevel; }); |
|
} |
|
|
|
function updateHero(type) { |
|
|
|
var hero = svg.selectAll("image").data([type]); |
|
|
|
hero.enter().append("image") |
|
.attr("x", "-20") |
|
.attr("y", "10") |
|
.attr("width", "432") |
|
.attr("height", "268"); |
|
|
|
hero |
|
.attr("xlink:href", function(d) { return "character_" + d + ".gif"; }) |
|
} |
|
|
|
function updateText(text) { |
|
|
|
var txt = svg.selectAll("#monolog").data([text]); |
|
|
|
txt.enter().append("text") |
|
.attr("id", "monolog"); |
|
|
|
txt |
|
.attr("x", function(d) { return randomPos(175, 185); }) |
|
.attr("y", function(d) { return randomPos(40, 80); }) |
|
.text(function(d) { return d }) |
|
.transition().duration(500).style('fill-opacity', 1) |
|
.transition().delay(function(d) { |
|
return (d.length / CPM) * 60 * 1000; |
|
}) |
|
.duration(4000).style('fill-opacity', 0) |
|
} |
|
|
|
function randomPos(min, max) { |
|
return Math.floor((Math.random() * (max - min + 1)) + min); |
|
} |
|
|
|
function updateClock(time) { |
|
|
|
var clock = svg.selectAll("#clock").data([time]); |
|
|
|
clock.enter().append("text") |
|
.attr("id", "clock") |
|
.attr("x", width - 123) |
|
.attr("y", "50"); |
|
|
|
clock |
|
.text(function(d) { return getReadableHour(d); }); |
|
} |
|
|
|
// I just use this as a counter |
|
function getReadableHour(time) { |
|
var mins = time.getMinutes(), |
|
secs = time.getSeconds(); |
|
mins = (mins < 10 ? "0" : "") + mins; |
|
secs = (secs < 10 ? "0" : "") + secs; |
|
return mins + ":" + secs; |
|
} |