/******************************************************************************* ** Author: Peter McCutcheon ** Date Created: 3/31/2017 ** Last Modified: 12/02/2017 ** **------------------------------------------------------------------------------ **Description of Code: ** ** ********************************************************************************/ function pageLoaded() { var frmtTime = d3.timeParse(":%S"); btnGenPlot = document.getElementById("btnGenPlot"); btnGenPlot.addEventListener("click", function () {getDataForGraph("daily", "")}, false); apRequest = new XMLHttpRequest(); apRequest.open("POST", "../php/getAirportList.php"); apRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); if (!apRequest) { alert("Error - Ajax object not created, browser may not support Ajax."); return false; } apRequest.onreadystatechange = function () { if (apRequest.readyState == 4 && apRequest.status === 200) { if (apRequest.responseText != null) { var apData = JSON.parse(apRequest.responseText); var airportSelect = document.getElementById("airportselect"); for (var i = 0; i < apData.apID.length; i++) { var opt = document.createElement("option"); opt.setAttribute("value", apData.apID[i]); opt.text = apData.apDesc[i]; airportSelect.appendChild(opt); } } } else { if (apRequest.status != 200) { alert("AJAX Error: " + apRequest.readyState + " --- " + apRequest.status); } } }; // // Send the ajax request to the server. // apRequest.send(); alRequest = new XMLHttpRequest(); alRequest.open("POST", "../php/getAirlineList.php"); alRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); if (!alRequest) { alert("Error - Ajax object not created, browser may not support Ajax."); return false; } alRequest.onreadystatechange = function () { if (alRequest.readyState == 4 && alRequest.status === 200) { if (alRequest.responseText != null) { var alData = JSON.parse(alRequest.responseText); var airlineSelect = document.getElementById("airlineselect"); for (var i = 0; i < alData.alID.length; i++) { var opt = document.createElement("option"); opt.setAttribute("value", alData.alID[i]); opt.text = alData.alDesc[i]; airlineSelect.appendChild(opt); } } } else { if (alRequest.status != 200) { alert("AJAX Error: " + alRequest.readyState + " --- " + alRequest.status); } } }; // // Send the ajax request to the server. // alRequest.send(); } function getDataForGraph(chartToGenerate, selectDate, flightNum) { // Date to string conversion. var strDate = d3.timeFormat("%Y-%m-%d"); // String to date conversion. var parseTime = d3.timeParse("%Y-%m-%d"); // // Gather the form information to send in the Ajax request to generate the plot per the user. // Get the user selection for the chart. This will be used to create // a an Ajax message to select the desired data from the database. // var airportSelected = document.getElementById("airportselect").value; var airlineSelected = document.getElementById("airlineselect").value; var startDate = document.getElementById("startdate").value; var endDate = document.getElementById("enddate").value; // // Get the type of chart, from the DOM, that the user wants. // var plotCircle = document.getElementById("plotcircle"); var plotBar = document.getElementById("plotbar"); if (plotCircle.checked) { var chartType = "C"; } else { if (plotBar.checked) { var chartType = "B"; } else { alert("You did not select a chart type, please select one."); return; } } var msg = ""; // // First clear out the div that contains the chart in preparation for the new plot. // Then set up the Ajax message based on the chart that will be generated. // if (chartToGenerate == "daily") { chartImageDiv = document.getElementById("chartimage"); chartImageDiv.innerHTML = ""; msg = "type=" + chartToGenerate + "&airport=" + airportSelected + "&airline=" + airlineSelected + "&startdate=" + startDate + "&enddate=" + endDate; alert("Retrieving flight information, this could take a minute or two..."); } else { if (chartToGenerate == "detail") { chartImageDiv = document.getElementById("detailimage") chartImageDiv.innerHTML = ""; // // On the detail for a given day force the graph to always be bar, regardless of what was selected. // This is so the flight numbers display ok, otherwise on the circle graph they can all run together. // chartType = "B"; //selectDate = startDate.substring(0, startDate.lastIndexOf("-")); //selectDate = selectDate + "-" + day; selectDate = strDate(selectDate); msg = "type=" + chartToGenerate + "&airport=" + airportSelected + "&airline=" + airlineSelected + "&selectdate=" + selectDate; } else { if (chartToGenerate == "flight") { chartImageDiv = document.getElementById("flightimage") chartImageDiv.innerHTML = ""; //selectDate = startDate.substring(0, startDate.lastIndexOf("-")); var tmpDate = parseTime(selectDate); selectDate = strDate(tmpDate); msg = "type=" + chartToGenerate + "&airport=" + airportSelected + "&airline=" + airlineSelected + "&selectdate=" + selectDate + "&flightnumber=" + flightNum; } } } // // Create the Ajax request and send it with our generated message. // frmrequest = new XMLHttpRequest(); frmrequest.open("POST", "../php/getFlightData.php"); frmrequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); if (!frmrequest) { alert("Error - Ajax object not created, browser may not support Ajax."); return false; } frmrequest.onreadystatechange = function () { if (frmrequest.readyState == 4 && frmrequest.status === 200) { if (frmrequest.responseText != null) { if (frmrequest.responseText == "0 results") { alert("No flights for the data selection. Please try a different selection."); return; } if (chartToGenerate == "daily") { var chartImageDiv = document.getElementById("chartimage"); } else { var chartImageDiv = document.getElementById("detailimage"); } var flightData = JSON.parse(frmrequest.responseText); if (chartToGenerate == "daily" || chartToGenerate == "detail") { var ret = generateGraph(chartType, flightData, chartImageDiv, chartToGenerate, selectDate) if (ret) { alert("Error encountered attempting to generate the graph."); } } else { if (chartToGenerate == "flight") { ret = displayFlightInfo(flightData); } else { alert("We are back with our specific flight data."); } } } } else { if (frmrequest.status != 200) { alert("AJAX Error: " + frmrequest.readyState + " --- " + frmrequest.status + " text " + frmrequest.responseText); } } }.bind(chartType); // // Send the ajax request to the server. // frmrequest.send(msg); } function generateGraph(typ, fd, ci, chartToGenerate, sDate) { var margin = {"top": 30, "right": 30, "bottom": 30, "left": 40}, height = 500 - margin.top - margin.bottom, width = 800 - margin.right - margin.left; var hDiv2 = height / 2; var padding = 40; var barPadding = 1; var circlePadding = 20; var hScaleFactor = 4; var txtTitle = ""; var tipText = ""; var xScale, yScale, xAxis, yAxis; //Empty, for now var flightData = new Array(new Object()); var startDate = document.getElementById("startdate").value; var endDate = document.getElementById("enddate").value; // For converting strings to dates. var parseTime = d3.timeParse("%Y-%m-%d"); //For converting Dates to strings var formatTime = d3.timeFormat("%d"); var formatNiceDate = d3.timeFormat("%B %d, %Y"); //Function for converting CSV values from strings to Dates and numbers if (chartToGenerate == "daily") { flightData[0] = {'xValue': parseTime(fd[0].xValue), 'yValue': parseInt(fd[0].yValue)}; txtTitle = "Flight Delay for " + formatNiceDate(parseTime(startDate)) + " To " + formatNiceDate(parseTime(endDate)); tipText = "Date: "; } else { if (chartToGenerate == "detail") { flightData[0] = {'xValue': fd[0].xValue, 'yValue': parseInt(fd[0].yValue)}; txtTitle = "Flight Information for " + formatNiceDate(parseTime(sDate)); tipText = "Flight Number: "; } } for (var i = 1; i < fd.length; i++) { if (chartToGenerate == "daily") { flightData.push({'xValue': parseTime(fd[i].xValue), 'yValue': parseInt(fd[i].yValue)}); } else { flightData.push({'xValue': fd[i].xValue, 'yValue': parseInt(fd[i].yValue)}); } } //*************************************************************************** //*************************************************************************** //Convert the array of objects to an object with arrays. var ds = {"xValue": new Array(), "yValue": new Array()}; for (var i = 0; i < flightData.length; i++) { ds.xValue.push(flightData[i].xValue); ds.yValue.push(+flightData[i].yValue); } var svg = d3.select("#chartimage") .append("svg") .attr("width", width + margin.right + margin.left) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var dMax = d3.max(flightData, function(d) { return d.yValue; }); var dMin = d3.min(flightData, function(d) { return d.yValue; }); if (typ == "C") { // // Set up the y-axis scale. // var yScale = d3.scaleLinear() .domain([dMin, dMax]) .range([height, 0]); // // set up the x-axis scale. // var ordScale = d3.scalePoint() .domain(ds.xValue) .range([margin.left,width]); // // This graph actually is an implementation of a scatterplot. // Here we just make the area of the circles dependent // on there y-value. // // Generate all of the circle for the scatterplot graph. // svg.selectAll("circle") .data(flightData) .enter() .append("circle") .attr("cx", function(d, i) { return ordScale(d.xValue); }) .attr("cy", function(d) { if (d.yValue < 0) { return yScale(d.yValue); } else { return yScale(d.yValue); } }) .attr("r", function(d) {return Math.sqrt(Math.abs(d.yValue))}) .attr("fill", function(d) { if (d.yValue < 0) { return "yellow"; } else { return "red"; } }) .on("mouseover", function() { d3.select(this).attr("fill", "green") }) .on("mouseout", function(d, i) { d3.select(this).attr("fill", function(d) { if (d.yValue < 0) { return "yellow"; } else { return "red"; } }) }) .on("click", function(d) {if (chartToGenerate == "daily") getDataForGraph("detail", d.xValue, ""); else if (chartToGenerate == "detail") getDataForGraph("flight", sDate, d.xValue);}); var txtElem = svg.selectAll("text") .data(flightData) .enter() .append("text") .text(function(d){return formatTime(d.xValue);}) .attr("x", function(d, i) {return ordScale(d.xValue) + 4;}) .attr("y", function(d) { if (d.yValue < 0) { return yScale(d.yValue); } else { return yScale(d.yValue); } }) .attr("font-family", "sans-serif") .attr("font-size", "20px") .attr("fill", "steelblue"); var xAxis1 = d3.axisBottom() .scale(ordScale) .tickSize(-height,0,0) .tickFormat(""); svg.append("g") .attr("class", "xAxis") .attr("transform", "translate(0," + height + ")") .call(xAxis1); var yAxisPos = d3.axisLeft() .scale(yScale) .tickSize(-width,0,0); var yAxisNeg = d3.axisLeft() .scale(yScale) .tickSize(-width,0,0); svg.append("g") .attr("class", "yAxis") .attr("transform", "translate(" + padding + ", 0)") .call(yAxisPos); svg.append("g") .attr("class", "yAxis") .attr("transform", "translate(" + padding + ", 0)") .call(yAxisNeg); svg.append("text") .attr("x", yScale(0)-30) .attr("y", margin.left - 30) .text("Minutes") .attr("text-anchor", "middle") .attr("font-size", "20px") .attr("fill", "steelblue") .attr("transform", "rotate(90)"); svg.append("text") .attr("x", (width / 2)) .attr("y", 0 - (margin.top / 2)) .attr("text-anchor", "middle") .style("font-size", "20px") .text(txtTitle) .attr("font-family", "sans-serif") .attr("fill", "steelblue"); } else { var yScale = d3.scaleLinear() .domain([dMin, dMax]) .range([height, 0]); var xScale = d3.scaleBand() .domain(d3.range(flightData.length)) .range([margin.left, width]) .round(true) .paddingInner(0.1); svg.selectAll("rect") .data(flightData) .enter() .append("rect") .attr("x", function(d, i) {return xScale(i);}) .attr("width", xScale.bandwidth()) .attr("y", function(d) {if (d.yValue < 0) return yScale(0); else return yScale(d.yValue);}) .attr("height", function(d) {return yScale(0) - yScale(Math.abs(d.yValue));}) .attr("fill", function(d) {if (d.yValue < 0) return "yellow"; else return "red";}) .on("mouseover", function() { d3.select(this).attr("fill", "green")}) .on("mouseout", function(d, i) { d3.select(this).attr("fill", function(d) { if (d.yValue < 0) { return "yellow"; } else { return "red"; } }) }) .on("click", function(d) {if (chartToGenerate == "daily") getDataForGraph("detail", d.xValue, ""); else if (chartToGenerate == "detail") getDataForGraph("flight", sDate, d.xValue);}) .append("title") .text(function(d) {if (chartToGenerate == "daily") return tipText + formatNiceDate(d.xValue); else return tipText + d.xValue;}); /* var txtElem = svg.selectAll("text") .data(flightData) .enter() .append("text") .text(function(d){return formatTime(d.xValue);}) .attr("x", function(d, i) {return xScale(i) + ((xScale.bandwidth()) / 2) - 4;}) .attr("y", function(d) { if (d.yValue < 0) { return yScale(0); } else { return yScale(0); } }) .attr("font-family", "sans-serif") .attr("font-size", "18px") .attr("fill", "white"); */ var yAxisPos = d3.axisLeft() .scale(yScale) .tickSize(-width,0,0); svg.append("g") .attr("class", "yAxis") .attr("transform", "translate(" + padding + ", 0)") .call(yAxisPos); svg.append("text") .attr("x", yScale(0)-30) .attr("y", margin.left - 30) .text("Minutes") .attr("text-anchor", "middle") .attr("font-size", "20px") .attr("fill", "steelblue") .attr("transform", "rotate(90)"); svg.append("text") .attr("x", (width / 2)) .attr("y", 0 - (margin.top / 2)) .attr("text-anchor", "middle") .style("font-size", "20px") .text(txtTitle) .attr("font-family", "sans-serif") .attr("fill", "steelblue"); } } function displayFlightInfo(data) { var flightInfo = ""; var flightDelay; flightInfo = data[data.length-1].yValue.split("|"); var flightInfoLen = flightInfo.length var flightInfoDiv = document.getElementById("flightinfo") flightInfoDiv.innerHTML = ""; var totalTime = 0; var delayTime = 0; var numData = []; for (var i = 0; i < data.length-2; i++) { delayTime = parseFloat(data[i].yValue); numData[i] = delayTime totalTime = totalTime + delayTime; } var aveTime = Math.round(totalTime / (data.length - 1)); var maxTime = d3.max(numData, function(d) {return d;}); var minTime = d3.min(numData, function(d) {return d;}); // // Create the form and the fieldset that will display the flight information. // var flightForm = document.createElement("form"); flightForm.setAttribute("class","flightform"); var flightFldSet = document.createElement("fieldset"); var fldsetLegend = document.createElement("legend"); var txtNode = document.createTextNode("Fligh Number: " + flightInfo[flightInfoLen-1]); fldsetLegend.appendChild(txtNode); flightFldSet.appendChild(fldsetLegend) // // Create the paragraph element for the first form row. // var p1 = document.createElement("p"); p1.setAttribute("class", "formrow"); // // Average delay for the year for flight number. // var aveLabel = document.createElement("label"); var aveText = document.createTextNode("Average Delay:"); aveLabel.appendChild(aveText); aveLabel.setAttribute("class", "formcelllbl"); var aveInput = document.createElement("input"); aveInput.setAttribute("class", "formcellinp"); aveInput.setAttribute("value", aveTime); p1.appendChild(aveLabel); p1.appendChild(aveInput); // // Minimum delay for the year for flight number. // var minLabel = document.createElement("label"); var minText = document.createTextNode("Minimum Delay:"); minLabel.appendChild(minText); minLabel.setAttribute("class", "formcelllbl"); var minInput = document.createElement("input"); minInput.setAttribute("class", "formcellinp"); minInput.setAttribute("value", minTime); p1.appendChild(minLabel); p1.appendChild(minInput); // // Maximum delay for the year for flight number. // var maxLabel = document.createElement("label"); var maxText = document.createTextNode("Maximum Delay:"); maxLabel.appendChild(maxText); maxLabel.setAttribute("class", "formcelllbl"); var maxInput = document.createElement("input"); maxInput.setAttribute("class", "formcellinp"); maxInput.setAttribute("value", maxTime); p1.appendChild(maxLabel); p1.appendChild(maxInput); flightFldSet.appendChild(p1); // // Create the paragraph element for the second form row. // var p2 = document.createElement("p"); p2.setAttribute("class", "formrow"); // // Airplane tail number. // var tnLabel = document.createElement("label"); var tnText = document.createTextNode("Tail Number:"); tnLabel.appendChild(tnText); tnLabel.setAttribute("class", "formcelllbl"); var tnInput = document.createElement("input"); tnInput.setAttribute("class", "formcellinp"); tnInput.setAttribute("value", flightInfo[0]); p2.appendChild(tnLabel); p2.appendChild(tnInput); // // Flight destination. // var destLabel = document.createElement("label"); var destText = document.createTextNode("Destination:"); destLabel.appendChild(destText); destLabel.setAttribute("class", "formcelllbl"); var destInput = document.createElement("input"); destInput.setAttribute("class", "formcellinp"); destInput.setAttribute("value", flightInfo[1]); p2.appendChild(destLabel); p2.appendChild(destInput); // // Flight delay time. // var fdLabel = document.createElement("label"); var fdText = document.createTextNode("Flight Delay:"); fdLabel.appendChild(fdText); fdLabel.setAttribute("class", "formcelllbl"); var fdInput = document.createElement("input"); fdInput.setAttribute("class", "formcellinp"); fdInput.setAttribute("value", flightInfo[2]); p2.appendChild(fdLabel); p2.appendChild(fdInput); flightFldSet.appendChild(p2); // // Create the paragraph element for the third form row. // var p3 = document.createElement("p"); p3.setAttribute("class", "formrow"); // // Carrier delay time. // var cdLabel = document.createElement("label"); var cdText = document.createTextNode("Carrier Delay:"); cdLabel.appendChild(cdText); cdLabel.setAttribute("class", "formcelllbl"); var cdInput = document.createElement("input"); cdInput.setAttribute("class", "formcellinp"); cdInput.setAttribute("value", flightInfo[3]); p3.appendChild(cdLabel); p3.appendChild(cdInput); // // Weather delay time. // var wdLabel = document.createElement("label"); var wdText = document.createTextNode("Weather Delay:"); wdLabel.appendChild(wdText); wdLabel.setAttribute("class", "formcelllbl"); var wdInput = document.createElement("input"); wdInput.setAttribute("class", "formcellinp"); wdInput.setAttribute("value", flightInfo[4]); p3.appendChild(wdLabel); p3.appendChild(wdInput); flightFldSet.appendChild(p3); // // Create the paragraph element for the fourth form row. // var p4 = document.createElement("p"); p4.setAttribute("class", "formrow"); // // Security delay time. // var sdLabel = document.createElement("label"); var sdText = document.createTextNode("Security Delay:"); sdLabel.appendChild(sdText); sdLabel.setAttribute("class", "formcelllbl"); var sdInput = document.createElement("input"); sdInput.setAttribute("class", "formcellinp"); sdInput.setAttribute("value", flightInfo[5]); p4.appendChild(sdLabel); p4.appendChild(sdInput); // // NAS delay time. // var ndLabel = document.createElement("label"); var ndText = document.createTextNode("NAS Delay:"); ndLabel.appendChild(ndText); ndLabel.setAttribute("class", "formcelllbl"); var ndInput = document.createElement("input"); ndInput.setAttribute("class", "formcellinp"); ndInput.setAttribute("value", flightInfo[6]); p4.appendChild(ndLabel); p4.appendChild(ndInput); flightFldSet.appendChild(p4); // // Create the paragraph element for the fifth form row. // var p5 = document.createElement("p"); p5.setAttribute("class", "formrow"); // // Late Aircraft delay time. // var laLabel = document.createElement("label"); var laText = document.createTextNode("Late Aircraft Delay:"); laLabel.appendChild(laText); laLabel.setAttribute("class", "formcelllbl"); var laInput = document.createElement("input"); laInput.setAttribute("class", "formcellinp"); laInput.setAttribute("value", flightInfo[6]); p5.appendChild(laLabel); p5.appendChild(laInput); flightFldSet.appendChild(p5); // // Finally append the field set to the form. // flightForm.appendChild(flightFldSet); flightInfoDiv.appendChild(flightForm); }