Public
Edited
Nov 9, 2022
Insert cell
# Paris Transit History Map 11.9.22
Insert cell
function getDistance(x1, y1, x2, y2){
let y = x2 - x1;
let x = y2 - y1;
return Math.sqrt(x * x + y * y);
}
Insert cell
d3 = require("d3@6")
Insert cell
bbox1 = FileAttachment("bbox.geojson").json()
Insert cell
GreenSpaces = FileAttachment("simplified green spaces.geojson").json()
Insert cell
railSpot = FileAttachment("railLn.geojson").json()
Insert cell
statSpot = FileAttachment("statSpot@1.geojson").json()
Insert cell
distSpot = FileAttachment("distSpot@1.geojson").json()
Insert cell
cSpot = FileAttachment("cSpot@1.geojson").json()
Insert cell
keyText = FileAttachment("keyText@1.geojson").json()
Insert cell
mapKey = FileAttachment("keyOutline.geojson").json()
Insert cell
lines1 = FileAttachment("19001920lines.geojson").json()
Insert cell
lines2 = FileAttachment("19201940lines.geojson").json()
Insert cell
lines3 = FileAttachment("19401960lines.geojson").json()
Insert cell
lines4 = FileAttachment("19601980lines.geojson").json()
Insert cell
lines5 = FileAttachment("19802000lines.geojson").json()
Insert cell
lines6 = FileAttachment("20002020lines.geojson").json()
Insert cell
lines7 = FileAttachment("2020lines.geojson").json()
Insert cell
bikeRoute = FileAttachment("bike route@1.geojson").json()
Insert cell
funSpotsLines = FileAttachment("fun spots lines@1.geojson").json()
Insert cell
outdoorScenicRoutes = FileAttachment("outdoor scenic routes.geojson").json()
Insert cell
existingRoutesForBus = FileAttachment("existing routes for bus and shuttle.geojson").json()
Insert cell
newRoutesForBus = FileAttachment("new routes for bus and shuttle.geojson").json()
Insert cell
rer = FileAttachment("RER.geojson").json()
Insert cell
stations = FileAttachment("stations@1.geojson").json()
Insert cell
Streets = FileAttachment("simplified streets.geojson").json()
Insert cell
water = FileAttachment("water@2.geojson").json()
Insert cell
district1 = FileAttachment("1901 district.geojson").json()
Insert cell
district2 = FileAttachment("1921 district.geojson").json()
Insert cell
district3 = FileAttachment("1946 district.geojson").json()
Insert cell
district4 = FileAttachment("1968 district.geojson").json()
Insert cell
district5 = FileAttachment("1990 district.geojson").json()
Insert cell
district6 = FileAttachment("2007 district.geojson").json()
Insert cell
district7 = FileAttachment("2017 district.geojson").json()
Insert cell
suburb1 = FileAttachment("1920-1940 suburb.geojson").json()
Insert cell
suburb2 = FileAttachment("1940-1960 suburb.geojson").json()
Insert cell
suburb3 = FileAttachment("1960-1980 suburb.geojson").json()
Insert cell
suburb4 = FileAttachment("1980-2000 suburb.geojson").json()
Insert cell
Underratedspots = d3.csv(UnderratedSpotsLink, d3.autoType)
Insert cell
Insert cell
Insert cell
spots = d3.csv(SpotsLink, d3.autoType)
Insert cell
layers = ['1900 - 1920', '1920 - 1940', '1940 - 1960','1960 - 1980','1980 - 2000','2000 - 2022','Full','Proposed']
Insert cell
districtsCombined = FileAttachment("Districts Combined V4.geojson").json()
Insert cell
import { wrap_text, wrap_text_nchar } from "@ben-tanen/svg-text-and-tspan-word-wrapping"
Insert cell
color = d3.scaleQuantize([8500, 100000], d3.schemePurples[9])
Insert cell
viewof uSpots = Inputs.select(Underratedspots, {label: "Cultural Spots", format: x => x.description, value: Underratedspots.find(s => s.description === "Museum")})
Insert cell
chart = {
const width = 960,
height = 900;
const svg = d3.create("svg")
.attr("viewBox", [0, 50, width-100, height-100]);

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

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 g = svg.append("g").attr("id", "paths");

var clickYear = 2000
var clicks = []
//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)")
*/


console.log(uSpots)
console.log(uSpots.latitude)


svg
.on('click',function(event){
var coords = d3.pointer(event)
console.log(coords[0],coords[1])

clicks.push(coords)

console.log(clicks)

c.enter().append("circle")
.data(clicks)
.enter()
.append("circle")
.attr("cx", function(d) {return d[0]})
.attr("cy", function(d) {return d[1]})
.attr('r',3)
.attr('fill','cyan')
.style('fill-opacity','1')

var distances = []
//loop through clicks array
for(let i = 0; i <clicks.length;i++){
var dist = getDistance(10,10,clicks[i][0],clicks[i][1])

//measure the distance from static point to clicks array point

//add distances to an array
distances.push(dist)
}
//sort distances to find the shortest
var sorted = distances.sort(function(a, b){return a - b});
console.log(sorted)

var c = document.getElementById("distances");
var ctx = c.getContext("2d");
var cx= coords[0];
var cy= coords[1];
ctx.moveTo(cx,function(d) {return d[0]});
ctx.lineTo(cy,function(d) {return d[1]});
ctx.lineWidth = 1
ctx.stroke("stroke", 'black');

/*
var c = document.getElementById("distances");
var ctx = c.getContext("2d");
var cx= function(dist)
var cy= function(dist)
ctx.moveTo(cx,function(d) {return d[0]});
ctx.lineTo(cy,function(d) {return d[1]});
ctx.lineWidth = 1
ctx.stroke("stroke", 'black');


svg.append('line')
.attr('class','spotLine')
.attr("cx",function(getDistance) {return d[0]})
.attr("cy", function(getDistance) {return d[1]})
.style('stroke-width','.75')
.style('stroke','black')
.style('stroke-dasharray','2 2')

but the function get distance feels like it could work


*/
})

/*
function draw() {
const dist = getDistance.selectAll('line');

if (!canvas.getContext) {
return;
}


function drawLine(ctx, begin, end, stroke = 'black', width = 1) {
if (stroke) {
ctx.strokeStyle = stroke;
}

*/

var t = svg.selectAll('circle')
.data(uSpots)
.enter()
.append('circle')
//.attr('class','spots')
.attr('x','200')
.attr('y',function(d,i){return 200+(i*20)})
.attr('r',8)
.attr('fill','floralwhite')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.text(function(d){return d})


g.selectAll("path2")
.data(lines1.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(lines2.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(lines3.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(lines4.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(lines5.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(lines6.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(lines7.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(bikeRoute.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(funSpotsLines.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1.5')
.style("stroke-width", '1.5')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(outdoorScenicRoutes.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(existingRoutesForBus.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(newRoutesForBus.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(rer.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb1.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.2')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb2.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.3')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb3.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.4')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb4.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "lightsteelblue")
.style('fill-opacity','0.5')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path3")
.data(GreenSpaces.features)
.enter()
.append("path")
.attr('class','greenspaces')
.attr("d", path3)
.style("fill", "rgb(186, 219, 203)")
.style("fill-opacity", ".2")
.style('stroke-opacity','.5')
.style("stroke-width", '.2')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path3")
.data(water.features)
.enter()
.append("path")
.attr('class','water')
.attr("d", path3)
.style("fill", "rgb(193, 219, 224)")
.style("fill-opacity", ".4")
.style('stroke-opacity','.4')
.style("stroke-width", '.5')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path3")
.data(Streets.features)
.enter()
.append("path")
.attr('class','streets')
.attr("d", path3)
.style("fill", "rgb(200,200,200)")
.style("fill-opacity", "0")
.style('stroke-opacity','.3')
.style("stroke-width", '.1')
.style("stroke", "rgb(0,0,0)")

var c = svg.selectAll("circle")
.data(stations.features)
.enter()
.append("circle")
.attr("cx", function(d) {return path1.centroid(d)[0]})
.attr("cy", function(d) {return path1.centroid(d)[1]})
.attr('r',2)
.attr('fill','rgb(120,120,120)')
.style('fill-opacity','1')
.style("stroke-width", '0.5')
.style("stroke", "black")

var t = svg.selectAll("text")
.data(layers)
.enter()
.append('text')
.attr('x',60)
.attr('y',function(d,i) {return 119+20*i})
.attr('fill','dimgray')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'bold')
.text(function(d) {return d})


c.enter().append('circle')
.data(layers)
.enter()
.append('circle')
.attr('cx',40)
.attr('cy',function(d,i) {return 115+20*i})
.attr('r',5)
.attr('fill','floralwhite')
.style("stroke-width", '.3')
.style("stroke", "rgb(0,0,0)")
.on('click',layersClick)

function layersClick(event,d){
console.log(d)
if(d=='1900 - 1920'){
clickYear = 1900 - 1920
d3.selectAll('path.outlines').remove()
d3.selectAll('text.layersText').remove()
d3.selectAll('path.districts').remove()

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'Bold')
.text('1st Metro Lines Reach Central Paris')

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','85')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('First metro line opened in 1900 with 18 stations.')

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','95')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('Lines 2-8 emerged to central Paris, which was the most populated district at the time.')
//draw the lines for 1920s

g.selectAll("path2")
.data(districtsCombined.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.attr("fill", d => color(d.properties.Y1900))
.style('fill-opacity','.4')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb1.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.2')
.style('stroke-opacity','0.1')
.style("stroke-width",'.6')
.style("stroke", "rgb(0,0,0)")
g.selectAll("path2")
.data(lines1.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1.5')
.style("stroke", "rgb(0,0,0)")
/*
g.selectAll("circle")
.data(spreadsheet.features)
.enter()
.append("circle")
.attr('class','outlines')
.attr("d", path2)
.style("fill", yearFill)
.style('stroke-opacity','0.6')
.style("stroke-width", '.5')
.style("stroke", "rgb(0,0,0)")
*/
}

if(d=='1920 - 1940'){
clickYear = 1920 - 1940
d3.selectAll('path.outlines').remove()
d3.selectAll('text.layersText').remove()
d3.selectAll('path.district').remove()

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'bold')
.text('1st Inner Suburbs are Reached')

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','85')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('The extension of subway lines continued and reached inner suburbs known as the banlieues.')

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','95')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('Lines 9-11, 14 were the first to extend outside of Paris.')

g.selectAll("path2")
.data(districtsCombined.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.attr("fill", d => color(d.properties.Y1920))
.style('fill-opacity','0.5')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")
g.selectAll("path2")
.data(suburb1.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.2')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb2.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.3')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(lines1.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','2 2')
g.selectAll("path2")
.data(lines2.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '2')
.style("stroke", "rgb(0,0,0)")
}
if(d=='1940 - 1960'){
clickYear = 1940 - 1960
d3.selectAll('path.outlines').remove()
d3.selectAll('text.layersText').remove()
d3.selectAll('path.district').remove()

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'bold')
.text('Post WWII Metro Development')

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','85')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('After WWII, the extensions become truly drastic.')

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','95')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('9 lines were extended, reaching the remaining suburbs.')

g.selectAll("path2")
.data(districtsCombined.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.attr("fill", d => color(d.properties.Y1940))
.style('fill-opacity','0.5')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb1.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.2')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb2.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.3')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb3.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.4')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")
g.selectAll("path2")
.data(lines1.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','2 2')
g.selectAll("path2")
.data(lines2.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','2 2')
g.selectAll("path2")
.data(lines3.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '2')
.style("stroke", "rgb(0,0,0)")
}

if(d=='1960 - 1980'){
clickYear = 1960 - 1980
d3.selectAll('path.outlines').remove()
d3.selectAll('text.layersText').remove()
d3.selectAll('path.district').remove()

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'bold')
.text('Development of the RER Lines')

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','85')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('Population boomed and suburbs grew, so the RER developed three lines, A,B, and C to connect the center of Paris to its surrounding suburbs.')

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','95')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('In addition, the outer districts of Paris become more populated.')
g.selectAll("path2")
.data(districtsCombined.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.attr("fill", d => color(d.properties.Y1960))
.style('fill-opacity','0.45')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")
g.selectAll("path2")
.data(suburb1.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.2')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb2.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.3')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb3.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.4')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb4.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "lightsteelblue")
.style('fill-opacity','0.5')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")
g.selectAll("path2")
.data(lines1.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','2 2')
g.selectAll("path2")
.data(lines2.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','2 2')
g.selectAll("path2")
.data(lines3.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','2 2')

g.selectAll("path2")
.data(lines4.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '2')
.style("stroke", "rgb(0,0,0)")
}

if(d=='1980 - 2000'){
clickYear = 1980 - 2000
d3.selectAll('path.outlines').remove()
d3.selectAll('text.layersText').remove()
d3.selectAll('path.district').remove()

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'bold')
.text('Paris High-Speed, East-West Metro Service')

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','85')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('Line 1,4, and 14 were the first fully automated lines part of the new metro system known as Météor, which is rapid east-west metro service.')

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','95')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('Lines 1,5,7,13, and 14 continue to extend, and the east-south districts of Paris grow in population.')

g.selectAll("path2")
.data(districtsCombined.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.attr("fill", d => color(d.properties.Y1980))
.style('fill-opacity','0.5')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb1.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.2')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb2.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.3')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb3.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.4')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb4.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "lightsteelblue")
.style('fill-opacity','0.5')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")
g.selectAll("path2")
.data(lines1.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','2 2')
g.selectAll("path2")
.data(lines2.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','2 2')
g.selectAll("path2")
.data(lines3.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','2 2')

g.selectAll("path2")
.data(lines4.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','2 2')

g.selectAll("path2")
.data(lines5.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '2')
.style("stroke", "rgb(0,0,0)")

}
if(d=='2000 - 2022'){
clickYear = 2000 - 2022
d3.selectAll('path.outlines').remove()
d3.selectAll('text.layersText').remove()
d3.selectAll('path.district').remove()

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'bold')
.text('21st century Metro Automation')

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','85')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('Lines 1 and 4 were converted to driverless operations. Three extensions were made to the suburbs.')

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','95')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('During this period, populations in central districts of Paris continue to decrease while the population in the outskirt districts continue to densify.')

g.selectAll("path2")
.data(districtsCombined.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.attr("fill", d => color(d.properties.Y2022))
.style('fill-opacity','0.5')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb1.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.2')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb2.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.3')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb3.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.4')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb4.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "lightsteelblue")
.style('fill-opacity','0.5')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")
g.selectAll("path2")
.data(lines1.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','2 2')
g.selectAll("path2")
.data(lines2.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','2 2')
g.selectAll("path2")
.data(lines3.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','2 2')

g.selectAll("path2")
.data(lines4.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','2 2')

g.selectAll("path2")
.data(lines5.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','2 2')

g.selectAll("path2")
.data(lines6.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '2')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(lines7.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '2')
.style("stroke", "rgb(0,0,0)")

}

if(d=='Full'){

d3.selectAll('path.outlines').remove()
d3.selectAll('text.layersText').remove()
d3.selectAll('path.district').remove()

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'bold')
.text('Current transportation system')

g.selectAll("path2")
.data(districtsCombined.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.attr("fill", d => color(d.properties.Y2022))
.style('fill-opacity','0.5')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb1.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.2')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb2.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.3')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb3.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.4')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb4.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "lightsteelblue")
.style('fill-opacity','0.5')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")
g.selectAll("path2")
.data(lines1.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
g.selectAll("path2")
.data(lines2.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")
g.selectAll("path2")
.data(lines3.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(lines4.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(lines5.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(lines6.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(lines7.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1')
.style("stroke", "rgb(0,0,0)")

}

if(d=='Proposed'){

d3.selectAll('path.outlines').remove()
d3.selectAll('text.layersText').remove()
d3.selectAll('path.district').remove()

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','70')
.attr('font-family','Helvetica')
.attr('font-size', '.65em')
.attr('text.anchor','start')
.attr('font-weight', 'bold')
.text('Proposed transportation system')

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','85')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('Reduced number of lines for easier understanding while also reaching all tourists points.')

svg.append('text')
.attr('class','layersText')
.attr('x', '20')
.attr('y','95')
.attr('font-family','Helvetica')
.attr('font-size', '.55em')
.attr('text.anchor','start')
.attr('font-weight', 'normal')
.text('Increased bus routes for neighborhoods in outskirts for greater safety.')

g.selectAll("path2")
.data(districtsCombined.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.attr("fill", d => color(d.properties.Y2022))
.style('fill-opacity','0.5')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb1.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.2')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb2.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.3')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb3.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "aliceblue")
.style('fill-opacity','0.4')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")

g.selectAll("path2")
.data(suburb4.features)
.enter()
.append("path")
.attr('class','district')
.attr("d", path2)
.style("fill", "lightsteelblue")
.style('fill-opacity','0.5')
.style('stroke-opacity','0.1')
.style("stroke-width", '.6')
.style("stroke", "rgb(0,0,0)")
g.selectAll("path2")
.data(bikeRoute.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '1.5')
.style("stroke", "darkorange")
.style('stroke-dasharray','2 2')

g.selectAll("path2")
.data(funSpotsLines.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1.5')
.style("stroke-width", '2')
.style("stroke", "darkmagenta")

g.selectAll("path2")
.data(outdoorScenicRoutes.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1.5')
.style("stroke-width", '2')
.style("stroke", "yellowgreen")

g.selectAll("path2")
.data(existingRoutesForBus.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1.5')
.style("stroke-width", '1.5')
.style("stroke", "rgb(139, 158, 166)")

g.selectAll("path2")
.data(newRoutesForBus.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1.5')
.style("stroke-width", '1.5')
.style("stroke", "lightskyblue")
.style('stroke-dasharray','2 2')

g.selectAll("path2")
.data(rer.features)
.enter()
.append("path")
.attr('class','outlines')
.attr("d", path2)
.style("fill", "none")
.style('stroke-opacity','1.5')
.style("stroke-width", '1.5')
.style("stroke", "rgb(0,0,0)")
.style('stroke-dasharray','4 4')


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

c.enter().append('circle')
.data(Underratedspots)
.enter()
.append("circle")
.attr("cx", function(d) {return projection([d.longitude, d.latitude])[0]})
.attr("cy", function(d) {return projection([d.longitude, d.latitude])[1]})
.attr('r',5)
.attr('fill','lightpink')
.style('fill-opacity','1')
.style('stroke','black')
.style('stroke-width','.8')
.on('mouseover', spotText)
.on('mouseout', removespotText)

c.enter().append('circle')
.data(spots)
.enter()
.append("circle")
.attr("cx", function(d) {return projection([d.longitude, d.latitude])[0]})
.attr("cy", function(d) {return projection([d.longitude, d.latitude])[1]})
.attr('r',5)
.attr('fill',colorType)
.style('fill-opacity','1')
.style('stroke','black')
.style('stroke-width','.8')
.on('mouseover', spotText)
.on('mouseout', removespotText)

g.selectAll("path4")
.data(mapKey.features)
.enter()
.append("path")
.attr('class','key')
.attr("d", path4)
.style("fill", "white")
.style('stroke-opacity','1')
.style("stroke-width", '.5')
.style("stroke", "rgb(0,0,0)")
g.selectAll("path4")
.data(keyText.features)
.enter()
.append("path")
.attr('class','key')
.attr("d", path4)
.style("fill", "none")
.style('stroke-opacity','1')
.style("stroke-width", '.25')
.style("stroke", "black")
g.selectAll("path4")
.data(cSpot.features)
.enter()
.append("path")
.attr('class','key')
.attr("d", path4)
.style("fill", "white")
.style('fill-opacity','1')
.style("stroke-width", '1')
.style("stroke", "black")

g.selectAll("path4")
.data(statSpot.features)
.enter()
.append("path")
.attr('class','key')
.attr("d", path4)
.style("fill", "black")
.style('fill-opacity','.5')
.style("stroke-width", '.15')
.style("stroke", "black")
g.selectAll("path4")
.data(distSpot.features)
.enter()
.append("path")
.attr('class','key')
.attr("d", path4)
.style("fill", "lavender")
.style('fill-opacity','.75')
.style("stroke-width", '.25')
.style("stroke", "black")

g.selectAll("path4")
.data(railSpot.features)
.enter()
.append("path")
.attr('class','key')
.attr("d", path4)
.style("fill", "none")
.style('fill-opacity','1')
.style("stroke-width", '1.5')
.style("stroke", "black")

function colorType(d,i){
var color = 'black'
if(d.type=='landmark')(color = 'white')
return color

}

/*
c.enter().append('circle')
.data(uSpots)
.enter()
.append('circle')
//.attr('class','spots')
.attr("cx",uSpots.longitude)
.attr("cy", uSpots.latitude)
//.attr("cx", projection([uSpots.longitude, uSpots.latitude])[0])
//.attr("cy", projection([uSpots.longitude, uSpots.latitude])[1])
//.attr("cx", function(d) {return projection([d.longitude, d.latitude])[0]})
//.attr("cy", function(d) {return projection([d.longitude, d.latitude])[1]})
//.attr("cx", d.longitude)
//.attr("cy", d.latitude)
.attr('r',30)
.attr('fill','green')
.style('fill-opacity','1')
.style('stroke','black')
.style('stroke-width','.8')
*/
svg
.append('circle')
.attr("cx", projection([uSpots.longitude, uSpots.latitude])[0])
.attr("cy", projection([uSpots.longitude, uSpots.latitude])[1])
.attr('r',30)
.attr('fill','yellow')
.style('fill-opacity','.5')
.style('stroke','black')
.style('stroke-width','.8')
function spotText(event,d){
d3.select(this).attr('fill','white')
svg.append('text')
.attr('class','spots')
.attr('x', '720')
.attr('y','780')
.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', '720')
.attr('y','790')
.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', '720')
.attr('y1', '786')
.attr('x2', projection([d.longitude, d.latitude])[0])
.attr('y2', '786')
.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', '786')
.attr('x2', projection([d.longitude, d.latitude])[0])
.attr('y2', projection([d.longitude, d.latitude])[1])
.style('stroke-width','.7')
.style('stroke','black')
.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()
}
svg .on('click',function(event){
var culturalspots = d3.pointer(event)
console.log(clicks)

c.enter().append("circle") //circle
.data(clicks)
.enter() //there are more data than elements, this selects them
.append("circle") //appends path to data
.attr("cx", function(d) {return d[0]})
.attr("cy", function(d) {return d[1]})
.attr('r',3)
.attr('fill','black')//add function to control color by 'type'
.style('fill-opacity','1')

})
/*
function yearFill(d,i){
var color = 'none'

if(d.year == clickYear){
color = 'white'
}

return color
}

*/
//}
return svg.node();

}

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