Merge pull request #27 from 0hAodha/conor
Add routing, state mgmt and train types
This commit is contained in:
@ -8,28 +8,6 @@ admin.initializeApp();
|
|||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const parseString = require('xml2js').parseString;
|
const parseString = require('xml2js').parseString;
|
||||||
|
|
||||||
// function to fetch live train data from the Firestore database
|
|
||||||
exports.getLiveTrainData = functions.https.onRequest((request, response) => {
|
|
||||||
response.set('Access-Control-Allow-Origin', '*');
|
|
||||||
response.set('Access-Control-Allow-Credentials', 'true');
|
|
||||||
let jsonData = [];
|
|
||||||
|
|
||||||
cors(request, response, () => {
|
|
||||||
// fetch the "liveTrainData" collection
|
|
||||||
admin.firestore().collection('liveTrainData').get().then((snapshot) => {
|
|
||||||
if (snapshot.empty) {
|
|
||||||
response.status(404).send({data: "Error fetching live train data from the database"});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// iterate through each of the collection's documents
|
|
||||||
snapshot.forEach(doc => {
|
|
||||||
jsonData.push(doc.data());
|
|
||||||
});
|
|
||||||
response.json({data: jsonData});
|
|
||||||
})
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
// function to fetch station data from the Firestore database
|
// function to fetch station data from the Firestore database
|
||||||
exports.getStationData = functions.https.onRequest((request, response) => {
|
exports.getStationData = functions.https.onRequest((request, response) => {
|
||||||
response.set('Access-Control-Allow-Origin', '*');
|
response.set('Access-Control-Allow-Origin', '*');
|
||||||
@ -40,7 +18,7 @@ exports.getStationData = functions.https.onRequest((request, response) => {
|
|||||||
// fetch the "stations" collection
|
// fetch the "stations" collection
|
||||||
admin.firestore().collection('stations').get().then((snapshot) => {
|
admin.firestore().collection('stations').get().then((snapshot) => {
|
||||||
if (snapshot.empty) {
|
if (snapshot.empty) {
|
||||||
response.status(404).send({data: "Error fetching station data from the database"})
|
response.send({data: "Error fetching station data from the database"})
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// iterate through each of the collection's documents
|
// iterate through each of the collection's documents
|
||||||
@ -94,21 +72,67 @@ exports.postStationData = functions.https.onRequest((request, response) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// function to fetch live train data from the Firestore database
|
||||||
|
exports.getLiveTrainData = functions.https.onRequest((request, response) => {
|
||||||
|
response.set('Access-Control-Allow-Origin', '*');
|
||||||
|
response.set('Access-Control-Allow-Credentials', 'true');
|
||||||
|
let jsonData = [];
|
||||||
|
|
||||||
|
cors(request, response, () => {
|
||||||
|
// fetch the "liveTrainData" collection
|
||||||
|
admin.firestore().collection('liveTrainData').get().then((snapshot) => {
|
||||||
|
if (snapshot.empty) {
|
||||||
|
response.status(404).send({data: "Error fetching live train data from the database"});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// iterate through each of the collection's documents
|
||||||
|
snapshot.forEach(doc => {
|
||||||
|
jsonData.push(doc.data());
|
||||||
|
});
|
||||||
|
response.json({data: jsonData});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
// function to populate the Firestore database with live train data from Irish Rail
|
// function to populate the Firestore database with live train data from Irish Rail
|
||||||
exports.postLiveTrainData = functions.https.onRequest((request, response) => {
|
exports.postLiveTrainData = functions.https.onRequest((request, response) => {
|
||||||
|
// helper function to parse train objects
|
||||||
|
function parseJSON(result) {
|
||||||
|
let jsonStr = JSON.stringify(result);
|
||||||
|
let jsonObj = JSON.parse(jsonStr);
|
||||||
|
let jsonData = jsonObj.ArrayOfObjTrainPositions.objTrainPositions;
|
||||||
|
return jsonData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function to write to the database
|
||||||
|
function batchWriteDB(request, response, db, jsonData, trainTypeCode) {
|
||||||
response.set('Access-Control-Allow-Origin', '*');
|
response.set('Access-Control-Allow-Origin', '*');
|
||||||
response.set('Access-Control-Allow-Credentials', 'true');
|
response.set('Access-Control-Allow-Credentials', 'true');
|
||||||
|
|
||||||
cors(request, response, () => {
|
cors(request, response, () => {
|
||||||
axios.get('http://api.irishrail.ie/realtime/realtime.asmx/getCurrentTrainsXML')
|
var batchWrite = db.batch();
|
||||||
.then((res) => {
|
jsonData.forEach((doc) => {
|
||||||
|
// ignore trains with longitudes or latitudes equal zero
|
||||||
|
if (!(doc["TrainLongitude"] == 0 || doc["TrainLatitude"] == 0)) {
|
||||||
|
doc["TrainType"] = [trainTypeCode]
|
||||||
|
var docID = db.collection('liveTrainData').doc(doc["TrainCode"][0]);
|
||||||
|
batchWrite.set(docID, doc);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
batchWrite.commit()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
response.set('Access-Control-Allow-Origin', '*');
|
||||||
|
response.set('Access-Control-Allow-Credentials', 'true');
|
||||||
|
cors(request, response, () => {
|
||||||
|
// fetch mainland trains
|
||||||
|
axios.get('https://api.irishrail.ie/realtime/realtime.asmx/getCurrentTrainsXML_WithTrainType?TrainType=M').then(res => {
|
||||||
// XML to JSON
|
// XML to JSON
|
||||||
parseString(res.data, function(err, result) {
|
parseString(res.data, function(err, result) {
|
||||||
let jsonStr = JSON.stringify(result);
|
let jsonData = parseJSON(result)
|
||||||
let jsonObj = JSON.parse(jsonStr);
|
|
||||||
let jsonData = jsonObj.ArrayOfObjTrainPositions.objTrainPositions;
|
|
||||||
|
|
||||||
// batch delete all of the "liveTrainData" collections's documents
|
// batch delete all of the liveTrainData collections's documents
|
||||||
var db = admin.firestore();
|
var db = admin.firestore();
|
||||||
admin.firestore().collection('liveTrainData').get().then((snapshot) => {
|
admin.firestore().collection('liveTrainData').get().then((snapshot) => {
|
||||||
var batchDelete = db.batch();
|
var batchDelete = db.batch();
|
||||||
@ -117,27 +141,28 @@ exports.postLiveTrainData = functions.https.onRequest((request, response) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
batchDelete.commit().then(function() {
|
batchDelete.commit().then(function() {
|
||||||
// batch write all train JSON objects to the "liveTrainData" collection
|
// batch write all station JSON objects to the liveTrainData collection
|
||||||
var batchWrite = db.batch();
|
batchWriteDB(request, response, db, jsonData, "M");
|
||||||
|
|
||||||
jsonData.forEach((doc) => {
|
// fetch suburban trains
|
||||||
// ignore trains with longitudes or latitudes equal zero
|
axios.get('https://api.irishrail.ie/realtime/realtime.asmx/getCurrentTrainsXML_WithTrainType?TrainType=S').then(res => {
|
||||||
if (!(doc["TrainLongitude"] == 0 || doc["TrainLatitude"] == 0)) {
|
parseString(res.data, function(err, result) {
|
||||||
// set the train's code as the document ID
|
let jsonData = parseJSON(result)
|
||||||
var docID = db.collection('liveTrainData').doc(doc["TrainCode"][0]);
|
batchWriteDB(request, response, db, jsonData, "S");
|
||||||
batchWrite.set(docID, doc);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
batchWrite.commit().then(function () {
|
// fetch dart trains
|
||||||
|
axios.get('https://api.irishrail.ie/realtime/realtime.asmx/getCurrentTrainsXML_WithTrainType?TrainType=D').then(res => {
|
||||||
|
parseString(res.data, function(err, result) {
|
||||||
|
let jsonData = parseJSON(result)
|
||||||
|
batchWriteDB(request, response, db, jsonData, "D");
|
||||||
response.send({data: "Successfully fetched and uploaded live train data from Irish Rail"});
|
response.send({data: "Successfully fetched and uploaded live train data from Irish Rail"});
|
||||||
});
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch((error) => {;
|
|
||||||
response.send({data: "Error fetching data from the IrishRail API"});
|
|
||||||
})
|
})
|
||||||
});
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
1
functions/package-lock.json
generated
1
functions/package-lock.json
generated
@ -9,6 +9,7 @@
|
|||||||
"axios": "^1.3.3",
|
"axios": "^1.3.3",
|
||||||
"chai": "^4.3.7",
|
"chai": "^4.3.7",
|
||||||
"chai-http": "^4.3.0",
|
"chai-http": "^4.3.0",
|
||||||
|
"cors": "^2.8.5",
|
||||||
"firebase": "^9.17.1",
|
"firebase": "^9.17.1",
|
||||||
"firebase-admin": "^11.5.0",
|
"firebase-admin": "^11.5.0",
|
||||||
"firebase-functions": "^4.2.0",
|
"firebase-functions": "^4.2.0",
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
"axios": "^1.3.3",
|
"axios": "^1.3.3",
|
||||||
"chai": "^4.3.7",
|
"chai": "^4.3.7",
|
||||||
"chai-http": "^4.3.0",
|
"chai-http": "^4.3.0",
|
||||||
|
"cors": "^2.8.5",
|
||||||
"firebase": "^9.17.1",
|
"firebase": "^9.17.1",
|
||||||
"firebase-admin": "^11.5.0",
|
"firebase-admin": "^11.5.0",
|
||||||
"firebase-functions": "^4.2.0",
|
"firebase-functions": "^4.2.0",
|
||||||
|
@ -6,7 +6,7 @@ const expect = chai.expect;
|
|||||||
|
|
||||||
describe('Firebase cloud function tests', function() {
|
describe('Firebase cloud function tests', function() {
|
||||||
this.timeout(100000);
|
this.timeout(100000);
|
||||||
it('Test getting live train data', async() => {
|
it('Test getting live train data from the database', async() => {
|
||||||
const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net')
|
const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net')
|
||||||
.get('/getLiveTrainData')
|
.get('/getLiveTrainData')
|
||||||
expect(result.statusCode).to.equal(200);
|
expect(result.statusCode).to.equal(200);
|
||||||
@ -18,6 +18,20 @@ describe('Firebase cloud function tests', function() {
|
|||||||
expect(result.body.data[0]).haveOwnProperty('TrainLongitude');
|
expect(result.body.data[0]).haveOwnProperty('TrainLongitude');
|
||||||
expect(result.body.data[0]).haveOwnProperty('TrainCode');
|
expect(result.body.data[0]).haveOwnProperty('TrainCode');
|
||||||
expect(result.body.data[0]).haveOwnProperty('TrainDate');
|
expect(result.body.data[0]).haveOwnProperty('TrainDate');
|
||||||
|
expect(result.body.data[0]).haveOwnProperty('TrainType');
|
||||||
|
}),
|
||||||
|
|
||||||
|
this.timeout(100000);
|
||||||
|
it('Test getting station data from the database', async() => {
|
||||||
|
const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net')
|
||||||
|
.get('/getStationData')
|
||||||
|
expect(result.statusCode).to.equal(200);
|
||||||
|
expect(result.body.data).to.be.an('Array');
|
||||||
|
expect(result.body.data[0]).haveOwnProperty('StationDesc');
|
||||||
|
expect(result.body.data[0]).haveOwnProperty('StationLatitude');
|
||||||
|
expect(result.body.data[0]).haveOwnProperty('StationLongitude');
|
||||||
|
expect(result.body.data[0]).haveOwnProperty('StationCode');
|
||||||
|
expect(result.body.data[0]).haveOwnProperty('StationId');
|
||||||
}),
|
}),
|
||||||
|
|
||||||
this.timeout(100000);
|
this.timeout(100000);
|
||||||
@ -27,19 +41,6 @@ describe('Firebase cloud function tests', function() {
|
|||||||
expect(result.statusCode).to.equal(200);
|
expect(result.statusCode).to.equal(200);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
this.timeout(100000);
|
|
||||||
it('test getting station data', async() => {
|
|
||||||
const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net')
|
|
||||||
.get('/getStationData')
|
|
||||||
expect(result.statusCode).to.equal(200);
|
|
||||||
expect(result.body.data).to.be.an('Array');
|
|
||||||
expect(result.body.data[0]).haveOwnProperty('StationDesc');
|
|
||||||
expect(result.body.data[0]).haveOwnProperty('StationLatitude');
|
|
||||||
expect(result.body.data[0]).haveOwnProperty('StationLongitude');
|
|
||||||
expect(result.body.data[0]).haveOwnProperty('StationCode');
|
|
||||||
expect(result.body.data[0]).haveOwnProperty('StationId');
|
|
||||||
})
|
|
||||||
|
|
||||||
this.timeout(100000);
|
this.timeout(100000);
|
||||||
it('Test updating the database with live station data', async() => {
|
it('Test updating the database with live station data', async() => {
|
||||||
const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net')
|
const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net')
|
||||||
|
20
package-lock.json
generated
20
package-lock.json
generated
@ -13,6 +13,7 @@
|
|||||||
"ol": "^7.2.2",
|
"ol": "^7.2.2",
|
||||||
"vue": "^3.2.45",
|
"vue": "^3.2.45",
|
||||||
"vue-loading-overlay": "^6.0.3",
|
"vue-loading-overlay": "^6.0.3",
|
||||||
|
"vue-router": "^4.1.6",
|
||||||
"vue3-openlayers": "^0.1.71"
|
"vue3-openlayers": "^0.1.71"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -1121,6 +1122,11 @@
|
|||||||
"@vue/shared": "3.2.45"
|
"@vue/shared": "3.2.45"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@vue/devtools-api": {
|
||||||
|
"version": "6.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz",
|
||||||
|
"integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q=="
|
||||||
|
},
|
||||||
"node_modules/@vue/reactivity": {
|
"node_modules/@vue/reactivity": {
|
||||||
"version": "3.2.45",
|
"version": "3.2.45",
|
||||||
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz",
|
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz",
|
||||||
@ -2201,6 +2207,20 @@
|
|||||||
"vue": "^3.2.0"
|
"vue": "^3.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-router": {
|
||||||
|
"version": "4.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.6.tgz",
|
||||||
|
"integrity": "sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@vue/devtools-api": "^6.4.5"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/posva"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vue3-openlayers": {
|
"node_modules/vue3-openlayers": {
|
||||||
"version": "0.1.71",
|
"version": "0.1.71",
|
||||||
"resolved": "https://registry.npmjs.org/vue3-openlayers/-/vue3-openlayers-0.1.71.tgz",
|
"resolved": "https://registry.npmjs.org/vue3-openlayers/-/vue3-openlayers-0.1.71.tgz",
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"ol": "^7.2.2",
|
"ol": "^7.2.2",
|
||||||
"vue": "^3.2.45",
|
"vue": "^3.2.45",
|
||||||
"vue-loading-overlay": "^6.0.3",
|
"vue-loading-overlay": "^6.0.3",
|
||||||
|
"vue-router": "^4.1.6",
|
||||||
"vue3-openlayers": "^0.1.71"
|
"vue3-openlayers": "^0.1.71"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import MapsOverlay from './components/Map.vue'
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<MapsOverlay></MapsOverlay>
|
<router-view></router-view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<h2>Insights:</h2>
|
<h2>Insights:</h2>
|
||||||
<p>Total number of trains: {{ this.numTrains }}</p>
|
<p>Total number of trains: {{ this.insights["totalNumTrains"] }}</p>
|
||||||
<p>Number of actively running trains: {{ this.numRunningTrains }}</p>
|
<p>Number of actively running trains: {{ this.insights["numRunningTrains"] }}</p>
|
||||||
<p>Percentage late: {{ this.percentageLate }}%</p>
|
<p>Percentage late: {{ this.insights["percentageLate"] }}%</p>
|
||||||
<p>Percentage early or ontime: {{ this.percentageEarly }}%</p>
|
<p>Percentage early or ontime: {{ this.insights["percentageNotLate"] }}%</p>
|
||||||
<p v-if="this.latestTrain['TrainCode']">Latest train: {{ this.latestTrain["TrainCode"][0] }}, {{ this.latestTrain["Direction"][0] }}, {{ this.latestTime }} mins late</p>
|
<p v-if="this.latestTrain['TrainCode']">Latest train: {{ this.latestTrain["TrainCode"][0] }}, {{ this.latestTrain["Direction"][0] }}, {{ this.insights["latestTime"] }} mins late</p>
|
||||||
<p v-if="this.earliestTrain['TrainCode']">Earliest train: {{ this.earliestTrain["TrainCode"][0] }}, {{ this.earliestTrain["Direction"][0] }}, {{ this.earliestTime * -1 }} mins early</p>
|
<p v-if="this.earliestTrain['TrainCode']">Earliest train: {{ this.earliestTrain["TrainCode"][0] }}, {{ this.earliestTrain["Direction"][0] }}, {{ this.insights["earliestTime"] * -1 }} mins early</p>
|
||||||
|
<p>Mainland: {{ this.insights["numMainland"] }}</p>
|
||||||
|
<p>Suburban: {{ this.insights["numSuburban"] }}</p>
|
||||||
|
<p>Darts: {{ this.insights["numDart"] }}</p>
|
||||||
|
|
||||||
<button @click="getLiveTrainData">Fetch Data</button>
|
<button @click="getLiveTrainData">Fetch Data</button>
|
||||||
<button @click="postLiveTrainData">Populate Database</button>
|
<button @click="postLiveTrainData">Populate Database</button>
|
||||||
@ -41,6 +44,7 @@
|
|||||||
<!-- overlay offset is the size of the image so that it is centered-->
|
<!-- overlay offset is the size of the image so that it is centered-->
|
||||||
<ol-overlay :position="coordinate" :positioning="center-center" :offset="[-14,-16]">
|
<ol-overlay :position="coordinate" :positioning="center-center" :offset="[-14,-16]">
|
||||||
<div class="overlay-content" @click="getSelectedTrain(i)">
|
<div class="overlay-content" @click="getSelectedTrain(i)">
|
||||||
|
<img src="../assets/red-train-solid.png" class="trainMapIcon" alt="Train Icon">
|
||||||
<img v-if="isTrainLate(i)" src="../assets/red-train-solid.png" class="trainMapIcon" alt="Train Icon">
|
<img v-if="isTrainLate(i)" src="../assets/red-train-solid.png" class="trainMapIcon" alt="Train Icon">
|
||||||
<img v-else src="../assets/green-train-solid.png" class="trainMapIcon" alt="Train Icon">
|
<img v-else src="../assets/green-train-solid.png" class="trainMapIcon" alt="Train Icon">
|
||||||
</div>
|
</div>
|
||||||
@ -85,15 +89,9 @@ export default {
|
|||||||
selectedDataMap: {},
|
selectedDataMap: {},
|
||||||
display: false,
|
display: false,
|
||||||
|
|
||||||
numTrains: 0,
|
insights: {},
|
||||||
numRunningTrains: 0,
|
|
||||||
numLateRunningTrains: 0,
|
|
||||||
latestTrain: {},
|
latestTrain: {},
|
||||||
earliestTrain: {},
|
earliestTrain: {},
|
||||||
percentageEarly: 0,
|
|
||||||
percentageLate: 0,
|
|
||||||
latestTime: 0,
|
|
||||||
earliestTime: 0,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -126,33 +124,44 @@ export default {
|
|||||||
getData().then((response) => {
|
getData().then((response) => {
|
||||||
try {
|
try {
|
||||||
this.dbLiveTrainData = response.data;
|
this.dbLiveTrainData = response.data;
|
||||||
console.log(this.dbLiveTrainData)
|
this.insights = {"numRunningTrains": 0,
|
||||||
|
"numLateRunningTrains": 0,
|
||||||
this.numRunningTrains = 0;
|
"numMainland": 0,
|
||||||
this.numTrains = 0;
|
"numSuburban": 0,
|
||||||
this.numLateRunningTrains = 0;
|
"numDart": 0}
|
||||||
var latest = null
|
var latest = null
|
||||||
var currLatestTime = 0
|
|
||||||
var earliest = null
|
var earliest = null
|
||||||
var currEarliestTime = 0
|
var currLatestTime = null
|
||||||
|
var currEarliestTime = null
|
||||||
|
|
||||||
// create an array of coordinates and hashmap with the key-values {index: JSON obj}
|
// create an array of coordinates and hashmap with the key-values {index: JSON obj}
|
||||||
for(var i=0; i<this.dbLiveTrainData.length; i++) {
|
for(var i=0; i<this.dbLiveTrainData.length; i++) {
|
||||||
this.coordinates[i] = ref(fromLonLat([this.dbLiveTrainData[i]["TrainLongitude"][0], this.dbLiveTrainData[i]["TrainLatitude"][0]]))
|
let train = this.dbLiveTrainData[i];
|
||||||
this.allDataMap[i] = this.dbLiveTrainData[i];
|
this.coordinates[i] = ref(fromLonLat([train["TrainLongitude"][0], train["TrainLatitude"][0]]))
|
||||||
|
this.allDataMap[i] = train;
|
||||||
|
|
||||||
|
if (train["TrainType"][0] == "M") {
|
||||||
|
this.insights["numMainland"] += 1;
|
||||||
|
}
|
||||||
|
else if (train["TrainType"][0] == "S") {
|
||||||
|
this.insights["numSuburban"] += 1;
|
||||||
|
}
|
||||||
|
else if (train["TrainType"][0] == "D") {
|
||||||
|
this.insights["numDart"] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
// check if the train is running
|
// check if the train is running
|
||||||
if (this.dbLiveTrainData[i]["TrainStatus"][0] == "R") {
|
if (this.dbLiveTrainData[i]["TrainStatus"][0] == "R") {
|
||||||
this.numRunningTrains += 1;
|
this.insights["numRunningTrains"] += 1;
|
||||||
|
let publicMessage = train["PublicMessage"][0];
|
||||||
let publicMessage = this.dbLiveTrainData[i]["PublicMessage"][0];
|
let startTimeStr = publicMessage.indexOf("(");
|
||||||
let startTimeStr = publicMessage.indexOf("(")
|
|
||||||
|
|
||||||
// late
|
// late
|
||||||
if (publicMessage[startTimeStr+1] != "-" && publicMessage[startTimeStr+1] != "0") {
|
if (publicMessage[startTimeStr+1] != "-" && publicMessage[startTimeStr+1] != "0") {
|
||||||
this.numLateRunningTrains += 1;
|
this.insights["numLateRunningTrains"] += 1;
|
||||||
|
|
||||||
if (!latest) {
|
if (!latest) {
|
||||||
latest = this.dbLiveTrainData[i];
|
latest = train;
|
||||||
}
|
}
|
||||||
|
|
||||||
let timeEnd = publicMessage.indexOf(" ", startTimeStr+1);
|
let timeEnd = publicMessage.indexOf(" ", startTimeStr+1);
|
||||||
@ -160,34 +169,34 @@ export default {
|
|||||||
|
|
||||||
// new latest train
|
// new latest train
|
||||||
if (num > currLatestTime) {
|
if (num > currLatestTime) {
|
||||||
latest = this.dbLiveTrainData[i]
|
latest = train
|
||||||
currLatestTime = num
|
currLatestTime = num
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// early or ontime
|
// early or ontime
|
||||||
else {
|
else {
|
||||||
if (!earliest) {
|
if (!earliest) {
|
||||||
earliest = this.dbLiveTrainData[i];
|
earliest = train;
|
||||||
}
|
}
|
||||||
let timeEnd = publicMessage.indexOf(" ", startTimeStr+1);
|
let timeEnd = publicMessage.indexOf(" ", startTimeStr+1);
|
||||||
let num = parseInt(publicMessage.substring(startTimeStr+1, timeEnd))
|
let num = parseInt(publicMessage.substring(startTimeStr+1, timeEnd))
|
||||||
|
|
||||||
// new earliest train, negative as early trains defined as negative x mins late
|
// new earliest train, negative as early trains defined as negative x mins late
|
||||||
if (num < currEarliestTime) {
|
if (num < currEarliestTime) {
|
||||||
earliest = this.dbLiveTrainData[i]
|
earliest = train
|
||||||
currEarliestTime = num
|
currEarliestTime = num
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.percentageLate = ((this.numLateRunningTrains / this.numRunningTrains) * 100).toFixed(2);
|
this.insights["percentageLate"] = ((this.insights["numLateRunningTrains"] / this.insights["numRunningTrains"]) * 100).toFixed(2);
|
||||||
this.percentageEarly = 100 - this.percentageLate;
|
this.insights["percentageNotLate"] = (100 - this.insights["percentageLate"]).toFixed(2);
|
||||||
this.numTrains = Object.keys(this.allDataMap).length;
|
this.insights["totalNumTrains"] = Object.keys(this.allDataMap).length;
|
||||||
|
this.insights["latestTime"] = currLatestTime;
|
||||||
|
this.insights["earliestTime"] = currEarliestTime
|
||||||
this.latestTrain = latest;
|
this.latestTrain = latest;
|
||||||
this.earliestTrain = earliest;
|
this.earliestTrain = earliest;
|
||||||
this.latestTime = currLatestTime;
|
|
||||||
this.earliestTime = currEarliestTime;
|
|
||||||
loader.hide();
|
loader.hide();
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
@ -224,7 +233,7 @@ export default {
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
// ---------------- TESTING ----------------
|
// used for mobile
|
||||||
postLiveTrainData() {
|
postLiveTrainData() {
|
||||||
const functions = getFunctions(app);
|
const functions = getFunctions(app);
|
||||||
let host = window.location.hostname
|
let host = window.location.hostname
|
||||||
@ -232,12 +241,10 @@ export default {
|
|||||||
connectFunctionsEmulator(functions, host, 5001);
|
connectFunctionsEmulator(functions, host, 5001);
|
||||||
}
|
}
|
||||||
const postData = httpsCallable(functions, 'postLiveTrainData');
|
const postData = httpsCallable(functions, 'postLiveTrainData');
|
||||||
|
|
||||||
postData().then((response) => {
|
postData().then((response) => {
|
||||||
this.getLiveTrainData()
|
this.getLiveTrainData()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// ---------------- TESTING ----------------
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -351,6 +358,7 @@ export default {
|
|||||||
float: right;
|
float: right;
|
||||||
right: 0%;
|
right: 0%;
|
||||||
top: 0%;
|
top: 0%;
|
||||||
|
|
||||||
width:100%;
|
width:100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -7,7 +7,16 @@ import 'vue3-openlayers/dist/vue3-openlayers.css'
|
|||||||
import { LoadingPlugin } from 'vue-loading-overlay'
|
import { LoadingPlugin } from 'vue-loading-overlay'
|
||||||
import 'vue-loading-overlay/dist/css/index.css'
|
import 'vue-loading-overlay/dist/css/index.css'
|
||||||
|
|
||||||
|
import { createRouter, createWebHistory } from 'vue-router';
|
||||||
|
import routes from './router/routes';
|
||||||
|
|
||||||
|
let router = createRouter({
|
||||||
|
history: createWebHistory(),
|
||||||
|
routes: routes
|
||||||
|
})
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
app.use(router);
|
||||||
app.use(OpenLayersMap)
|
app.use(OpenLayersMap)
|
||||||
app.use(LoadingPlugin)
|
app.use(LoadingPlugin)
|
||||||
app.mount('#app')
|
app.mount('#app')
|
44
src/pages/InsightsPage.vue
Normal file
44
src/pages/InsightsPage.vue
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<template>
|
||||||
|
<router-link to="/">Home</router-link>
|
||||||
|
<router-link to="/insights">Insights</router-link>
|
||||||
|
|
||||||
|
<h1>Insights</h1>
|
||||||
|
<div v-if="this.insights">
|
||||||
|
<p>Total number of trains: {{ this.insights["totalNumTrains"] }}</p>
|
||||||
|
<p>Number of actively running trains: {{ this.insights["numRunningTrains"] }}</p>
|
||||||
|
<p>Percentage late: {{ this.insights["percentageLate"] }}%</p>
|
||||||
|
<p>Percentage early or ontime: {{ this.insights["percentageNotLate"] }}%</p>
|
||||||
|
|
||||||
|
<p v-if="this.latestTrain['TrainCode']">Latest train: {{ this.latestTrain["TrainCode"][0] }}, {{ this.insights["latestTime"] }} mins late</p>
|
||||||
|
<p v-if="this.earliestTrain['TrainCode']">Earliest train: {{ this.earliestTrain["TrainCode"][0] }}, {{ this.insights["earliestTime"] * -1 }} mins early</p>
|
||||||
|
|
||||||
|
<p>Mainland: {{ this.insights["numMainland"] }}</p>
|
||||||
|
<p>Suburban: {{ this.insights["numSuburban"] }}</p>
|
||||||
|
<p>Darts: {{ this.insights["numDart"] }}</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {store} from '../store/store'
|
||||||
|
export default {
|
||||||
|
name: "InsightsPage",
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
insights: {},
|
||||||
|
latestTrain: {},
|
||||||
|
earliestTrain: {},
|
||||||
|
store
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
this.insights = store.insights
|
||||||
|
this.latestTrain = store.latestTrain
|
||||||
|
this.earliestTrain = store.earliestTrain
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
</style>
|
364
src/pages/MapPage.vue
Normal file
364
src/pages/MapPage.vue
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
<template>
|
||||||
|
<router-link to="/">Home</router-link>
|
||||||
|
<router-link to="/insights">Insights</router-link>
|
||||||
|
<button @click="postLiveTrainData">Populate Database</button>
|
||||||
|
|
||||||
|
<!--Sidebar, fades out on click of X button-->
|
||||||
|
<transition id="sidebar" name="slideLeft">
|
||||||
|
<div v-if="this.display" id= "sidebarDiv">
|
||||||
|
<div id = "sidebarHeader">
|
||||||
|
<img id = "headerImage" src="../assets/train-solid.svg" alt="Train Icon">
|
||||||
|
<div v-on:click="this.display = false" id="xButton">X</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id= "sidebarDiv">
|
||||||
|
<h2>Train Code: {{ selectedDataMap["TrainCode"] }}</h2>
|
||||||
|
<p>Date: {{ selectedDataMap["TrainDate"] }}</p>
|
||||||
|
<p>Status: {{ selectedDataMap["TrainStatus"] }}</p>
|
||||||
|
<p>Longitude: {{ selectedDataMap["TrainLongitude"] }}</p>
|
||||||
|
<p>Latitude: {{ selectedDataMap["TrainLatitude"] }}</p>
|
||||||
|
<p>Direction: {{ selectedDataMap["Direction"] }}</p>
|
||||||
|
<p>Public Message: {{ selectedDataMap["PublicMessage"] }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
<ol-map :loadTilesWhileAnimating="true" :loadTilesWhileInteracting="true" style="height: 100vh; width: 100vw">
|
||||||
|
<ol-view ref="view" :center="center" :rotation="rotation" :zoom="zoom" :projection="projection" />
|
||||||
|
<ol-tile-layer>
|
||||||
|
<ol-source-osm />
|
||||||
|
</ol-tile-layer>
|
||||||
|
|
||||||
|
<template v-for="coordinate, i in coordinates" :position="inline-block">
|
||||||
|
<!-- overlay offset is the size of the image so that it is centered-->
|
||||||
|
<ol-overlay :position="coordinate" :positioning="center-center" :offset="[-14,-16]">
|
||||||
|
<div class="overlay-content" @click="getSelectedTrain(i)">
|
||||||
|
<img v-if="isTrainLate(i)" src="../assets/red-train-solid.png" class="trainMapIcon" alt="Train Icon">
|
||||||
|
<img v-else src="../assets/green-train-solid.png" class="trainMapIcon" alt="Train Icon">
|
||||||
|
</div>
|
||||||
|
</ol-overlay>
|
||||||
|
</template>
|
||||||
|
</ol-map>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {store} from '../store/store'
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import {fromLonLat, toLonLat} from 'ol/proj.js';
|
||||||
|
import app from '../api/firebase';
|
||||||
|
import { getFunctions, httpsCallable, connectFunctionsEmulator } from "firebase/functions";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "MapPage",
|
||||||
|
|
||||||
|
data() {
|
||||||
|
const center = ref(fromLonLat([-7.5029786, 53.4494762]))
|
||||||
|
const projection = ref('EPSG:3857')
|
||||||
|
const zoom = ref(7)
|
||||||
|
const rotation = ref(0)
|
||||||
|
const radius = ref(10)
|
||||||
|
const strokeWidth = ref(1)
|
||||||
|
const strokeColor = ref('black')
|
||||||
|
const fillColor = ref('red')
|
||||||
|
|
||||||
|
return {
|
||||||
|
center,
|
||||||
|
projection,
|
||||||
|
zoom,
|
||||||
|
rotation,
|
||||||
|
radius,
|
||||||
|
strokeWidth,
|
||||||
|
strokeColor,
|
||||||
|
fillColor,
|
||||||
|
|
||||||
|
coordinates: [],
|
||||||
|
dbLiveTrainData: [],
|
||||||
|
allDataMap: {},
|
||||||
|
selectedDataMap: {},
|
||||||
|
display: false,
|
||||||
|
store
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
let host = window.location.hostname
|
||||||
|
if (host === '127.0.0.1' || host === 'localhost') {
|
||||||
|
this.postLiveTrainData();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.getLiveTrainData();
|
||||||
|
}
|
||||||
|
// request new data every 60 seconds
|
||||||
|
// window.setInterval(this.getLiveTrainData, 60000);
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
// method to assign a single train's data to the selected hashmap
|
||||||
|
getSelectedTrain(i) {
|
||||||
|
this.display = true;
|
||||||
|
this.selectedDataMap = this.allDataMap[i];
|
||||||
|
},
|
||||||
|
|
||||||
|
// method to determine whether or not a selected train is late
|
||||||
|
isTrainLate(i) {
|
||||||
|
// check if the train is running
|
||||||
|
if (this.allDataMap[i]["TrainStatus"][0] == "R") {
|
||||||
|
let publicMessage = this.allDataMap[i]["PublicMessage"][0];
|
||||||
|
let startTimeStr = publicMessage.indexOf("(");
|
||||||
|
|
||||||
|
// check if the train is late
|
||||||
|
if (publicMessage[startTimeStr+1] != "-" && publicMessage[startTimeStr+1] != "0") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
// method to fetch live train data from the database
|
||||||
|
getLiveTrainData() {
|
||||||
|
const functions = getFunctions(app);
|
||||||
|
let host = window.location.hostname
|
||||||
|
if (host === '127.0.0.1' || host == 'localhost') {
|
||||||
|
connectFunctionsEmulator(functions, host, 5001);
|
||||||
|
}
|
||||||
|
const getData = httpsCallable(functions, 'getLiveTrainData');
|
||||||
|
let loader = this.$loading.show({
|
||||||
|
loader: 'dots',
|
||||||
|
container: this.$refs.container,
|
||||||
|
canCancel: false
|
||||||
|
});
|
||||||
|
|
||||||
|
getData().then((response) => {
|
||||||
|
try {
|
||||||
|
this.dbLiveTrainData = response.data;
|
||||||
|
if (!this.dbLiveTrainData) throw new Error("Error fetching live train data from the database");
|
||||||
|
|
||||||
|
var insights = {"numRunningTrains": 0,
|
||||||
|
"numLateRunningTrains": 0,
|
||||||
|
"numMainland": 0,
|
||||||
|
"numSuburban": 0,
|
||||||
|
"numDart": 0}
|
||||||
|
var latest = null
|
||||||
|
var earliest = null
|
||||||
|
var currLatestTime = null
|
||||||
|
var currEarliestTime = null
|
||||||
|
|
||||||
|
// create an array of coordinates and hashmap with the key-values {index: JSON obj}
|
||||||
|
for (var i=0; i<this.dbLiveTrainData.length; i++) {
|
||||||
|
let train = this.dbLiveTrainData[i];
|
||||||
|
this.coordinates[i] = ref(fromLonLat([train["TrainLongitude"][0], train["TrainLatitude"][0]]))
|
||||||
|
this.allDataMap[i] = train;
|
||||||
|
|
||||||
|
if (train["TrainType"][0] == "M") insights["numMainland"] += 1;
|
||||||
|
else if (train["TrainType"][0] == "S") insights["numSuburban"] += 1;
|
||||||
|
else if (train["TrainType"][0] == "D") insights["numDart"] += 1;
|
||||||
|
|
||||||
|
// check if the train is running
|
||||||
|
if (this.dbLiveTrainData[i]["TrainStatus"][0] == "R") {
|
||||||
|
insights["numRunningTrains"] += 1;
|
||||||
|
let publicMessage = train["PublicMessage"][0];
|
||||||
|
let startTimeStr = publicMessage.indexOf("(");
|
||||||
|
|
||||||
|
// check if the train is late
|
||||||
|
if (publicMessage[startTimeStr+1] != "-" && publicMessage[startTimeStr+1] != "0") {
|
||||||
|
insights["numLateRunningTrains"] += 1;
|
||||||
|
|
||||||
|
if (!latest) latest = train;
|
||||||
|
let timeEnd = publicMessage.indexOf(" ", startTimeStr+1);
|
||||||
|
let num = parseInt(publicMessage.substring(startTimeStr+1, timeEnd))
|
||||||
|
|
||||||
|
// check for a new latest train
|
||||||
|
if (num > currLatestTime) {
|
||||||
|
latest = train
|
||||||
|
currLatestTime = num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// train is early or ontime
|
||||||
|
else {
|
||||||
|
if (!earliest) earliest = train;
|
||||||
|
let timeEnd = publicMessage.indexOf(" ", startTimeStr+1);
|
||||||
|
let num = parseInt(publicMessage.substring(startTimeStr+1, timeEnd))
|
||||||
|
|
||||||
|
// check for a new earliest train (early trains a -x mins late)
|
||||||
|
if (num < currEarliestTime) {
|
||||||
|
earliest = train
|
||||||
|
currEarliestTime = num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
insights["percentageLate"] = ((insights["numLateRunningTrains"] / insights["numRunningTrains"]) * 100).toFixed(2);
|
||||||
|
insights["percentageNotLate"] = (100 - insights["percentageLate"]).toFixed(2);
|
||||||
|
insights["totalNumTrains"] = Object.keys(this.allDataMap).length;
|
||||||
|
insights["latestTime"] = currLatestTime;
|
||||||
|
insights["earliestTime"] = currEarliestTime
|
||||||
|
|
||||||
|
// assign the results to the Vue Store
|
||||||
|
store.setInsights(insights);
|
||||||
|
store.setEarliestTrain(earliest);
|
||||||
|
store.setLatestTrain(latest);
|
||||||
|
loader.hide();
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
loader.hide();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// method to populate the database for local testing
|
||||||
|
postLiveTrainData() {
|
||||||
|
const functions = getFunctions(app);
|
||||||
|
let host = window.location.hostname
|
||||||
|
if (host === '127.0.0.1' || host === 'localhost') {
|
||||||
|
connectFunctionsEmulator(functions, host, 5001);
|
||||||
|
}
|
||||||
|
const postData = httpsCallable(functions, 'postLiveTrainData');
|
||||||
|
postData().then((response) => {
|
||||||
|
this.getLiveTrainData()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.overlay-content {
|
||||||
|
width: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trainMapIcon {
|
||||||
|
width: 28px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slideLeft-enter-active, .slideLeft-leave-active {
|
||||||
|
transition: opacity .5s;
|
||||||
|
transition: all 0.8s;
|
||||||
|
|
||||||
|
}
|
||||||
|
.slideLeft-enter-from, .slideLeft-leave-to{
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-100px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes gradient {
|
||||||
|
0% {
|
||||||
|
background-position: 0% 50%;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
background-position: 100% 50%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: 0% 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar{
|
||||||
|
position: absolute;
|
||||||
|
height: 85%;
|
||||||
|
width: 20%;
|
||||||
|
left: 2%;
|
||||||
|
top: 12%;
|
||||||
|
z-index: 2;
|
||||||
|
text-align: center;
|
||||||
|
animation: gradient 15s ease infinite;
|
||||||
|
background: linear-gradient(45deg, #000000, #111111, #222222, #333333, #444444, #555555);
|
||||||
|
background-size: 400%, 400%;
|
||||||
|
box-shadow: 0 0 4px 2px #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebarDiv{
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebarHeader{
|
||||||
|
position: relative;
|
||||||
|
top:0%;
|
||||||
|
height: 10%;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#headerImage{
|
||||||
|
height: 100%;
|
||||||
|
width: auto;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#xButton{
|
||||||
|
font-size: 80%;
|
||||||
|
font-family: Georgia;
|
||||||
|
color: white;
|
||||||
|
position: absolute;
|
||||||
|
top:10px;
|
||||||
|
right:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#xButton:hover{
|
||||||
|
color:red;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebarFooter{
|
||||||
|
position: relative;
|
||||||
|
bottom:0%;
|
||||||
|
height:10%;
|
||||||
|
text-align: center;
|
||||||
|
color: azure;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebarMain{
|
||||||
|
position: relative;
|
||||||
|
height:80%;
|
||||||
|
width:100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebarContent{
|
||||||
|
position: relative;
|
||||||
|
size: 6px;
|
||||||
|
color: white;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
font-family: Georgia, 'Times New Roman', Times, serif ;
|
||||||
|
}
|
||||||
|
|
||||||
|
#mapDiv{
|
||||||
|
background-color: black;
|
||||||
|
position: absolute;
|
||||||
|
float: right;
|
||||||
|
right: 0%;
|
||||||
|
top: 0%;
|
||||||
|
|
||||||
|
width:100%;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#mapIFrame{
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
top: 0%;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#buttonDiv{
|
||||||
|
position: absolute;
|
||||||
|
float: right;
|
||||||
|
right: 10%;
|
||||||
|
top: 0%;
|
||||||
|
width:10%;
|
||||||
|
height:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#buttonElement{
|
||||||
|
position: relative;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
</style>
|
7
src/router/routes.js
Normal file
7
src/router/routes.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
function loadPage(component) {
|
||||||
|
return () => import(`@/pages/${component}.vue`)
|
||||||
|
}
|
||||||
|
export default [
|
||||||
|
{path: "/", component:loadPage("MapPage")},
|
||||||
|
{path: "/insights", component:loadPage("InsightsPage")}
|
||||||
|
]
|
17
src/store/store.js
Normal file
17
src/store/store.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { reactive } from 'vue'
|
||||||
|
|
||||||
|
export const store = reactive({
|
||||||
|
insights: {},
|
||||||
|
latestTrain: {},
|
||||||
|
earliestTrain: {},
|
||||||
|
|
||||||
|
setInsights(insights) {
|
||||||
|
this.insights = insights
|
||||||
|
},
|
||||||
|
setLatestTrain(latestTrain) {
|
||||||
|
this.latestTrain = latestTrain
|
||||||
|
},
|
||||||
|
setEarliestTrain(earliestTrain) {
|
||||||
|
this.earliestTrain = earliestTrain
|
||||||
|
}
|
||||||
|
})
|
Reference in New Issue
Block a user