Public
Edited
Feb 8, 2023
1 fork
Insert cell
# CASE Field Trip Game
Insert cell
boundingBox = FileAttachment("Bounding Box 2.geojson").json()
Insert cell
boroughBoundaries = FileAttachment("Borough Boundaries.geojson").json()
Insert cell
ferryLine = FileAttachment("Ferry Line.geojson").json()
Insert cell
parkWaters = FileAttachment("Park Waters.geojson").json()
Insert cell
parks2V2 = FileAttachment("Parks 2 v2.geojson").json()
Insert cell
parksV2 = FileAttachment("Parks v2.geojson").json()
Insert cell
streets = FileAttachment("Streets.geojson").json()
Insert cell
waterfrontParks2 = FileAttachment("Waterfront Parks 2.geojson").json()
Insert cell
d3 = require("d3@6")
Insert cell
/* totalValues = {
var totalTime = 0
totalTime = totalTime +(triptime[0].time*cemetery)
totalTime = totalTime +(triptime[1].time*bat)
totalTime = totalTime +(triptime[2].time*ferry)
totalTime = totalTime +(triptime[3].time*rockawaybeach)
totalTime = totalTime +(triptime[4].time*twa)

var totalExperience = 0
totalExperience = totalExperience +(triptime[0].experience*cemetery)
totalExperience = totalExperience +(triptime[1].experience*bat)
totalExperience = totalExperience +(triptime[2].experience*ferry)
totalExperience = totalExperience +(triptime[3].experience*rockawaybeach)
totalExperience = totalExperience +(triptime[4].experience*twa)

return [totalTime,totalExperience]
}
*/
Insert cell
tripemoji = [
{ emoji: "🤩", feeling: "amazing",},
{ emoji: "🤷", feeling: "alright" },
{ emoji: "💩", feeling: "terrible" }
]
Insert cell
totalEmotions = {
var totalEmoji = 0
totalEmoji = totalEmoji +(cemetery)
totalEmoji = totalEmoji +(bat)
totalEmoji = totalEmoji +(ferry)
totalEmoji = totalEmoji +(rockawaybeach)
totalEmoji = totalEmoji +(twa)
var totalFeeling = 0
totalFeeling = totalFeeling +(cemetery)
totalFeeling = totalFeeling +(bat)
totalFeeling = totalFeeling +(ferry)
totalFeeling = totalFeeling +(rockawaybeach)
totalFeeling = totalFeeling +(twa)

return [totalEmoji, totalFeeling]
}
Insert cell
//viewof emojis = tripemoji.select(["🤩", "🤷", "💩"])
Insert cell
triptime = [//create time to complete all field trip stops tt: trip time
{name:"cemetery", time:2, experience:"60"},
{name:"bat", time:1.5, experience:"95"},
{name:"ferry", time:0.5, experience:"90"},
{name:"rockawaybeach", time:.5, experience:"85"},
{name:"twa", time:2, experience:"100"},

]
Insert cell
totalValues = {
var totalTime = 0
totalTime = totalTime +(cemetery)
totalTime = totalTime +(bat)
totalTime = totalTime +(ferry)
totalTime = totalTime +(rockawaybeach)
totalTime = totalTime +(twa)

var totalExperience = 0
totalExperience = totalExperience +(triptime[0].experience*cemetery)
totalExperience = totalExperience +(triptime[1].experience*bat)
totalExperience = totalExperience +(triptime[2].experience*ferry)
totalExperience = totalExperience +(triptime[3].experience*rockawaybeach)
totalExperience = totalExperience +(triptime[4].experience*twa)

return [totalTime,totalExperience]
}
Insert cell
viewof emojis = Inputs.select(tripemoji, {label: "Overall trip experience", format: x => x.emoji, value: tripemoji.find(s => s.emoji === "🤩")})
Insert cell
viewof cemetery = Inputs.range([0, 3], {step: .5, label: "Greenwood Cemetery", value:0})
Insert cell
viewof bat = Inputs.range([0, 3], {step: .5, label: "BAT", value:0})
Insert cell
viewof ferry = Inputs.range([0, 3], {step: .5, label: "Ferry", value:0})
Insert cell
viewof rockawaybeach = Inputs.range([0, 3], {step: .5, label: "Rockaway Beach", value:0})
Insert cell
viewof twa = Inputs.range([0, 3], {step: .5, label: "TWA Hotel", value:0})
Insert cell
chart = {
const width = 960,
height = 900;
const svg = d3.create("svg")
.attr("viewBox", [12, 60, width-100, height-80]);

// Use Mercator projection
var projection = d3
.geoMercator()
.fitSize([width - 60, height - 50], boundingBox);

var path1 = d3.geoPath().projection(projection);
var path2 = d3.geoPath().projection(projection);
var path3 = d3.geoPath().projection(projection);

var g = svg.append("g").attr("id", "paths");
//i'm not using the boundary lines, so I'm going to comment them out
/*
g.selectAll("path1") //d3 geopath
.data(boundary.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path1) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '.5')
.style("stroke", "rgb(0,0,0)")
*/

//Mission: find the exact time and tranportation it takes to have the best CASE Field Trip!
//Greenwood Cemetery: 9:30 10 10:30 11:30 total hours: 2 hrs (0-3)
//BAT: 11:30 12:00 12:30 1:00 total hours: 1:45 hrs
//Ferry: 12:30 1:15 2:00 1:45 total hours: 45 min
//Rockaway Beach: 1:15 1:30 2:15 2:30 total hrs: 30min
//TWA Hotel: 2:30 3:00 3:30 4:30 total hours: 2 hrs
// Ideal total hours: 7hrs
// Total trip experience: 100
// Total transportation: 2
// Congrats, you had the Best CASE Trip!
// Too slow! you're falling behind :(
// Too fast! you're getting ahead of the group
// [0,3] stepvalue: 0.5


svg.append('image')
.attr('href',streetsUnderlay)
.attr('class','spotImage')
.attr('x', '-15')
.attr('y','-50')
.attr('width', 905)
.attr('height', 845)


g.selectAll("path3") //d3 geopath
.data(boroughs1.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path3) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1.25')
.style("stroke", "slategrey")

g.selectAll("path3") //d3 geopath
.data(boroughs2.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path3) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "slategrey")
.style("fill-opacity", ".1")
.style('stroke-opacity','1')
.style("stroke-width", '.5')
.style("stroke", "slategrey")

