// TODO - delete highlighted // TODO - different colors for each highted dot, matched in table row backgrounds const WIDTH = 800; const HEIGHT = 600; const parseTime = d3.timeParse("%B %e, %Y"); let instances; let xScale, yScale; let highlighted = [] const renderTable = () => { const trs = d3.select('tbody') .html('') .selectAll('tr') .data(highlighted, d => d.id) .enter() .append('tr') .selectAll('td') .data(d => [ d.instance_id, d.course, d.graduation_date, d.total_students, `${d.dropped} (${Math.floor(d.dropped/d.total_students*100)}%)`, d.graduates, `${d.ninety_day_outcomes} (${Math.floor(d.ninety_day_outcomes/d.graduates*100)}%)` ]) .enter() .append('td') .text(value => value) } const renderPoints = () => { const circles = d3.select('#points') .selectAll('circle') .data(instances, d => d.id) .enter() .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') .classed('highlighted', (datum, index)=> highlighted.find(i => i.instance_id === datum.instance_id) !== undefined) d3.selectAll('circle').on('click', (event, datum) => { const found = highlighted.find(i => i.instance_id === datum.instance_id) if(found === undefined){ highlighted.push(datum) } else { highlighted = highlighted.filter(i => i.instance_id != datum.instance_id) } renderPoints() renderTable() }); } const setupGraph = ()=>{ d3.select('svg'); d3.select('svg') .style('width', WIDTH) .style('height', HEIGHT); xScale = d3.scaleTime(); xScale.range([0,WIDTH]); const xDomain = d3.extent(instances, (datum, index) => { return parseTime(datum.graduation_date); }); xScale.domain(xDomain); yScale = d3.scaleLinear(); yScale.range([HEIGHT, 0]); const yDomain = d3.extent(instances, (datum, index) => { return datum.ninety_day_outcomes/datum.graduates*100; }) yScale.domain(yDomain); } const createAxes = () => { const bottomAxis = d3.axisBottom(xScale); d3.select('#container') .append('g') .attr('id', 'x-axis') .call(bottomAxis) .attr('transform', 'translate(0,'+HEIGHT+')'); const leftAxis = d3.axisLeft(yScale); d3.select('#container') .append('g') .attr('id', 'y-axis') .call(leftAxis); } const createFormSubmissionHandler = () => { d3.select('form').on('submit', (event)=>{ event.preventDefault(); const instanceID = parseInt(d3.select('input[type="text"]').property('value')) const found = instances.find(i => i.instance_id === instanceID) if(found !== undefined && highlighted.find(instance => instance.instance_id === instanceID) === undefined){ highlighted.push(found); } renderTable(); renderPoints(); }); } window.onload = async ()=>{ instances = await d3.json('/instances'); setupGraph(); createAxes(); renderPoints(); createFormSubmissionHandler(); }