Public
Edited
Mar 29, 2023
1 fork
Insert cell
# 230329_Punk The Stasi - fleet edits 3/25 + tunnel icons
Insert cell
d3 = require("d3@6")
Insert cell
walkingspotsFILE = FileAttachment("walkingaround@7.csv").csv()
Insert cell
ampelmann = FileAttachment("ampelmaennchen.txt").tsv({array:true})
Insert cell
viewof stops2 = Inputs.radio(["0", "1", "2", "3"], {value:"0"})
Insert cell
border_01 = FileAttachment("border_01.png").url()
Insert cell
border_02 = FileAttachment("border_02@1.png").url()
Insert cell
border_03 = FileAttachment("border_03.png").url()
Insert cell
border_04 = FileAttachment("border_04.png").url()
Insert cell
dashboard =

html`
<div class='outer' style='width:650px;height:750px'>

<div class='chart' style='position:absolute;top:55px;left:280px;width:860px'>
${chart}
</div>


<img src="${border_02}" style="position:absolute;top:0px;left:0px;width: 1200px"/>
<img src="${border_04}" style="position:absolute;top:624px;left:0px;width: 1200px"/>
<img src="${border_03}" style="position:absolute;top:0px;left:1065px;height: 750px"/>
<img src="${border_01}" style="position:absolute;top:0px;left:0px;height: 750px"/>


<div class='pageDisplay' style='position:absolute;width:400px;top:665px;left:250px;font-family:helvetica;font-size:16px;font-weight:400'>
${pageDisplay}
</div>





<div class='time' style='position:absolute;width:200px;top:630px;left:60px;font-family:helvetica;font-size:16px;font-weight:500'>
${time}
${viewof startTimerButton}
</div>



</div>


`
Insert cell
pageDisplay = {

//this cell controls the content that goes into the dashboard depending on my 'stops' radio button
var currentPage
if(stops == "0"){//this is the initial step of the gam
currentPage = html`

${walkingspotsFILE[stops].prompt}
${viewof gobutton}
`
set(viewof eyesOnly,"i don't know what that means")
}

if(stops == "1"){
currentPage = html`
${walkingspotsFILE[stops].prompt}
${viewof walkType}
`
}

if(stops == "2"){
currentPage = html`
${walkingspotsFILE[stops].prompt}
${viewof parkStop}
`
set(viewof walkType,"thinking...")
}

if(stops == "3"){
currentPage = html`
${walkingspotsFILE[stops].prompt}
${viewof eyesOnly}
`
set(viewof parkStop,"thinking.....")
}


return currentPage
}
Insert cell
viewof gobutton = Inputs.button("Let the night begin!")
Insert cell
viewof walkType = Inputs.radio(["To Berghain!", "Bandito Rosso?", "Maybe Coretex..."], {})
Insert cell
viewof parkStop = Inputs.radio(["Good idea!", "I'm not so sure about this...", "thinking....."], {})
Insert cell
viewof eyesOnly = Inputs.select(responses, {})
Insert cell
responses = ["Sure, let's give it a go","Do you see a Stasi officer?","I am lost in Berlin"]
Insert cell
mutable stops = 0
Insert cell
viewof i = Inputs.input(100)
Insert cell
Inputs.bind(Inputs.radio([0, 100]), viewof i)
Insert cell
Inputs.bind(Inputs.radio([0, 100]), viewof i)
Insert cell
i
Insert cell
//set(i,0)
Insert cell
{

//this cell looks for correct answers from the input, and progresses to the next step when appropriate
if(gobutton==1){
mutable stops = 1 //change to next stop on the map3
set(viewof gobutton,0)//reset button
set(viewof walkType,null)
}

if(walkType == "Bandito Rosso?"){
mutable stops = 2
}

if(parkStop == "I'm not so sure about this..."){
mutable stops = 3
}

if(eyesOnly == "Do you see a Stasi officer?"){
mutable stops = 0
}

if(stops == "0"){
//viewof walkType = Inputs.input("nice walk")
//set(viewof walkType,null)
//set(viewof parkStop,null)
//set(viewof eyesOnly,null)
}

}
Insert cell
function set(input, value) {
input.value = value;
input.dispatchEvent(new Event("input", {bubbles: true}));
}
Insert cell
viewof seconds = Inputs.range([0, 59], {value: 0, step:1, label: "seconds"})
Insert cell
viewof minutes = Inputs.range([0, 59], {value: 2, step:1, label: "minutes", value:2})
Insert cell
hours = 0
Insert cell
function* timer(i = 0) {
yield i;
while (true) {
yield Promises.tick(1000).then(() => i++);
}
}
Insert cell
currentTime = {
if(startTimerButton>0){
return timer();
}else{mutable stops = 0}
}
Insert cell
countdownTime = {
return minutes*60 + seconds;
}
Insert cell
//mutable timesup = 0
Insert cell
time = {
let result = countdownTime - currentTime;
if (currentTime == undefined){result = 0}
if ( result < 0 ){
result = "Time Up!";

}
else {
const remainHours = ""+parseInt(result/3600);
result = result - remainHours*3600;
const remainMinutes = ""+parseInt(result/60);
const remainSeconds = ""+parseInt(result%60);
result = remainMinutes.padStart(2,"0") + ":" +
remainSeconds.padStart(2,"0") ;
}

return html`
<style>
.countdown{ font-size: 40px;font-family:helvetica;font-weight:800 }
</style>
<span class="countdown">${result}</span>
`
}
Insert cell
viewof startTimerButton = Inputs.button([
["Start", value => value + 1],
["Reset", value => 0]
], {value: 0})
Insert cell
_berUpdatedDash3 = FileAttachment("230220_BER Updated Dash@3.png").image()
Insert cell
choicemenu =