g.selectAll("path3") //d3 geopath
.data(parks2V2.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path3) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "lightsteelblue")
.style("fill-opacity", ".5")
.style('stroke-opacity','.1')
.style("stroke-width", '.1')
.style("stroke", "lightsteelgrey")

g.selectAll("path3") //d3 geopath
.data(parks3.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path3) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "none")
.style("fill-opacity", ".5")
.style('stroke-opacity','.1')
.style("stroke-width", '.1')
.style("stroke", "lightsteelgrey")
g.selectAll("path3") //d3 geopath
.data(waterfrontParks2.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path3) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "slategrey")
.style("fill-opacity", ".1")
.style('stroke-opacity','.1')
.style("stroke-width", '.1')
.style("stroke", "lightslategrey")

g.selectAll("path3") //d3 geopath
.data(parkWaters.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path3) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "none")
.style('stroke-opacity','.1')
.style("stroke-width", '.1')
.style("stroke", "black")

g.selectAll("path2") //d3 geopath
.data(ferryLine.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path2) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '2')
.style("stroke", "dodgerblue")
.style('stroke-dasharray','2 2')

g.selectAll("path2") //d3 geopath
.data(trail1.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path2) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '2')
.style("stroke", "dodgerblue")
.style('stroke-dasharray','2 2')

g.selectAll("path2") //d3 geopath
.data(trail2.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path2) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '2')
.style("stroke", "dodgerblue")
.style('stroke-dasharray','2 2')
g.selectAll("path2") //d3 geopath
.data(batBoundary.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path2) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "slategrey")
.style("fill-opacity", ".3")
.style('stroke-opacity','.1')
.style("stroke-width", '.1')
.style("stroke", "lightslategrey")
.on('mouseover', spotImage3)
.on('mouseout', removespotImage3)
g.selectAll("path2") //d3 geopath
.data(rockawayBeachBoundary.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path2) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "slategrey")
.style("fill-opacity", ".3")
.style('stroke-opacity','.1')
.style("stroke-width", '.1')
.style("stroke", "lightslategrey")
.on('mouseover', spotImage2)
.on('mouseout', removespotImage2)

g.selectAll("path2") //d3 geopath
.data(cemeteryBoundary.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path2) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "slategrey")
.style("fill-opacity", ".3")
.style('stroke-opacity','.1')
.style("stroke-width", '.1')
.style("stroke", "lightslategrey")
.on('mouseover', spotImage1)
.on('mouseout', removespotImage1)

