<?php | <?php |
/* | /* |
* Copyright 2010,2011 Alexander Sadleir | * Copyright 2010,2011 Alexander Sadleir |
Licensed under the Apache License, Version 2.0 (the "License"); | Licensed under the Apache License, Version 2.0 (the "License"); |
you may not use this file except in compliance with the License. | you may not use this file except in compliance with the License. |
You may obtain a copy of the License at | You may obtain a copy of the License at |
http://www.apache.org/licenses/LICENSE-2.0 | http://www.apache.org/licenses/LICENSE-2.0 |
Unless required by applicable law or agreed to in writing, software | Unless required by applicable law or agreed to in writing, software |
distributed under the License is distributed on an "AS IS" BASIS, | distributed under the License is distributed on an "AS IS" BASIS, |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
See the License for the specific language governing permissions and | See the License for the specific language governing permissions and |
limitations under the License. | limitations under the License. |
*/ | */ |
if (isset($_REQUEST['firstLetter'])) { | if (isset($_REQUEST['firstLetter'])) { |
$firstLetter = filter_var($_REQUEST['firstLetter'], FILTER_SANITIZE_STRING); | $firstLetter = filter_var($_REQUEST['firstLetter'], FILTER_SANITIZE_STRING); |
} | } |
if (isset($_REQUEST['bysuburbs'])) { | if (isset($_REQUEST['bysuburbs'])) { |
$bysuburbs = true; | $bysuburbs = true; |
} | } |
if (isset($_REQUEST['bynumber'])) { | if (isset($_REQUEST['bynumber'])) { |
$bynumber = true; | $bynumber = true; |
} | } |
if (isset($_REQUEST['allstops'])) { | if (isset($_REQUEST['allstops'])) { |
$allstops = true; | $allstops = true; |
} | } |
if (isset($_REQUEST['nearby'])) { | if (isset($_REQUEST['nearby'])) { |
$nearby = true; | $nearby = true; |
} | |
if (isset($_REQUEST['labs'])) { | |
$labs = true; | |
} | } |
if (isset($_REQUEST['suburb'])) { | if (isset($_REQUEST['suburb'])) { |
$suburb = $_REQUEST['suburb']; | $suburb = $_REQUEST['suburb']; |
} | } |
if (isset($_REQUEST['pageKey'])) { | if (isset($_REQUEST['pageKey'])) { |
$pageKey = filter_var($_REQUEST['pageKey'], FILTER_SANITIZE_NUMBER_INT); | $pageKey = filter_var($_REQUEST['pageKey'], FILTER_SANITIZE_NUMBER_INT); |
} | } |
if (isset($_REQUEST['lat'])) { | if (isset($_REQUEST['lat'])) { |
$lat = filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); | $lat = filter_var($_REQUEST['lat'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); |
} | } |
if (isset($_REQUEST['lon'])) { | if (isset($_REQUEST['lon'])) { |
$lon = filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); | $lon = filter_var($_REQUEST['lon'], FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); |
} | } |
if (isset($_REQUEST['radius'])) { | if (isset($_REQUEST['radius'])) { |
$max_distance = filter_var($_REQUEST['radius'], FILTER_SANITIZE_NUMBER_INT); | $max_distance = filter_var($_REQUEST['radius'], FILTER_SANITIZE_NUMBER_INT); |
} | } |
if (isset($_REQUEST['numberSeries'])) { | if (isset($_REQUEST['numberSeries'])) { |
$numberSeries = filter_var($_REQUEST['numberSeries'], FILTER_SANITIZE_NUMBER_INT); | $numberSeries = filter_var($_REQUEST['numberSeries'], FILTER_SANITIZE_NUMBER_INT); |
} | } |
if (isset($_REQUEST['routeDestination'])) { | if (isset($_REQUEST['routeDestination'])) { |
$routeDestination = urldecode(filter_var($_REQUEST['routeDestination'], FILTER_SANITIZE_ENCODED)); | $routeDestination = urldecode(filter_var($_REQUEST['routeDestination'], FILTER_SANITIZE_ENCODED)); |
} | } |
if (isset($_REQUEST['routename'])) { | if (isset($_REQUEST['routename'])) { |
$routename = urldecode(filter_var($_REQUEST['routename'], FILTER_SANITIZE_ENCODED)); | $routename = urldecode(filter_var($_REQUEST['routename'], FILTER_SANITIZE_ENCODED)); |
} | } |
if (isset($_REQUEST['stopcode'])) { | if (isset($_REQUEST['stopcode'])) { |
$stopcode = filter_var($_REQUEST['stopcode'], FILTER_SANITIZE_STRING); | $stopcode = filter_var($_REQUEST['stopcode'], FILTER_SANITIZE_STRING); |
} | } |
if (isset($_REQUEST['stopids'])) { | if (isset($_REQUEST['stopids'])) { |
$stopids = explode(",", filter_var($_REQUEST['stopids'], FILTER_SANITIZE_STRING)); | $stopids = explode(",", filter_var($_REQUEST['stopids'], FILTER_SANITIZE_STRING)); |
} | } |
if (isset($_REQUEST['filterIncludeRoutes'])) { | if (isset($_REQUEST['filterIncludeRoutes'])) { |
$filterIncludeRoutes = explode(",", filter_var($_REQUEST['filterIncludeRoutes'], FILTER_SANITIZE_STRING)); | $filterIncludeRoutes = explode(",", filter_var($_REQUEST['filterIncludeRoutes'], FILTER_SANITIZE_STRING)); |
} | } |
if (isset($_REQUEST['filterHasStop'])) { | if (isset($_REQUEST['filterHasStop'])) { |
$filterHasStop = filter_var($_REQUEST['filterHasStop'], FILTER_SANITIZE_STRING); | $filterHasStop = filter_var($_REQUEST['filterHasStop'], FILTER_SANITIZE_STRING); |
} | } |
if (isset($_REQUEST['tripid'])) { | if (isset($_REQUEST['tripid'])) { |
$tripid = filter_var($_REQUEST['tripid'], FILTER_SANITIZE_STRING); | $tripid = filter_var($_REQUEST['tripid'], FILTER_SANITIZE_STRING); |
} | } |
if (isset($_REQUEST['routeid'])) { | if (isset($_REQUEST['routeid'])) { |
$routeid = filter_var($_REQUEST['routeid'], FILTER_SANITIZE_STRING); | $routeid = filter_var($_REQUEST['routeid'], FILTER_SANITIZE_STRING); |
} | } |
if (isset($_REQUEST['directionid'])) { | if (isset($_REQUEST['directionid'])) { |
$directionid = filter_var($_REQUEST['directionid'], FILTER_SANITIZE_STRING); | $directionid = filter_var($_REQUEST['directionid'], FILTER_SANITIZE_STRING); |
} | } |
if (isset($_REQUEST['stopid'])) { | if (isset($_REQUEST['stopid'])) { |
$stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT); | $stopid = filter_var($_REQUEST['stopid'], FILTER_SANITIZE_NUMBER_INT); |
} | } |
if (isset($_REQUEST['geolocate'])) { | if (isset($_REQUEST['geolocate'])) { |
$geolocate = filter_var($_REQUEST['geolocate'], FILTER_SANITIZE_URL); | $geolocate = filter_var($_REQUEST['geolocate'], FILTER_SANITIZE_URL); |
} | } |
<?php | <?php |
setlocale(LC_CTYPE, 'C'); | setlocale(LC_CTYPE, 'C'); |
// source: http://stackoverflow.com/questions/81934/easy-way-to-export-a-sql-table-without-access-to-the-server-or-phpmyadmin#81951 | // source: http://stackoverflow.com/questions/81934/easy-way-to-export-a-sql-table-without-access-to-the-server-or-phpmyadmin#81951 |
include ('../include/common.inc.php'); | include ('../include/common.inc.php'); |
$query = $conn->prepare(' | $query = $conn->prepare(' |
SELECT * from myway_timingdeltas' | SELECT * from myway_timingdeltas' |
, array(PDO::ATTR_CURSOR => PDO::FETCH_ORI_NEXT)); | , array(PDO::ATTR_CURSOR => PDO::FETCH_ORI_NEXT)); |
$query->execute(); | $query->execute(); |
$errors = $conn->errorInfo(); | $errors = $conn->errorInfo(); |
if ($errors[2] != "") { | if ($errors[2] != "") { |
die("Export terminated, db error" . print_r($errors, true)); | die("Export terminated, db error" . print_r($errors, true)); |
} | } |
$headers = Array("date", "delay", "distance", "origin", "destination"); | $headers = Array("date", "delay", "distance", "origin", "destination"); |
$fp = fopen('php://output', 'w'); | $fp = fopen('php://output', 'w'); |
if ($fp && $query) { | if ($fp && $query) { |
//header('Content-Type: text/csv'); | //header('Content-Type: text/csv'); |
header('Pragma: no-cache'); | header('Pragma: no-cache'); |
header('Expires: 0'); | header('Expires: 0'); |
fputcsv($fp, $headers); | fputcsv($fp, $headers); |
while ($r = $query->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT)) { | while ($r = $query->fetch(PDO::FETCH_ASSOC, PDO::FETCH_ORI_NEXT)) { |
$row = Array(); | $row = Array(); |
foreach ($headers as $i => $fieldName) { | foreach ($headers as $i => $fieldName) { |
switch ($fieldName) { | switch ($fieldName) { |
case "date": | case "date": |
$row[] = date("dm",strtotime($r['date'])).date("Hi",strtotime($r['time'])); | $row[] = date("r",strtotime($r['date']." ".$r['time'])); |
break; | break; |
case "delay": | case "delay": |
$row[] = $r['timing_delta']; | $row[] = $r['timing_delta']; |
break; | break; |
case "distance": | case "distance": |
$row[] = $r['stop_sequence']; | $row[] = $r['stop_sequence']; |
break; | break; |
case "origin": | case "origin": |
$row[] = $r['myway_stop']; | $row[] = $r['myway_stop']; |
break; | break; |
case "destination": | case "destination": |
$row[] = $r['route_name']; | $row[] = $r['route_name']; |
break; | break; |
default: | default: |
break; | break; |
} | } |
} | } |
fputcsv($fp, array_values($row)); | fputcsv($fp, array_values($row)); |
} | } |
die; | die; |
} | } |
?> | ?> |
<!DOCTYPE html> | <!DOCTYPE html> |
<meta charset="utf-8"> | <meta charset="utf-8"> |
<title>Tesseract</title> | <title>Tesseract</title> |
<style> | <style> |
#charts { | #charts { |
padding: 10px 0; | padding: 10px 0; |
} | } |
.chart { | .chart { |
display: inline-block; | display: inline-block; |
height: 151px; | height: 151px; |
margin-bottom: 20px; | margin-bottom: 20px; |
} | } |
.reset { | .reset { |
padding-left: 1em; | padding-left: 1em; |
font-size: smaller; | font-size: smaller; |
color: #ccc; | color: #ccc; |
} | } |
.background.bar { | .background.bar { |
fill: #ccc; | fill: #ccc; |
} | } |
.foreground.bar { | .foreground.bar { |
fill: steelblue; | fill: steelblue; |
} | } |
.axis path, .axis line { | .axis path, .axis line { |
fill: none; | fill: none; |
stroke: #000; | stroke: #000; |
shape-rendering: crispEdges; | shape-rendering: crispEdges; |
} | } |
.axis text { | .axis text { |
font: 10px sans-serif; | font: 10px sans-serif; |
} | } |
.brush rect.extent { | .brush rect.extent { |
fill: steelblue; | fill: steelblue; |
fill-opacity: .125; | fill-opacity: .125; |
} | } |
.brush .resize path { | .brush .resize path { |
fill: #eee; | fill: #eee; |
stroke: #666; | stroke: #666; |
} | } |
#hour-chart { | #hour-chart { |
width: 260px; | width: 260px; |
} | } |
#delay-chart { | #delay-chart { |
width: 230px; | width: 230px; |
} | } |
#distance-chart { | #distance-chart { |
width: 420px; | width: 420px; |
} | } |
#date-chart { | #date-chart { |
width: 920px; | width: 920px; |
} | } |
#flight-list { | #flight-list { |
min-height: 1024px; | min-height: 1024px; |
} | } |
#flight-list .date, | #flight-list .date, |
#flight-list .day { | #flight-list .day { |
margin-bottom: .4em; | margin-bottom: .4em; |
} | } |
#flight-list .flight { | #flight-list .flight { |
line-height: 1.5em; | line-height: 1.5em; |
background: #eee; | background: #eee; |
width: 640px; | width: 640px; |
margin-bottom: 1px; | margin-bottom: 1px; |
} | } |
#flight-list .time { | #flight-list .time { |
color: #999; | color: #999; |
} | } |
#flight-list .flight div { | #flight-list .flight div { |
display: inline-block; | display: inline-block; |
width: 100px; | width: 100px; |
} | } |
#flight-list div.distance, | #flight-list div.distance, |
#flight-list div.delay { | #flight-list div.delay { |
width: 160px; | width: 160px; |
padding-right: 10px; | padding-right: 10px; |
text-align: right; | text-align: right; |
} | } |
#flight-list .early { | #flight-list .early { |
color: green; | color: green; |
} | } |
aside { | aside { |
position: absolute; | position: absolute; |
left: 740px; | left: 740px; |
font-size: smaller; | font-size: smaller; |
width: 220px; | width: 220px; |
} | } |
</style> | </style> |
<div id="charts"> | <div id="charts"> |
<div id="hour-chart" class="chart"> | <div id="hour-chart" class="chart"> |
<div class="title">Time of Day</div> | <div class="title">Time of Day</div> |
</div> | </div> |
<div id="delay-chart" class="chart"> | <div id="delay-chart" class="chart"> |
<div class="title">Arrival Delay (min.)</div> | <div class="title">Arrival Delay (min.)</div> |
</div> | </div> |
<div id="distance-chart" class="chart"> | <div id="distance-chart" class="chart"> |
<div class="title">Distance (mi.)</div> | <div class="title">Distance (mi.)</div> |
</div> | </div> |
<div id="date-chart" class="chart"> | <div id="date-chart" class="chart"> |
<div class="title">Date</div> | <div class="title">Date</div> |
</div> | </div> |
</div> | </div> |
<aside id="totals"><span id="active">-</span> of <span id="total">-</span> flights selected.</aside> | <aside id="totals"><span id="active">-</span> of <span id="total">-</span> flights selected.</aside> |
<div id="lists"> | <div id="lists"> |
<div id="flight-list" class="list"></div> | <div id="flight-list" class="list"></div> |
</div> | </div> |
</div> | </div> |
<script src="../js/tesseract/tesseract.min.js"></script> | <script src="../js/tesseract/tesseract.min.js"></script> |
<script src="../js/d3/d3.v2.min.js"></script> | <script src="../js/d3/d3.v2.min.js"></script> |
<script> | <script> |
d3.csv("busdelay.csv.php", function(flights) { | d3.csv("busdelay.csv.php", function(flights) { |
// Various formatters. | // Various formatters. |
var formatNumber = d3.format(",d"), | var formatNumber = d3.format(",d"), |
formatChange = d3.format("+,d"), | formatChange = d3.format("+,d"), |
formatDate = d3.time.format("%B %d, %Y"), | formatDate = d3.time.format("%B %d, %Y"), |
formatTime = d3.time.format("%I:%M %p"); | formatTime = d3.time.format("%I:%M %p"); |
// A nest operator, for grouping the flight list. | // A nest operator, for grouping the flight list. |
var nestByDate = d3.nest() | var nestByDate = d3.nest() |
.key(function(d) { return d3.time.day(d.date); }); | .key(function(d) { return d3.time.day(d.date); }); |
// A little coercion, since the CSV is untyped. | // A little coercion, since the CSV is untyped. |
flights.forEach(function(d, i) { | flights.forEach(function(d, i) { |
d.index = i; | d.index = i; |
d.date = parseDate(d.date); | d.date = parseDate(d.date); |
d.delay = +d.delay; | d.delay = +d.delay; |
d.distance = +d.distance; | d.distance = +d.distance; |
}); | }); |
// Create the tesseract and relevant dimensions and groups. | // Create the tesseract and relevant dimensions and groups. |
flight = tesseract(flights), | flight = tesseract(flights), |
all = flight.groupAll(), | all = flight.groupAll(), |
date = flight.dimension(function(d) { return d3.time.day(d.date); }), | date = flight.dimension(function(d) { return d3.time.day(d.date); }), |
dates = date.group(), | dates = date.group(), |
hour = flight.dimension(function(d) { return d.date.getHours() + d.date.getMinutes() / 60; }), | hour = flight.dimension(function(d) { return d.date.getHours() + d.date.getMinutes() / 60; }), |
hours = hour.group(Math.floor), | hours = hour.group(Math.floor), |
delay = flight.dimension(function(d) { return Math.max(-60, Math.min(149, d.delay)); }), | //delay = flight.dimension(function(d) { return Math.max(-60, Math.min(149, d.delay)); }), |
delay = flight.dimension(function(d) { return d.delay; }), | |
delays = delay.group(function(d) { return Math.floor(d / 10) * 10; }), | delays = delay.group(function(d) { return Math.floor(d / 10) * 10; }), |
distance = flight.dimension(function(d) { return Math.min(90, d.distance); }), | distance = flight.dimension(function(d) { return Math.min(60, d.distance); }), |
distances = distance.group(function(d) { return Math.floor(d / 50) * 50; }); | distances = distance.group(function(d) { return Math.floor(d / 50) * 50; }); |
var charts = [ | var charts = [ |
barChart() | barChart() |
.dimension(hour) | .dimension(hour) |
.group(hours) | .group(hours) |
.x(d3.scale.linear() | .x(d3.scale.linear() |
.domain([0, 24]) | .domain([0, 24]) |
.rangeRound([0, 10 * 24])), | .rangeRound([0, 10 * 24])), |
barChart() | barChart() |
.dimension(delay) | .dimension(delay) |
.group(delays) | .group(delays) |
.x(d3.scale.linear() | .x(d3.scale.linear() |
.domain([-60, 150]) | .domain([-650, 650]) |
.rangeRound([0, 10 * 21])), | .rangeRound([0, 10 * 21])), |
barChart() | barChart() |
.dimension(distance) | .dimension(distance) |
.group(distances) | .group(distances) |
.x(d3.scale.linear() | .x(d3.scale.linear() |
.domain([0, 90]) | .domain([0, 60]) |
.rangeRound([0, 10 * 40])), | .rangeRound([0, 10 * 40])), |
barChart() | barChart() |
.dimension(date) | .dimension(date) |
.group(dates) | .group(dates) |
.round(d3.time.day.round) | .round(d3.time.day.round) |
.x(d3.time.scale() | .x(d3.time.scale() |
.domain([new Date(2001, 0, 1), new Date(2001, 3, 1)]) | .domain([new Date(2011, 4, 1), new Date(2012, 1, 4)]) |
.rangeRound([0, 10 * 90])) | .rangeRound([0, 10 * 90])) |
.filter([new Date(2001, 1, 1), new Date(2001, 2, 1)]) | .filter([new Date(2011, 4, 4), new Date(2012, 4, 4)]) |
]; | ]; |
// Given our array of charts, which we assume are in the same order as the | // Given our array of charts, which we assume are in the same order as the |
// .chart elements in the DOM, bind the charts to the DOM and render them. | // .chart elements in the DOM, bind the charts to the DOM and render them. |
// We also listen to the chart's brush events to update the display. | // We also listen to the chart's brush events to update the display. |
var chart = d3.selectAll(".chart") | var chart = d3.selectAll(".chart") |
.data(charts) | .data(charts) |
.each(function(chart) { chart.on("brush", renderAll).on("brushend", renderAll); }); | .each(function(chart) { chart.on("brush", renderAll).on("brushend", renderAll); }); |
// Render the initial lists. | // Render the initial lists. |
var list = d3.selectAll(".list") | var list = d3.selectAll(".list") |
.data([flightList]); | .data([flightList]); |
// Render the total. | // Render the total. |
d3.selectAll("#total") | d3.selectAll("#total") |
.text(formatNumber(flight.size())); | .text(formatNumber(flight.size())); |
renderAll(); | renderAll(); |
// Renders the specified chart or list. | // Renders the specified chart or list. |
function render(method) { | function render(method) { |
d3.select(this).call(method); | d3.select(this).call(method); |
} | } |
// Whenever the brush moves, re-rendering everything. | // Whenever the brush moves, re-rendering everything. |
function renderAll() { | function renderAll() { |
chart.each(render); | chart.each(render); |
list.each(render); | list.each(render); |
d3.select("#active").text(formatNumber(all.value())); | d3.select("#active").text(formatNumber(all.value())); |
} | } |