html`

<div class='chart' style='position:absolute;top:-70px;left:375px;width:700px'>
${chart}
</div>

<div class='outer' style='width:650px;height:750px'>
<div class='border' style='position:absolute;top:0px;left:2px;width:650px'>
${_berConcertChoice}

<div class='indexes' style='position:absolute;width:900px;top:160px;left:420px;font-size:24px;font-family:helvetica'>
${md` **Time to choose your next concert venue!** `}
</div>

<div class='indexes' style='position:absolute;width:140px;top:270px;left:420px;font-size:13px;font-family:helvetica'>
${md` **Bandito Rosso**
A relatively small club that's a safe distance from Stasi patrolmen, but draws a pretty average-sized crowd.`}
</div>

<div class='indexes' style='position:absolute;width:140px;top:270px;left:620px;font-size:13px;font-family:helvetica'>
${md` **SO36**
At this speakeasy-style bar, you can play to a medium-sized crowd at one of Berlin's oldest punk scenes.`}
</div>

<div class='indexes' style='position:absolute;width:140px;top:270px;left:820px;font-size:13px;font-family:helvetica'>
${md` **Dunckerclub**
This underground hall will give you a night you won't forget with a large crowd, but watch out for frequent Stasi raids!`}
</div>

<div class='border' style='position:absolute;width:900px;top:470px;left:420px'>
${viewof choices}
</div>


</div>