g.selectAll("path2") //d3 geopath
.data(twaBoundary2.features) //get data to define path
.enter() //there are more data than elements, this selects them
.append("path") //appends path to data
.attr('class','outlines')
.attr("d", path2) //The d attribute defines a path to be drawn, only applies to appended elements
.style("fill", "slategrey")
.style("fill-opacity", ".3")
.style('stroke-opacity','.1')
.style("stroke-width", '.1')
.style("stroke", "lightslategrey")
.on('mouseover', spotImage)
.on('mouseout', removespotImage)
function spotImage(event,d){
d3.select(this).attr('fill','lavenderblush')
svg.append('image')
.attr('xlink:href','https://api.time.com/wp-content/uploads/2019/08/twa-hotel-queens-new-york.jpg')
.attr('class','spotImage')
.attr('x', '485')
.attr('y','720')
.attr('width', 350)
.attr('height', 150)
}
function removespotImage(event,d){
d3.select(this).attr('fill',colorType)
d3.selectAll('image.spotImage').remove()
}

function spotImage1(event,d){
d3.select(this).attr('fill','lavenderblush')
svg.append('image')
.attr('xlink:href','https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/Green-Wood_Cemetery_gate_%2853784p%29_cropped.jpg/1200px-Green-Wood_Cemetery_gate_%2853784p%29_cropped.jpg')
.attr('class','spotImage1')
.attr('x', '485')
.attr('y','720')
.attr('width', 350)
.attr('height', 150)
}
function removespotImage1(event,d){
d3.select(this).attr('fill',colorType)
d3.selectAll('image.spotImage1').remove()
}

function spotImage2(event,d){
d3.select(this).attr('fill','lavenderblush')
svg.append('image')
.attr('xlink:href','https://media.timeout.com/images/103881813/750/562/image.jpg')
.attr('class','spotImage2')
.attr('x', '485')
.attr('y','720')
.attr('width', 350)
.attr('height', 150)
}
function removespotImage2(event,d){
d3.select(this).attr('fill',colorType)
d3.selectAll('image.spotImage2').remove()
}

function spotImage3(event,d){
d3.select(this).attr('fill','lavenderblush')
svg.append('image')
.attr('xlink:href','https://www.nycgo.com/images/venues/30801/brooklyn-army-terminal-sunset-park-manhattan-nyc-freightnyc_july_2018-071__large.jpg')
.attr('class','spotImage3')
.attr('x', '485')
.attr('y','720')
.attr('width', 350)
.attr('height', 150)
}
function removespotImage3(event,d){
d3.select(this).attr('fill',colorType)
d3.selectAll('image.spotImage3').remove()
}

var c = svg.selectAll("circle") //d3 geopath
.data(spots)
.enter() //there are more data than elements, this selects them
.append("circle") //appends path to data
.attr("cx", function(d) {return projection([d.longitude, d.latitude])[0]})
.attr("cy", function(d) {return projection([d.longitude, d.latitude])[1]})
.attr('r',4)
.attr('fill',colorType)
.style('fill-opacity','2')
.style('stroke','black')
.style('stroke-width','.8')
.on('mouseover', spotText)
.on('mouseout', removespotText)

function colorType(d,i){
var color = 'steelblue'
if(d.type=='Food'){color = 'steelblue'}
if(d.type=='Academics'){color = 'steelblue'}
if(d.type=='House'){color = 'steelblue'}
if(d.type=='Sports Facility'){color = 'steelblue'}
if(d.type=='Social Facility'){color = 'steelblue'}
if(d.type=='Market'){color = 'steelblue'}
if(d.type=='Field'){color = 'steelblue'}
return color

}


svg.append('text')
//.attr('class','spotInfo')
.attr('x','145')
.attr('y','725')
.attr('font-family','Helvetica')
.attr('font-size','.8em')
.attr('font-weight','light')
.attr('text-anchor','end')
.text(totalValues[0])

svg.append('text')
//.attr('class','spotInfo')
.attr('x','40')
.attr('y','725')
.attr('font-family','Helvetica')
.attr('font-size','.8em')
.attr('font-weight','bold')
.attr('text-anchor','start')
.text('Total Hours: ')

svg.append('text')
//.attr('class','spotInfo')
.attr('x','190')
.attr('y','745')
.attr('font-family','Helvetica')
.attr('font-size','.8em')
.attr('font-weight','light')
.attr('text-anchor','end')
.text(totalValues[1])
svg.append('text')
//.attr('class','spotInfo')
.attr('x','40')
.attr('y','745')
.attr('font-family','Helvetica')
.attr('font-size','.8em')
.attr('font-weight','bold')
.attr('text-anchor','start')
.text('Total Experience: ')

svg.append("rect")
.attr("x", 33)
.attr("y", 708)
.attr("width", 162)
.attr("height", 44)
.attr('fill', 'lightsteelblue')
.style('fill-opacity','.1')
.style('stroke', 'slategrey')
.style('stroke-width', '0.75')
if(totalEmotions[0]="🤩" && totalValues[1]>450){
svg.append('text')
.attr('class','spots')
.attr('x','480')
.attr('y','135')
.attr('font-family','Helvetica')
.attr('font-size','.8em')
.attr('text-anchor','middle')
.attr('font-weight','bold')
.text('(YOU WERE GREAT!)')
}

