|
|
|
|
@ -7,6 +7,8 @@ const parseTime = d3.timeParse("%B %e, %Y");
|
|
|
|
|
let instances;
|
|
|
|
|
let xScale, yScale;
|
|
|
|
|
let highlighted = []
|
|
|
|
|
const courses = [];
|
|
|
|
|
const metros = [];
|
|
|
|
|
|
|
|
|
|
const randomColor = ()=>{
|
|
|
|
|
const red = Math.floor(Math.random()*128) + 64;
|
|
|
|
|
@ -61,27 +63,36 @@ const renderPoints = () => {
|
|
|
|
|
.append('circle');
|
|
|
|
|
|
|
|
|
|
d3.selectAll('circle')
|
|
|
|
|
.attr('cy', (datum, index) => yScale(datum.ninety_day_outcomes/datum.graduates*100) );
|
|
|
|
|
|
|
|
|
|
d3.selectAll('circle')
|
|
|
|
|
.attr('cx', (datum, index) => xScale(parseTime(datum.graduation_date)) );
|
|
|
|
|
|
|
|
|
|
d3.selectAll('circle')
|
|
|
|
|
.attr('cy', (datum, index) => yScale(datum.ninety_day_outcomes/datum.graduates*100) )
|
|
|
|
|
.attr('cx', (datum, index) => xScale(parseTime(datum.graduation_date)) )
|
|
|
|
|
.attr('fill', datum => datum.color? datum.color : 'black')
|
|
|
|
|
.attr('r', datum => datum.color? 10 : 5)
|
|
|
|
|
|
|
|
|
|
d3.selectAll('circle').on('click', (event, datum) => {
|
|
|
|
|
const found = highlighted.find(i => i.instance_id === datum.instance_id)
|
|
|
|
|
if(found === undefined){
|
|
|
|
|
datum.color = randomColor()
|
|
|
|
|
highlighted.push(datum)
|
|
|
|
|
} else {
|
|
|
|
|
delete datum.color
|
|
|
|
|
highlighted = highlighted.filter(i => i.instance_id != datum.instance_id)
|
|
|
|
|
}
|
|
|
|
|
renderPoints()
|
|
|
|
|
renderTable()
|
|
|
|
|
});
|
|
|
|
|
.style('display', (datum)=>{
|
|
|
|
|
const instanceMetro = datum.course.split('-')[0]
|
|
|
|
|
const instanceCourse = datum.course.split('-')[1]
|
|
|
|
|
|
|
|
|
|
const metro = metros.find(m => m.metro === instanceMetro)
|
|
|
|
|
const course = courses.find(c => c.course === instanceCourse)
|
|
|
|
|
|
|
|
|
|
if(metro.checked && course.checked){
|
|
|
|
|
return 'block'
|
|
|
|
|
} else {
|
|
|
|
|
return 'none'
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.on('click', (event, datum) => {
|
|
|
|
|
const found = highlighted.find(i => i.instance_id === datum.instance_id)
|
|
|
|
|
|
|
|
|
|
if(found === undefined){
|
|
|
|
|
datum.color = randomColor()
|
|
|
|
|
highlighted.push(datum)
|
|
|
|
|
} else {
|
|
|
|
|
delete datum.color
|
|
|
|
|
highlighted = highlighted.filter(i => i.instance_id != datum.instance_id)
|
|
|
|
|
}
|
|
|
|
|
renderPoints()
|
|
|
|
|
renderTable()
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -135,8 +146,47 @@ const createFormSubmissionHandler = () => {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const populateMetrosCoursesCheckboxes = ()=>{
|
|
|
|
|
for(let instance of instances){
|
|
|
|
|
const segments = instance.course.split('-')
|
|
|
|
|
|
|
|
|
|
if(metros.find(m => m.metro === segments[0]) === undefined){
|
|
|
|
|
metros.push({ checked:true, metro: segments[0] })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(courses.find(c => c.course === segments[1]) === undefined){
|
|
|
|
|
courses.push({ checked:true, course: segments[1] })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
d3.select('#courses')
|
|
|
|
|
.selectAll('li')
|
|
|
|
|
.data(courses)
|
|
|
|
|
.enter()
|
|
|
|
|
.append('li').text(d => d.course)
|
|
|
|
|
.append('input').attr('type', 'checkbox')
|
|
|
|
|
.property('checked', d => d.checked)
|
|
|
|
|
.on('click', (event, datum)=>{
|
|
|
|
|
datum.checked = !datum.checked
|
|
|
|
|
renderPoints()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
d3.select('#metros')
|
|
|
|
|
.selectAll('li')
|
|
|
|
|
.data(metros)
|
|
|
|
|
.enter()
|
|
|
|
|
.append('li').text(d => d.metro)
|
|
|
|
|
.append('input').attr('type', 'checkbox')
|
|
|
|
|
.property('checked', d => d.checked)
|
|
|
|
|
.on('click', (event, datum)=>{
|
|
|
|
|
datum.checked = !datum.checked
|
|
|
|
|
renderPoints()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
window.onload = async ()=>{
|
|
|
|
|
instances = await d3.json('/instances');
|
|
|
|
|
populateMetrosCoursesCheckboxes();
|
|
|
|
|
setupGraph();
|
|
|
|
|
createAxes();
|
|
|
|
|
renderPoints();
|
|
|
|
|
|