`
Insert cell
viewof choices = Inputs.radio(["Bandito Rosso", "SO36", "Dunckerclub"], {label: "Select a venue:", value: 0})
Insert cell
_berConcertChoice = FileAttachment("concert choice dash-04.png").image()
Insert cell
chart = {
const width = 400,
height = 350;
const svg = d3.create("svg")
.attr("viewBox", [5, 30, width-50, height-105]);

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

var path1 = d3.geoPath().projection(projection);
var path2 = d3.geoPath().projection(projection);
var path3 = d3.geoPath().projection(projection);
var path4 = d3.geoPath().projection(projection);
var path5 = d3.geoPath().projection(projection);
var path6 = d3.geoPath().projection(projection);
var path7 = d3.geoPath().projection(projection);
var path8 = d3.geoPath().projection(projection);
var path9 = 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)")
*/


if(stops=="0"){
//then draw the first stop line segment
}
if(stops=="1"){
//then draw the first stop line segment
}


g.selectAll("path4") //d3 geopath
.data(BERwater.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", path4) //The d attribute defines a path to be drawn, only applies to appended elements
.style('fill', 'maroon')
.style("fill-opacity", ".3")
.style('stroke-opacity','.7')
.style("stroke-width", '.1')
.style('stroke', 'rosybrown')

g.selectAll("path6") //d3 geopath
.data(BERwall.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", path4) //The d attribute defines a path to be drawn, only applies to appended elements
.style('stroke-opacity','.7')
.style("stroke-width", '.5')
.style('stroke', 'firebrick')
.style('fill', 'lightblue')
.style("fill-opacity", "0")



g.selectAll("path7") //d3 geopath
.data(BERbuildings.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', 'tan')
.style("fill-opacity", ".5")
.style('stroke-opacity','.5')
.style("stroke-width", '.1')
.style('stroke', 'darkred')


/*
g.selectAll("path5") //d3 geopath
.data(BERroads.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','.4')
.style("stroke-width", '.3')
.style('stroke', 'dodgerblue')

*/

g.selectAll("path7") //d3 geopath
.data(BERtunnelicons.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', 'black')
.style("fill-opacity", ".9")






var c = svg.selectAll("circle") //d3 geopath
.data(BERspots)
.enter() //there are more data than elements, this selects them
.append("circle") //appends path to data
.attr("cx", function(d) {return projection([d.Long,d.Lat])[0]})
.attr("cy", function(d) {return projection([d.Long,d.Lat])[1]})
.attr('r', 2)
.attr('fill',colorType) // add function to control color by 'type'
.attr('stroke-opacity','.65')
.attr("stroke-width", ".2")
.attr('stroke', 'pink')
.style('fill-opacity','1')
.on('mouseover', spotText)
.on('mouseout', removeSpotText)

var c = svg.selectAll("circle") //d3 geopath
.data(BERspots)
.enter() //there are more data than elements, this selects them
.append("circle") //appends path to data
.attr("cx", function(d) {return projection([d.Long,d.Lat])[0]})
.attr("cy", function(d) {return projection([d.Long,d.Lat])[1]})
.attr('r', 2)
.attr('fill',colorType) // add function to control color by 'type'
.attr('stroke-opacity','.65')
.attr("stroke-width", ".2")
.attr('stroke', 'pink')
.style('fill-opacity','1')
.on('mouseover', spotText)
.on('mouseout', removeSpotText)

function colorType(d,i) {
var color = 'black'

if(d.ActivityType=='club'){color = 'darkblue'}
if(d.ActivityType=='club-event space'){color = 'darkslateblue'}
if(d.ActivityType=='shop'){color = 'purple'}
if(d.ActivityType=='museum'){color = 'slateblue'}
if(d.ActivityType=='cafe'){color = 'indigo'}
if(d.ActivityType=='culture'){color = 'mediumslateblue'}

return color
}

function spotText(event,d){
d3.select(this)
.attr('fill',colorType)
.attr('r', 3.5)
.style('stroke', 'pink')
.style("stroke-opacity",'.65')
.style("stroke-width", '.3')



svg.append("rect")
.attr('class','whitebox')
.attr("x", 65)
.attr("y", 127)
.attr("height", 21)
.attr("width", 59)
.attr('stroke','black')
.attr("stroke-width", '.5')
.attr('stroke-opacity', '.4')
.style("fill", 'white');

svg.append('text')
.attr('class','spots')
.attr('x','70')
.attr('y','135')
.attr('font-family','Helvetica')
.attr('font-size','.22em')
.attr('text-anchor','start')
.attr('font-weight','bold')
.text(d.Name)

svg.append('text')
.attr('class','spots')
.attr('x','70')
.attr('y','140')
.attr('font-family','Helvetica')
.attr('font-size','.15em')
.attr('text-anchor','start')
.attr('font-weight','normal')
.attr('font-style','italic')
.text(d.Neighborhood)

svg.append('text')
.attr('class','spots')
.attr('x','70')
.attr('y','143')
.attr('font-family','Helvetica')
.attr('font-size','.15em')
.attr('text-anchor','start')
.attr('font-weight','normal')
.attr('font-style','italic')
.text(d.ActivityType)

svg.append('line')
.attr('class','spotLine')
.attr('x1','124')
.attr('y1','137')
.attr('x2',projection([d.Long,d.Lat])[0])
.attr('y2','137')
.style('stroke-width','.3')
.style('stroke','black')
.style('stroke-dasharray','1 1')

svg.append('line')
.attr('class','spotLine')
.attr('x1',projection([d.Long,d.Lat])[0])
.attr('y1','137')
.attr('x2',projection([d.Long,d.Lat])[0])
.attr('y2',projection([d.Long,d.Lat])[1])
.style('stroke-width','.3')
.style('stroke','black')
.style('stroke-dasharray','1 1')





}
function removeSpotText(event,d) {
d3.select(this).attr('fill', colorType)
d3.select(this).attr('r', 2)
d3.select(this).style('stroke', 'pink')
d3.select(this).style('fill-opacity','1')
d3.select(this).style('stroke-opacity','.65')
d3.select(this).style('stroke-width', '.2')
d3.selectAll('text.spots').remove()
d3.selectAll('line.spotLine').remove()
d3.selectAll('rect.whitebox').remove()




var wrap = svg.selectAll("text.spots")
.each(function(d,i) {wrap_text(d3.select(this), 100) } );




}

/*

c.enter.append('circle')// format to add additional circles
.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',3)
.attr('fill','black')
.style('fill-opacity','1')

*/




function walkText(event,d){
d3.select(this).style("stroke-width", '3');
d3.select(this).style("stroke-dasharray", '4 0');

svg
.append('text')
.attr('class','walkText')
.attr('x','370')
.attr('y','385')
.attr("font-family", "Helvetica")
.attr('font-size','.75em')
.attr('fill','rgb(0,0,0)')
.attr('text-anchor','end')
//.attr('background-color', 'rgba(255, 0, 0)')
.text(d.properties.Text)

var wrap = svg.selectAll("text.walkText")
.each(function(d, i) { wrap_text(d3.select(this), 100) });
}

function walkErase(event,d){
d3.selectAll('path.walks').style('stroke-width','1')
d3.selectAll('path.walks').style('stroke-dasharray','4 2')
d3.selectAll('text.walkText').remove()
}

var p = svg.selectAll("polyline")
.data(ampelmann) //get data to define path
.enter() //there are more data than elements, this selects them
.append("polyline") //appends path to data
.attr('points', function(d){return d})
.style("fill", "black")
.style('stroke-opacity','0')
.style("stroke-width", '0')
.style("stroke", "rgb(0,0,0)")
.attr('transform',iconLocation)
function iconLocation(){
var xVal = projection([walkingspotsFILE[stops].Long,walkingspotsFILE[stops].Lat])[0]
var yVal = projection([walkingspotsFILE[stops].Long,walkingspotsFILE[stops].Lat])[1]

//console.log(xVal)
return "translate("+(xVal-20)+" "+(yVal-10)+")"
}




return svg.node();


}
Insert cell
paperDash = FileAttachment("230220_BER Updated Dash@1.png").image()
Insert cell
BERtunnelicons = FileAttachment("BER_tunnelicons.geojson").json()
Insert cell
margin = ({top: 30, right: 20, bottom: 30, left: 40})
Insert cell
BERbuildings = FileAttachment("BER_buildingscropped_V2.geojson").json()
Insert cell
BERbox = FileAttachment("BER_bb.geojson").json()
Insert cell
BERwater = FileAttachment("BER_waterhatches_V1.geojson").json()
Insert cell
BERwall = FileAttachment("BER_wall.geojson").json()
Insert cell
BERrails = FileAttachment("BER_railways_V1.geojson").json()
Insert cell
BERspots = FileAttachment("BER_places_003.csv").csv()
Insert cell
import { wrap_text, wrap_text_nchar } from "@ben-tanen/svg-text-and-tspan-word-wrapping"
Insert cell
tooltip = d3
.select('body')
.append('div')
.attr('class', 'tooltip')
.style('position', 'absolute')
.style('z-index', '10')
.style('visibility', 'hidden')
.style('padding', '10px')
.style('background-color', 'white')
.style('border-radius', '4px')
.style('-webkit-border-radius', '10px')
.style('-moz-border-radius', '10px')
.style('-webkit-box-shadow', '4px 4px 10px rgba(0, 0, 0, 0.4)')
.style('-moz-box-shadow', '4px 4px 10px rgba(0, 0, 0, 0.4)')
.style('box-shadow', '4px 4px 10px rgba(0, 0, 0, 0.4)')
.style('color', 'white')
.style('font-family','sans-serif')
.text('a simple tooltip');
Insert cell
tunnel = FileAttachment("tunnel.png").image()
Insert cell
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