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.
forked from TommyCoin80's block: stacked normailzed hz pkl
forked from noblemillie's block: stacked normailzed hz pkl
forked from noblemillie's block: stacked normailzed hz pkl
xxxxxxxxxx
<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(4000)
.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(4000)
.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>
https://d3js.org/d3.v4.min.js