Skip to content

Instantly share code, notes, and snippets.

@TommyCoin80
Last active August 4, 2017 18:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TommyCoin80/5ac432646d1e11f028c807a94a3a580d to your computer and use it in GitHub Desktop.
Save TommyCoin80/5ac432646d1e11f028c807a94a3a580d to your computer and use it in GitHub Desktop.
When Same-Day FP+ Runs Out by Crowd Level at MK

A visual representation of how FastPass+ availablity changes for Magic Kingdom attractions based on crowd level. Data from pg 495 of the 2017 Walt Disney World Unoffical Guide. The graph will toggle through crowd levels until the user clicks on the crowd level toggle.

var dataIn = [{attraction:"Ariel's Grotto",lowStart:5,lowEnd:5,medStart:5,medEnd:7,highStart:7,highEnd:8},
{attraction:"The Barnstormer",lowStart:5,lowEnd:6,medStart:5,medEnd:8,highStart:7,highEnd:8},
{attraction:"Big Thunder Mountain",lowStart:3,lowEnd:4,medStart:4,medEnd:5,highStart:3,highEnd:5},
{attraction:"Buzz Lightyear's Space Ranger Spin",lowStart:5,lowEnd:6,medStart:5,medEnd:7,highStart:7,highEnd:8},
{attraction:"Dumbo the Flying Elephant",lowStart:5,lowEnd:6,medStart:5,medEnd:8,highStart:8,highEnd:9},
{attraction:"Enchanted Tales with Belle",lowStart:5,lowEnd:6,medStart:5,medEnd:8,highStart:7,highEnd:8},
{attraction:"The Haunted Mansion",lowStart:5,lowEnd:7,medStart:5,medEnd:7,highStart:6,highEnd:8},
{attraction:"It's a Small World",lowStart:5,lowEnd:6,medStart:6,medEnd:8,highStart:8,highEnd:9},
{attraction:"Jungle Cruise",lowStart:5,lowEnd:6,medStart:5,medEnd:7,highStart:8,highEnd:8},
{attraction:"Monsters, Inc. Laugh Floor",lowStart:5,lowEnd:6,medStart:5,medEnd:8,highStart:8,highEnd:8},
{attraction:"Mad Tea Party",lowStart:6,lowEnd:7,medStart:7,medEnd:8,highStart:8,highEnd:9},
{attraction:"The Magic Carpets of Aladdin",lowStart:5,lowEnd:7,medStart:7,medEnd:8,highStart:8,highEnd:9},
{attraction:"The Many Adventues of Winnie the Pooh",lowStart:5,lowEnd:6,medStart:5,medEnd:8,highStart:8,highEnd:9},
{attraction:"Peter Pan's Flight",lowStart:2,lowEnd:3,medStart:3,medEnd:4,highStart:3,highEnd:4},
{attraction:"Mickey's PhilharMagic",lowStart:5,lowEnd:6,medStart:5,medEnd:7,highStart:7,highEnd:7},
{attraction:"Pirates of the Carribean",lowStart:5,lowEnd:6,medStart:4,medEnd:6,highStart:7,highEnd:8},
{attraction:"Princess Fairytale Hall: Cinderella and Friends",lowStart:3,lowEnd:4,medStart:4,medEnd:6,highStart:7,highEnd:8},
{attraction:"Seven Dwarfs Mine Train",lowStart:1,lowEnd:1,medStart:null,medEnd:null,highStart:null,highEnd:null},
{attraction:"Space Mountain",lowStart:4,lowEnd:6,medStart:3,medEnd:5,highStart:2,highEnd:4},
{attraction:"Splash Mountain",lowStart:2,lowEnd:5,medStart:1,medEnd:4,highStart:3,highEnd:4},
{attraction:"Tomorrowland Speedway",lowStart:5,lowEnd:6,medStart:5,medEnd:8,highStart:8,highEnd:9},
{attraction:"Town Square Mickey Mouse Meet and Greet",lowStart:4,lowEnd:5,medStart:5,medEnd:7,highStart:6,highEnd:8},
{attraction:"Town Square Tinker Bell Meet and Greet",lowStart:5,lowEnd:6,medStart:5,medEnd:8,highStart:8,highEnd:9},
{attraction:"Under the Sea: Journey of the Little Mermaid",lowStart:5,lowEnd:6,medStart:5,medEnd:8,highStart:8,highEnd:9}];
<!DOCTYPE html>
<meta charset="utf-8">
<head>
<link href='https://fonts.googleapis.com/css?family=Josefin+Sans' rel='stylesheet' type='text/css'>
<style>
body {
margin:auto;
font-family: 'Josefin Sans', sans-serif;
font-size:100%;
}
text {
font-family: 'Josefin Sans', sans-serif;
}
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="dataIn.js"></script>
<script>
var FpChart = function(opts) {
this.elementId = opts.elementId;
this.height = opts.height || 500;
this.width = opts.width || 960;
this.margin = opts.margin || {top:10,left:50,bottom:30,right:10};
this.s = {};
this.prepData(opts.data);
this.setScales();
this.setAxes();
this.setGrids()
this.draw()
this.drawGrids();
this.drawAxes();
this.drawBars();
this.drawLabels(opts.data);
this.drawToggle();
this.drawLegend();
var _this = this;
var counter = 0;
this.timer = d3.interval(function(elapsed) {
if(counter == 0) _this.toggleCrowdLevel({key:"med"});
if(counter == 1) _this.toggleCrowdLevel({key:"high"});
if(counter == 2) _this.toggleCrowdLevel({key:"low"});
counter++;
if(counter == 3) counter = 0;
},2000)
}
FpChart.prototype.setGrids = function() {
this.grid = {};
this.grid.y = d3.axisTop(this.scale.time)
.tickSizeInner(-this.height)
.tickFormat("");
}
FpChart.prototype.drawGrids = function() {
this.s.chart.append("g")
.call(this.grid.y)
.each(function(d) {
d3.select(this)
.style("opacity", .15)
.select(".domain")
.style("display","none")
})
}
FpChart.prototype.toggleCrowdLevel = function(d) {
var cl = d.key,
_this = this;
this.s.bars.transition()
.duration(1000)
.attr("x", function(d) { return _this.scale.time(d.crowdLevel[cl].start)})
.attr("width",function(d) { return _this.scale.time(d.crowdLevel[cl].end) - _this.scale.time(d.crowdLevel[cl].start) });
this.s.slider.transition()
.duration(1000)
.attr("transform","translate(" + (this.width + 10) + "," + _this.scale.toggle(cl) +")");
}
FpChart.prototype.drawLegend = function() {
var _this = this;
var legend = this.s.chart.append("g").attr("transform","translate(" + (this.width + 10) + ",0)")
.selectAll(".legend")
.data(this.legendData)
.enter()
.append("g")
.attr("transform",function(d) { return "translate(0," + _this.scale.legend(d.key) + ")" })
legend.append("rect")
.attr("height", this.scale.legend.bandwidth())
.attr("width", 100)
.style("fill", function(d) { return _this.scale.color(d.key)})
.style("fill-opacity",.65)
.style("stroke", function(d) { return _this.scale.color(d.key)})
.style("stroke-width",2)
legend.append("text")
.style("text-anchor","middle")
.text(function(d) { return d.value;})
.attr("x", (legend.select("rect").attr("width"))/2)
.attr("y", this.scale.legend.bandwidth()/2 + 1.5)
.attr("dy",".3em")
.style("fill","black")
this.s.chart.append("text")
.attr("transform","translate(" + (this.width + 10 + (+legend.select("rect").attr("width"))/2) + "," +
this.height*(2.8/10) + ")")
.style("text-anchor","middle")
.style("font-weight","bold")
.text("Availability")
this.s.chart.append("text")
.attr("x",this.width + 10 + (legend.select("rect").attr("width"))/2)
.attr("y", this.height*(2.4/10) )
.style("text-anchor","middle")
.style("font-weight","bold")
.text("FastPass")
}
FpChart.prototype.drawToggle = function() {
var _this = this;
this.s.toggles = this.s.chart.append("g").attr("transform","translate(" + (this.width + 10) + ",0)")
.selectAll(".toggle")
.data(this.toggleData)
.enter()
.append("g")
.attr("transform",function(d) { return "translate(0," + _this.scale.toggle(d.key) + ")" })
.style("cursor","pointer")
.on("click", function(d) {
_this.timer.stop();
_this.toggleCrowdLevel(d);})
this.s.toggles.append("rect")
.attr("height", this.scale.toggle.bandwidth())
.attr("width", 100)
.style("fill", "white")
.style("stroke","gray");
this.s.toggles.append("text")
.style("text-anchor","middle")
.text(function(d) { return d.value;})
.attr("x", (+this.s.toggles.select("rect").attr("width"))/2)
.attr("y", this.scale.toggle.bandwidth()/2 + 1.5)
.attr("dy",".3em")
.style("fill","black")
this.s.slider = this.s.chart.append("g")
.attr("transform","translate(" + (this.width + 10) + "," + _this.scale.toggle("low") +")");
this.s.slider.append("rect")
.attr("width", +this.s.toggles.select("rect").attr("width"))
.attr("height", +this.s.toggles.select("rect").attr("height"))
.style("stroke","black")
.style("stroke-width", 4)
.style("fill","none")
this.s.chart.append("text")
.attr("transform","translate(" + (this.width + 10 + (+this.s.toggles.select("rect").attr("width"))/2) + "," +
this.height*(6.8/10) + ")")
.style("text-anchor","middle")
.style("font-weight","bold")
.text("Level")
this.s.chart.append("text")
.attr("x",this.width + 10 + (+this.s.toggles.select("rect").attr("width"))/2)
.attr("y", this.height*(6.4/10) )
.style("text-anchor","middle")
.style("font-weight","bold")
.text("Crowd")
}
FpChart.prototype.drawLabels = function(data) {
var _this = this;
this.s.chart.selectAll(".label")
.data(data)
.enter()
.append("text")
.attr("y", function(d) { return _this.scale.attraction(d.attraction) + _this.scale.attraction.bandwidth()/2})
.attr("x",10)
.text(function(d) { return d.attraction})
.style("text-anchor","start")
.attr("dy", ".37em")
.style("fill", "black")
.style("font-size",".78em")
}
FpChart.prototype.drawBars = function() {
var _this = this;
this.s.bars = this.s.chart.selectAll(".attraction")
.data(this.data)
.enter()
.append("rect")
.attr("x", function(d) { return _this.scale.time(d.crowdLevel.low.start)})
.attr("y", function(d) { return _this.scale.attraction(d.attraction)})
.attr("height", _this.scale.attraction.bandwidth())
.attr("width",function(d) { return _this.scale.time(d.crowdLevel.low.end) - _this.scale.time(d.crowdLevel.low.start) })
.style("fill", function(d) { return _this.scale.color(d.status)})
.style("stroke",function(d) { return _this.scale.color(d.status)})
.style("stroke-width",2)
.style("fill-opacity",.6)
}
FpChart.prototype.draw = function() {
this.s.svg = d3.select("#" + this.elementId)
.append("svg")
.attr("height", this.height + this.margin.top + this.margin.bottom)
.attr("width", this.width + this.margin.left + this.margin.right)
.style("-webkit-user-select","none")
.style("cursor","default");
this.s.chart = this.s.svg.append("g")
.attr("transform","translate(" + this.margin.left + "," + this.margin.top + ")");
}
FpChart.prototype.drawAxes = function() {
this.s.axis = {};
this.s.axis.bottom = this.s.chart.append("g").attr("transform","translate(0," + (this.height+2) + ")")
.call(this.axis.bottom);
this.s.axis.top = this.s.chart.append("g").attr("transform","translate(0,-2)").call(this.axis.top);
}
FpChart.prototype.setAxes = function() {
this.axis = {};
this.axis.bottom = d3.axisBottom(this.scale.time).tickFormat(d3.timeFormat('%I:%M %p'));
this.axis.top = d3.axisTop(this.scale.time).tickFormat(d3.timeFormat('%I:%M %p'));
}
FpChart.prototype.setScales = function() {
this.scale = {};
this.scale.color = d3.scaleOrdinal()
.domain(["available","runningOut","gone"])
.range(["#5cb85c","#f0ad4e","#d9534f"]);
this.scale.attraction = d3.scaleBand()
.domain(this.data.map(function(d) { return d.attraction}))
.range([0, this.height])
.padding(.23);
this.scale.time = d3.scaleTime()
.domain([new Date(2017, 7, 4, 9, 0, 0, 0),new Date(2017, 7, 4, 22, 0, 0, 0)])
.range([0,this.width]);
this.scale.toggle = d3.scaleBand()
.domain(this.toggleData.map(function(d) { return d.key}))
.range([this.height*(7/10), this.height*(9/10)])
this.scale.legend = d3.scaleBand()
.domain(this.scale.color.domain())
.range([this.height*(3/10), this.height*(5/10)])
.padding(.1)
}
FpChart.prototype.prepData = function(data) {
var _this = this;
this.data = [];
data.forEach(function(d){
["available","runningOut","gone"].forEach(function(e) {
var o = {attraction:d.attraction, status:e, crowdLevel: {low:{},med:{},high:{}}};
if(e == "available") {
o.crowdLevel.low.start = new Date(2017, 7, 4, 9, 0, 0, 0);
o.crowdLevel.med.start = new Date(2017, 7, 4, 9, 0, 0, 0);
o.crowdLevel.high.start = new Date(2017, 7, 4, 9, 0, 0, 0);
o.crowdLevel.low.end = !d.lowStart ? new Date(2017, 7, 4, 9, 0, 0, 0) : new Date(2017, 7, 4, 12 + d.lowStart, 0, 0, 0);
o.crowdLevel.med.end = !d.medStart ? new Date(2017, 7, 4, 9, 0, 0, 0) : new Date(2017, 7, 4, 12 + d.medStart, 0, 0, 0);
o.crowdLevel.high.end = !d.highStart ? new Date(2017, 7, 4, 9, 0, 0, 0) : new Date(2017, 7, 4, 12 + d.highStart, 0, 0, 0);
} else if (e == "runningOut") {
o.crowdLevel.low.start = !d.lowStart ? new Date(2017, 7, 4, 9, 0, 0, 0) : new Date(2017, 7, 4, 12 + d.lowStart, 0, 0, 0);
o.crowdLevel.med.start = !d.medStart ? new Date(2017, 7, 4, 9, 0, 0, 0) : new Date(2017, 7, 4, 12 + d.medStart, 0, 0, 0);
o.crowdLevel.high.start = !d.highStart ? new Date(2017, 7, 4, 9, 0, 0, 0) : new Date(2017, 7, 4, 12 + d.highStart, 0, 0, 0);
o.crowdLevel.low.end = !d.lowEnd ? new Date(2017, 7, 4, 9, 0, 0, 0) : new Date(2017, 7, 4, 12 + d.lowEnd, 0, 0, 0);
o.crowdLevel.med.end = !d.medEnd ? new Date(2017, 7, 4, 9, 0, 0, 0) : new Date(2017, 7, 4, 12 + d.medEnd, 0, 0, 0);
o.crowdLevel.high.end = !d.highEnd ? new Date(2017, 7, 4, 9, 0, 0, 0) : new Date(2017, 7, 4, 12 + d.highEnd, 0, 0, 0);
} else {
o.crowdLevel.low.start = !d.lowEnd ? new Date(2017, 7, 4, 9, 0, 0, 0): new Date(2017, 7, 4, 12 + d.lowEnd, 0, 0, 0);
o.crowdLevel.med.start = !d.medEnd ? new Date(2017, 7, 4, 9, 0, 0, 0): new Date(2017, 7, 4, 12 + d.medEnd, 0, 0, 0);
o.crowdLevel.high.start = !d.highEnd ? new Date(2017, 7, 4, 9, 0, 0, 0): new Date(2017, 7, 4, 12 + d.highEnd, 0, 0, 0);
o.crowdLevel.low.end = new Date(2017,7,4,22,0,0,0);
o.crowdLevel.med.end = new Date(2017,7,4,22,0,0,0);
o.crowdLevel.high.end = new Date(2017,7,4,22,0,0,0);
}
_this.data.push(o)
})
})
this.toggleData = [
{key:"low", value:"Low"},
{key:"med", value:"Medium"},
{key:"high", value:"High"}
];
this.legendData = [
{key:'available', value:'Available'},
{key:'runningOut', value:'Running Out'},
{key:'gone',value:'Gone'}
];
}
</script>
<body>
<div id="chartDiv"></div>
<script>
var fpChart = new FpChart({
elementId:"chartDiv",
data:dataIn,
height:450,
width:800,
margin: {top:25,left:30,bottom:25,right:130}
})
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment