├── .gitignore ├── LICENSE ├── Procfile ├── README.md ├── app.js ├── bower.json ├── coax.json ├── models └── database.js ├── package.json ├── public ├── imgs │ ├── alignment.jpg │ ├── dwelltime.png │ ├── frequency.png │ ├── marker-flag-end-shadowed.png │ ├── marker-flag-shadow.png │ ├── marker-flag-start-shadowed.png │ ├── mfc_qr.png │ ├── phil │ │ ├── brt_black_yellow.svg │ │ ├── heart.svg │ │ ├── home_icon.svg │ │ ├── platform_black_yellow.svg │ │ ├── pole_black_yellow.svg │ │ └── shopping_cart.svg │ ├── runningtime.png │ ├── start.png │ ├── stop.png │ ├── stop0.png │ ├── stop1.png │ ├── stop2.png │ ├── stops │ │ ├── 0.png │ │ ├── 1.png │ │ └── 2.png │ ├── userHeart.png │ ├── userHome.png │ └── userShop.png ├── ng-views │ └── maps.html ├── routes │ ├── destinations │ │ ├── chartLabels.json │ │ └── indicators.json │ ├── scenario │ │ ├── A.json │ │ ├── B.json │ │ ├── BaseCombined.json │ │ ├── C.json │ │ ├── D.json │ │ ├── E.json │ │ ├── UpCombined.json │ │ └── corridors.json │ └── shapefiles │ │ └── mapApp │ │ ├── cached │ │ ├── baseline.json │ │ └── exampleDiff.json │ │ ├── cordon.json │ │ ├── homelocation.json │ │ ├── lines.geojson │ │ ├── priority.geojson │ │ ├── proposed.geojson │ │ ├── routes.geojson │ │ ├── stations.geojson │ │ ├── stops.geojson │ │ └── trunks.geojson ├── scripts │ ├── analyst.js │ ├── bootstrap-tour-standalone.min.js │ ├── browsochrones.js │ ├── filesaver.js │ ├── leaflet-search.js │ ├── leaflet-transitivelayer.js │ ├── main.js │ ├── main │ │ ├── controllers │ │ │ └── mapsController.js │ │ ├── misc │ │ │ └── filters.js │ │ └── services │ │ │ ├── analystService.js │ │ │ ├── d3Service.js │ │ │ ├── leftService.js │ │ │ ├── loadService.js │ │ │ ├── scorecardService.js │ │ │ ├── supportService.js │ │ │ └── targetService.js │ ├── polyfill.js │ └── transitive.js └── style │ ├── bootstrap-tour-standalone.min.css │ ├── d3.css │ ├── leaflet-search.css │ ├── leaflet-search.mobile.css │ ├── main.css │ ├── slider.css │ └── transitive.css ├── temporary.json └── views └── index.ejs /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .env 3 | .DS_STORE 4 | node_modules 5 | bower_components 6 | build 7 | credentials.js 8 | temporary.json 9 | npm-debug.log 10 | npm-debug.log.298913980 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015 Mobility Futures Collaborative 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | start: node app.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CoAXs 2 | An interactive transit corridor “modifier/builder,” available as a web based tool and intended for use as an interactive, browser-based tool presented in an interactive transit exhibit. Learn more: http://mittransportanalyst.github.io/ 3 | 4 | ##### Warnings 5 | Note to users: There are scroll bar issues present. Also, recorded issues of `post` fails on retrieving large geoJSONs. For usability, make sure you are running Mozilla FF (latest version). Also, since we have yet to custom remove the scroll bar issue - if you are running a Windows OS, use https://userstyles.org/styles/5449/scrollbar-hidden-hide-scrollbars-totally to deal with the scroll bar situation. 6 | 7 | ### View staging server online 8 | See an online demo at http://mittransportanalyst.github.io/boston/. Due to cross-origin request issues, please be sure that on Heroku you are going to `http` and NOT `https`. If you type in the address without specifically designating `http`, Heroku will route you automatically to `https`, so please be aware of that. 9 | 10 | ### How to get this up and running 11 | ##### Node, npm, Bower 12 | You need Node installed on your computer. If you do not have it, go to https://nodejs.org/ and click the green button named "Install". 13 | 14 | npm is Node's package manager, and comes bundled. Bower is a package manager for client side libraries. Install it if you don't have it by entering `npm install -g bower` in your terminal. More information on Bower can be found at http://bower.io/. 15 | 16 | #### Cloning repo 17 | If you don't have the repo cloned already, navigate to a fresh/clean/empty directory in your computer and enter `git clone https://github.com/mitTransportAnalyst/CoAXs.git`. Make sure you are in the `master` branch (you should be by default), by entering `git status` and checking which branch is highlighted. 18 | 19 | #### Installing dependencies 20 | Run `bower install` and `npm install` to install dependencies for client and server-side libraries, respectively. You can view the dependencies in `bower.json` for Bower and `package.json` for Node. 21 | 22 | #### Starting up node 23 | Once all dependencies have been installed, all that's left to do is enter `npm start`. Now open a web browser and navigate to `http://127.0.0.1:3000`. The app should be up and running there. 24 | 25 | (Note: Install Heroku Toolbelt. use ​foreman start​ instead of ​npm start) 26 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var app = express(); 3 | 4 | var fs = require('fs'); 5 | 6 | var morgan = require('morgan'); 7 | var bodyParser = require('body-parser'); 8 | 9 | var http = require('http'); 10 | var path = require('path'); 11 | 12 | app.use(morgan('dev')); 13 | app.use(bodyParser.json({limit: '50mb'})); 14 | app.use(bodyParser.urlencoded({limit: '50mb', extended: true})); 15 | 16 | 17 | app.use('/public', express.static(__dirname + '/public')); // set up ejs static file management 18 | app.use('/bower_components', express.static(__dirname + '/bower_components')); 19 | app.set('view engine', 'ejs'); 20 | 21 | 22 | /// ROUTING /// 23 | var http = require('http'); 24 | var request = require('request'); 25 | var csv = require('csv-streamify'); 26 | 27 | var analystCreds = require('request'); 28 | 29 | var analystReqOpts = { 30 | url: 'http://coaxs.mit.edu:9090/oauth/token', 31 | method: 'POST', 32 | timeout: 10000, 33 | auth: { 34 | 'user' : process.env.analyst_key, 35 | 'pass' : process.env.analyst_secret 36 | }, 37 | headers : { 38 | 'content-type' : 'application/x-www-form-urlencoded', 39 | 'Access-Control-Allow-Origin': '*' 40 | }, 41 | body: 'grant_type=client_credentials' 42 | }; 43 | 44 | app.get('/credentials', function (req, res) { 45 | var credExpiration = 0, 46 | clientCredentials = ''; 47 | 48 | console.log('date: '); 49 | console.log(parseFloat(credExpiration)); 50 | if ( parseFloat(Date.now()) >= parseFloat(credExpiration)) { 51 | console.log('Requesting new credentials from analyst-server') 52 | analystCreds(analystReqOpts, function (error, response, body){ 53 | console.log(error); 54 | clientCredentials = body; 55 | credExpiration = 3600*1000+parseFloat(Date.now()-60000); 56 | console.log('New credentials received: ' + clientCredentials +',' + credExpiration); 57 | console.log(clientCredentials); 58 | res.send(clientCredentials); 59 | }); 60 | }; 61 | }); 62 | 63 | app.get('/', function (req, res) { 64 | res.render('index.ejs', { 65 | data : 'foo', 66 | }); 67 | }); 68 | 69 | var fileNames = { 70 | existing: 'lines.geojson', 71 | proposed: 'proposed.geojson', 72 | proposed_priority: 'priority.geojson', 73 | t_stops: 'stations.geojson', 74 | proposed_stops: 'stops.geojson', 75 | cordons: 'cordon.json', 76 | } 77 | 78 | app.get('/geojson/:fileId', function (req, res) { 79 | var options = { 80 | 'root' : __dirname + '/public/routes/shapefiles/mapApp/', 81 | 'dotfiles' : 'deny', 82 | 'headers' : { 83 | 'x-timestamp' : Date.now(), 84 | 'x-sent' : true 85 | } 86 | }; 87 | var file = fileNames[req.params.fileId]; 88 | res.sendFile(file, options, function (err) { 89 | if (err) { 90 | console.log('sendFile error:', err); 91 | res.status(err.status).end(); 92 | } 93 | }); 94 | }); 95 | 96 | 97 | //get for scenario files 98 | app.get('/load/scenario/:fileName', function (req, res) { 99 | var options = { 100 | 'root' : __dirname + '/public/routes/scenario', 101 | 'dotfiles' : 'deny', 102 | 'headers' : { 103 | 'x-timestamp' : Date.now(), 104 | 'x-sent' : true 105 | } 106 | }; 107 | var file = req.params.fileName+".json"; 108 | res.sendFile(file, options, function (err) { 109 | if (err) { 110 | console.log('sendFile error:', err); 111 | res.status(err.status).end(); 112 | } 113 | }); 114 | }); 115 | 116 | //get for destination data 117 | app.get('/load/destinations/:fileName', function (req, res) { 118 | var options = { 119 | 'root' : __dirname + '/public/routes/destinations', 120 | 'dotfiles' : 'deny', 121 | 'headers' : { 122 | 'x-timestamp' : Date.now(), 123 | 'x-sent' : true 124 | } 125 | }; 126 | var file = req.params.fileName+".json"; 127 | res.sendFile(file, options, function (err) { 128 | if (err) { 129 | console.log('sendFile error:', err); 130 | res.status(err.status).end(); 131 | } 132 | }); 133 | }); 134 | 135 | app.get('/load/routes', function (req, res) { 136 | var path = __dirname + '/public/routes/shapefiles/mapApp/routes.geojson'; 137 | res.sendFile(path, function (err) { 138 | if (err) { 139 | console.log('sendFile error:', err); 140 | res.status(err.status).end(); 141 | } 142 | }); 143 | }); 144 | 145 | 146 | app.get('/load/homelocation', function (req, res) { 147 | var path = __dirname + '/public/routes/shapefiles/mapApp/homelocation.json'; 148 | res.sendFile(path, function (err) { 149 | if (err) { 150 | console.log('sendFile error:', err); 151 | res.status(err.status).end(); 152 | } 153 | }); 154 | }); 155 | 156 | app.get('/load/trunks', function (req, res) { 157 | var path = __dirname + '/public/routes/shapefiles/mapApp/trunks.geojson'; 158 | res.sendFile(path, function (err) { 159 | if (err) { 160 | console.log('sendFile error:', err); 161 | res.status(err.status).end(); 162 | } 163 | }); 164 | }); 165 | 166 | var globalGetDone = false; 167 | app.get('/startSnapCache/:fileId', function (req, res) { 168 | globalGetDone = false; 169 | var params = { 170 | Bucket: S3_BUCKET, 171 | Key: req.params.fileId 172 | }; 173 | var file = require('fs').createWriteStream('temporary.json'); 174 | 175 | s3.getObject(params).on('httpData', function(chunk) { 176 | file.write(chunk); 177 | }).on('httpDone', function() { 178 | file.end(); 179 | globalGetDone = true; 180 | res.status(200).send({started: true}); 181 | }).send(); 182 | }); 183 | 184 | app.get('/loadSnapCache', function (req, res) { 185 | if (globalGetDone) { 186 | var options = { 187 | root: __dirname, 188 | dotfiles: 'deny', 189 | headers: { 190 | 'x-timestamp': Date.now(), 191 | 'x-sent': true 192 | } 193 | }; 194 | var file = 'temporary.json'; 195 | res.sendFile(file, options, function (err) { 196 | if (err) { 197 | console.log('sendFile error:', err); 198 | res.status(err.status).end(); 199 | } 200 | }); 201 | } else { 202 | res.status(200).send({notReady: true}); 203 | } 204 | }); 205 | 206 | app.get('/cachedLocs', bodyParser.json({limit: '50mb'}), function (req, res) { 207 | var allKeys = []; 208 | var params = {Bucket: S3_BUCKET}; 209 | 210 | s3.listObjects(params, function (err, data) { 211 | if (data) { 212 | allKeys.push(data.Contents); 213 | if (data.IsTruncated && data.hasOwnProperty('Contents')) { 214 | listAllKeys(data.Contents.slice(-1)[0].Key); 215 | } 216 | else { 217 | if (data.hasOwnProperty('Contents')) { 218 | data = data.Contents.map(function (each) { return each.Key; }); 219 | res.status(200).send(data) 220 | } else { 221 | res.status(500).send('Error missing Contents key value.'); 222 | } 223 | } 224 | } else { 225 | console.log('Error occured', err); 226 | var status = err.status ? err.status : 500; 227 | res.status(status).send('Error accessing S3 bucket.'); 228 | } 229 | }); 230 | }); 231 | 232 | app.post('/cachedLocs/:fileId', bodyParser.json({limit: '50mb'}), function (req, res) { 233 | var fileName = req.params.fileId; 234 | var params = { 235 | ACL: 'public-read-write', 236 | Bucket: BUCKET_NAME, 237 | Key: fileName, 238 | Body: req.body.newPOIs, 239 | ContentType: 'application/json' 240 | } 241 | 242 | s3.putObject(params, function(err, response) { 243 | if (err) { 244 | console.log('Write file error:', err); 245 | res.status(err.status).end(); 246 | } else { 247 | res.status(200).end(); 248 | } 249 | }); 250 | }); 251 | 252 | 253 | // gather google responses from phil's survey, uses csv-streamify to convert csv (not the best library to use) 254 | app.get('/load/users/:fileId', function (req, res) { 255 | var url = 'https://www.dropbox.com/s/k97r75o90j3z8w6/'+req.params.fileId+'.json?dl=1'; 256 | request.get(url,function(err, response, body){ 257 | if (!err && response.statusCode == 200) { 258 | res.send(body); 259 | } 260 | }) 261 | }); 262 | 263 | 264 | // this is how the app is actually started up, the port can be specified either in command line or will default to 3000 265 | var server = app.listen(process.env.PORT || 3000, function () { 266 | var host = server.address().address; 267 | var port = server.address().port; 268 | console.log('Coaxs app listening at http://%s:%s', host, port); 269 | }); 270 | 271 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coaxs", 3 | "version": "0.1.0", 4 | "homepage": "https://github.com/mitTransportAnalyst/CoAXs", 5 | "authors": [ 6 | "Kuan Butts " 7 | ], 8 | "description": "CoAXs interactive transit corridor modifier/builder", 9 | "main": "", 10 | "moduleType": [ 11 | "node" 12 | ], 13 | "license": "Apache 2.0", 14 | "ignore": [ 15 | "**/.*", 16 | "node_modules", 17 | "bower_components", 18 | "test", 19 | "tests" 20 | ], 21 | "dependencies": { 22 | "angular": "~1.4.x", 23 | "angular-bootstrap": "~0.13.0", 24 | "angular-leaflet-directive": "~0.8.1", 25 | "angular-simple-logger": "~0.0.1", 26 | "angular-resource": "~1.3.15", 27 | "bootstrap": "~3.3.4", 28 | "d3": "~3.5.5", 29 | "es6-promise": "~2.2.0", 30 | "fetch": "~0.9.0", 31 | "font-awesome": "~4.4.0", 32 | "font-awesome-animation": "~0.0.7", 33 | "jquery": "~2.1.4", 34 | "leaflet": "~0.7.5", 35 | "ui-router": "~0.2.14" 36 | }, 37 | "resolutions": { 38 | "angular": "~1.4.6", 39 | "font-awesome": "~4.4.0" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /models/database.js: -------------------------------------------------------------------------------- 1 | var pg = require('pg'); 2 | var connectionString = process.env.DATABASE_URL || 'postgres://localhost:5432/coaxs'; 3 | 4 | var client = new pg.Client(connectionString); 5 | client.connect(); 6 | 7 | var query = client.query('CREATE TABLE items(id SERIAL PRIMARY KEY, text VARCHAR(40) not null, complete BOOLEAN)'); 8 | query.on('end', function() { client.end(); }); 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "coaxs", 3 | "main": "app.js", 4 | "engines": { 5 | "node": "6.11.1" 6 | }, 7 | "dependencies": { 8 | "aws-sdk": "^2.1.45", 9 | "body-parser": "^1.12.4", 10 | "bower": "1.4.1", 11 | "browsochrones": "~0.7.0", 12 | "csv-streamify": "^2.0.0", 13 | "debug": "^2.2.0", 14 | "ejs": "~0.8.5", 15 | "express": "~4.9.0", 16 | "googleapis": "^2.0.5", 17 | "leaflet-search": "^2.7.0", 18 | "leaflet-transitivelayer": "^0.2.0", 19 | "morgan": "^1.6.1", 20 | "pg": "^4.4.0", 21 | "request": "^2.57.0", 22 | "transitive-js": "^0.8.2" 23 | }, 24 | "devDependencies": {}, 25 | "scripts": { 26 | "start": "node app.js", 27 | "postinstall": "./node_modules/bower/bin/bower install" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /public/imgs/alignment.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/alignment.jpg -------------------------------------------------------------------------------- /public/imgs/dwelltime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/dwelltime.png -------------------------------------------------------------------------------- /public/imgs/frequency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/frequency.png -------------------------------------------------------------------------------- /public/imgs/marker-flag-end-shadowed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/marker-flag-end-shadowed.png -------------------------------------------------------------------------------- /public/imgs/marker-flag-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/marker-flag-shadow.png -------------------------------------------------------------------------------- /public/imgs/marker-flag-start-shadowed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/marker-flag-start-shadowed.png -------------------------------------------------------------------------------- /public/imgs/mfc_qr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/mfc_qr.png -------------------------------------------------------------------------------- /public/imgs/phil/brt_black_yellow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 13 | 20 | 21 | 25 | 28 | 29 | 32 | 38 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/imgs/phil/heart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /public/imgs/phil/home_icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/imgs/phil/platform_black_yellow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 13 | 20 | 21 | 24 | 28 | 31 | 32 | -------------------------------------------------------------------------------- /public/imgs/phil/pole_black_yellow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 12 | 16 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /public/imgs/phil/shopping_cart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /public/imgs/runningtime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/runningtime.png -------------------------------------------------------------------------------- /public/imgs/start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/start.png -------------------------------------------------------------------------------- /public/imgs/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/stop.png -------------------------------------------------------------------------------- /public/imgs/stop0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/stop0.png -------------------------------------------------------------------------------- /public/imgs/stop1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/stop1.png -------------------------------------------------------------------------------- /public/imgs/stop2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/stop2.png -------------------------------------------------------------------------------- /public/imgs/stops/0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/stops/0.png -------------------------------------------------------------------------------- /public/imgs/stops/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/stops/1.png -------------------------------------------------------------------------------- /public/imgs/stops/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/stops/2.png -------------------------------------------------------------------------------- /public/imgs/userHeart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/userHeart.png -------------------------------------------------------------------------------- /public/imgs/userHome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/userHome.png -------------------------------------------------------------------------------- /public/imgs/userShop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mitTransportAnalyst/CoAXs/45946f952184a3971846386e4dbf352036cda2ce/public/imgs/userShop.png -------------------------------------------------------------------------------- /public/routes/destinations/chartLabels.json: -------------------------------------------------------------------------------- 1 | [{"code": "jobs1", "verbose": "Jobs | $", "color": "#FFA728"}, {"code": "jobs2", "verbose": "Jobs | $$", "color": "#FF9314"}, {"code": "jobs3", "verbose": "Jobs | $$$", "color": "#FF7F00"}, 2 | {"code": "workers1", "verbose": "Workers | $", "color": "#FFA728"}, {"code": "workers2", "verbose": "Workers | $$", "color": "#FF9314"}, {"code": "workers3", "verbose": "Workers | $$$", "color": "#FF7F00"}, 3 | {"code": "walkTime", "verbose": "min. walking", "color": "#FFA728"}, {"code": "waitTime", "verbose": "min. waiting", "color": "#FF9314"}, {"code": "rideTime", "verbose": "min. riding", "color": "#FF7F00"}] -------------------------------------------------------------------------------- /public/routes/destinations/indicators.json: -------------------------------------------------------------------------------- 1 | {"jobs":[ 2 | {"id": "jobs1", 3 | "grid": "Jobs_with_earnings__1250_per_month_or_less.grid", 4 | "verbose": "Jobs | $"}, 5 | {"id": "jobs2", 6 | "grid": "Jobs_with_earnings__1251_-__3333_per_month.grid", 7 | "verbose": "Jobs | $$"}, 8 | {"id": "jobs3", 9 | "grid": "Jobs_with_earnings_greater_than__3333_per_month.grid", 10 | "verbose": "Jobs | $$$"}], 11 | "workers":[ 12 | {"id": "workers1", 13 | "grid": "Workers_with_earnings__1250_per_month_or_less.grid", 14 | "verbose": "Workers | $"}, 15 | {"id": "workers2", 16 | "grid": "Workers_with_earnings__1251_-__3333_per_month.grid", 17 | "verbose": "Workers | $$"}, 18 | {"id": "workers3", 19 | "grid": "Workers_with_earnings_greater_than__3333_per_month.grid", 20 | "verbose": "Workers | $$$"}] 21 | } -------------------------------------------------------------------------------- /public/routes/scenario/A.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 0, 3 | "description": "LS Scenario v1", 4 | "feedChecksums": { 5 | "MBTA": 993571431 6 | }, 7 | "modifications": [ 8 | { 9 | "type": "adjust-dwell-time", 10 | "routes": [ 11 | "MBTA:1" 12 | ], 13 | "stops": null, 14 | "scale": 0.6, 15 | "comment": "1-Dwell" 16 | }, 17 | { 18 | "type": "adjust-dwell-time", 19 | "routes": [ 20 | "MBTA:701" 21 | ], 22 | "stops": null, 23 | "scale": 0.6, 24 | "comment": "CT1-Dwell" 25 | }, 26 | { 27 | "type": "adjust-dwell-time", 28 | "routes": [ 29 | "MBTA:64" 30 | ], 31 | "stops": null, 32 | "scale": 0.6, 33 | "comment": "64-Dwell" 34 | }, 35 | { 36 | "type": "adjust-speed", 37 | "routes": [ 38 | "MBTA:1" 39 | ], 40 | "hops": [ 41 | [ 42 | "MBTA:57", 43 | "MBTA:58" 44 | ], 45 | [ 46 | "MBTA:58", 47 | "MBTA:10590" 48 | ], 49 | [ 50 | "MBTA:10590", 51 | "MBTA:87" 52 | ], 53 | [ 54 | "MBTA:87", 55 | "MBTA:88" 56 | ], 57 | [ 58 | "MBTA:88", 59 | "MBTA:188" 60 | ], 61 | [ 62 | "MBTA:188", 63 | "MBTA:89" 64 | ], 65 | [ 66 | "MBTA:89", 67 | "MBTA:91" 68 | ], 69 | [ 70 | "MBTA:91", 71 | "MBTA:93" 72 | ], 73 | [ 74 | "MBTA:93", 75 | "MBTA:95" 76 | ], 77 | [ 78 | "MBTA:95", 79 | "MBTA:96" 80 | ], 81 | [ 82 | "MBTA:96", 83 | "MBTA:97" 84 | ], 85 | [ 86 | "MBTA:97", 87 | "MBTA:99" 88 | ], 89 | [ 90 | "MBTA:99", 91 | "MBTA:101" 92 | ], 93 | [ 94 | "MBTA:101", 95 | "MBTA:102" 96 | ], 97 | [ 98 | "MBTA:102", 99 | "MBTA:104" 100 | ], 101 | [ 102 | "MBTA:104", 103 | "MBTA:106" 104 | ], 105 | [ 106 | "MBTA:106", 107 | "MBTA:107" 108 | ], 109 | [ 110 | "MBTA:107", 111 | "MBTA:108" 112 | ], 113 | [ 114 | "MBTA:66", 115 | "MBTA:67" 116 | ], 117 | [ 118 | "MBTA:67", 119 | "MBTA:68" 120 | ], 121 | [ 122 | "MBTA:68", 123 | "MBTA:69" 124 | ], 125 | [ 126 | "MBTA:69", 127 | "MBTA:71" 128 | ], 129 | [ 130 | "MBTA:71", 131 | "MBTA:72" 132 | ], 133 | [ 134 | "MBTA:72", 135 | "MBTA:73" 136 | ], 137 | [ 138 | "MBTA:73", 139 | "MBTA:74" 140 | ], 141 | [ 142 | "MBTA:74", 143 | "MBTA:75" 144 | ], 145 | [ 146 | "MBTA:75", 147 | "MBTA:77" 148 | ], 149 | [ 150 | "MBTA:77", 151 | "MBTA:79" 152 | ], 153 | [ 154 | "MBTA:79", 155 | "MBTA:80" 156 | ], 157 | [ 158 | "MBTA:80", 159 | "MBTA:82" 160 | ], 161 | [ 162 | "MBTA:82", 163 | "MBTA:187" 164 | ], 165 | [ 166 | "MBTA:187", 167 | "MBTA:83" 168 | ], 169 | [ 170 | "MBTA:83", 171 | "MBTA:84" 172 | ], 173 | [ 174 | "MBTA:84", 175 | "MBTA:59" 176 | ], 177 | [ 178 | "MBTA:59", 179 | "MBTA:854" 180 | ], 181 | [ 182 | "MBTA:854", 183 | "MBTA:856" 184 | ] 185 | ], 186 | "scale": 1.4, 187 | "comment": "1-Speed" 188 | }, 189 | { 190 | "type": "adjust-speed", 191 | "routes": [ 192 | "MBTA:701" 193 | ], 194 | "hops": [ 195 | [ 196 | "MBTA:58", 197 | "MBTA:10590" 198 | ], 199 | [ 200 | "MBTA:10590", 201 | "MBTA:87" 202 | ], 203 | [ 204 | "MBTA:87", 205 | "MBTA:188" 206 | ], 207 | [ 208 | "MBTA:188", 209 | "MBTA:89" 210 | ], 211 | [ 212 | "MBTA:89", 213 | "MBTA:93" 214 | ], 215 | [ 216 | "MBTA:93", 217 | "MBTA:95" 218 | ], 219 | [ 220 | "MBTA:95", 221 | "MBTA:97" 222 | ], 223 | [ 224 | "MBTA:97", 225 | "MBTA:101" 226 | ], 227 | [ 228 | "MBTA:101", 229 | "MBTA:1060" 230 | ], 231 | [ 232 | "MBTA:1060", 233 | "MBTA:72" 234 | ], 235 | [ 236 | "MBTA:72", 237 | "MBTA:73" 238 | ], 239 | [ 240 | "MBTA:73", 241 | "MBTA:75" 242 | ], 243 | [ 244 | "MBTA:75", 245 | "MBTA:77" 246 | ], 247 | [ 248 | "MBTA:77", 249 | "MBTA:79" 250 | ], 251 | [ 252 | "MBTA:79", 253 | "MBTA:82" 254 | ], 255 | [ 256 | "MBTA:82", 257 | "MBTA:187" 258 | ], 259 | [ 260 | "MBTA:187", 261 | "MBTA:84" 262 | ], 263 | [ 264 | "MBTA:84", 265 | "MBTA:59" 266 | ], 267 | [ 268 | "MBTA:59", 269 | "MBTA:854" 270 | ], 271 | [ 272 | "MBTA:1060", 273 | "MBTA:72" 274 | ], 275 | [ 276 | "MBTA:72", 277 | "MBTA:73" 278 | ], 279 | [ 280 | "MBTA:73", 281 | "MBTA:75" 282 | ], 283 | [ 284 | "MBTA:75", 285 | "MBTA:77" 286 | ], 287 | [ 288 | "MBTA:77", 289 | "MBTA:79" 290 | ], 291 | [ 292 | "MBTA:79", 293 | "MBTA:82" 294 | ], 295 | [ 296 | "MBTA:82", 297 | "MBTA:187" 298 | ], 299 | [ 300 | "MBTA:187", 301 | "MBTA:84" 302 | ], 303 | [ 304 | "MBTA:84", 305 | "MBTA:59" 306 | ], 307 | [ 308 | "MBTA:59", 309 | "MBTA:854" 310 | ] 311 | ], 312 | "scale": 1.4, 313 | "comment": "CT1-Speed" 314 | }, 315 | { 316 | "type": "adjust-speed", 317 | "routes": [ 318 | "MBTA:64" 319 | ], 320 | "hops": [ 321 | [ 322 | "MBTA:72", 323 | "MBTA:73" 324 | ], 325 | [ 326 | "MBTA:1060", 327 | "MBTA:72" 328 | ], 329 | [ 330 | "MBTA:1060", 331 | "MBTA:72" 332 | ], 333 | [ 334 | "MBTA:72", 335 | "MBTA:1123" 336 | ], 337 | [ 338 | "MBTA:73", 339 | "MBTA:730" 340 | ] 341 | ], 342 | "scale": 1.4, 343 | "comment": "64-Speed" 344 | }, 345 | { 346 | "type": "adjust-speed", 347 | "routes": [ 348 | "MBTA:45" 349 | ], 350 | "hops": [ 351 | [ 352 | "MBTA:11257", 353 | "MBTA:1259" 354 | ], 355 | [ 356 | "MBTA:1259", 357 | "MBTA:11323" 358 | ], 359 | [ 360 | "MBTA:11323", 361 | "MBTA:1149" 362 | ], 363 | [ 364 | "MBTA:1149", 365 | "MBTA:1146" 366 | ], 367 | [ 368 | "MBTA:1146", 369 | "MBTA:1147" 370 | ], 371 | [ 372 | "MBTA:1147", 373 | "MBTA:64000" 374 | ], 375 | [ 376 | "MBTA:64000", 377 | "MBTA:1493" 378 | ], 379 | [ 380 | "MBTA:1493", 381 | "MBTA:1495" 382 | ], 383 | [ 384 | "MBTA:1495", 385 | "MBTA:1496" 386 | ], 387 | [ 388 | "MBTA:1496", 389 | "MBTA:1577" 390 | ], 391 | [ 392 | "MBTA:1577", 393 | "MBTA:1578" 394 | ], 395 | [ 396 | "MBTA:1578", 397 | "MBTA:1579" 398 | ], 399 | [ 400 | "MBTA:1579", 401 | "MBTA:1580" 402 | ], 403 | [ 404 | "MBTA:1580", 405 | "MBTA:1581" 406 | ], 407 | [ 408 | "MBTA:1581", 409 | "MBTA:1582" 410 | ], 411 | [ 412 | "MBTA:1582", 413 | "MBTA:15820" 414 | ], 415 | [ 416 | "MBTA:15820", 417 | "MBTA:1583" 418 | ], 419 | [ 420 | "MBTA:1583", 421 | "MBTA:1584" 422 | ], 423 | [ 424 | "MBTA:1584", 425 | "MBTA:1585" 426 | ], 427 | [ 428 | "MBTA:1585", 429 | "MBTA:1586" 430 | ], 431 | [ 432 | "MBTA:1586", 433 | "MBTA:413" 434 | ], 435 | [ 436 | "MBTA:413", 437 | "MBTA:414" 438 | ], 439 | [ 440 | "MBTA:414", 441 | "MBTA:1587" 442 | ], 443 | [ 444 | "MBTA:1587", 445 | "MBTA:1565" 446 | ], 447 | [ 448 | "MBTA:1565", 449 | "MBTA:383" 450 | ], 451 | [ 452 | "MBTA:383", 453 | "MBTA:384" 454 | ], 455 | [ 456 | "MBTA:384", 457 | "MBTA:385" 458 | ], 459 | [ 460 | "MBTA:385", 461 | "MBTA:1566" 462 | ], 463 | [ 464 | "MBTA:1566", 465 | "MBTA:15660" 466 | ], 467 | [ 468 | "MBTA:15660", 469 | "MBTA:1567" 470 | ], 471 | [ 472 | "MBTA:1567", 473 | "MBTA:15661" 474 | ], 475 | [ 476 | "MBTA:15661", 477 | "MBTA:1569" 478 | ], 479 | [ 480 | "MBTA:1569", 481 | "MBTA:1570" 482 | ], 483 | [ 484 | "MBTA:1570", 485 | "MBTA:1571" 486 | ], 487 | [ 488 | "MBTA:1571", 489 | "MBTA:1572" 490 | ], 491 | [ 492 | "MBTA:1572", 493 | "MBTA:1573" 494 | ], 495 | [ 496 | "MBTA:1573", 497 | "MBTA:1574" 498 | ], 499 | [ 500 | "MBTA:1574", 501 | "MBTA:1575" 502 | ], 503 | [ 504 | "MBTA:1575", 505 | "MBTA:1576" 506 | ], 507 | [ 508 | "MBTA:1576", 509 | "MBTA:1487" 510 | ], 511 | [ 512 | "MBTA:1487", 513 | "MBTA:1488" 514 | ], 515 | [ 516 | "MBTA:1488", 517 | "MBTA:1489" 518 | ], 519 | [ 520 | "MBTA:1489", 521 | "MBTA:1491" 522 | ], 523 | [ 524 | "MBTA:1491", 525 | "MBTA:64000" 526 | ], 527 | [ 528 | "MBTA:1565", 529 | "MBTA:383" 530 | ], 531 | [ 532 | "MBTA:383", 533 | "MBTA:384" 534 | ], 535 | [ 536 | "MBTA:384", 537 | "MBTA:385" 538 | ], 539 | [ 540 | "MBTA:385", 541 | "MBTA:1566" 542 | ], 543 | [ 544 | "MBTA:1566", 545 | "MBTA:15660" 546 | ], 547 | [ 548 | "MBTA:15660", 549 | "MBTA:1567" 550 | ], 551 | [ 552 | "MBTA:1567", 553 | "MBTA:15661" 554 | ], 555 | [ 556 | "MBTA:15661", 557 | "MBTA:1569" 558 | ], 559 | [ 560 | "MBTA:1569", 561 | "MBTA:1570" 562 | ], 563 | [ 564 | "MBTA:1570", 565 | "MBTA:1571" 566 | ], 567 | [ 568 | "MBTA:1571", 569 | "MBTA:1572" 570 | ], 571 | [ 572 | "MBTA:1572", 573 | "MBTA:1573" 574 | ], 575 | [ 576 | "MBTA:1573", 577 | "MBTA:1574" 578 | ], 579 | [ 580 | "MBTA:1574", 581 | "MBTA:1575" 582 | ], 583 | [ 584 | "MBTA:1575", 585 | "MBTA:1576" 586 | ], 587 | [ 588 | "MBTA:1576", 589 | "MBTA:1487" 590 | ], 591 | [ 592 | "MBTA:1487", 593 | "MBTA:1488" 594 | ], 595 | [ 596 | "MBTA:1488", 597 | "MBTA:1489" 598 | ], 599 | [ 600 | "MBTA:1489", 601 | "MBTA:1491" 602 | ], 603 | [ 604 | "MBTA:1491", 605 | "MBTA:64000" 606 | ], 607 | [ 608 | "MBTA:64000", 609 | "MBTA:1148" 610 | ], 611 | [ 612 | "MBTA:1148", 613 | "MBTA:11149" 614 | ], 615 | [ 616 | "MBTA:11149", 617 | "MBTA:11148" 618 | ], 619 | [ 620 | "MBTA:11148", 621 | "MBTA:21148" 622 | ], 623 | [ 624 | "MBTA:1737", 625 | "MBTA:381" 626 | ], 627 | [ 628 | "MBTA:381", 629 | "MBTA:382" 630 | ], 631 | [ 632 | "MBTA:382", 633 | "MBTA:383" 634 | ], 635 | [ 636 | "MBTA:383", 637 | "MBTA:384" 638 | ], 639 | [ 640 | "MBTA:384", 641 | "MBTA:385" 642 | ], 643 | [ 644 | "MBTA:385", 645 | "MBTA:1566" 646 | ], 647 | [ 648 | "MBTA:1566", 649 | "MBTA:15660" 650 | ], 651 | [ 652 | "MBTA:15660", 653 | "MBTA:1567" 654 | ], 655 | [ 656 | "MBTA:1567", 657 | "MBTA:15661" 658 | ], 659 | [ 660 | "MBTA:15661", 661 | "MBTA:1569" 662 | ], 663 | [ 664 | "MBTA:1569", 665 | "MBTA:1570" 666 | ], 667 | [ 668 | "MBTA:1570", 669 | "MBTA:1571" 670 | ], 671 | [ 672 | "MBTA:1571", 673 | "MBTA:1572" 674 | ], 675 | [ 676 | "MBTA:1572", 677 | "MBTA:1573" 678 | ], 679 | [ 680 | "MBTA:1573", 681 | "MBTA:1574" 682 | ], 683 | [ 684 | "MBTA:1574", 685 | "MBTA:1575" 686 | ], 687 | [ 688 | "MBTA:1575", 689 | "MBTA:1576" 690 | ], 691 | [ 692 | "MBTA:1576", 693 | "MBTA:1487" 694 | ], 695 | [ 696 | "MBTA:1487", 697 | "MBTA:1488" 698 | ], 699 | [ 700 | "MBTA:1488", 701 | "MBTA:1489" 702 | ], 703 | [ 704 | "MBTA:1489", 705 | "MBTA:1491" 706 | ], 707 | [ 708 | "MBTA:1491", 709 | "MBTA:64000" 710 | ], 711 | [ 712 | "MBTA:64000", 713 | "MBTA:1148" 714 | ], 715 | [ 716 | "MBTA:1148", 717 | "MBTA:11149" 718 | ], 719 | [ 720 | "MBTA:11149", 721 | "MBTA:11148" 722 | ], 723 | [ 724 | "MBTA:11148", 725 | "MBTA:21148" 726 | ], 727 | [ 728 | "MBTA:11257", 729 | "MBTA:1259" 730 | ], 731 | [ 732 | "MBTA:1259", 733 | "MBTA:11323" 734 | ], 735 | [ 736 | "MBTA:11323", 737 | "MBTA:11259" 738 | ], 739 | [ 740 | "MBTA:11259", 741 | "MBTA:64000" 742 | ], 743 | [ 744 | "MBTA:64000", 745 | "MBTA:1493" 746 | ], 747 | [ 748 | "MBTA:1493", 749 | "MBTA:1495" 750 | ], 751 | [ 752 | "MBTA:1495", 753 | "MBTA:1496" 754 | ], 755 | [ 756 | "MBTA:1496", 757 | "MBTA:1577" 758 | ], 759 | [ 760 | "MBTA:1577", 761 | "MBTA:1578" 762 | ], 763 | [ 764 | "MBTA:1578", 765 | "MBTA:1579" 766 | ], 767 | [ 768 | "MBTA:1579", 769 | "MBTA:1580" 770 | ], 771 | [ 772 | "MBTA:1580", 773 | "MBTA:1581" 774 | ], 775 | [ 776 | "MBTA:1581", 777 | "MBTA:1582" 778 | ], 779 | [ 780 | "MBTA:1582", 781 | "MBTA:15820" 782 | ], 783 | [ 784 | "MBTA:15820", 785 | "MBTA:1583" 786 | ], 787 | [ 788 | "MBTA:1583", 789 | "MBTA:1584" 790 | ], 791 | [ 792 | "MBTA:1584", 793 | "MBTA:1585" 794 | ], 795 | [ 796 | "MBTA:1585", 797 | "MBTA:1586" 798 | ], 799 | [ 800 | "MBTA:1586", 801 | "MBTA:413" 802 | ], 803 | [ 804 | "MBTA:413", 805 | "MBTA:414" 806 | ], 807 | [ 808 | "MBTA:414", 809 | "MBTA:415" 810 | ], 811 | [ 812 | "MBTA:415", 813 | "MBTA:416" 814 | ], 815 | [ 816 | "MBTA:416", 817 | "MBTA:417" 818 | ], 819 | [ 820 | "MBTA:417", 821 | "MBTA:419" 822 | ], 823 | [ 824 | "MBTA:11257", 825 | "MBTA:1259" 826 | ], 827 | [ 828 | "MBTA:1259", 829 | "MBTA:11323" 830 | ], 831 | [ 832 | "MBTA:11323", 833 | "MBTA:11259" 834 | ], 835 | [ 836 | "MBTA:11259", 837 | "MBTA:64000" 838 | ], 839 | [ 840 | "MBTA:64000", 841 | "MBTA:1493" 842 | ], 843 | [ 844 | "MBTA:1493", 845 | "MBTA:1495" 846 | ], 847 | [ 848 | "MBTA:1495", 849 | "MBTA:1496" 850 | ], 851 | [ 852 | "MBTA:1496", 853 | "MBTA:1577" 854 | ], 855 | [ 856 | "MBTA:1577", 857 | "MBTA:1578" 858 | ], 859 | [ 860 | "MBTA:1578", 861 | "MBTA:1579" 862 | ], 863 | [ 864 | "MBTA:1579", 865 | "MBTA:1580" 866 | ], 867 | [ 868 | "MBTA:1580", 869 | "MBTA:1581" 870 | ], 871 | [ 872 | "MBTA:1581", 873 | "MBTA:1582" 874 | ], 875 | [ 876 | "MBTA:1582", 877 | "MBTA:15820" 878 | ], 879 | [ 880 | "MBTA:15820", 881 | "MBTA:1583" 882 | ], 883 | [ 884 | "MBTA:1583", 885 | "MBTA:1584" 886 | ], 887 | [ 888 | "MBTA:1584", 889 | "MBTA:1585" 890 | ], 891 | [ 892 | "MBTA:1585", 893 | "MBTA:1586" 894 | ], 895 | [ 896 | "MBTA:1586", 897 | "MBTA:413" 898 | ], 899 | [ 900 | "MBTA:413", 901 | "MBTA:414" 902 | ], 903 | [ 904 | "MBTA:414", 905 | "MBTA:1587" 906 | ], 907 | [ 908 | "MBTA:1587", 909 | "MBTA:1565" 910 | ] 911 | ], 912 | "scale": 1.4, 913 | "comment": "45-Speed" 914 | }, 915 | { 916 | "type": "adjust-frequency", 917 | "route": "MBTA:701", 918 | "retainTripsOutsideFrequencyEntries": false, 919 | "entries": [ 920 | { 921 | "monday": true, 922 | "tuesday": true, 923 | "wednesday": true, 924 | "thursday": true, 925 | "friday": true, 926 | "saturday": false, 927 | "sunday": false, 928 | "name": "CT1-OB", 929 | "startTime": 25200, 930 | "endTime": 32400, 931 | "headwaySecs": 780, 932 | "firstDepartures": null, 933 | "sourceTrip": "MBTA:28269200" 934 | }, 935 | { 936 | "monday": true, 937 | "tuesday": true, 938 | "wednesday": true, 939 | "thursday": true, 940 | "friday": true, 941 | "saturday": false, 942 | "sunday": false, 943 | "name": "CT1-IB", 944 | "startTime": 25200, 945 | "endTime": 32400, 946 | "headwaySecs": 900, 947 | "firstDepartures": null, 948 | "sourceTrip": "MBTA:28273410" 949 | } 950 | ], 951 | "comment": "CT1-Frequency" 952 | }, 953 | { 954 | "type": "adjust-frequency", 955 | "route": "MBTA:64", 956 | "retainTripsOutsideFrequencyEntries": false, 957 | "entries": [ 958 | { 959 | "monday": true, 960 | "tuesday": true, 961 | "wednesday": true, 962 | "thursday": true, 963 | "friday": true, 964 | "saturday": false, 965 | "sunday": false, 966 | "name": "64-OB", 967 | "startTime": 25200, 968 | "endTime": 32400, 969 | "headwaySecs": 900, 970 | "firstDepartures": null, 971 | "sourceTrip": "MBTA:28759180" 972 | }, 973 | { 974 | "monday": true, 975 | "tuesday": true, 976 | "wednesday": true, 977 | "thursday": true, 978 | "friday": true, 979 | "saturday": false, 980 | "sunday": false, 981 | "name": "64-IB", 982 | "startTime": 25200, 983 | "endTime": 32400, 984 | "headwaySecs": 720, 985 | "firstDepartures": null, 986 | "sourceTrip": "MBTA:28766359" 987 | } 988 | ], 989 | "comment": "64-Frequency" 990 | } 991 | ] 992 | } -------------------------------------------------------------------------------- /public/routes/scenario/B.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 0, 3 | "description": "LS Scenario v1", 4 | "feedChecksums": { 5 | "MBTA": 993571431 6 | }, 7 | "modifications": [ 8 | { 9 | "type": "adjust-dwell-time", 10 | "routes": [ 11 | "MBTA:111" 12 | ], 13 | "stops": null, 14 | "scale": 0.6, 15 | "comment": "111-Dwell" 16 | }, 17 | { 18 | "type": "adjust-dwell-time", 19 | "routes": [ 20 | "MBTA:426" 21 | ], 22 | "stops": null, 23 | "scale": 0.6, 24 | "comment": "426-Dwell" 25 | }, 26 | { 27 | "type": "adjust-dwell-time", 28 | "routes": [ 29 | "MBTA:428" 30 | ], 31 | "stops": null, 32 | "scale": 0.6, 33 | "comment": "428-Dwell" 34 | }, 35 | { 36 | "type": "adjust-speed", 37 | "routes": [ 38 | "MBTA:111" 39 | ], 40 | "hops": [ 41 | [ 42 | "MBTA:2829", 43 | "MBTA:8310" 44 | ], 45 | [ 46 | "MBTA:2829", 47 | "MBTA:8310" 48 | ], 49 | [ 50 | "MBTA:8310", 51 | "MBTA:2832" 52 | ], 53 | [ 54 | "MBTA:2832", 55 | "MBTA:2833" 56 | ], 57 | [ 58 | "MBTA:2829", 59 | "MBTA:8310" 60 | ], 61 | [ 62 | "MBTA:2829", 63 | "MBTA:8310" 64 | ], 65 | [ 66 | "MBTA:8310", 67 | "MBTA:2832" 68 | ], 69 | [ 70 | "MBTA:2832", 71 | "MBTA:2833" 72 | ], 73 | [ 74 | "MBTA:8310", 75 | "MBTA:2832" 76 | ], 77 | [ 78 | "MBTA:2832", 79 | "MBTA:2833" 80 | ], 81 | [ 82 | "MBTA:2833", 83 | "MBTA:5611" 84 | ], 85 | [ 86 | "MBTA:2833", 87 | "MBTA:5611" 88 | ], 89 | [ 90 | "MBTA:2833", 91 | "MBTA:5611" 92 | ] 93 | ], 94 | "scale": 1.4, 95 | "comment": "111-Speed" 96 | }, 97 | { 98 | "type": "adjust-speed", 99 | "routes": [ 100 | "MBTA:426" 101 | ], 102 | "hops": [ 103 | [ 104 | "MBTA:2829", 105 | "MBTA:8310" 106 | ], 107 | [ 108 | "MBTA:2829", 109 | "MBTA:8310" 110 | ] 111 | ], 112 | "scale": 1.4, 113 | "comment": "426-Speed" 114 | }, 115 | { 116 | "type": "adjust-speed", 117 | "routes": [ 118 | "MBTA:428" 119 | ], 120 | "hops": [ 121 | [ 122 | "MBTA:2829", 123 | "MBTA:8310" 124 | ] 125 | ], 126 | "scale": 1.4, 127 | "comment": "428-Speed" 128 | }, 129 | { 130 | "type": "adjust-frequency", 131 | "route": "MBTA:1", 132 | "retainTripsOutsideFrequencyEntries": false, 133 | "entries": [ 134 | { 135 | "monday": true, 136 | "tuesday": true, 137 | "wednesday": true, 138 | "thursday": true, 139 | "friday": true, 140 | "saturday": false, 141 | "sunday": false, 142 | "name": "1-OB", 143 | "startTime": 25200, 144 | "endTime": 32400, 145 | "headwaySecs": 420, 146 | "firstDepartures": null, 147 | "sourceTrip": "MBTA:27501555" 148 | }, 149 | { 150 | "monday": true, 151 | "tuesday": true, 152 | "wednesday": true, 153 | "thursday": true, 154 | "friday": true, 155 | "saturday": false, 156 | "sunday": false, 157 | "name": "1-IB", 158 | "startTime": 25200, 159 | "endTime": 32400, 160 | "headwaySecs": 420, 161 | "firstDepartures": null, 162 | "sourceTrip": "MBTA:28258581" 163 | } 164 | ], 165 | "comment": "1-Frequency" 166 | }, 167 | { 168 | "type": "adjust-frequency", 169 | "route": "MBTA:111", 170 | "retainTripsOutsideFrequencyEntries": false, 171 | "entries": [ 172 | { 173 | "monday": true, 174 | "tuesday": true, 175 | "wednesday": true, 176 | "thursday": true, 177 | "friday": true, 178 | "saturday": false, 179 | "sunday": false, 180 | "name": "111-OB", 181 | "startTime": 25200, 182 | "endTime": 32400, 183 | "headwaySecs": 660, 184 | "firstDepartures": null, 185 | "sourceTrip": "MBTA:28655055" 186 | }, 187 | { 188 | "monday": true, 189 | "tuesday": true, 190 | "wednesday": true, 191 | "thursday": true, 192 | "friday": true, 193 | "saturday": false, 194 | "sunday": false, 195 | "name": "111OB2", 196 | "startTime": 25200, 197 | "endTime": 32400, 198 | "headwaySecs": 450, 199 | "firstDepartures": null, 200 | "sourceTrip": "MBTA:28894212" 201 | }, 202 | { 203 | "monday": true, 204 | "tuesday": true, 205 | "wednesday": true, 206 | "thursday": true, 207 | "friday": true, 208 | "saturday": false, 209 | "sunday": false, 210 | "name": "111-IB", 211 | "startTime": 25200, 212 | "endTime": 32400, 213 | "headwaySecs": 1080, 214 | "firstDepartures": null, 215 | "sourceTrip": "MBTA:28673770" 216 | }, 217 | { 218 | "monday": true, 219 | "tuesday": true, 220 | "wednesday": true, 221 | "thursday": true, 222 | "friday": true, 223 | "saturday": false, 224 | "sunday": false, 225 | "name": "111-IB2", 226 | "startTime": 25200, 227 | "endTime": 32400, 228 | "headwaySecs": 420, 229 | "firstDepartures": null, 230 | "sourceTrip": "MBTA:28899568" 231 | } 232 | ], 233 | "comment": "111-Frequency" 234 | }, 235 | { 236 | "type": "adjust-frequency", 237 | "route": "MBTA:426", 238 | "retainTripsOutsideFrequencyEntries": false, 239 | "entries": [ 240 | { 241 | "sourceTrip": "MBTA:28878779", 242 | "headwaySecs": 1800, 243 | "startTime": 25200, 244 | "endTime": 32400, 245 | "monday": true, 246 | "tuesday": true, 247 | "wednesday": true, 248 | "thursday": true, 249 | "friday": true, 250 | "saturday": false, 251 | "sunday": false 252 | }, 253 | { 254 | "sourceTrip": "MBTA:27936492", 255 | "headwaySecs": 1800, 256 | "startTime": 25200, 257 | "endTime": 32400, 258 | "monday": true, 259 | "tuesday": true, 260 | "wednesday": true, 261 | "thursday": true, 262 | "friday": true, 263 | "saturday": false, 264 | "sunday": false, 265 | "name": "426-Outbound" 266 | } 267 | ], 268 | "comment": "426-Frequency" 269 | }, 270 | { 271 | "type": "adjust-frequency", 272 | "route": "MBTA:428", 273 | "retainTripsOutsideFrequencyEntries": false, 274 | "entries": [ 275 | { 276 | "sourceTrip": "MBTA:27936455", 277 | "headwaySecs": 2700, 278 | "startTime": 25200, 279 | "endTime": 32400, 280 | "monday": true, 281 | "tuesday": true, 282 | "wednesday": true, 283 | "thursday": true, 284 | "friday": true, 285 | "saturday": false, 286 | "sunday": false, 287 | "name": "428-IB" 288 | } 289 | ], 290 | "comment": "428-Frequency" 291 | } 292 | ] 293 | } -------------------------------------------------------------------------------- /public/routes/scenario/C.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 0, 3 | "description": "LS Scenario v1", 4 | "feedChecksums": { 5 | "MBTA": 993571431 6 | }, 7 | "modifications": [ 8 | { 9 | "type": "adjust-dwell-time", 10 | "routes": [ 11 | "MBTA:39" 12 | ], 13 | "stops": null, 14 | "scale": 0.6, 15 | "comment": "39-Dwell" 16 | }, 17 | { 18 | "type": "adjust-speed", 19 | "routes": [ 20 | "MBTA:39" 21 | ], 22 | "hops": [ 23 | [ 24 | "MBTA:1363", 25 | "MBTA:1365" 26 | ], 27 | [ 28 | "MBTA:1365", 29 | "MBTA:21365" 30 | ], 31 | [ 32 | "MBTA:6575", 33 | "MBTA:1315" 34 | ], 35 | [ 36 | "MBTA:1315", 37 | "MBTA:1317" 38 | ], 39 | [ 40 | "MBTA:1363", 41 | "MBTA:1365" 42 | ], 43 | [ 44 | "MBTA:1365", 45 | "MBTA:21365" 46 | ], 47 | [ 48 | "MBTA:6575", 49 | "MBTA:1315" 50 | ], 51 | [ 52 | "MBTA:1315", 53 | "MBTA:1317" 54 | ], 55 | [ 56 | "MBTA:1363", 57 | "MBTA:1365" 58 | ], 59 | [ 60 | "MBTA:1365", 61 | "MBTA:21365" 62 | ], 63 | [ 64 | "MBTA:6575", 65 | "MBTA:1315" 66 | ], 67 | [ 68 | "MBTA:1315", 69 | "MBTA:1317" 70 | ] 71 | ], 72 | "scale": 1.4, 73 | "comment": "39-Speed" 74 | }, 75 | { 76 | "type": "adjust-dwell-time", 77 | "routes": [ 78 | "MBTA:66" 79 | ], 80 | "stops": null, 81 | "scale": 0.6, 82 | "comment": "66-Dwell" 83 | }, 84 | { 85 | "type": "adjust-speed", 86 | "routes": [ 87 | "MBTA:66" 88 | ], 89 | "hops": [ 90 | [ 91 | "MBTA:1363", 92 | "MBTA:1365" 93 | ], 94 | [ 95 | "MBTA:1365", 96 | "MBTA:1366" 97 | ], 98 | [ 99 | "MBTA:1314", 100 | "MBTA:1315" 101 | ], 102 | [ 103 | "MBTA:1315", 104 | "MBTA:1317" 105 | ], 106 | [ 107 | "MBTA:1363", 108 | "MBTA:1365" 109 | ], 110 | [ 111 | "MBTA:1365", 112 | "MBTA:1366" 113 | ], 114 | [ 115 | "MBTA:1314", 116 | "MBTA:1315" 117 | ], 118 | [ 119 | "MBTA:1315", 120 | "MBTA:1317" 121 | ], 122 | [ 123 | "MBTA:1363", 124 | "MBTA:1365" 125 | ], 126 | [ 127 | "MBTA:1365", 128 | "MBTA:1366" 129 | ], 130 | [ 131 | "MBTA:1314", 132 | "MBTA:1315" 133 | ], 134 | [ 135 | "MBTA:1315", 136 | "MBTA:1317" 137 | ], 138 | [ 139 | "MBTA:1362", 140 | "MBTA:1363" 141 | ], 142 | [ 143 | "MBTA:1363", 144 | "MBTA:1365" 145 | ], 146 | [ 147 | "MBTA:1365", 148 | "MBTA:1366" 149 | ], 150 | [ 151 | "MBTA:1314", 152 | "MBTA:1315" 153 | ], 154 | [ 155 | "MBTA:1315", 156 | "MBTA:1317" 157 | ], 158 | [ 159 | "MBTA:1317", 160 | "MBTA:1319" 161 | ], 162 | [ 163 | "MBTA:1362", 164 | "MBTA:1363" 165 | ], 166 | [ 167 | "MBTA:1363", 168 | "MBTA:1365" 169 | ], 170 | [ 171 | "MBTA:1365", 172 | "MBTA:1366" 173 | ], 174 | [ 175 | "MBTA:1314", 176 | "MBTA:1315" 177 | ], 178 | [ 179 | "MBTA:1315", 180 | "MBTA:1317" 181 | ], 182 | [ 183 | "MBTA:1317", 184 | "MBTA:1319" 185 | ], 186 | [ 187 | "MBTA:1362", 188 | "MBTA:1363" 189 | ], 190 | [ 191 | "MBTA:1363", 192 | "MBTA:1365" 193 | ], 194 | [ 195 | "MBTA:1365", 196 | "MBTA:1366" 197 | ], 198 | [ 199 | "MBTA:1314", 200 | "MBTA:1315" 201 | ], 202 | [ 203 | "MBTA:1315", 204 | "MBTA:1317" 205 | ], 206 | [ 207 | "MBTA:1317", 208 | "MBTA:1319" 209 | ] 210 | ], 211 | "scale": 1.4, 212 | "comment": "66-Speed" 213 | }, 214 | { 215 | "type": "adjust-speed", 216 | "routes": [ 217 | "MBTA:45" 218 | ], 219 | "hops": [ 220 | [ 221 | "MBTA:11257", 222 | "MBTA:1259" 223 | ], 224 | [ 225 | "MBTA:1259", 226 | "MBTA:11323" 227 | ], 228 | [ 229 | "MBTA:11323", 230 | "MBTA:1149" 231 | ], 232 | [ 233 | "MBTA:1149", 234 | "MBTA:1146" 235 | ], 236 | [ 237 | "MBTA:1146", 238 | "MBTA:1147" 239 | ], 240 | [ 241 | "MBTA:1147", 242 | "MBTA:64000" 243 | ], 244 | [ 245 | "MBTA:64000", 246 | "MBTA:1493" 247 | ], 248 | [ 249 | "MBTA:1493", 250 | "MBTA:1495" 251 | ], 252 | [ 253 | "MBTA:1495", 254 | "MBTA:1496" 255 | ], 256 | [ 257 | "MBTA:1496", 258 | "MBTA:1577" 259 | ], 260 | [ 261 | "MBTA:1577", 262 | "MBTA:1578" 263 | ], 264 | [ 265 | "MBTA:1578", 266 | "MBTA:1579" 267 | ], 268 | [ 269 | "MBTA:1579", 270 | "MBTA:1580" 271 | ], 272 | [ 273 | "MBTA:1580", 274 | "MBTA:1581" 275 | ], 276 | [ 277 | "MBTA:1581", 278 | "MBTA:1582" 279 | ], 280 | [ 281 | "MBTA:1582", 282 | "MBTA:15820" 283 | ], 284 | [ 285 | "MBTA:15820", 286 | "MBTA:1583" 287 | ], 288 | [ 289 | "MBTA:1583", 290 | "MBTA:1584" 291 | ], 292 | [ 293 | "MBTA:1584", 294 | "MBTA:1585" 295 | ], 296 | [ 297 | "MBTA:1585", 298 | "MBTA:1586" 299 | ], 300 | [ 301 | "MBTA:1586", 302 | "MBTA:413" 303 | ], 304 | [ 305 | "MBTA:413", 306 | "MBTA:414" 307 | ], 308 | [ 309 | "MBTA:414", 310 | "MBTA:1587" 311 | ], 312 | [ 313 | "MBTA:1587", 314 | "MBTA:1565" 315 | ], 316 | [ 317 | "MBTA:1565", 318 | "MBTA:383" 319 | ], 320 | [ 321 | "MBTA:383", 322 | "MBTA:384" 323 | ], 324 | [ 325 | "MBTA:384", 326 | "MBTA:385" 327 | ], 328 | [ 329 | "MBTA:385", 330 | "MBTA:1566" 331 | ], 332 | [ 333 | "MBTA:1566", 334 | "MBTA:15660" 335 | ], 336 | [ 337 | "MBTA:15660", 338 | "MBTA:1567" 339 | ], 340 | [ 341 | "MBTA:1567", 342 | "MBTA:15661" 343 | ], 344 | [ 345 | "MBTA:15661", 346 | "MBTA:1569" 347 | ], 348 | [ 349 | "MBTA:1569", 350 | "MBTA:1570" 351 | ], 352 | [ 353 | "MBTA:1570", 354 | "MBTA:1571" 355 | ], 356 | [ 357 | "MBTA:1571", 358 | "MBTA:1572" 359 | ], 360 | [ 361 | "MBTA:1572", 362 | "MBTA:1573" 363 | ], 364 | [ 365 | "MBTA:1573", 366 | "MBTA:1574" 367 | ], 368 | [ 369 | "MBTA:1574", 370 | "MBTA:1575" 371 | ], 372 | [ 373 | "MBTA:1575", 374 | "MBTA:1576" 375 | ], 376 | [ 377 | "MBTA:1576", 378 | "MBTA:1487" 379 | ], 380 | [ 381 | "MBTA:1487", 382 | "MBTA:1488" 383 | ], 384 | [ 385 | "MBTA:1488", 386 | "MBTA:1489" 387 | ], 388 | [ 389 | "MBTA:1489", 390 | "MBTA:1491" 391 | ], 392 | [ 393 | "MBTA:1491", 394 | "MBTA:64000" 395 | ], 396 | [ 397 | "MBTA:1565", 398 | "MBTA:383" 399 | ], 400 | [ 401 | "MBTA:383", 402 | "MBTA:384" 403 | ], 404 | [ 405 | "MBTA:384", 406 | "MBTA:385" 407 | ], 408 | [ 409 | "MBTA:385", 410 | "MBTA:1566" 411 | ], 412 | [ 413 | "MBTA:1566", 414 | "MBTA:15660" 415 | ], 416 | [ 417 | "MBTA:15660", 418 | "MBTA:1567" 419 | ], 420 | [ 421 | "MBTA:1567", 422 | "MBTA:15661" 423 | ], 424 | [ 425 | "MBTA:15661", 426 | "MBTA:1569" 427 | ], 428 | [ 429 | "MBTA:1569", 430 | "MBTA:1570" 431 | ], 432 | [ 433 | "MBTA:1570", 434 | "MBTA:1571" 435 | ], 436 | [ 437 | "MBTA:1571", 438 | "MBTA:1572" 439 | ], 440 | [ 441 | "MBTA:1572", 442 | "MBTA:1573" 443 | ], 444 | [ 445 | "MBTA:1573", 446 | "MBTA:1574" 447 | ], 448 | [ 449 | "MBTA:1574", 450 | "MBTA:1575" 451 | ], 452 | [ 453 | "MBTA:1575", 454 | "MBTA:1576" 455 | ], 456 | [ 457 | "MBTA:1576", 458 | "MBTA:1487" 459 | ], 460 | [ 461 | "MBTA:1487", 462 | "MBTA:1488" 463 | ], 464 | [ 465 | "MBTA:1488", 466 | "MBTA:1489" 467 | ], 468 | [ 469 | "MBTA:1489", 470 | "MBTA:1491" 471 | ], 472 | [ 473 | "MBTA:1491", 474 | "MBTA:64000" 475 | ], 476 | [ 477 | "MBTA:64000", 478 | "MBTA:1148" 479 | ], 480 | [ 481 | "MBTA:1148", 482 | "MBTA:11149" 483 | ], 484 | [ 485 | "MBTA:11149", 486 | "MBTA:11148" 487 | ], 488 | [ 489 | "MBTA:11148", 490 | "MBTA:21148" 491 | ], 492 | [ 493 | "MBTA:1737", 494 | "MBTA:381" 495 | ], 496 | [ 497 | "MBTA:381", 498 | "MBTA:382" 499 | ], 500 | [ 501 | "MBTA:382", 502 | "MBTA:383" 503 | ], 504 | [ 505 | "MBTA:383", 506 | "MBTA:384" 507 | ], 508 | [ 509 | "MBTA:384", 510 | "MBTA:385" 511 | ], 512 | [ 513 | "MBTA:385", 514 | "MBTA:1566" 515 | ], 516 | [ 517 | "MBTA:1566", 518 | "MBTA:15660" 519 | ], 520 | [ 521 | "MBTA:15660", 522 | "MBTA:1567" 523 | ], 524 | [ 525 | "MBTA:1567", 526 | "MBTA:15661" 527 | ], 528 | [ 529 | "MBTA:15661", 530 | "MBTA:1569" 531 | ], 532 | [ 533 | "MBTA:1569", 534 | "MBTA:1570" 535 | ], 536 | [ 537 | "MBTA:1570", 538 | "MBTA:1571" 539 | ], 540 | [ 541 | "MBTA:1571", 542 | "MBTA:1572" 543 | ], 544 | [ 545 | "MBTA:1572", 546 | "MBTA:1573" 547 | ], 548 | [ 549 | "MBTA:1573", 550 | "MBTA:1574" 551 | ], 552 | [ 553 | "MBTA:1574", 554 | "MBTA:1575" 555 | ], 556 | [ 557 | "MBTA:1575", 558 | "MBTA:1576" 559 | ], 560 | [ 561 | "MBTA:1576", 562 | "MBTA:1487" 563 | ], 564 | [ 565 | "MBTA:1487", 566 | "MBTA:1488" 567 | ], 568 | [ 569 | "MBTA:1488", 570 | "MBTA:1489" 571 | ], 572 | [ 573 | "MBTA:1489", 574 | "MBTA:1491" 575 | ], 576 | [ 577 | "MBTA:1491", 578 | "MBTA:64000" 579 | ], 580 | [ 581 | "MBTA:64000", 582 | "MBTA:1148" 583 | ], 584 | [ 585 | "MBTA:1148", 586 | "MBTA:11149" 587 | ], 588 | [ 589 | "MBTA:11149", 590 | "MBTA:11148" 591 | ], 592 | [ 593 | "MBTA:11148", 594 | "MBTA:21148" 595 | ], 596 | [ 597 | "MBTA:11257", 598 | "MBTA:1259" 599 | ], 600 | [ 601 | "MBTA:1259", 602 | "MBTA:11323" 603 | ], 604 | [ 605 | "MBTA:11323", 606 | "MBTA:11259" 607 | ], 608 | [ 609 | "MBTA:11259", 610 | "MBTA:64000" 611 | ], 612 | [ 613 | "MBTA:64000", 614 | "MBTA:1493" 615 | ], 616 | [ 617 | "MBTA:1493", 618 | "MBTA:1495" 619 | ], 620 | [ 621 | "MBTA:1495", 622 | "MBTA:1496" 623 | ], 624 | [ 625 | "MBTA:1496", 626 | "MBTA:1577" 627 | ], 628 | [ 629 | "MBTA:1577", 630 | "MBTA:1578" 631 | ], 632 | [ 633 | "MBTA:1578", 634 | "MBTA:1579" 635 | ], 636 | [ 637 | "MBTA:1579", 638 | "MBTA:1580" 639 | ], 640 | [ 641 | "MBTA:1580", 642 | "MBTA:1581" 643 | ], 644 | [ 645 | "MBTA:1581", 646 | "MBTA:1582" 647 | ], 648 | [ 649 | "MBTA:1582", 650 | "MBTA:15820" 651 | ], 652 | [ 653 | "MBTA:15820", 654 | "MBTA:1583" 655 | ], 656 | [ 657 | "MBTA:1583", 658 | "MBTA:1584" 659 | ], 660 | [ 661 | "MBTA:1584", 662 | "MBTA:1585" 663 | ], 664 | [ 665 | "MBTA:1585", 666 | "MBTA:1586" 667 | ], 668 | [ 669 | "MBTA:1586", 670 | "MBTA:413" 671 | ], 672 | [ 673 | "MBTA:413", 674 | "MBTA:414" 675 | ], 676 | [ 677 | "MBTA:414", 678 | "MBTA:415" 679 | ], 680 | [ 681 | "MBTA:415", 682 | "MBTA:416" 683 | ], 684 | [ 685 | "MBTA:416", 686 | "MBTA:417" 687 | ], 688 | [ 689 | "MBTA:417", 690 | "MBTA:419" 691 | ], 692 | [ 693 | "MBTA:11257", 694 | "MBTA:1259" 695 | ], 696 | [ 697 | "MBTA:1259", 698 | "MBTA:11323" 699 | ], 700 | [ 701 | "MBTA:11323", 702 | "MBTA:11259" 703 | ], 704 | [ 705 | "MBTA:11259", 706 | "MBTA:64000" 707 | ], 708 | [ 709 | "MBTA:64000", 710 | "MBTA:1493" 711 | ], 712 | [ 713 | "MBTA:1493", 714 | "MBTA:1495" 715 | ], 716 | [ 717 | "MBTA:1495", 718 | "MBTA:1496" 719 | ], 720 | [ 721 | "MBTA:1496", 722 | "MBTA:1577" 723 | ], 724 | [ 725 | "MBTA:1577", 726 | "MBTA:1578" 727 | ], 728 | [ 729 | "MBTA:1578", 730 | "MBTA:1579" 731 | ], 732 | [ 733 | "MBTA:1579", 734 | "MBTA:1580" 735 | ], 736 | [ 737 | "MBTA:1580", 738 | "MBTA:1581" 739 | ], 740 | [ 741 | "MBTA:1581", 742 | "MBTA:1582" 743 | ], 744 | [ 745 | "MBTA:1582", 746 | "MBTA:15820" 747 | ], 748 | [ 749 | "MBTA:15820", 750 | "MBTA:1583" 751 | ], 752 | [ 753 | "MBTA:1583", 754 | "MBTA:1584" 755 | ], 756 | [ 757 | "MBTA:1584", 758 | "MBTA:1585" 759 | ], 760 | [ 761 | "MBTA:1585", 762 | "MBTA:1586" 763 | ], 764 | [ 765 | "MBTA:1586", 766 | "MBTA:413" 767 | ], 768 | [ 769 | "MBTA:413", 770 | "MBTA:414" 771 | ], 772 | [ 773 | "MBTA:414", 774 | "MBTA:1587" 775 | ], 776 | [ 777 | "MBTA:1587", 778 | "MBTA:1565" 779 | ] 780 | ], 781 | "scale": 1.4, 782 | "comment": "45-Speed" 783 | }, 784 | { 785 | "type": "adjust-frequency", 786 | "route": "MBTA:39", 787 | "retainTripsOutsideFrequencyEntries": false, 788 | "entries": [ 789 | { 790 | "monday": true, 791 | "tuesday": true, 792 | "wednesday": true, 793 | "thursday": true, 794 | "friday": true, 795 | "saturday": false, 796 | "sunday": false, 797 | "name": "39-IB", 798 | "startTime": 25200, 799 | "endTime": 32400, 800 | "headwaySecs": 270, 801 | "firstDepartures": null, 802 | "sourceTrip": "MBTA:27641754" 803 | }, 804 | { 805 | "monday": true, 806 | "tuesday": true, 807 | "wednesday": true, 808 | "thursday": true, 809 | "friday": true, 810 | "saturday": false, 811 | "sunday": false, 812 | "name": "39-OB", 813 | "startTime": 25200, 814 | "endTime": 32400, 815 | "headwaySecs": 270, 816 | "firstDepartures": null, 817 | "sourceTrip": "MBTA:28695800" 818 | } 819 | ], 820 | "comment": "39-Frequency" 821 | }, 822 | { 823 | "type": "adjust-frequency", 824 | "route": "MBTA:66", 825 | "retainTripsOutsideFrequencyEntries": false, 826 | "entries": [ 827 | { 828 | "monday": true, 829 | "tuesday": true, 830 | "wednesday": true, 831 | "thursday": true, 832 | "friday": true, 833 | "saturday": false, 834 | "sunday": false, 835 | "name": "66-IB", 836 | "startTime": 25200, 837 | "endTime": 32400, 838 | "headwaySecs": 420, 839 | "firstDepartures": null, 840 | "sourceTrip": "MBTA:27494992" 841 | }, 842 | { 843 | "monday": true, 844 | "tuesday": true, 845 | "wednesday": true, 846 | "thursday": true, 847 | "friday": true, 848 | "saturday": false, 849 | "sunday": false, 850 | "name": "66-OB", 851 | "startTime": 25200, 852 | "endTime": 79200, 853 | "headwaySecs": 390, 854 | "firstDepartures": null, 855 | "sourceTrip": "MBTA:27489228" 856 | } 857 | ], 858 | "comment": "66-Frequency" 859 | } 860 | ] 861 | } -------------------------------------------------------------------------------- /public/routes/scenario/corridors.json: -------------------------------------------------------------------------------- 1 | {"A" : { "sel" : 0, "all" : {}, "color": "#555555", 2 | "buslines":["1", "CT1", "64"], 3 | "corName": "Mass Ave", 4 | "segmentData":{"length":2.6}, 5 | "routeData": { 6 | "1":{ 7 | "baseHeadway":9, 8 | "totalTime":91, 9 | "segmentTime":42, 10 | "segmentDist":2.6, 11 | "stops":54 12 | }, 13 | "CT1":{ 14 | "baseHeadway":20, 15 | "totalTime":56, 16 | "segmentTime":44, 17 | "segmentDist":2.6, 18 | "stops":25 19 | }, 20 | "64":{ 21 | "baseHeadway":17, 22 | "totalTime":91, 23 | "segmentTime":1, 24 | "segmentDist":0.02, 25 | "stops":68 26 | } 27 | } 28 | }, 29 | "B" : { "sel" : null, "all" : {}, "color": "#7DD5ED", 30 | "buslines":["111", "426", "428"], 31 | "corName":"N. Washington St", 32 | "segmentData":{"length":0.6}, 33 | "routeData": { 34 | "111":{ 35 | "baseHeadway":5, 36 | "totalTime":70, 37 | "segmentTime":10, 38 | "segmentDist":0.6, 39 | "stops":37 40 | }, 41 | "426":{ 42 | "baseHeadway":40, 43 | "totalTime":113, 44 | "segmentTime":10, 45 | "segmentDist":0.6, 46 | "stops":108 47 | }, 48 | "428":{ 49 | "baseHeadway":60, 50 | "totalTime":137, 51 | "segmentTime":10, 52 | "segmentDist":0.6, 53 | "stops":100 54 | } 55 | } 56 | }, 57 | "C" : { "sel" : null, "all" : {}, "color": "#F3E05E", 58 | "buslines":["39", "66"], 59 | "corName":"Huntington Ave", 60 | "segmentData":{"length":0.4}, 61 | "routeData": { 62 | "66":{ 63 | "baseHeadway":9, 64 | "totalTime":113, 65 | "segmentTime":10, 66 | "segmentDist":0.4, 67 | "stops":70 68 | }, 69 | "39":{ 70 | "baseHeadway":6, 71 | "totalTime":97, 72 | "segmentTime":8, 73 | "segmentDist":0.4, 74 | "stops":54 75 | } 76 | } 77 | }, 78 | "D" : { "sel" : null, "all" : {}, "color": "#E092DF" , 79 | "buslines":["30", "34", "35", "36", "37", "40", "50", "51"], 80 | "corName":"Roslindale/Forest Hills", 81 | "segmentData":{"length":1.2}, 82 | "routeData": { 83 | "30":{ 84 | "baseHeadway":20, 85 | "totalTime":44, 86 | "segmentTime":12, 87 | "segmentDist":1.2, 88 | "stops":55 89 | }, 90 | "34":{ 91 | "baseHeadway":20, 92 | "totalTime":49, 93 | "segmentTime":12, 94 | "segmentDist":1.2, 95 | "stops":59 96 | }, 97 | "35":{ 98 | "baseHeadway":20, 99 | "totalTime":53, 100 | "segmentTime":14, 101 | "segmentDist":1.2, 102 | "stops":77 103 | }, 104 | "36":{ 105 | "baseHeadway":24, 106 | "totalTime":49, 107 | "segmentTime":16, 108 | "segmentDist":1.2, 109 | "stops":63 110 | }, 111 | "37":{ 112 | "baseHeadway":40, 113 | "totalTime":49, 114 | "segmentTime":14, 115 | "segmentDist":1.2, 116 | "stops":66 117 | }, 118 | "40":{ 119 | "baseHeadway":24, 120 | "totalTime":58, 121 | "segmentTime":12, 122 | "segmentDist":1.2, 123 | "stops":58 124 | }, 125 | "50":{ 126 | "baseHeadway":24, 127 | "totalTime":53, 128 | "segmentTime":18, 129 | "segmentDist":1.2, 130 | "stops":63 131 | }, 132 | "51":{ 133 | "baseHeadway":20, 134 | "totalTime":71, 135 | "segmentTime":12, 136 | "segmentDist":1.2, 137 | "stops":98 138 | } 139 | } 140 | }, 141 | "E" : { "sel" : 0 , "all" : {}, "color": "#8D6AA8", 142 | "buslines":["14", "19", "22", "23", "28", "29", "44", "45"], "corName":"Blue Hill Ave", 143 | "segmentData":{"length": 2.4}, 144 | "routeData": { 145 | "14":{ 146 | "baseHeadway":40, 147 | "totalTime":107, 148 | "segmentTime":36, 149 | "segmentDist":2.2, 150 | "stops":100 151 | }, 152 | "19":{ 153 | "baseHeadway":17, 154 | "totalTime":100, 155 | "segmentTime":18, 156 | "segmentDist":1.6, 157 | "stops":84 158 | }, 159 | "22":{ 160 | "baseHeadway":7, 161 | "totalTime":88, 162 | "segmentTime":12, 163 | "segmentDist":0.73, 164 | "stops":60 165 | }, 166 | "23":{ 167 | "baseHeadway":5, 168 | "totalTime":76, 169 | "segmentTime":20, 170 | "segmentDist":1.6, 171 | "stops":61 172 | }, 173 | "28":{ 174 | "baseHeadway":7, 175 | "totalTime":84, 176 | "segmentTime":34, 177 | "segmentDist":2.4, 178 | "stops":73 179 | }, 180 | "29":{ 181 | "baseHeadway":20, 182 | "totalTime":76, 183 | "segmentTime":8, 184 | "segmentDist":0.85, 185 | "stops":59 186 | }, 187 | "44":{ 188 | "baseHeadway":13, 189 | "totalTime":53, 190 | "segmentTime":6, 191 | "segmentDist":0.3, 192 | "stops":57 193 | }, 194 | "45":{ 195 | "baseHeadway":10, 196 | "totalTime":58, 197 | "segmentTime":6, 198 | "segmentDist":1.0, 199 | "stops":51 200 | } 201 | } 202 | } 203 | } -------------------------------------------------------------------------------- /public/routes/shapefiles/mapApp/homelocation.json: -------------------------------------------------------------------------------- 1 | { 2 | PD:{homeLoc:[42.3752666,-71.112716],workLoc:[42.3601382,-71.0948792]}, 3 | AS:{homeLoc:[42.376542,-71.0994836],workLoc:[42.3601382,-71.0948792]}, 4 | } -------------------------------------------------------------------------------- /public/routes/shapefiles/mapApp/trunks.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, 4 | "features": [ 5 | { "type": "Feature", "properties": { "id": null, "corridorId": "A" }, "geometry": { "type": "LineString", "coordinates": [ [ -71.103970295823103, 42.365567420822636 ], [ -71.102060307453897, 42.36439387330919 ], [ -71.099460042586344, 42.362913290530813 ], [ -71.096169501220473, 42.360942427214539 ], [ -71.094835860218808, 42.360179815272616 ], [ -71.09426621456484, 42.359783649571874 ], [ -71.093649656915829, 42.359149779255333 ], [ -71.093281062669149, 42.358605041843354 ], [ -71.092483558753571, 42.356985658197381 ], [ -71.08765162326516, 42.347095122171481 ], [ -71.08582875717245, 42.34339010411616 ], [ -71.081432433066496, 42.340457635570075 ], [ -71.075695766245303, 42.335484014761768 ] ] } }, 6 | { "type": "Feature", "properties": { "id": null, "corridorId": "B" }, "geometry": { "type": "LineString", "coordinates": [ [ -71.064812183397635, 42.372326033573955 ], [ -71.061923744846311, 42.371004076421293 ], [ -71.061434519755238, 42.370726808469968 ], [ -71.061025715227103, 42.370395075562868 ], [ -71.059571443381074, 42.368424446954606 ], [ -71.058566186344663, 42.366963765252763 ], [ -71.058391941791683, 42.365295080526053 ] ] } }, 7 | { "type": "Feature", "properties": { "id": null, "corridorId": "C" }, "geometry": { "type": "LineString", "coordinates": [ [ -71.112086070963855, 42.331926941101713 ], [ -71.110906569374464, 42.332719621176203 ], [ -71.110062153463858, 42.33313577421611 ], [ -71.109231140980413, 42.33326458293233 ], [ -71.107810377702279, 42.333274491284186 ], [ -71.106604069258566, 42.333284399634493 ], [ -71.106215369871151, 42.333403299716302 ], [ -71.104821413447311, 42.334116695486827 ] ] } }, 8 | { "type": "Feature", "properties": { "id": null, "corridorId": "D" }, "geometry": { "type": "LineString", "coordinates": [ [ -71.11453889813275, 42.301014539552902 ], [ -71.114646125549967, 42.300518866013405 ], [ -71.114873983811549, 42.299914139011101 ], [ -71.11558436545063, 42.298694753787096 ], [ -71.11628134366255, 42.297633968573642 ], [ -71.118586733132744, 42.295413201480294 ], [ -71.121133384291696, 42.29300397719031 ], [ -71.127634046460571, 42.286955724152605 ] ] } }, 9 | { "type": "Feature", "properties": { "id": null, "corridorId": "E" }, "geometry": { "type": "LineString", "coordinates": [ [ -71.087852674672476, 42.294967055787232 ], [ -71.0857081263281, 42.301827435710607 ], [ -71.084689465864514, 42.304603099586124 ], [ -71.084421397321492, 42.306664942107339 ], [ -71.082973827189022, 42.308726717100605 ], [ -71.082759372354602, 42.309598986192405 ], [ -71.083295509440688, 42.31070912937318 ], [ -71.082920213480421, 42.312057134056118 ], [ -71.083724419109558, 42.31360333917165 ], [ -71.083456350566522, 42.315228795899962 ], [ -71.082223235268501, 42.318043511912975 ], [ -71.081365415930748, 42.319668853959882 ], [ -71.082973827189036, 42.324306794327548 ], [ -71.083456350566522, 42.326011250600928 ], [ -71.083134668314855, 42.32827057494746 ] ] } } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /public/scripts/filesaver.js: -------------------------------------------------------------------------------- 1 | /* FileSaver.js 2 | * A saveAs() FileSaver implementation. 3 | * 1.1.20150716 4 | * 5 | * By Eli Grey, http://eligrey.com 6 | * License: X11/MIT 7 | * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md 8 | */ 9 | 10 | /*global self */ 11 | /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ 12 | 13 | /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ 14 | 15 | var saveAs = saveAs || (function(view) { 16 | "use strict"; 17 | // IE <10 is explicitly unsupported 18 | if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) { 19 | return; 20 | } 21 | var 22 | doc = view.document 23 | // only get URL when necessary in case Blob.js hasn't overridden it yet 24 | , get_URL = function() { 25 | return view.URL || view.webkitURL || view; 26 | } 27 | , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") 28 | , can_use_save_link = "download" in save_link 29 | , click = function(node) { 30 | var event = new MouseEvent("click"); 31 | node.dispatchEvent(event); 32 | } 33 | , webkit_req_fs = view.webkitRequestFileSystem 34 | , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem 35 | , throw_outside = function(ex) { 36 | (view.setImmediate || view.setTimeout)(function() { 37 | throw ex; 38 | }, 0); 39 | } 40 | , force_saveable_type = "application/octet-stream" 41 | , fs_min_size = 0 42 | // See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and 43 | // https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047 44 | // for the reasoning behind the timeout and revocation flow 45 | , arbitrary_revoke_timeout = 500 // in ms 46 | , revoke = function(file) { 47 | var revoker = function() { 48 | if (typeof file === "string") { // file is an object URL 49 | get_URL().revokeObjectURL(file); 50 | } else { // file is a File 51 | file.remove(); 52 | } 53 | }; 54 | if (view.chrome) { 55 | revoker(); 56 | } else { 57 | setTimeout(revoker, arbitrary_revoke_timeout); 58 | } 59 | } 60 | , dispatch = function(filesaver, event_types, event) { 61 | event_types = [].concat(event_types); 62 | var i = event_types.length; 63 | while (i--) { 64 | var listener = filesaver["on" + event_types[i]]; 65 | if (typeof listener === "function") { 66 | try { 67 | listener.call(filesaver, event || filesaver); 68 | } catch (ex) { 69 | throw_outside(ex); 70 | } 71 | } 72 | } 73 | } 74 | , auto_bom = function(blob) { 75 | // prepend BOM for UTF-8 XML and text/* types (including HTML) 76 | if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { 77 | return new Blob(["\ufeff", blob], {type: blob.type}); 78 | } 79 | return blob; 80 | } 81 | , FileSaver = function(blob, name, no_auto_bom) { 82 | if (!no_auto_bom) { 83 | blob = auto_bom(blob); 84 | } 85 | // First try a.download, then web filesystem, then object URLs 86 | var 87 | filesaver = this 88 | , type = blob.type 89 | , blob_changed = false 90 | , object_url 91 | , target_view 92 | , dispatch_all = function() { 93 | dispatch(filesaver, "writestart progress write writeend".split(" ")); 94 | } 95 | // on any filesys errors revert to saving with object URLs 96 | , fs_error = function() { 97 | // don't create more object URLs than needed 98 | if (blob_changed || !object_url) { 99 | object_url = get_URL().createObjectURL(blob); 100 | } 101 | if (target_view) { 102 | target_view.location.href = object_url; 103 | } else { 104 | var new_tab = view.open(object_url, "_blank"); 105 | if (new_tab == undefined && typeof safari !== "undefined") { 106 | //Apple do not allow window.open, see http://bit.ly/1kZffRI 107 | view.location.href = object_url 108 | } 109 | } 110 | filesaver.readyState = filesaver.DONE; 111 | dispatch_all(); 112 | revoke(object_url); 113 | } 114 | , abortable = function(func) { 115 | return function() { 116 | if (filesaver.readyState !== filesaver.DONE) { 117 | return func.apply(this, arguments); 118 | } 119 | }; 120 | } 121 | , create_if_not_found = {create: true, exclusive: false} 122 | , slice 123 | ; 124 | filesaver.readyState = filesaver.INIT; 125 | if (!name) { 126 | name = "download"; 127 | } 128 | if (can_use_save_link) { 129 | object_url = get_URL().createObjectURL(blob); 130 | save_link.href = object_url; 131 | save_link.download = name; 132 | setTimeout(function() { 133 | click(save_link); 134 | dispatch_all(); 135 | revoke(object_url); 136 | filesaver.readyState = filesaver.DONE; 137 | }); 138 | return; 139 | } 140 | // Object and web filesystem URLs have a problem saving in Google Chrome when 141 | // viewed in a tab, so I force save with application/octet-stream 142 | // http://code.google.com/p/chromium/issues/detail?id=91158 143 | // Update: Google errantly closed 91158, I submitted it again: 144 | // https://code.google.com/p/chromium/issues/detail?id=389642 145 | if (view.chrome && type && type !== force_saveable_type) { 146 | slice = blob.slice || blob.webkitSlice; 147 | blob = slice.call(blob, 0, blob.size, force_saveable_type); 148 | blob_changed = true; 149 | } 150 | // Since I can't be sure that the guessed media type will trigger a download 151 | // in WebKit, I append .download to the filename. 152 | // https://bugs.webkit.org/show_bug.cgi?id=65440 153 | if (webkit_req_fs && name !== "download") { 154 | name += ".download"; 155 | } 156 | if (type === force_saveable_type || webkit_req_fs) { 157 | target_view = view; 158 | } 159 | if (!req_fs) { 160 | fs_error(); 161 | return; 162 | } 163 | fs_min_size += blob.size; 164 | req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { 165 | fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { 166 | var save = function() { 167 | dir.getFile(name, create_if_not_found, abortable(function(file) { 168 | file.createWriter(abortable(function(writer) { 169 | writer.onwriteend = function(event) { 170 | target_view.location.href = file.toURL(); 171 | filesaver.readyState = filesaver.DONE; 172 | dispatch(filesaver, "writeend", event); 173 | revoke(file); 174 | }; 175 | writer.onerror = function() { 176 | var error = writer.error; 177 | if (error.code !== error.ABORT_ERR) { 178 | fs_error(); 179 | } 180 | }; 181 | "writestart progress write abort".split(" ").forEach(function(event) { 182 | writer["on" + event] = filesaver["on" + event]; 183 | }); 184 | writer.write(blob); 185 | filesaver.abort = function() { 186 | writer.abort(); 187 | filesaver.readyState = filesaver.DONE; 188 | }; 189 | filesaver.readyState = filesaver.WRITING; 190 | }), fs_error); 191 | }), fs_error); 192 | }; 193 | dir.getFile(name, {create: false}, abortable(function(file) { 194 | // delete file if it already exists 195 | file.remove(); 196 | save(); 197 | }), abortable(function(ex) { 198 | if (ex.code === ex.NOT_FOUND_ERR) { 199 | save(); 200 | } else { 201 | fs_error(); 202 | } 203 | })); 204 | }), fs_error); 205 | }), fs_error); 206 | } 207 | , FS_proto = FileSaver.prototype 208 | , saveAs = function(blob, name, no_auto_bom) { 209 | return new FileSaver(blob, name, no_auto_bom); 210 | } 211 | ; 212 | // IE 10+ (native saveAs) 213 | if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) { 214 | return function(blob, name, no_auto_bom) { 215 | if (!no_auto_bom) { 216 | blob = auto_bom(blob); 217 | } 218 | return navigator.msSaveOrOpenBlob(blob, name || "download"); 219 | }; 220 | } 221 | 222 | FS_proto.abort = function() { 223 | var filesaver = this; 224 | filesaver.readyState = filesaver.DONE; 225 | dispatch(filesaver, "abort"); 226 | }; 227 | FS_proto.readyState = FS_proto.INIT = 0; 228 | FS_proto.WRITING = 1; 229 | FS_proto.DONE = 2; 230 | 231 | FS_proto.error = 232 | FS_proto.onwritestart = 233 | FS_proto.onprogress = 234 | FS_proto.onwrite = 235 | FS_proto.onabort = 236 | FS_proto.onerror = 237 | FS_proto.onwriteend = 238 | null; 239 | 240 | return saveAs; 241 | }( 242 | typeof self !== "undefined" && self 243 | || typeof window !== "undefined" && window 244 | || this.content 245 | )); 246 | // `self` is undefined in Firefox for Android content script context 247 | // while `this` is nsIContentFrameMessageManager 248 | // with an attribute `content` that corresponds to the window 249 | 250 | if (typeof module !== "undefined" && module.exports) { 251 | module.exports.saveAs = saveAs; 252 | } else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) { 253 | define([], function() { 254 | return saveAs; 255 | }); 256 | } -------------------------------------------------------------------------------- /public/scripts/main.js: -------------------------------------------------------------------------------- 1 | // this is the main router and allows you to create multiple views the main app (currently we only have one) 2 | 3 | var coaxsApp = angular.module('coaxsApp', ['coaxsFilters', 'ui.router', 'ui.bootstrap', 'leaflet-directive']); 4 | 5 | coaxsApp.config(function($stateProvider, $urlRouterProvider) { 6 | 7 | $urlRouterProvider.otherwise('/maps'); 8 | 9 | $stateProvider 10 | .state('maps', { 11 | url: '/maps', 12 | templateUrl: '/public/ng-views/maps.html', 13 | controller: 'mapsController' 14 | }) 15 | }); 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /public/scripts/main/misc/filters.js: -------------------------------------------------------------------------------- 1 | // this module handles front end filters which are piped through "|" bars between double brackets 2 | angular.module('coaxsFilters', []) 3 | 4 | // this just makes values all 2 characters long (and does not control for numbers greater than 100, because we do not run into them) 5 | .filter('integerLength', function () { 6 | return function (input) { 7 | if (input < 10) { 8 | input = '0' + String(input) 9 | } 10 | return input; 11 | }; 12 | }) 13 | 14 | 15 | // UPDATED AVG WAIT TIME FILTER TO PREVENT NnN DEFAULT STATE 16 | // this converts minute values in half for the purpose of getting avg wait times (and converts fractions into seconds) 17 | 18 | .filter('avgWaitTime', function () { 19 | return function(input) { 20 | var min = Math.ceil(input/2); 21 | if (min <10) {min = '0' + String(min)}; 22 | return min; 23 | } 24 | }) 25 | 26 | // gives you the length of the array of the key values 27 | .filter('keyLength', function () { 28 | return function (input){ 29 | if (angular.isObject(input)) { 30 | return Object.keys(input).length; 31 | } 32 | }; 33 | }) 34 | 35 | // take and object and return an array of its keys 36 | .filter('toArray', function () { 37 | return function (input) { 38 | if (!(input instanceof Object)) { return input; } 39 | return Object.keys(input).map(function(k) { 40 | var val = input[k]; 41 | val._key = k; 42 | return val; 43 | }); 44 | } 45 | }) 46 | 47 | // standardize minutes so that they all have the same number of characters in hh:mm format 48 | .filter('minuteConverter', function () { 49 | return function (input) { 50 | input = Math.floor(Number(input)); 51 | if (input < 60) { 52 | var seconds = Math.round((input-Math.floor(input))/60); 53 | var minutes = Math.floor(input); 54 | if (seconds < 10){ 55 | seconds = '0' + seconds; 56 | } 57 | return String(minutes + ' m, ' + seconds + ' s'); 58 | } else { 59 | var minutes = Math.floor(input%60); 60 | var hours = Math.floor(input/60); 61 | return String(hours + ' h, ' + minutes + ' m') 62 | } 63 | } 64 | }) 65 | 66 | // convert a decimal to a percentage 67 | .filter('convertPercentage', function () { 68 | return function (input) { 69 | return Number(input)*100; 70 | } 71 | }) 72 | 73 | // standardize input lengths 74 | .filter('vectorTimeValFilter', function () { 75 | return function (input) { 76 | input = String(input); 77 | if (input.length == 1) { return '00' + input } 78 | if (input.length == 2) { return '0' + input } 79 | if (input.length > 2) { return input } 80 | } 81 | }) 82 | 83 | .filter('altNum', function () { 84 | return function (input) { 85 | return input.charAt(0); 86 | } 87 | }) 88 | 89 | .filter('altNumInc', function () { 90 | return function (input) { 91 | if(input){ 92 | return String.fromCharCode(input.charCodeAt(0)+1)+'|'+input.substring(2,input.length);} 93 | } 94 | }) 95 | 96 | .filter('altAbbrev', function () { 97 | return function (input) { 98 | if(input){ 99 | len = input.length; 100 | if (len > 17) {name = input.substring(0,15)+'...';} 101 | else{name = input}; 102 | return name;} 103 | } 104 | }) 105 | 106 | .filter('altName', function () { 107 | return function (input) { 108 | return input.substring(2,input.length); 109 | } 110 | }) -------------------------------------------------------------------------------- /public/scripts/main/services/analystService.js: -------------------------------------------------------------------------------- 1 | // this handles interactions with the analyst.js library, read the library's readme for further examples and details 2 | coaxsApp.service('analystService', function (supportService, $interval, $http, $q) { 3 | 4 | var token = null; //oauth2 token for analyst-server login 5 | var analystUrlBase = 'http://coaxs.mit.edu/enqueue/single'; //base URL for Conveyal Analyst-Server 6 | var analystUrl = 'http://coaxs.mit.edu/enqueue/single/'; //to take the base and the oauth2 token 7 | var destinationUrlBase = 'https://analyst-static.s3.amazonaws.com/grids/boston/'; //base URL for destination grid data 8 | var defaultShapefile = 'd54d12d0-b34a-4921-89f7-484973dbc3ac', 9 | defaultGraph = '1132f8aaa8cf441eabe6329ae3186720', 10 | workerVersion = 'v2.4.0'; 11 | var indicatorAttributes = {}; 12 | var attributeUrlArray = []; 13 | var attributeIdArray = []; 14 | 15 | this.setDestinationData = function(){ 16 | return new Promise(function(resolve, reject){ 17 | $http.get('/load/destinations/indicators') 18 | .success(function (data, status) { 19 | indicatorAttributes = data; 20 | for (indicator in indicatorAttributes){ 21 | for (var i =0 ; i < indicatorAttributes[indicator].length; i ++){ 22 | attributeUrlArray.push(indicatorAttributes[indicator][i]['grid']); 23 | attributeIdArray.push(indicatorAttributes[indicator][i]['id']); 24 | } 25 | }; 26 | resolve(); 27 | }) 28 | }) 29 | }; 30 | 31 | var minutes = []; 32 | for (var i = 1; i <= 120; i++){minutes.push(i)}; 33 | 34 | var isochrones = []; 35 | var isochroneLayer = []; 36 | var plotData = []; 37 | var transitiveLayer = []; 38 | var Browsochrones = window.Browsochrones; 39 | var browsochrones = []; 40 | 41 | for (var i=0; i<2; i++){ 42 | isochrones[i] = null; 43 | isochroneLayer[i] = null; 44 | browsochrones[i] = new Browsochrones(); 45 | } 46 | 47 | refreshCred = function () { 48 | return new Promise(function(resolve, reject){ 49 | // $http.get('/credentials').success(function (t, status) { 50 | // token = t.access_token 51 | // analystUrl = ''; 52 | // analystUrl = analystUrlBase + token; 53 | resolve(); 54 | // }); 55 | }) 56 | }; 57 | 58 | this.refreshCred = refreshCred; 59 | 60 | var staticRequest = { 61 | "jobId": supportService.generateUUID(), 62 | "transportNetworkId": defaultGraph, 63 | "request": { 64 | "date":"2015-10-14","fromTime":25200,"toTime":32400,"accessModes":"WALK","directModes":"WALK","egressModes":"WALK","transitModes":"TRANSIT","walkSpeed":1.1,"bikeSpeed":4.1,"carSpeed":20,"streetTime":90,"maxWalkTime":60,"maxBikeTime":20,"maxCarTime":45,"minBikeTime":10,"minCarTime":10,"suboptimalMinutes":5,"reachabilityThreshold":0,"bikeSafe":1,"bikeSlope":1,"bikeTime":1,"maxRides":8,"bikeTrafficStress":4,"monteCarloDraws":120, 65 | "scenario":{"id":99999} 66 | } 67 | }; 68 | 69 | //to get transit network metadata 70 | var metadataBody = { 71 | "type": 'static-metadata', 72 | "graphId": defaultGraph, 73 | "workerVersion": workerVersion, 74 | "request": staticRequest 75 | }; 76 | 77 | //to get stopTrees (walking distances from grid cells to nearby stops) 78 | var stopTreesBody = JSON.stringify({ 79 | "type": 'static-stop-trees', 80 | "graphId": defaultGraph, 81 | "workerVersion": workerVersion, 82 | "request": staticRequest 83 | }); 84 | 85 | var postToAnalyst = function(body,cb) {return fetch(analystUrl,{method: 'POST', body: body}); 86 | }; 87 | 88 | var checkWarmup = function(){ 89 | return new Promise(function(resolve, reject){ 90 | console.log('checking if analyst server is warmed up'); 91 | refreshCred() 92 | .then(function(){ 93 | postToAnalyst(JSON.stringify(metadataBody)) 94 | .then(function(res){ 95 | if(res.status == 200){ 96 | console.log('analyst server is warmed up'); 97 | resolve(); 98 | }else{ 99 | setTimeout(function () {checkWarmup()} , 15000); 100 | } 101 | }) 102 | }) 103 | }) 104 | }; 105 | 106 | fetchMetadataIfNeeded = function (isPointToPoint, scenNum, scenarios){ 107 | var metadataBodyForScen = metadataBody; 108 | metadataBodyForScen.request.request.scenario = scenarios[scenNum]; 109 | metadataBodyForScen.request.request.scenario.id = supportService.generateUUID() 110 | return new Promise(function(resolve, reject){ 111 | if(!isPointToPoint || browsochrones[scenNum].surfaceLoaded){ //if we're not in point-to-point mode, or if there is already a surface loaded, we don't need to get new metadata.transitiveData, so we can resolve immediately. resetAll() below is used to set surfaceLoaded to null if the scenario changes. 112 | resolve(); 113 | } else { 114 | postToAnalyst(JSON.stringify(metadataBodyForScen)).then(function(res){ 115 | console.log('fetched metadata'); 116 | return res.json() 117 | }).then(function(metadata){ 118 | browsochrones[scenNum].setTransitiveNetwork(metadata.transitiveData); 119 | resolve(); 120 | }) 121 | }}) 122 | }; 123 | 124 | this.fetchStopTreesAndGrids = function () { 125 | return new Promise(function(resolve, reject){ 126 | checkWarmup().then(function(){ 127 | $q.all([ 128 | postToAnalyst(JSON.stringify(metadataBody)).then(function(res){ 129 | console.log('fetched metadata'); 130 | return res.json()}), 131 | postToAnalyst(stopTreesBody).then(function(res){ 132 | console.log('fetched stopTrees'); 133 | return res.arrayBuffer(); 134 | })]).then(function([metadata, stopTrees]){ 135 | browsochrones[0].setQuery(metadata); 136 | browsochrones[0].setStopTrees(stopTrees.slice(0)); 137 | browsochrones[1].setQuery(metadata); 138 | browsochrones[1].setStopTrees(stopTrees.slice(0)); 139 | resolve(); 140 | }); 141 | }); 142 | 143 | //get destination grid data for calculating accessibility indicators 144 | $q.all(attributeUrlArray.map(function(gridName){ 145 | return fetch(destinationUrlBase+gridName).then(function(res){ 146 | return res.arrayBuffer()}) 147 | })).then( function(res){ 148 | console.log('fetched grids'); 149 | for (i in attributeIdArray) { 150 | browsochrones[0].putGrid(attributeIdArray[i],res[i].slice(0)); 151 | browsochrones[1].putGrid(attributeIdArray[i],res[i].slice(0)); 152 | } 153 | }) 154 | }); 155 | }; 156 | 157 | var makeIsochrones = function(scenNum){ 158 | return new Promise(function(resolve, reject){ 159 | console.log('making isochrones') 160 | $q.all(minutes.map(function(minute){ 161 | return browsochrones[scenNum].getIsochrone(minute)}) 162 | ) 163 | .then(function(res){ 164 | isochrones[scenNum] = res; 165 | resolve(); 166 | }) 167 | }) 168 | }; 169 | 170 | var makeIsochronesAndPlotData = function(scenNum, type){ 171 | return new Promise(function(resolve, reject){ 172 | //first, generate a browsochrones surface 173 | browsochrones[scenNum].generateSurface(type).then(function(){ 174 | if(type == 'AVERAGE'){ //we requested average times for point-to-point mode, so we can resolve without making isochrones. 175 | resolve(); 176 | } else { //we requested median times because we want isochrones 177 | makeIsochrones(scenNum).then(function(){ 178 | //and get an accessibility number for each destination attribute at each minte, to be plotted later 179 | $q.all( 180 | attributeIdArray.map(function(attribute){ 181 | return $q.all(minutes.map(function(minute){ 182 | return browsochrones[scenNum].getAccessibilityForGrid(attribute,minute)})) 183 | })).then(function(res){ 184 | plotDataTemp = {}; 185 | for (var i = 0; i < attributeIdArray.length; i++){ 186 | plotDataTemp[attributeIdArray[i]] = res[i]; 187 | } 188 | plotData[scenNum]={} 189 | for (indicator in indicatorAttributes){ 190 | plotData[scenNum][indicator] = {}; 191 | for (var i =0 ; i < indicatorAttributes[indicator].length; i ++){ 192 | var attr = indicatorAttributes[indicator][i].id; 193 | plotData[scenNum][indicator][attr]={id: attr, verbose: indicatorAttributes[indicator][i].verbose, data: plotDataTemp[attr]} 194 | } 195 | } 196 | resolve(); 197 | }) 198 | }) 199 | } 200 | }) 201 | }) 202 | }; 203 | 204 | //called when start pin is moved 205 | this.moveOrigin = function (marker, scenarios, isComparison, isPointToPoint){ 206 | plotData = []; 207 | var type = ''; 208 | isPointToPoint ? type = 'AVERAGE' : type = 'MEDIAN'; 209 | return new Promise(function(resolve, reject){ 210 | var staticBody = []; 211 | var staticDefault = []; 212 | var xy = {}; 213 | var scenNumArray = [] 214 | for (var i=0; i 254){ //not a feasible journey 266 | plotData[scenNum] = { 267 | 'walkTime' : 0, 268 | 'waitTime': 999, 269 | 'rideTime': 0 270 | } 271 | } else if (res.waitTime > 254 && res.inVehicleTravelTime > 254) { //walk-only journey 272 | plotData[scenNum] = { 273 | 'walkTime' : res.travelTime, 274 | 'waitTime': 0, 275 | 'rideTime': 0 276 | } 277 | } else { //regular transit and walk journey 278 | plotData[scenNum] = { 279 | 'walkTime' : res.travelTime-res.waitTime-res.inVehicleTravelTime, 280 | 'waitTime' : res.waitTime, 281 | 'rideTime' : res.inVehicleTravelTime 282 | } 283 | } 284 | var transitiveLines = new Transitive({ 285 | data:transitive, 286 | styles: { 287 | multipoints_merged: { 288 | r: 6 289 | }, 290 | stops_merged: { 291 | r: 4 292 | }, 293 | places: { 294 | r: 6 295 | }, 296 | labels: { 297 | display: 'none' 298 | }, 299 | segments: { 300 | 'stroke-width': '4px', 301 | 'stroke-opacity': 0.8, 302 | 'stroke-dasharray': function(display, segment){ 303 | if (segment.type === 'WALK'){return '6,8'} 304 | } 305 | }, 306 | 'segments-halo': { 307 | 'stroke-opacity': 0.4 308 | } 309 | }, 310 | zoomFactors: [{ 311 | minScale: 0, 312 | gridCellSize: 25, 313 | internalVertexFactor: 50, 314 | angleConstraint: 10, 315 | mergeVertexThreshold: 50 316 | }, { 317 | minScale: 0.5, 318 | gridCellSize: 0, 319 | internalVertexFactor: 0, 320 | angleConstraint: 5, 321 | mergeVertexThreshold: 0 322 | }] 323 | }); 324 | transitiveLayer[scenNum] = new L.TransitiveLayer(transitiveLines) 325 | } 326 | 327 | this.moveDestination = function (cb, marker, isComparison, map){ 328 | plotData = []; 329 | if (browsochrones[0].surfaceLoaded ){ //time surface for origin already loaded 330 | if(transitiveLayer[0]){map.removeLayer(transitiveLayer[0])}; 331 | if(transitiveLayer[1]){map.removeLayer(transitiveLayer[1])}; 332 | var xy = browsochrones[0].latLonToOriginPoint(marker.getLatLng()); 333 | browsochrones[0].generateDestinationData(xy). 334 | then(function(res){ 335 | processTransitiveResult(res,0); 336 | if(!isComparison){ 337 | cb(plotData); 338 | map.addLayer(transitiveLayer[0]); 339 | transitiveLayer[0]._refresh(); 340 | } else { 341 | browsochrones[1].generateDestinationData(xy). 342 | then(function(res){ 343 | processTransitiveResult(res,1) 344 | cb(plotData); 345 | map.addLayer(transitiveLayer[1]); 346 | transitiveLayer[1] ._refresh(); 347 | }); 348 | } 349 | }) 350 | } else { //time surface for origin not yet loaded 351 | cb(null); //passing null to the callback function runs refresh origin 352 | } 353 | } 354 | 355 | // clear out everything that already exists, reset opacities to defaults 356 | this.resetAll = function (map, c) { 357 | for (var i = 0; i < 2; i++){ 358 | browsochrones[i].surfaceLoaded = false; 359 | isochrones[i] = null; 360 | if(transitiveLayer[i]){map.removeLayer(transitiveLayer[i])}; 361 | if(isochroneLayer[i]){map.removeLayer(isochroneLayer[i])}; 362 | } 363 | }; 364 | 365 | // New modification functions corridorID: "A", "B", "C", "D", "E" scale: the modification scale 366 | this.modifyDwells = function (corridorId,scale,cb) { 367 | $http.get('/load/scenario/'+corridorId) 368 | .success(function (data, status) { 369 | var scenarioJSON = []; 370 | data.modifications.forEach(function(route){ 371 | if (route.type === "adjust-dwell-time"){ 372 | route.scale = scale; 373 | scenarioJSON.push(route); 374 | } 375 | } 376 | ); 377 | cb(scenarioJSON) 378 | }) 379 | }; 380 | 381 | this.modifySpeed = function (corridorId,scale,cb) { 382 | $http.get('/load/scenario/'+corridorId) 383 | .success(function (data, status) { 384 | var scenarioJSON = []; 385 | data.modifications.forEach(function(route){ 386 | if (route.type === "adjust-speed"){ 387 | route.scale = scale; 388 | scenarioJSON.push(route); 389 | } 390 | } 391 | ); 392 | cb(scenarioJSON) 393 | }) 394 | }; 395 | 396 | this.modifyHeadway = function (corridorId,scale,cb) { 397 | $http.get('/load/scenario/'+corridorId) 398 | .success(function (data, status) { 399 | var scenarioJSON = []; 400 | data.modifications.forEach(function(route){ 401 | if (route.type === "adjust-frequency"){ 402 | route.entries.forEach(function (entry) { 403 | entry.headwaySecs = entry.headwaySecs*scale ; 404 | }); 405 | scenarioJSON.push(route); 406 | } 407 | } 408 | ); 409 | cb(scenarioJSON) 410 | }) 411 | }; 412 | 413 | this.modifyModes = function (routeTypes, c) { 414 | optionC[c].scenario.modifications.push({ 415 | type: 'remove-trip', 416 | agencyId: agencyId, 417 | routeId: null, 418 | tripId: null, 419 | routeType: routeTypes 420 | }); 421 | }; 422 | 423 | // show vector isochrones for selected cutoff timeVal 424 | this.showVectorIsos = function(timeVal, map, isComparison) { 425 | if(isochroneLayer[0]){map.removeLayer(isochroneLayer[0])}; 426 | if(isochroneLayer[1]){map.removeLayer(isochroneLayer[1])}; 427 | isochroneLayer[0] = L.geoJson(isochrones[0][timeVal], { 428 | style: { 429 | stroke : true, 430 | fillColor : '#FDB813', 431 | color : '#F68B1F', 432 | weight : 1, 433 | fillOpacity : 0.25, 434 | opacity : 1, 435 | clickable : false 436 | } 437 | }); 438 | isochroneLayer[0].addTo(map); 439 | if (isComparison) { 440 | isochroneLayer[1] = L.geoJson(isochrones[1][timeVal], { 441 | style: { 442 | stroke : true, 443 | fillColor : '#89cff0', 444 | color : '#45b3e7', 445 | weight : 1, 446 | fillOpacity : 0.25, 447 | opacity : 1 448 | } 449 | }); 450 | isochroneLayer[1].addTo(map); 451 | } 452 | }; 453 | }); -------------------------------------------------------------------------------- /public/scripts/main/services/d3Service.js: -------------------------------------------------------------------------------- 1 | // this is the boiler to visualize the d3 graph 2 | coaxsApp.service('d3Service', function () { 3 | //Styling info. 4 | var attributes = []; 5 | 6 | this.setChartLabels = function(data){ 7 | attributes = data; 8 | attributes = d3.map(attributes, function(d){return d.code;}); 9 | }; 10 | 11 | //Map attributes so they can be get/set by code. 12 | 13 | //Defaults 14 | var selCode = 'jobs1', 15 | xScale = null; 16 | 17 | colors = d3.scale.category10(); 18 | 19 | var formatAccStat = function (val) { 20 | if (val < 1000) { 21 | return val; 22 | } else if (val < 1000000) { 23 | return (d3.format(".1f")(val/1000) + ' k'); 24 | } else { 25 | return (d3.format(".3f")(val/1000000) + ' M'); 26 | } 27 | } 28 | 29 | var updateSubsetTotal = function(roundTo){ 30 | d3.selectAll("#subTotal") 31 | .html(function(d){ 32 | subsetTotal = 0; 33 | d.forEach(function (e) { 34 | if (e[0].attr == selCode) 35 | {subsetTotal = subsetTotal + e[0]['y']}; 36 | }); 37 | return formatAccStat(subsetTotal); 38 | })}; 39 | 40 | var updateSubsetLabels = function () { 41 | //put a black border around stacked bar elements when their parent attribute code selected 42 | d3.selectAll("rect") 43 | .style('stroke', function (d) { 44 | if (d.attr == selCode) {return 'black'} 45 | else {return}}); 46 | //update the subtotal text 47 | d3.selectAll("#subsetLabel") 48 | .style("fill", function () { 49 | return attributes.get(selCode).color}) 50 | .text( function (){ 51 | return attributes.get(selCode).verbose});; 52 | }; 53 | 54 | this.clearCharts = function(){ 55 | d3.select("#plot1").selectAll("*").remove(); 56 | d3.select("#compPlot2").selectAll("*").remove(); 57 | }; 58 | 59 | //Stacked bar graph showing jobs and transport capacity by default 60 | this.drawCordonGraph = function (dataset) { 61 | 62 | var margins = { 63 | top: 50, 64 | left: 35, 65 | right: 150, 66 | bottom: 125 67 | }, 68 | //Room for summary stats at top 69 | legendPanel = { 70 | height: 40 71 | }, 72 | width = 400 - margins.left - margins.right, 73 | height = 400 - margins.top - margins.bottom - legendPanel.height; 74 | 75 | d3.select("#plot1").selectAll("*").remove(); 76 | 77 | vis = d3.select("#plot1").append('g') 78 | .attr('width', width + margins.left + margins.right) 79 | .attr('height', height + margins.top + margins.bottom + legendPanel.height) 80 | .attr('transform', 'translate(' + margins.left + ',' + margins.top + ')'); 81 | 82 | dataset = dataset.map(function (d) { 83 | return d3.map(d.data).entries().map(function(e){ 84 | return { attr: e.key, 85 | val: [{ 86 | x: d.indicator, 87 | y: e.value, 88 | }] 89 | } 90 | }) 91 | }); 92 | 93 | stack = d3.layout.stack().values(function(d){return d.val}).order('default'); 94 | 95 | dataset.forEach(function(e){ 96 | stack(e)}); 97 | 98 | dataset = dataset.map(function(e){ 99 | return e.map(function(g){ 100 | return g.val.map(function(d){ 101 | return { 102 | x: d.x, 103 | y: d.y, 104 | y0: d.y0, 105 | attr: g.attr, 106 | }; 107 | }); 108 | }); 109 | }), 110 | 111 | indicators = dataset.map(function (d) { 112 | return d[0][0].x; 113 | }), 114 | 115 | yMax = d3.max(dataset[0], function (group) { 116 | return d3.max(group, function (d) { 117 | return d.y + d.y0; 118 | }); 119 | }), 120 | 121 | yScale = d3.scale.linear() 122 | .domain([0,yMax]) 123 | .range([height,0]), 124 | 125 | xScale = d3.scale.ordinal() 126 | .domain(indicators) 127 | .rangeBands([0, width], .2), 128 | 129 | yAxis = d3.svg.axis() 130 | .scale(yScale) 131 | .ticks(4) 132 | .orient('left') 133 | .tickFormat(function (d) { 134 | var prefix = d3.formatPrefix(d); 135 | return prefix.scale(d) + prefix.symbol; 136 | }), 137 | 138 | xAxis = d3.svg.axis() 139 | .scale(xScale) 140 | .tickSize(0), 141 | 142 | groups = 143 | vis.selectAll('g') 144 | .data(dataset[0].concat(dataset[1]).concat(dataset[2])) 145 | .enter() 146 | .append('g') 147 | .style('fill', function (d, i) { 148 | if (attributes.get(d[0].attr)){ 149 | return attributes.get(d[0].attr).color} 150 | else {return colors(i)}}), 151 | 152 | rects = groups.selectAll('rect') 153 | .data(function (d) { 154 | return d; 155 | }) 156 | .enter() 157 | .append('rect') 158 | .style('cursor','pointer') 159 | .attr('x', function (d) { 160 | return xScale(d.x); 161 | }) 162 | .attr('y', function (d, i) { 163 | return yScale(d.y0+d.y); 164 | }) 165 | .attr('height', function (d) { 166 | return (d.y/yMax*height); 167 | }) 168 | .attr('width', function (d) { 169 | return xScale.rangeBand(); 170 | }) 171 | .on('click', function (d) { 172 | //only enable for the first column of stacked bars 173 | if(d.x == indicators[0]) { 174 | selCode = d.attr; 175 | updateSubsetLabels(); 176 | updateSubsetTotal(); 177 | } 178 | }) 179 | .on('mouseover', function (d) { 180 | var yPos = parseFloat(d3.select(this).attr('y')) + height +10; 181 | var xPos = parseFloat(d3.select(this).attr('x')) + xScale.rangeBand() / 2+500; 182 | 183 | d3.select('#tooltip') 184 | .style('left', xPos + 'px') 185 | .style('top', yPos + 'px') 186 | .select('#value') 187 | .html(''+ 188 | d3.format(",")(d3.round(d.y,-1)) 189 | + '
' 190 | + attributes.get(d.attr).verbose); 191 | 192 | d3.select('#tooltip').classed('hidden', false); 193 | }) 194 | .on('mouseout', function () { 195 | d3.select('#tooltip').classed('hidden', true); 196 | }); 197 | vis.append('g') 198 | .attr('class', 'axis') 199 | .attr('transform', 'translate(0,' + height + ')') 200 | .call(xAxis) 201 | .selectAll("text") 202 | .style('text-anchor','start') 203 | .attr('transform', 'rotate(30)'); 204 | 205 | vis.append('g') 206 | .attr('class', 'axis') 207 | .call(yAxis); 208 | 209 | //Summary stats 210 | vis.append('g') 211 | .append("text") 212 | .attr("class","stat") 213 | .attr("y", 25-margins.top) 214 | .attr("x", xScale(indicators[0])+xScale.rangeBand()-3) 215 | .style("text-anchor","end") 216 | .style("opacity", 0.95) 217 | .html( function (){ 218 | return d3.format(",")(d3.round(yMax,-2))}); 219 | vis.append('g') 220 | .append("text") 221 | .attr("class","stat") 222 | .attr("y", 25-margins.top) 223 | .attr("x", xScale(indicators[1])+2) 224 | .style("text-anchor","start") 225 | .style("opacity", 0.75) 226 | .html("Total"); 227 | vis.append('g') 228 | .data(dataset) 229 | .append("text") 230 | .attr("id","subTotal") 231 | .attr("class","stat") 232 | .attr("text-anchor","end") 233 | .attr("y", 38-margins.top) 234 | .attr("x", xScale(indicators[0])+xScale.rangeBand()-3); 235 | vis.append('g') 236 | .append("text") 237 | .attr("id","subsetLabel") 238 | .attr("class","stat") 239 | .style("text-anchor","start") 240 | .attr("y", 38-margins.top) 241 | .attr("x", xScale(indicators[1])+2) 242 | .style("opacity", 0.75) 243 | .style("fill", attributes.get(selCode).color) 244 | .text( function (){ 245 | return attributes.get(selCode).verbose}) 246 | 247 | updateSubsetLabels(); 248 | updateSubsetTotal(); 249 | 250 | }; 251 | 252 | 253 | this.drawTimeGraph = function(plotData, indicator) { 254 | selCode = 'rideTime'; 255 | var margins = { 256 | top: 45, 257 | left: 45, 258 | right: 10, 259 | bottom: 10 260 | }, 261 | 262 | legendPanel = { 263 | height: 50 264 | }, 265 | 266 | width = 300 - margins.left - margins.right, 267 | height = 400 - margins.top - margins.bottom - legendPanel.height; 268 | 269 | d3.select("#compPlot3").selectAll("*").remove(); 270 | 271 | vis1 = d3.select("#compPlot3").append('g') 272 | .attr('width', width + margins.left + margins.right) 273 | .attr('height', height + margins.top + margins.bottom + legendPanel.height) 274 | .attr('transform', 'translate(' + margins.left + ',' + margins.top + ')'); 275 | 276 | var total = [], 277 | dataset = [], 278 | compare = false; 279 | 280 | for (var i = 0; i < plotData.length; i++){ 281 | dataset[i] = []; 282 | for (tid in plotData[i].data){ 283 | dataset[i].push({'attr':tid,'val':[]}); 284 | dataset[i][dataset[i].length-1].val.push({'x': plotData[i].name, 'y': plotData[i].data[tid]}); 285 | }; 286 | } 287 | 288 | if (plotData.length > 1){compare=true;} 289 | 290 | stack = d3.layout.stack().values(function(d){return d.val}).order('default'); 291 | 292 | dataset.forEach(function(d){ 293 | stack(d)}); 294 | 295 | dataset = dataset.map(function(e){ 296 | return e.map(function(g){ 297 | return g.val.map(function(d){ 298 | return { 299 | x: d.x, 300 | y: d.y, 301 | y0: d.y0, 302 | attr: g.attr, 303 | }; 304 | }); 305 | }); 306 | }), 307 | 308 | yMax0 = d3.max(dataset[0], function (group) { 309 | return d3.max(group, function (d) { 310 | return d.y + d.y0; 311 | }); 312 | }), 313 | 314 | dataset[1] ? yMax1 = d3.max(dataset[1], function (group) { 315 | return d3.max(group, function (d) { 316 | return d.y + d.y0; 317 | }); 318 | }) : yMax1 = 0; 319 | 320 | yMax0 > yMax1 ? yMax = yMax0 : yMax = yMax1; 321 | 322 | indicators2 = dataset.map(function (d) { 323 | return d[0][0].x; 324 | }), 325 | 326 | xRange1 = d3.scale.linear().range([0,width/3]).domain([0, 120]), 327 | 328 | yRange = d3.scale.linear().domain([0, yMax]).range([height,0]); 329 | 330 | xScale2 = d3.scale.ordinal() 331 | .domain(indicators2) 332 | .rangeBands([0,width-150], .05), 333 | 334 | xAxis2 = d3.svg.axis() 335 | .scale(xScale2) 336 | .tickSize(0), 337 | 338 | groups = 339 | vis1.selectAll('g') 340 | .data(dataset[1] ? dataset[0].concat(dataset[1]) : dataset[0]) 341 | .enter() 342 | .append('g') 343 | .style('fill', function (d, i) { 344 | if (attributes.get(d[0].attr)){ 345 | return attributes.get(d[0].attr).color} 346 | else {return colors(i)} 347 | }); 348 | 349 | rects = groups.selectAll('rect') 350 | .data(function (d) { 351 | return d; 352 | }) 353 | .enter() 354 | .append('rect') 355 | .style('cursor','pointer') 356 | .attr('x', function (d) { 357 | return xScale2(d.x); 358 | }) 359 | .attr('y', function (d, i) { 360 | return yRange(d.y0+d.y); 361 | }) 362 | .attr('height', function (d) { 363 | return (d.y*height/yMax); 364 | }) 365 | .attr('width', function (d) { 366 | return xScale2.rangeBand(); 367 | }) 368 | .on('click', function (d) { 369 | selCode = d.attr; 370 | updateSubsetLabels(); 371 | updateSubsetTotal(); 372 | }) 373 | // .on('mouseover', function (d) { 374 | // var yPos = parseFloat(d3.select(this).attr('y')) + height +10; 375 | // var xPos = parseFloat(d3.select(this).attr('x')) + xScale2.rangeBand() / 2 +100; 376 | 377 | // d3.select('#tooltip') 378 | // .style('left', xPos + 'px') 379 | // .style('top', yPos + 'px') 380 | // .select('#value') 381 | // .html(''+ 382 | // d3.format(",")(d3.round(d.y,1)) 383 | // + '
' 384 | // + attributes.get(d.attr).verbose); 385 | 386 | // d3.select('#tooltip').classed('hidden', false); 387 | // }) 388 | // .on('mouseout', function () { 389 | // d3.select('#tooltip').classed('hidden', true); 390 | // }); 391 | 392 | vis1.append('g') 393 | .attr('class', 'axis') 394 | .attr('transform', 'translate(0,' + height + ')') 395 | .call(xAxis2) 396 | .selectAll("text") 397 | .style('text-anchor','start') 398 | .attr('transform', 'rotate(30)'); 399 | 400 | 401 | yAxis1 = d3.svg.axis() 402 | .scale(yRange) 403 | .ticks(4) 404 | .tickFormat(function (d) { 405 | var prefix = d3.formatPrefix(d); 406 | return prefix.scale(d) + prefix.symbol; 407 | }) 408 | .orient("left") 409 | 410 | vis1.append('g') 411 | .attr("class", "y axis") 412 | .call(yAxis1) 413 | .append("text") 414 | .text("Minutes") 415 | .style("text-anchor","middle") 416 | .attr("transform", 'translate(-45,'+height/2+')rotate(90)'); 417 | 418 | //total time, scenario 0 419 | vis1.append("svg:g") 420 | .attr("class", "stat") 421 | .append("text") 422 | .attr("y", 25-margins.top) 423 | .attr("x", xScale2(indicators2[0])+xScale2.rangeBand()-3) 424 | .style("text-anchor","end") 425 | .html( function (){ 426 | return d3.format(",")(d3.round(yMax0,1)); 427 | }); 428 | 429 | vis1.append("svg:g") 430 | .selectAll("text") 431 | .data(dataset) 432 | .enter() 433 | .append("text") 434 | .attr("class", "stat") 435 | .attr("id","subTotal") 436 | .attr("y", 38-margins.top) 437 | .attr("x", function(d){ 438 | return xScale2(d[0][0].x)+xScale2.rangeBand()-3}) 439 | .style("text-anchor","end"); 440 | 441 | if (compare){ 442 | //total time, scenario 1 443 | vis1.append("svg:g") 444 | .append("text") 445 | .attr("class", "stat") 446 | .attr("y", 25-margins.top) 447 | .attr("x", xScale2(indicators2[1])+xScale2.rangeBand()-3) 448 | .style("text-anchor","end") 449 | .html( function (){ 450 | return d3.format(",")(d3.round(yMax1,1)); 451 | }); 452 | } 453 | 454 | vis1.append('g') 455 | .append("text") 456 | .attr("class","stat") 457 | .attr("y", 25-margins.top) 458 | .attr("x", xScale2(indicators2[0])+(indicators2.length)*xScale2.rangeBand()+24) 459 | .style("text-anchor","start") 460 | .style("opacity", 0.75) 461 | .html("minutes total"); 462 | 463 | vis1.append('g') 464 | .append("text") 465 | .attr("id","subsetLabel") 466 | .attr("class","stat") 467 | .attr("y", 38-margins.top) 468 | .attr("x", xScale2(indicators2[0])+(indicators2.length)*xScale2.rangeBand()+24) 469 | .style("text-anchor","start") 470 | .style("opacity", 0.75) 471 | .style("fill", attributes.get(selCode).color) 472 | .html( function (){ 473 | return attributes.get(selCode).verbose}); 474 | 475 | updateSubsetLabels(); 476 | updateSubsetTotal(); 477 | 478 | }; 479 | 480 | //Cumulative plot of accessible opportunities vs time, and stacked bar chart 481 | this.drawGraph = function (cutoff, plotData, indicator) { 482 | 483 | selCode = 'jobs1'; 484 | 485 | if (indicator.sel === 'workers'){ 486 | selCode = 'workers1'; 487 | }; 488 | 489 | var margins = { 490 | top: 45, 491 | left: 45, 492 | right: 10, 493 | bottom: 10 494 | }, 495 | 496 | legendPanel = { 497 | height: 50 498 | }, 499 | 500 | width = 300 - margins.left - margins.right, 501 | height = 400 - margins.top - margins.bottom - legendPanel.height; 502 | 503 | d3.select("#compPlot2").selectAll("*").remove(); 504 | 505 | vis1 = d3.select("#compPlot2").append('g') 506 | .attr('width', width + margins.left + margins.right) 507 | .attr('height', height + margins.top + margins.bottom + legendPanel.height) 508 | .attr('transform', 'translate(' + margins.left + ',' + margins.top + ')'); 509 | 510 | var total = [], 511 | dataset = [], 512 | compare = false; 513 | 514 | for (i = 0; i < plotData.length; i++){ 515 | total[i] = Array(120); 516 | dataset[i]={data: {}, indicator: plotData[i].name} 517 | for (j = 0; j < 120; j++){ 518 | total[i][j]={x:j+1, y:0}; 519 | } 520 | for (id in plotData[i].data){ 521 | for (j = 0; j < 120; j++){ 522 | total[i][j]['y']=total[i][j]['y']+plotData[i].data[id].data[j]; 523 | if (j <= (cutoff)){ 524 | dataset[i].data[id] = plotData[i].data[id].data[j];}; 525 | } 526 | }; 527 | if (i>0){compare=true;} 528 | } 529 | 530 | dataset = dataset.map(function (d) { 531 | return d3.map(d.data).entries().map(function(e){ 532 | return { 533 | attr: e.key, 534 | val: [{ 535 | x: d.indicator, 536 | y: e.value, 537 | }] 538 | } 539 | }) 540 | }); 541 | 542 | stack = d3.layout.stack().values(function(d){return d.val}).order('default'); 543 | 544 | dataset.forEach(function(e){ 545 | stack(e)}); 546 | 547 | dataset = dataset.map(function(e){ 548 | return e.map(function(g){ 549 | return g.val.map(function(d){ 550 | return { 551 | x: d.x, 552 | y: d.y, 553 | y0: d.y0, 554 | attr: g.attr, 555 | }; 556 | }); 557 | }); 558 | }), 559 | indicators2 = dataset.map(function (d) { 560 | return d[0][0].x; 561 | }), 562 | 563 | combined = total[1] ? total[0].concat(total[1]) : total[0], 564 | 565 | xRange1 = d3.scale.linear().range([0,0]).domain([0, 120]), 566 | 567 | yRange = d3.scale.linear().domain([0,d3.max(combined, function (d) { return d.y;}) 568 | ]).range([height,0]); 569 | 570 | xScale2 = d3.scale.ordinal() 571 | .domain(indicators2) 572 | .rangeBands([0, width-100], .05), 573 | 574 | xScale3 = xScale2; 575 | 576 | xAxis2 = d3.svg.axis() 577 | .scale(xScale2) 578 | .tickSize(0), 579 | 580 | 581 | groups = 582 | vis1.selectAll('g') 583 | .data(dataset[1] ? dataset[0].concat(dataset[1]) : dataset[0]) 584 | .enter() 585 | .append('g') 586 | .style('fill', function (d, i) { 587 | if (attributes.get(d[0].attr)){ 588 | return attributes.get(d[0].attr).color} 589 | else {return colors(i)} 590 | }); 591 | 592 | rects = groups.selectAll('rect') 593 | .data(function (d) { 594 | return d; 595 | }) 596 | .enter() 597 | .append('rect') 598 | .style('cursor','pointer') 599 | .attr('x', function (d) { 600 | return xScale2(d.x); 601 | }) 602 | .attr('y', function (d, i) { 603 | return yRange(d.y0+d.y); 604 | }) 605 | .attr('height', function (d) { 606 | return (d.y*height/d3.max(combined, function (d) { return d.y;})); 607 | }) 608 | .attr('width', function (d) { 609 | return xScale3.rangeBand(); 610 | }) 611 | .on('click', function (d) { 612 | selCode = d.attr; 613 | updateSubsetLabels(); 614 | updateSubsetTotal(); 615 | }) 616 | // .on('mouseover', function (d) { 617 | // var yPos = parseFloat(d3.select(this).attr('y')) + height +10; 618 | // var xPos = parseFloat(d3.select(this).attr('x')) + xScale3.rangeBand() / 2 +100; 619 | 620 | // d3.select('#tooltip') 621 | // .style('left', xPos + 'px') 622 | // .style('top', yPos + 'px') 623 | // .select('#value') 624 | // .html(''+ 625 | // d3.format(",")(d3.round(d.y,-1)) 626 | // + '
' 627 | // + attributes.get(d.attr).verbose); 628 | 629 | // d3.select('#tooltip').classed('hidden', false); 630 | // }) 631 | // .on('mouseout', function () { 632 | // d3.select('#tooltip').classed('hidden', true); 633 | // }); 634 | 635 | vis1.append('g') 636 | .attr('class', 'axis') 637 | .attr('transform', 'translate(0,' + height + ')') 638 | .call(xAxis2) 639 | .selectAll("text") 640 | .style('text-anchor','start') 641 | .attr('transform', 'rotate(30)'); 642 | 643 | 644 | xAxis1 = d3.svg.axis() 645 | .scale(xRange1) 646 | .tickValues([0,120]) 647 | .tickSize(5) 648 | .orient("bottom"), 649 | 650 | yAxis1 = d3.svg.axis() 651 | .scale(yRange) 652 | .ticks(4) 653 | .tickFormat(function (d) { 654 | var prefix = d3.formatPrefix(d); 655 | return prefix.scale(d) + prefix.symbol; 656 | }) 657 | .orient("left") 658 | 659 | // vis1.append('g') 660 | // .attr("class", "x axis") 661 | // .attr('transform', 'translate(0,' + height + ')') 662 | // .call(xAxis1) 663 | // .append("text") 664 | // .attr("dy", 32) 665 | // .attr("x",width/6) 666 | // .style("text-anchor", "middle") 667 | // .text("Minutes"); 668 | 669 | vis1.append('g') 670 | .attr("class", "y axis") 671 | .call(yAxis1) 672 | .append("text") 673 | .text(indicator.all[indicator.sel]) 674 | .style("text-anchor","middle") 675 | .attr("transform", 'translate(-45,'+height/2+')rotate(90)'); 676 | 677 | // var lineFunc = d3.svg.line() 678 | // .x(function (d) { 679 | // return xRange1(d.x); 680 | // }) 681 | // .y(function (d) { 682 | // return yRange(d.y); 683 | // }) 684 | // .interpolate('basis'); 685 | 686 | // vis1.append("svg:path") 687 | // .attr("d", lineFunc(total[0])) 688 | // .attr("class", "line") 689 | 690 | // if (compare) { 691 | // vis1.append("svg:path") 692 | // .attr("d", lineFunc(total[1])) 693 | // .attr("class", "lineC") 694 | // .style("stroke-dasharray", ("3,3")) 695 | // } 696 | 697 | 698 | 699 | vis1.append("svg:g") 700 | .attr("class", "stat") 701 | .append("text") 702 | .attr("y", 25-margins.top) 703 | .attr("x", xScale2(indicators2[0])+xScale3.rangeBand()-3) 704 | .style("text-anchor","end") 705 | .html( function (){ 706 | return formatAccStat(total[0][cutoff].y); 707 | }); 708 | 709 | vis1.append("svg:g") 710 | .selectAll("text") 711 | .data(dataset) 712 | .enter() 713 | .append("text") 714 | .attr("class", "stat") 715 | .attr("id","subTotal") 716 | .attr("y", 38-margins.top) 717 | .attr("x", function(d){ 718 | return xScale2(d[0][0].x)+xScale3.rangeBand()-3}) 719 | .style("text-anchor","end"); 720 | 721 | if (dataset[1]){ 722 | 723 | vis1.append("svg:g") 724 | .append("text") 725 | .attr("class", "stat") 726 | .attr("y", 25-margins.top) 727 | .attr("x", xScale2(indicators2[1])+xScale3.rangeBand()-3) 728 | .style("text-anchor","end") 729 | .html( function (){ 730 | return formatAccStat(total[1][cutoff].y); 731 | }); 732 | 733 | } 734 | 735 | vis1.append('g') 736 | .append("text") 737 | .attr("class","stat") 738 | .attr("y", 25-margins.top) 739 | .attr("x", xScale2(indicators2[0])+(indicators2.length)*xScale3.rangeBand()+14) 740 | .style("text-anchor","start") 741 | .style("opacity", 0.75) 742 | .html("Total"); 743 | 744 | vis1.append('g') 745 | .append("text") 746 | .attr("id","subsetLabel") 747 | .attr("class","stat") 748 | .attr("y", 38-margins.top) 749 | .attr("x", xScale2(indicators2[0])+(indicators2.length)*xScale3.rangeBand()+14) 750 | .style("text-anchor","start") 751 | .style("opacity", 0.75) 752 | .style("fill", attributes.get(selCode).color) 753 | .html( function (){ 754 | return attributes.get(selCode).verbose}); 755 | 756 | // vis1.append("svg:line") 757 | // .attr("id", "sliderLine") 758 | // .attr("class", "line") 759 | // .attr("x1", xRange1(cutoff)) 760 | // .attr("y1", yRange(total[0][cutoff].y)) 761 | // .attr("x2", xRange1(cutoff)) 762 | // .attr("y2", height) 763 | // .style("stroke", "rgb(255,255,255)") 764 | // .style("opacity", 0.85); 765 | 766 | updateSubsetLabels(); 767 | updateSubsetTotal(); 768 | 769 | }; 770 | 771 | }); -------------------------------------------------------------------------------- /public/scripts/main/services/leftService.js: -------------------------------------------------------------------------------- 1 | coaxsApp.service('leftService', function (leafletData) { 2 | 3 | this.updateLeftRoutes = function (combo, variants, routesLayer, geoJsonLeft, cb) { 4 | leafletData.getMap('map_left').then(function(map) { 5 | if (geoJsonLeft) { map.removeLayer(geoJsonLeft); } 6 | var geoJson = L.geoJson(); 7 | routesLayer.eachLayer(function (layer) { 8 | var currenCor = layer.options.base.corName; 9 | var variantName = combo.sel[currenCor]; 10 | var variant = variantName ? variants[currenCor].all[variantName] : null; 11 | 12 | if (variant && variant.routeId == layer.options.base.routeId) { 13 | geoJson.addData({ 14 | 'type' : 'Feature', 15 | 'properties' : layer.options.base, 16 | 'geometry' : layer.toGeoJSON().features[0].geometry, 17 | }); 18 | } 19 | }); 20 | 21 | geoJson.eachLayer(function(layer) { 22 | layer.setStyle({ 23 | color : '#' + layer.feature.properties.routeColor, 24 | weight : 1, 25 | }); 26 | }) 27 | 28 | geoJson.addTo(map); 29 | cb(geoJson); 30 | }) 31 | }; 32 | 33 | 34 | this.targetPOIUsers = function (poiUsers, id) { 35 | poiUsers.eachLayer( function (layer) { 36 | if (layer.userId == id) { layer.setOpacity(1); } 37 | else { layer.setOpacity(0); } 38 | }); 39 | } 40 | 41 | }); 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /public/scripts/main/services/loadService.js: -------------------------------------------------------------------------------- 1 | // all of these have been explained in main controller, this is simple the services portion and each function 2 | // roughly shares the same name 3 | // here, in the service, is the boilerplate involved in interfacing with leaflet's api and putting the actual marker or route on the map 4 | coaxsApp.service('loadService', function ($q, $http, analystService, leafletData, targetService, supportService) { 5 | 6 | this.getCordons = function (cb) { 7 | 8 | $http.get('/geojson/cordons') 9 | .success(function (data, status) { 10 | cordonGeos = L.layerGroup(); 11 | var cordonData = {}; //new Array(numCordons); 12 | for (cordonId in data){ 13 | cordonGeos.addLayer( 14 | L.geoJson(data[cordonId], 15 | {style: {weight: 1.5, 16 | opacity:0, 17 | fillOpacity:0, 18 | id: cordonId, 19 | dashArray: 3, 20 | color: data[cordonId].features[0].properties.color}})); 21 | cordonData[cordonId] = data[cordonId].features[0].properties; 22 | } 23 | cb([cordonGeos,cordonData]); 24 | }); 25 | } 26 | 27 | this.getExisting = function (cb, gs) { 28 | $http.get('/geojson/existing') 29 | .success(function (data, status) { 30 | var subwayRoutes = L.geoJson(data, { 31 | style: function (feature, grayscale) { 32 | var col = "#AAAAAA"; 33 | if (!gs){col = feature.properties.COLOR;} 34 | return { 35 | color : col, 36 | weight : 1.5, 37 | opacity : 0.5, 38 | dashArray : 0, 39 | }; 40 | } 41 | }); 42 | cb(subwayRoutes); 43 | }); 44 | }; 45 | 46 | this.getProposedPriorityLanes = function (cb) { 47 | $http.get('/geojson/proposed_priority') 48 | .success(function (data, status) { 49 | var geojsonList = []; 50 | var routes = {}; 51 | for (var i = 0; i < data.features.length; i++) { 52 | var feature = data.features[i].properties; 53 | if (!routes[feature.routeId]) { routes[feature.routeId] = {} }; 54 | var color = '#' + feature.routeColor; 55 | routes[feature.routeId][feature.direction] = L.geoJson(data.features[i], { 56 | style: function (feature) { 57 | return { color: color, 58 | weight: 16, 59 | opacity: 0 60 | }; 61 | }, 62 | base: feature 63 | }); 64 | geojsonList.push(routes[feature.routeId][feature.direction]); 65 | } 66 | 67 | var priorityLayer = L.layerGroup(geojsonList); 68 | cb(priorityLayer); 69 | }); 70 | }; 71 | 72 | 73 | 74 | 75 | this.getProposedRoutes = function (cb,variants) { 76 | $http.get('/load/routes') 77 | .success(function (data, status) { 78 | var geojsonList = []; 79 | var routes = {}; 80 | 81 | for (var i = 0; i < data.features.length; i++) { 82 | var feature = data.features[i].properties; 83 | feature['length'] = supportService.getLength(data.features[i].geometry); 84 | 85 | if (!routes[feature.pid]) { routes[feature.pid] = {} }; 86 | var color = variants[feature.corridorId].color; 87 | routes[feature.pid] = L.geoJson(data.features[i], { 88 | style: function (feature) { 89 | return { 90 | color: color, 91 | weight: 1, 92 | opacity: 0.5 93 | }; 94 | }, 95 | base: feature 96 | }); 97 | 98 | geojsonList.push(routes[feature.pid]); 99 | } 100 | var routesLayer = L.layerGroup(geojsonList); 101 | cb({layerGroup:L.layerGroup(geojsonList), geoJsons:routes}); 102 | 103 | }); 104 | }; 105 | 106 | this.getTrunk = function (cb,variants) { 107 | $http.get('/load/trunks') 108 | .success(function (data, status) { 109 | var geojsonList = []; 110 | var routes = {}; 111 | 112 | for (var i = 0; i < data.features.length; i++) { 113 | var feature = data.features[i].properties; 114 | feature['length'] = supportService.getLength(data.features[i].geometry); 115 | 116 | var color = variants[feature.corridorId].color; 117 | routes[i] = L.geoJson(data.features[i], { 118 | style: function (feature) { 119 | return { 120 | color: color, 121 | weight: 10, 122 | opacity: 0.4 123 | }; 124 | }, 125 | base: feature 126 | }); 127 | 128 | geojsonList.push(routes[i]); 129 | } 130 | var routesLayer = L.layerGroup(geojsonList); 131 | cb({layerGroup:L.layerGroup(geojsonList), geoJsons:routes}); 132 | 133 | }); 134 | }; 135 | 136 | this.getTrunkforleft = function (cb,variants) { 137 | $http.get('/load/trunks') 138 | .success(function (data, status) { 139 | var geojsonList = []; 140 | var routes = {}; 141 | 142 | for (var i = 0; i < data.features.length; i++) { 143 | var feature = data.features[i].properties; 144 | feature['length'] = supportService.getLength(data.features[i].geometry); 145 | 146 | var color = variants[feature.corridorId].color; 147 | routes[i] = L.geoJson(data.features[i], { 148 | style: function (feature) { 149 | return { 150 | color: color, 151 | weight: 10, 152 | opacity: 0.4 153 | }; 154 | }, 155 | base: feature 156 | }); 157 | 158 | geojsonList.push(routes[i]); 159 | } 160 | var routesLayer = L.layerGroup(geojsonList); 161 | cb({layerGroup:L.layerGroup(geojsonList), geoJsons:routes}); 162 | 163 | }); 164 | }; 165 | 166 | this.getStops = function (url, cb) { 167 | $http.get(url) 168 | .success(function (data, status) { 169 | 170 | var stopList = []; 171 | 172 | for (var i=0; i.dropdown-toggle.btn-default{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default:active:hover,.btn-default.active:hover,.open>.dropdown-toggle.btn-default:hover,.btn-default:active:focus,.btn-default.active:focus,.open>.dropdown-toggle.btn-default:focus,.btn-default:active.focus,.btn-default.active.focus,.open>.dropdown-toggle.btn-default.focus{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default:active,.btn-default.active,.open>.dropdown-toggle.btn-default{background-image:none}.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled.focus,.btn-default[disabled].focus,fieldset[disabled] .btn-default.focus{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#337ab7;border-color:#2e6da4}.btn-primary:focus,.btn-primary.focus{color:#fff;background-color:#286090;border-color:#122b40}.btn-primary:hover{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{color:#fff;background-color:#286090;border-color:#204d74}.btn-primary:active:hover,.btn-primary.active:hover,.open>.dropdown-toggle.btn-primary:hover,.btn-primary:active:focus,.btn-primary.active:focus,.open>.dropdown-toggle.btn-primary:focus,.btn-primary:active.focus,.btn-primary.active.focus,.open>.dropdown-toggle.btn-primary.focus{color:#fff;background-color:#204d74;border-color:#122b40}.btn-primary:active,.btn-primary.active,.open>.dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled.focus,.btn-primary[disabled].focus,fieldset[disabled] .btn-primary.focus{background-color:#337ab7;border-color:#2e6da4}.btn-primary .badge{color:#337ab7;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:focus,.btn-success.focus{color:#fff;background-color:#449d44;border-color:#255625}.btn-success:hover{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{color:#fff;background-color:#449d44;border-color:#398439}.btn-success:active:hover,.btn-success.active:hover,.open>.dropdown-toggle.btn-success:hover,.btn-success:active:focus,.btn-success.active:focus,.open>.dropdown-toggle.btn-success:focus,.btn-success:active.focus,.btn-success.active.focus,.open>.dropdown-toggle.btn-success.focus{color:#fff;background-color:#398439;border-color:#255625}.btn-success:active,.btn-success.active,.open>.dropdown-toggle.btn-success{background-image:none}.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled.focus,.btn-success[disabled].focus,fieldset[disabled] .btn-success.focus{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:focus,.btn-info.focus{color:#fff;background-color:#31b0d5;border-color:#1b6d85}.btn-info:hover{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{color:#fff;background-color:#31b0d5;border-color:#269abc}.btn-info:active:hover,.btn-info.active:hover,.open>.dropdown-toggle.btn-info:hover,.btn-info:active:focus,.btn-info.active:focus,.open>.dropdown-toggle.btn-info:focus,.btn-info:active.focus,.btn-info.active.focus,.open>.dropdown-toggle.btn-info.focus{color:#fff;background-color:#269abc;border-color:#1b6d85}.btn-info:active,.btn-info.active,.open>.dropdown-toggle.btn-info{background-image:none}.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled.focus,.btn-info[disabled].focus,fieldset[disabled] .btn-info.focus{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:focus,.btn-warning.focus{color:#fff;background-color:#ec971f;border-color:#985f0d}.btn-warning:hover{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{color:#fff;background-color:#ec971f;border-color:#d58512}.btn-warning:active:hover,.btn-warning.active:hover,.open>.dropdown-toggle.btn-warning:hover,.btn-warning:active:focus,.btn-warning.active:focus,.open>.dropdown-toggle.btn-warning:focus,.btn-warning:active.focus,.btn-warning.active.focus,.open>.dropdown-toggle.btn-warning.focus{color:#fff;background-color:#d58512;border-color:#985f0d}.btn-warning:active,.btn-warning.active,.open>.dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled.focus,.btn-warning[disabled].focus,fieldset[disabled] .btn-warning.focus{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:focus,.btn-danger.focus{color:#fff;background-color:#c9302c;border-color:#761c19}.btn-danger:hover{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{color:#fff;background-color:#c9302c;border-color:#ac2925}.btn-danger:active:hover,.btn-danger.active:hover,.open>.dropdown-toggle.btn-danger:hover,.btn-danger:active:focus,.btn-danger.active:focus,.open>.dropdown-toggle.btn-danger:focus,.btn-danger:active.focus,.btn-danger.active.focus,.open>.dropdown-toggle.btn-danger.focus{color:#fff;background-color:#ac2925;border-color:#761c19}.btn-danger:active,.btn-danger.active,.open>.dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled.focus,.btn-danger[disabled].focus,fieldset[disabled] .btn-danger.focus{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#337ab7;font-weight:400;border-radius:0}.btn-link,.btn-link:active,.btn-link.active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#23527c;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#777;text-decoration:none}.btn-lg,.btn-group-lg>.btn{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:6px}.btn-sm,.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs,.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-top-left-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-top-left-radius:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn input[type=radio],[data-toggle=buttons]>.btn-group>.btn input[type=radio],[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=checkbox]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.42857143;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:14px;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition-property:height,visibility;transition-property:height,visibility;-webkit-transition-duration:.35s;transition-duration:.35s;-webkit-transition-timing-function:ease;transition-timing-function:ease}.tour-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1100;background-color:#000;opacity:.8;filter:alpha(opacity=80)}.tour-step-backdrop{position:relative;z-index:1101}.tour-step-backdrop>td{position:relative;z-index:1101}.tour-step-background{position:absolute!important;z-index:1100;background:inherit;border-radius:6px}.popover[class*=tour-]{z-index:1102}.popover[class*=tour-] .popover-navigation{padding:9px 14px;overflow:hidden}.popover[class*=tour-] .popover-navigation [data-role=end]{float:right}.popover[class*=tour-] .popover-navigation [data-role=prev],.popover[class*=tour-] .popover-navigation [data-role=next],.popover[class*=tour-] .popover-navigation [data-role=end]{cursor:pointer}.popover[class*=tour-] .popover-navigation [data-role=prev].disabled,.popover[class*=tour-] .popover-navigation [data-role=next].disabled,.popover[class*=tour-] .popover-navigation [data-role=end].disabled{cursor:default}.popover[class*=tour-].orphan{position:fixed;margin-top:0}.popover[class*=tour-].orphan .arrow{display:none} -------------------------------------------------------------------------------- /public/style/d3.css: -------------------------------------------------------------------------------- 1 | /* stylings for d3 svg graph */ 2 | 3 | .axis path, .axis line { 4 | fill: none; 5 | stroke: #CCC; 6 | shape-rendering: crispEdges; 7 | } 8 | 9 | .axis text { 10 | font-family: 'Arial'; 11 | font-size: 12px; 12 | fill: #EEE; 13 | } 14 | 15 | .stat { 16 | font-size: 14px; 17 | fill: #FFF; 18 | } 19 | 20 | .line { 21 | fill: none; 22 | stroke: #FDB813; 23 | stroke-width: 2px; 24 | } 25 | 26 | .lineC { 27 | fill: none; 28 | stroke: #89cff0; 29 | stroke-width: 2px; 30 | } 31 | 32 | .title text { 33 | fill: #FFF; 34 | font-size: 20px; 35 | } 36 | 37 | #tooltip { 38 | position: absolute; 39 | text-align: center; 40 | width: 190px; 41 | height: auto; 42 | padding: 10px; 43 | background-color: white; 44 | -webkit-border-radius: 10px; 45 | -moz-border-radius: 10px; 46 | border-radius: 10px; 47 | -webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); 48 | -moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); 49 | box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4); 50 | pointer-events: none; 51 | } 52 | #tooltip.hidden { 53 | display: none; 54 | } 55 | #tooltip p { 56 | margin: 0; 57 | font-family: sans-serif; 58 | font-size: 12px; 59 | line-height: 14px; 60 | color: #000; 61 | } -------------------------------------------------------------------------------- /public/style/leaflet-search.css: -------------------------------------------------------------------------------- 1 | 2 | .leaflet-container .leaflet-control-search { 3 | position:relative; 4 | float:left; 5 | background:#fff; 6 | color:#1978cf; 7 | -moz-border-radius: 4px; 8 | -webkit-border-radius: 4px; 9 | border-radius: 4px; 10 | background-color: rgba(255, 255, 255, 0.8); 11 | z-index:1000; 12 | box-shadow: 0 1px 7px rgba(0,0,0,0.65); 13 | margin-left: 10px; 14 | margin-top: 10px; 15 | } 16 | .leaflet-control-search.search-exp {/*expanded*/ 17 | box-shadow: 0 1px 7px #999; 18 | background: #fff; 19 | } 20 | .leaflet-control-search .search-input { 21 | display:block; 22 | float:left; 23 | background: #fff; 24 | border:1px solid #666; 25 | border-radius:2px; 26 | height:18px; 27 | padding:0 18px 0 2px; 28 | margin:3px 0 3px 3px; 29 | } 30 | .leaflet-control-search.search-load .search-input { 31 | background: url('../images/loader.gif') no-repeat center right #fff; 32 | } 33 | .leaflet-control-search.search-load .search-cancel { 34 | visibility:hidden; 35 | } 36 | .leaflet-control-search .search-cancel { 37 | display:block; 38 | width:22px; 39 | height:18px; 40 | position:absolute; 41 | right:22px; 42 | margin:3px 0; 43 | background: url('../images/search-icon.png') no-repeat 0 -46px; 44 | text-decoration:none; 45 | filter: alpha(opacity=80); 46 | opacity: 0.8; 47 | } 48 | .leaflet-control-search .search-cancel:hover { 49 | filter: alpha(opacity=100); 50 | opacity: 1; 51 | } 52 | .leaflet-control-search .search-cancel span { 53 | display:none;/* comment for cancel button imageless */ 54 | font-size:18px; 55 | line-height:20px; 56 | color:#ccc; 57 | font-weight:bold; 58 | } 59 | .leaflet-control-search .search-cancel:hover span { 60 | color:#aaa; 61 | } 62 | .leaflet-control-search .search-button { 63 | display:block; 64 | float:left; 65 | width:26px; 66 | height:26px; 67 | background: url('../images/search-icon.png') no-repeat 2px 2px #fff; 68 | border-radius:4px; 69 | } 70 | .leaflet-control-search .search-button:hover { 71 | background: url('../images/search-icon.png') no-repeat 2px -22px #fafafa; 72 | } 73 | .leaflet-control-search .search-tooltip { 74 | position:absolute; 75 | top:100%; 76 | left:0; 77 | float:left; 78 | list-style: none; 79 | padding-left: 0; 80 | min-width:120px; 81 | max-height:122px; 82 | box-shadow: 1px 1px 6px rgba(0,0,0,0.4); 83 | background-color: rgba(0, 0, 0, 0.25); 84 | z-index:1010; 85 | overflow-y:auto; 86 | overflow-x:hidden; 87 | cursor: pointer; 88 | } 89 | .leaflet-control-search .search-tip { 90 | margin:2px; 91 | padding:2px 4px; 92 | display:block; 93 | color:black; 94 | background: #eee; 95 | border-radius:.25em; 96 | text-decoration:none; 97 | white-space:nowrap; 98 | vertical-align:center; 99 | } 100 | .leaflet-control-search .search-button:hover { 101 | background-color: #f4f4f4; 102 | } 103 | .leaflet-control-search .search-tip-select, 104 | .leaflet-control-search .search-tip:hover { 105 | background-color: #fff; 106 | } 107 | .leaflet-control-search .search-alert { 108 | cursor:pointer; 109 | clear:both; 110 | font-size:.75em; 111 | margin-bottom:5px; 112 | padding:0 .25em; 113 | color:#e00; 114 | font-weight:bold; 115 | border-radius:.25em; 116 | } 117 | 118 | 119 | -------------------------------------------------------------------------------- /public/style/leaflet-search.mobile.css: -------------------------------------------------------------------------------- 1 | 2 | /* SEARCH */ 3 | .leaflet-control.leaflet-control-search { 4 | z-index:2000; 5 | } 6 | .leaflet-control-search .search-input { 7 | display:block; 8 | float:left; 9 | background: #fff; 10 | border:1px solid #666; 11 | border-radius:2px; 12 | height:24px; 13 | font-size:1.25em; 14 | padding:0 .125em; 15 | margin:3px; 16 | padding-right:30px; 17 | } 18 | .leaflet-control-search .search-button:hover, 19 | .leaflet-control-search .search-button { 20 | background-image: url('../images/search-icon-mobile.png'); 21 | -webkit-border-radius: 4px; 22 | border-radius: 4px; 23 | background-position: 1px 1px; 24 | width:32px; 25 | height:32px; 26 | } 27 | .leaflet-control-search.search-load .search-input { 28 | background: url('../images/loader.gif') no-repeat center right #fff; 29 | } 30 | .leaflet-control-search .search-cancel { 31 | background-image: url('../images/search-icon-mobile.png'); 32 | -webkit-border-radius: 4px; 33 | border-radius: 4px; 34 | background-position: 0px -62px; 35 | width:26px; 36 | height:26px; 37 | right:34px; 38 | margin:3px; 39 | } 40 | .leaflet-control-search .search-tooltip { 41 | max-height:142px;/*(.search-tip height * 5)*/ 42 | } 43 | .leaflet-control-search .search-tip { 44 | font-size:1em; 45 | margin:2px; 46 | padding:2px; 47 | display:block; 48 | color:black; 49 | background: rgba(255,255,255,0.8); 50 | border-radius:.25em; 51 | text-decoration:none; 52 | white-space:nowrap; 53 | vertical-align:center; 54 | } 55 | .leaflet-control-search .search-tip .climbo-icon-mini { 56 | float:right; 57 | display:block; 58 | white-space:nowrap; 59 | } 60 | .leaflet-control-search .search-button:hover, 61 | .leaflet-control-search .search-tip-select, 62 | .leaflet-control-search .search-tip:hover { 63 | background-color: #fff; 64 | } 65 | .leaflet-control-search .search-alert { 66 | font-size:1.2em; 67 | } -------------------------------------------------------------------------------- /public/style/main.css: -------------------------------------------------------------------------------- 1 | /* main css for angular app */ 2 | 3 | body { 4 | word-wrap : break-word; 5 | background-color : #F5F5F3; 6 | color: #4D4D4D; 7 | -moz-user-select : none; 8 | -webkit-user-select : none; 9 | -ms-user-select : none; 10 | user-select : none; 11 | -o-user-select : none; 12 | min-height: 680; 13 | min-width: 1280; 14 | } 15 | 16 | /*bs modification*/ 17 | .btn { 18 | border-radius: 0px; 19 | text-align: left; 20 | } 21 | 22 | button { 23 | cursor: pointer; 24 | } 25 | .badge { 26 | background-color: #FFF; 27 | color: #5D5D5D; 28 | cursor: pointer; 29 | } 30 | .form-control { 31 | border-width : 0px; 32 | border-radius : 0px; 33 | } 34 | .btn-savealt { 35 | background-color : #1fa67a; 36 | border-width : 1px; 37 | } 38 | 39 | .tiny { 40 | background-color: #959595; 41 | width: 100% 42 | 43 | } 44 | 45 | .btn-savealt.active, .btn-savealt.focus, .btn-savealt.hover, .btn-savealt:active, .btn-savealt:focus, .btn-savealt:hover { 46 | color : #FFF; 47 | border-left-width: 0px; 48 | } 49 | .btn-choose.active, .btn-choose.focus, .btn-choose.hover, .btn-choose:active, .btn-choose:focus, .btn-choose:hover { 50 | color : #FFF; 51 | } 52 | .table-hover tbody tr:hover td, .table-hover tbody tr:hover th { 53 | background-color: rgb(220, 220, 220); 54 | } 55 | .fa .pull-right { 56 | line-height: inherit; 57 | } 58 | i.fa { 59 | cursor: pointer; 60 | } 61 | 62 | .blink { 63 | animation: blinker 2s linear infinite; 64 | } 65 | 66 | @keyframes blinker { 67 | 50% { opacity: 0; } 68 | } 69 | 70 | 71 | /*navigation*/ 72 | nav { 73 | position : absolute; 74 | width : 50%; 75 | left : 50%; 76 | z-index : 100; 77 | color : #FFF; 78 | background-color : #000; 79 | height : 32; 80 | overflow : hidden; 81 | } 82 | nav div.section { 83 | background-color : #000; 84 | float : right; 85 | padding-left : 10px; 86 | padding-right : 10px; 87 | cursor : pointer; 88 | } 89 | .topcol { 90 | position: absolute; 91 | color: #FFF; 92 | width: 100%; 93 | } 94 | .topcol h1, .topcol h2, .topcol h3, .topcol h4, .topcol h5, .topcol h6 { 95 | padding-left: 20px; 96 | padding-right: 20px; 97 | } 98 | 99 | .topright { 100 | width: 50%; 101 | width: -moz-calc(100% - 300px); 102 | width: calc(100% - 300px); 103 | position : absolute; 104 | left : 300px; 105 | overflow : auto; 106 | z-index: 999; 107 | background-color : #696969 108 | } 109 | 110 | .route-base { 111 | width: 50%; 112 | display:inline-block; 113 | text-align:center 114 | } 115 | 116 | /* .routeData-table th{ 117 | width:300px; 118 | padding-left:25px; 119 | text-align: center; 120 | } */ 121 | 122 | .routeData-table .route:nth-child(odd) { 123 | background: #DDD; 124 | } 125 | 126 | .topleft { 127 | width : 300px; 128 | overflow : hidden; 129 | z-index: 10; 130 | background-color : #696969 131 | } 132 | .topinfo { 133 | background-color : #5F0D0A; 134 | } 135 | .topinfo-body { 136 | background-color : rgba(255,255,255,0.2); 137 | margin-bottom : 5px; 138 | width : 100%; 139 | overflow-x : auto; 140 | } 141 | .topnav { 142 | position : absolute; 143 | padding : 10px; 144 | z-index : 10; 145 | cursor : pointer; 146 | width : 62%; 147 | right : 0px; 148 | } 149 | 150 | .topnav .legend { 151 | width: 275px; 152 | height: 150px; 153 | top: 0px; 154 | right: 0px; 155 | position: absolute; 156 | margin-top: 10px; 157 | margin-right: 12px; 158 | } 159 | 160 | .bottomCol { 161 | position: absolute; 162 | color: #FFF; 163 | z-index: 95; 164 | width: 100%; 165 | bottom: 25%; 166 | } 167 | .bottomCol h1, .bottomCol h2, .bottomCol h3, .bottomCol h4, .bottomCol h5, .bottomCol h6, .introPan h4 { 168 | padding-left: 15px; 169 | padding-right: 15px; 170 | } 171 | .bottomCol .saveComb{ 172 | position: absolute; 173 | background-color : rgba(211,211,211,0.975); 174 | overflow : hidden; 175 | height: 1000px; 176 | width: 995px; 177 | width: -moz-calc(50% + 35px); 178 | width: calc(50% + 35px); 179 | bottom: 0px; 180 | z-index: 10; 181 | } 182 | 183 | .introPan{ 184 | position: absolute; 185 | color: #FFF; 186 | right: 0px; 187 | top: 0px; 188 | background-color : rgba(211,211,211,0.975); 189 | overflow : hidden; 190 | height: 75%; 191 | width: 50%; 192 | width: -moz-calc(50% + 2px); 193 | width: calc(50% + 2px); 194 | z-index: 10; 195 | box-shadow: 0px 0px 4px rgba(0,0,0,0.1); 196 | } 197 | 198 | .introPan ol , .introPan ul { 199 | line-height: 1.2; 200 | } 201 | 202 | .bottomCol .saveComb .title{ 203 | position: absolute; 204 | background-color : #696969; 205 | overflow : hidden; 206 | width: 100%; 207 | bottom: 0px; 208 | box-shadow: 0px 0px 4px rgba(0,0,0,0.1); 209 | } 210 | 211 | .introPan .title { 212 | position: absolute; 213 | background-color : #696969; 214 | overflow : hidden; 215 | width: 100%; 216 | top: 0px; 217 | box-shadow: 0px 0px 4px rgba(0,0,0,0.1); 218 | } 219 | 220 | .introPan h4{ 221 | margin-left: 4px; 222 | } 223 | 224 | .introPan .station-list{ 225 | position: absolute; 226 | bottom: 25px; 227 | margin-left: 45px; 228 | } 229 | 230 | .bottomCol .saveVar{ 231 | position: absolute; 232 | right: 0px; 233 | background-color : #696969; 234 | overflow : hidden; 235 | width: 960px; 236 | width: -moz-calc(50% - 35px); 237 | width: calc(50% - 35px); 238 | bottom: 0px; 239 | } 240 | 241 | .input-group{ 242 | width: 90% 243 | } 244 | 245 | .col-head-button{ 246 | background-color : #696969; 247 | } 248 | 249 | .saveAlt-body { 250 | background-color : #b4b4b4; 251 | width : 100%; 252 | } 253 | 254 | .legend .panel { 255 | border-radius: 0px 256 | } 257 | 258 | .legend .panel-heading { 259 | padding-top: 8px; 260 | padding-bottom: 8px; 261 | } 262 | .legend .panel-title { 263 | font-size: 0.8em; 264 | } 265 | .legend .panel-body { 266 | padding-top: 5px; 267 | padding-bottom: 5px; 268 | } 269 | 270 | .right { 271 | left : 50%; 272 | } 273 | .unselected { 274 | opacity : 0.5; 275 | } 276 | 277 | /* in app navigation */ 278 | .progress { 279 | border-radius: 0px; 280 | margin: 0px 0px 0px 0px; 281 | overflow: hidden; 282 | position: absolute; 283 | width: 100%; 284 | top: 75%; 285 | height: 25%; 286 | z-index: 100; 287 | background-color: #ff7f7f; 288 | } 289 | 290 | .leftNav { 291 | text-align: center; 292 | position: absolute; 293 | max-height: 65%; 294 | bottom: 27vh; 295 | left: 300px; 296 | display: inline; 297 | 298 | } 299 | 300 | .leftNav .badge { 301 | text-align: center; 302 | display: block; 303 | margin: 8px; 304 | cursor: pointer; 305 | background-color: orange; 306 | font-size: 0.65em; 307 | left: 300px; 308 | 309 | } 310 | 311 | .introPan .badge { 312 | text-align: center; 313 | margin: 4px; 314 | background-color: orange; 315 | font-size: 0.65em; 316 | } 317 | 318 | .bottomNav { 319 | position: absolute; 320 | background-color: #d3d3d3; 321 | bottom: 0px; 322 | height: 27vh; 323 | min-height: 150px; 324 | overflow: hidden; 325 | padding-top: 28px; 326 | z-index: 10; 327 | } 328 | 329 | .bottomNav .colBody { 330 | height: 100%; 331 | float: left; 332 | width: 300px; 333 | overflow-x: hidden; 334 | overflow-y: hidden; 335 | cursor: pointer; 336 | z-index: 5; 337 | box-shadow: 0px 0px 4px rgba(0,0,0,0.1); 338 | } 339 | 340 | .colBody .placeHolder { 341 | font-size: 7em; 342 | height:100%; 343 | width:100%; 344 | display: table; 345 | overflow-y: hidden; 346 | } 347 | 348 | 349 | .placeHolder .bigText { 350 | display: table-cell; 351 | vertical-align: middle; 352 | text-align:center; 353 | } 354 | 355 | .colBody .colHead { 356 | height: 28px; 357 | line-height: 28px; 358 | background-color: #696969; 359 | position: absolute;; 360 | top: 0px; 361 | width: inherit; 362 | text-align: center; 363 | color: white; 364 | btn box-shadow: 0px 5px 3px rgba(0,0,0,0.25); 365 | z-index: 99; 366 | } 367 | 368 | .btn .small{ 369 | height: 20px; 370 | 371 | 372 | } 373 | 374 | #service-tab { 375 | width: 450px; 376 | } 377 | 378 | .colBody .subHead { 379 | overflow: hidden; 380 | height: 18px; 381 | line-height: 18px; 382 | padding: 0px 8px 0px 8px; 383 | background-color: #b4b4b4; 384 | text-align: left; 385 | font-size: 12px; 386 | color: white; 387 | cursor: pointer; 388 | } 389 | 390 | .colBody .setTimesTitle { 391 | padding: 0px 8px 0px 8px; 392 | margin: 5px 0px 0px 0px; 393 | } 394 | 395 | .setTimesTitle h6 { 396 | margin: 2px 0px 5px 0px; 397 | } 398 | 399 | .colBody .bottomFixed { 400 | position:absolute; 401 | bottom: 0px; 402 | margin: 0px 0px 5px 0px; 403 | width: inherit; 404 | } 405 | 406 | .bottomNav:not(:first-child) .colHead { 407 | border: 0px solid #7e7e7e; 408 | border-right-width: 1px; 409 | } 410 | .bottomNav:not(:first-child) .colBody { 411 | border: 0px solid #d3d3d3; 412 | border-right-width: 0px; 413 | } 414 | 415 | .bottomNav .table { 416 | font-size: 0.75em; 417 | } 418 | 419 | .bottomNav .setTimesTitle .left{ 420 | position: absolute; 421 | left: 0px; 422 | width: 49%; 423 | } 424 | 425 | .bottomNav .setTimesTitle .right{ 426 | float: right; 427 | width: 70%; 428 | margin-top: 5px; 429 | } 430 | 431 | 432 | .bottomNav .isosRange { 433 | margin: 2px; 434 | } 435 | 436 | .colBody .smallColVal { 437 | text-align: left; 438 | padding: 0px 0px 0px 0px; 439 | } 440 | 441 | .colBody .showToggle { 442 | height: inherit; 443 | width: inherit; 444 | padding: inherit; 445 | overflow: hidden; 446 | position: relative; 447 | } 448 | 449 | .colBody .scenariosTable { 450 | overflow-y: hidden; 451 | overflow-x: auto; 452 | height: inherit; 453 | } 454 | 455 | .scenarioEntries { 456 | margin-left:24px; 457 | height:100%; 458 | width:10000px; 459 | overflow-y:auto; 460 | overflow-x:auto; 461 | } 462 | 463 | .scenariosTable .square { 464 | color: rgba(255,255,255,1); 465 | height: 18px; 466 | line-height: 18px; 467 | width: 18px; 468 | overflow: hidden; 469 | font-size: 10px; 470 | text-align: center; 471 | margin-bottom: 2px; 472 | top: 2px; 473 | } 474 | 475 | .scenariosTable .scenario { 476 | padding: 0px 3px 0px 3px; 477 | position: relative; 478 | float: left; 479 | width: 150px; 480 | height: inherit; 481 | white-space: nowrap; 482 | z-index: 9; 483 | overflow: hidden; 484 | } 485 | 486 | .scenario .subHead { 487 | margin:0px -3px 0px -3px; 488 | background-color: rgba(255,165,0,0.5) 489 | } 490 | 491 | .scenariosTable .selected { 492 | background-color: rgba(255,165,0,0.5) !important; 493 | } 494 | 495 | .scenariosTable .cselected { 496 | background-color: rgba(137,207,240,0.5) !important; 497 | } 498 | 499 | .scenariosTable .scenario:nth-child(odd) { 500 | background: #DDD; 501 | } 502 | 503 | 504 | .noTopMargin { 505 | margin-top : 0px; 506 | } 507 | .noBottomMargin { 508 | margin-bottom : 0px; 509 | } 510 | 511 | 512 | /*leaflet map*/ 513 | .icon-off { 514 | display: none; 515 | } 516 | .icon-on { 517 | display: inline; 518 | } 519 | 520 | 521 | .station-sign .leaflet-popup-content-wrapper { 522 | padding: 0px; 523 | text-align: center; 524 | border-radius: 0px; 525 | } 526 | 527 | .station-sign .leaflet-popup-content { 528 | margin: 0px; 529 | line-height: 1; 530 | } 531 | 532 | .station-sign .leaflet-popup-content p { 533 | margin: 0px 0; 534 | color: white; 535 | background-color: black; 536 | text-transform: uppercase; 537 | padding-left: 15px; 538 | padding-right: 15px; 539 | padding-top: 5px; 540 | padding-bottom: 5px; 541 | text-align: center; 542 | } 543 | 544 | .station-sign .leaflet-popup-content .blackText { 545 | color: black; 546 | } 547 | 548 | input { 549 | border: none; 550 | background: transparent; 551 | } 552 | 553 | /*maps*/ 554 | .angular-leaflet-map { 555 | height : 73%; 556 | /*width: 50%;*/ 557 | /*width: -moz-calc(100% - 300px);*/ 558 | width: calc(100% - 300px); 559 | position : absolute; 560 | left : 300px; 561 | z-index : 9 562 | } 563 | 564 | #map_right { 565 | height : 73%; 566 | /*width: 50%;*/ 567 | /*width: -moz-calc(100% - 300px);*/ 568 | width: calc(100% - 300px); 569 | position : absolute; 570 | left : 300px; 571 | z-index : 10 572 | } 573 | 574 | 575 | .leaflet-container { 576 | background : -webkit-linear-gradient( #CDD2D4, #F5F5F3) !important; /* For Safari 5.1 to 6.0 */ 577 | background : -o-linear-gradient( #CDD2D4, #F5F5F3) !important; /* For Opera 11.1 to 12.0 */ 578 | background : -moz-linear-gradient( #CDD2D4, #F5F5F3) !important; /* For Firefox 3.6 to 15 */ 579 | background : linear-gradient( #CDD2D4, #F5F5F3) !important; /* Standard syntax */ 580 | } 581 | 582 | .missed-train{ 583 | background-color: rgba(36,200,100,0.5); 584 | } 585 | 586 | .missed-bus{ 587 | background-color: rgba(36,100,200,0.5); 588 | } 589 | 590 | .projects { 591 | margin-top : 550px; 592 | } 593 | .project-cards .panel-default { 594 | color : #000; 595 | } 596 | .project-cards .panel-default:hover { 597 | background-color : #ff4500; 598 | color : #FFF; 599 | } 600 | 601 | 602 | .card{ 603 | width: 25px; 604 | 605 | height: 25px; 606 | 607 | display: inline-table; 608 | 609 | background-color: #959595; 610 | 611 | background-size: 100%; 612 | 613 | background-repeat: no-repeat; 614 | 615 | margin: 5px 5px 5px 5px; 616 | 617 | text-align: center; 618 | vertical-align: middle; 619 | border-radius: 5px; 620 | } -------------------------------------------------------------------------------- /public/style/slider.css: -------------------------------------------------------------------------------- 1 | /* this css is exclusively to customize the range sliders so that they can look consistent across browsers */ 2 | 3 | input[type=range] { 4 | -webkit-appearance: none; 5 | margin: 0px 0; 6 | width: 100%; 7 | } 8 | input[type=range]:focus { 9 | outline: none; 10 | } 11 | input[type=range]::-webkit-slider-runnable-track { 12 | width: 100%; 13 | height: 1.5vh; 14 | cursor: pointer; 15 | animate: 0.2s; 16 | box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d; 17 | background: #DBDBDB; 18 | border-radius: 0px; 19 | border: 1px solid #252525; 20 | } 21 | input[type=range]::-webkit-slider-thumb { 22 | box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d; 23 | border: 1px solid #353535; 24 | height: 2.2vh; 25 | width: 2.2vh; 26 | border-radius: 0px; 27 | background: #808080; 28 | cursor: pointer; 29 | -webkit-appearance: none; 30 | margin-top: -3.6px; 31 | } 32 | input[type=range]:focus::-webkit-slider-runnable-track { 33 | background: #DBDBDB; 34 | } 35 | input[type=range]::-moz-range-track { 36 | width: 100%; 37 | height: 1.5vh; 38 | cursor: pointer; 39 | animate: 0.2s; 40 | box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d; 41 | background: #DBDBDB; 42 | border-radius: 0px; 43 | border: 1px solid #252525; 44 | } 45 | input[type=range]::-moz-range-thumb { 46 | box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d; 47 | border: 1px solid #353535; 48 | height: 2.2vh; 49 | width: 2.2vh; 50 | border-radius: 0px; 51 | background: #808080; 52 | cursor: pointer; 53 | } 54 | input[type=range]::-ms-track { 55 | width: 100%; 56 | height: 1.5vh; 57 | cursor: pointer; 58 | animate: 0.2s; 59 | background: transparent; 60 | border-color: transparent; 61 | border-width: 39px 0; 62 | color: transparent; 63 | } 64 | input[type=range]::-ms-fill-lower { 65 | background: #DBDBDB; 66 | border: 1px solid #252525; 67 | border-radius: 0px; 68 | box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d; 69 | } 70 | input[type=range]::-ms-fill-upper { 71 | background: #DBDBDB; 72 | border: 1px solid #252525; 73 | border-radius: 0px; 74 | box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d; 75 | } 76 | input[type=range]::-ms-thumb { 77 | box-shadow: 0px 0px 0px #000000, 0px 0px 0px #0d0d0d; 78 | border: 1px solid #353535; 79 | height: 2.2vh; 80 | width: 2.2vh; 81 | border-radius: 0px; 82 | background: #808080; 83 | cursor: pointer; 84 | } 85 | input[type=range]:focus::-ms-fill-lower { 86 | background: #DBDBDB; 87 | } 88 | input[type=range]:focus::-ms-fill-upper { 89 | background: #DBDBDB; 90 | } 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /public/style/transitive.css: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Transitive Base Styles 4 | */ 5 | 6 | .Transitive { 7 | overflow: hidden; 8 | } 9 | 10 | /** 11 | * Schematic Map 12 | */ 13 | 14 | .Transitive > .schematic-map { 15 | position: absolute; 16 | left: 0; 17 | top: 0; 18 | width: 100%; 19 | height: 100%; 20 | z-index: 100; 21 | } 22 | 23 | /** 24 | * Labels 25 | */ 26 | 27 | .Transitive > .schematic-map .transitive-stop-label, 28 | .Transitive > .schematic-map .transitive-multi-label, 29 | .Transitive > .schematic-map .transitive-place-label { 30 | text-shadow: 31 | -2px -2px 0 #fff, 32 | 2px -2px 0 #fff, 33 | -2px 2px 0 #fff, 34 | 2px 2px 0 #fff; 35 | display: none; 36 | } 37 | 38 | .Transitive > .schematic-map .transitive-segment-label { 39 | fill: #fff; 40 | } 41 | 42 | /** 43 | * Label Container 44 | */ 45 | 46 | .Transitive > .schematic-map .transitive-segment-label-container { 47 | fill: #008; 48 | } 49 | 50 | /** 51 | * Lines 52 | */ 53 | 54 | .Transitive > .schematic-map .transitive-line { 55 | stroke-linecap: round; 56 | fill: none; 57 | } 58 | 59 | /** 60 | * Places 61 | */ 62 | 63 | .Transitive > .schematic-map .transitive-place-circle { 64 | fill: #fff; 65 | stroke: #333; 66 | stroke-width: 2px; 67 | } 68 | 69 | /** 70 | * Stops 71 | */ 72 | 73 | .Transitive > .schematic-map .transitive-stop-marker-pattern, 74 | .Transitive > .schematic-map .transitive-stop-marker-merged, 75 | .Transitive > .schematic-map .transitive-multipoint-marker-merged { 76 | fill: #fff; 77 | stroke: #333; 78 | stroke-width: 1px; 79 | } 80 | 81 | /** 82 | * Tile Layer 83 | */ 84 | 85 | .Transitive > .tile-layer { 86 | position: absolute; 87 | z-index: 50; 88 | } 89 | 90 | .Transitive > .tile-layer > .tile { 91 | pointer-events: none; 92 | position: absolute; 93 | width: 256px; 94 | height: 256px; 95 | } 96 | 97 | /** 98 | * Grid 99 | */ 100 | 101 | .Transitive .gridline { 102 | fill: none; 103 | stroke: #ccc; 104 | stroke-width: 1px; 105 | } 106 | -------------------------------------------------------------------------------- /views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CoAXs 6 | 7 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 86 | 87 | 88 | 89 | 90 | 91 | 92 |
93 | 94 |
95 |
96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | --------------------------------------------------------------------------------