if(totalEmotions[0]="🤷" && totalValues[0]>5 && totalValues[1]<450){
svg.append('text')
.attr('class','spots')
.attr('x','480')
.attr('y','135')
.attr('font-family','Helvetica')
.attr('font-size','.8em')
.attr('text-anchor','middle')
.attr('font-weight','bold')
.text('(YOU WERE A TROOPER!)')
}

if(totalEmotions[0]="💩" && totalValues[1]<350){
svg.append('text')
.attr('class','spots')
.attr('x','480')
.attr('y','135')
.attr('font-family','Helvetica')
.attr('font-size','.8em')
.attr('text-anchor','middle')
.attr('font-weight','bold')
.text('(BETTER LUCK NEXT TIME!)')
}
if(totalValues[0]>7){
svg.append('text')
.attr('class','spots')
.attr('x','480')
.attr('y','120')
.attr('font-family','Helvetica')
.attr('font-size','1.5em')
.attr('text-anchor','middle')
.attr('font-weight','bold')
.text('⌛TOO SLOW⌛')
}

if(totalValues[0]<5){
svg.append('text')
.attr('class','spots')
.attr('x','480')
.attr('y','120')
.attr('font-family','Helvetica')
.attr('font-size','1.8em')
.attr('text-anchor','middle')
.attr('font-weight','bold')
.text('🏃🏻TOO RUSHED🏃🏻')
}
if(totalValues[0]<7 && totalValues[1]>450 ){
svg.append('text')
.attr('class','spots')
.attr('x','480')
.attr('y','120')
.attr('font-family','Helvetica')
.attr('font-size','1.8em')
.attr('text-anchor','middle')
.attr('font-weight','bold')
.text('💯 PERFECT TRIP 💯')
}

function spotText(event,d){
d3.select(this).attr('fill','lavenderblush')
svg.append('text')
.attr('class','spots')
.attr('x', '550')
.attr('y','687')
.attr('font-family','Helvetica')
.attr('font-size', '.7em')
.attr('text.anchor','start')
.attr('font-weight', 'bold')
.text(d.name)

svg.append('text')
.attr('class','spots')
.attr('x', '550')
.attr('y','705')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text(d.description)

svg.append('line')
.attr('class','spotLine')
.attr('x1', '550')
.attr('y1', '692')
.attr('x2', projection([d.longitude, d.latitude])[0])
.attr('y2', '692')
.style('stroke-width','.5')
.style('stroke','black')
.style('stroke-dasharray','2 2')
svg.append('line')
.attr('class','spotLine')
.attr('x1', projection([d.longitude, d.latitude])[0])
.attr('y1', '692')
.attr('x2', projection([d.longitude, d.latitude])[0])
.attr('y2', projection([d.longitude, d.latitude])[1])
.style('stroke-width','.7')
.style('stroke','darkblue')
.style('stroke-dasharray','2 2')
}
function removespotText(event,d){
d3.select(this).attr('fill',colorType)
d3.selectAll('text.spots').remove()
d3.selectAll('line.spotLine').remove()
}





return svg.node();
}
Insert cell
streetsUnderlay = FileAttachment("Streets Underlay.png").url()
Insert cell
twaBoundary2 = FileAttachment("TWA boundary 2.geojson").json()
Insert cell
twaBoundary = FileAttachment("TWA boundary.geojson").json()
Insert cell
batBoundary = FileAttachment("BAT boundary@1.geojson").json()
Insert cell
cemeteryBoundary = FileAttachment("Cemetery boundary.geojson").json()
Insert cell
rockawayBeachBoundary = FileAttachment("Rockaway beach boundary.geojson").json()
Insert cell
park3 = FileAttachment("PARK 3.geojson").json()
Insert cell
trail1 = FileAttachment("trail 1.geojson").json()
Insert cell
trail2 = FileAttachment("trail 2.geojson").json()
Insert cell
trail = FileAttachment("trail.geojson").json()
Insert cell
parks3 = FileAttachment("Parks 3.geojson").json()
Insert cell
parks2V3 = FileAttachment("Parks 2 v3.geojson").json()
Insert cell
bboxHatch = FileAttachment("bbox hatch.geojson").json()
Insert cell
boroughs1 = FileAttachment("Boroughs 1.geojson").json()
Insert cell
boroughs2 = FileAttachment("Boroughs 2.geojson").json()
Insert cell
Insert cell
spots = d3.csv(spotsLink,d3.autoType)
Insert cell
streetsunderlay = FileAttachment("StreetsUnderlay.png").url()
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more