· 6 years ago · Oct 17, 2019, 09:20 AM
1/* Classes */
2class Ship
3{
4 constructor(name,maxSpeed,range,desc,cost,status,comments,source)
5 {
6 this._name = name;
7 this._maxSpeed = maxSpeed * FACTOR_KNOTS_TO_KMPERH; //Max speed converted to km/h
8 this._range = range;
9 this._desc = desc;
10 this._cost = cost;
11 this._status = status;
12 this._comments = comments;
13 this._source = source;
14 }
15
16 get name() { return this._name; }
17 get maxSpeed() { return this._maxSpeed; } //km/h
18 get range() { return this._range; } //km
19 get desc() { return this._desc; }
20 get cost() { return this._cost; } //units/km
21 get status() { return this._status; }
22 get comments() { return this._comments; }
23 get source() { return this._source; }
24
25 printShipInfo()
26 {
27 let output = '<h4 id="shipViewed">' + this._name + '</h4>' +
28 '<p><b>Maximum Speed:</b> ' + this._maxSpeed.toFixed(2) + ' km/h<br>' +
29 '<p><b>Range:</b> ' + this._range + ' km<br>' +
30 '<p><b>Description:</b> ' + this._desc + '<br>' +
31 '<p><b>Cost:</b> ' + this._cost + ' units/km<br>' +
32 '<p><b>Status:</b> ' + this._status + '<br>' +
33 '<p><b>Comments:</b> ' + this._comments + '<br>';
34
35 return output;
36 }
37}
38
39class Ships
40{
41 constructor()
42 {
43 this._versionAPI;
44 this._shipsAPI = [];
45 this._shipsUser = [];
46 this._shipsDisplay = [];
47 }
48
49 get versionAPI() { return this._versionAPI; }
50 get shipsAPI() { return this._shipsAPI; }
51 get shipsUser() { return this._shipsUser; }
52 get shipsDisplay() { return this._shipsDisplay; }
53
54 addAPIShip(ship) { this._shipsAPI.push(ship); }
55
56 refreshList(onlyAvailable) // FINISHDOC
57 {
58 // Create new array which contains both API and User Ships
59 let allShips = [];
60
61 for (let i = 0;i < this._shipsAPI.length;i++)
62 {
63 allShips.push(this._shipsAPI[i]);
64 }
65
66 for (let i = 0;i < this._shipsUser.length;i++)
67 {
68 allShips.push(this._shipsUser[i]);
69 }
70
71 // Reset shipsDisplay array each time before refilling
72 this._shipsDisplay = [];
73
74 for (let i = 0;i < allShips.length;i++)
75 {
76 // If only available checked, only add ship to shipsDisplay if it is available
77 if (onlyAvailable === true)
78 {
79 if (allShips[i].status == "available")
80 {
81 this._shipsDisplay.push(allShips[i]);
82 }
83 }
84 // If only available not checked, just fill shipsDisplay with all ships
85 else if (onlyAvailable === false)
86 {
87 this._shipsDisplay.push(allShips[i]);
88 }
89 }
90 }
91
92 sortBy(criterion) //FINISHDOC
93 {
94 // Sort ships by name
95 if (criterion == "name")
96 {
97 myShips._shipsDisplay.sort((a,b) => {
98 let nameA = a.name.toUpperCase();
99 let nameB = b.name.toUpperCase();
100
101 if(nameA < nameB) { return -1; }
102 if(nameA > nameB) { return 1; }
103 return 0;
104 });
105 }
106 // Sort ships by maximum speed (high to low)
107 else if (criterion == "speed")
108 {
109 myShips._shipsDisplay.sort((a,b) => { return b.maxSpeed - a.maxSpeed; });
110 }
111
112 // Sort ships by range (high to low)
113 else if (criterion == "range")
114 {
115 myShips._shipsDisplay.sort((a,b) => { return b.range - a.range; });
116 }
117
118 // Sort ships by cost (low to high)
119 else if (criterion =="cost")
120 {
121 myShips._shipsDisplay.sort((a,b) => { return a.cost - b.cost; });
122 }
123 }
124
125 printShipList()
126 {
127 let output = "<thead class='displayList'><tr>";
128
129 // Generate table head
130 let tableHead = ["Source","Name"];
131 for(let head in tableHead)
132 {
133 output += "<th>"+tableHead[head]+"</th>";
134 }
135 output += "</tr></thead><tbody class='displayList scrollList'>";
136
137 for(let shipIndex in this._shipsDisplay)
138 {
139 output += "<tr><td>" + this._shipsDisplay[shipIndex].source + "</td>" +
140 "<td>" + this._shipsDisplay[shipIndex].name + "</td>" +
141 "<td><button onclick='enableSelectButton();showShipInfo(" + shipIndex + ")' class='mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--accent'>View</button></td></tr>";
142 }
143
144 output += "</div></tbody>";
145
146 return output;
147 }
148}
149
150class Port
151{
152 constructor(name,country,type,size,locPrecision,lat,lng,source)
153 {
154 this._name = name;
155 this._country = country;
156 this._type = type;
157 this._size = size;
158 this._locPrecision = locPrecision;
159 this._lat = lat;
160 this._lng = lng;
161 this._source = source;
162 }
163
164 get name() { return this._name; }
165 get country() { return this._country; }
166 get type() { return this._type; }
167 get size() { return this._size; }
168 get locPrecision() { return this._locPrecision; }
169 get lat() { return this._lat; }
170 get lng() { return this._lng; }
171 get source() { return this._source; }
172
173 printPortInfo()
174 {
175 let output = '<h4 id="portViewed">' + this._name + '</h4>' +
176 '<p><b>Country:</b> ' + this._country + '<br>' +
177 '<p><b>Type:</b> ' + this.type + '<br>' +
178 '<p><b>Size:</b> ' + this.size + '<br>' +
179 '<p><b>Location Precision:</b> ' + this._locPrecision + '<br>' +
180 '<p><b>Latitude:</b> ' + this._lat + '<br>' +
181 '<p><b>Longitude:</b> ' + this._lng + '<br>';
182
183 return output;
184 }
185}
186
187class Ports
188{
189 constructor()
190 {
191 this._versionAPI;
192 this._portsAPI = [];
193 this._portsUser = [];
194 this._portsDisplay = [];
195 this._countries = [];
196 this._types = [];
197 this._sizes = [];
198 }
199
200 get versionAPI() { return this._versionAPI; }
201 get portsAPI() { return this._portsAPI; }
202 get portsUser() { return this._portsUser; }
203 get portsDisplay() { return this._portsDisplay; }
204 get countries() { return this._countries; }
205 get types() { return this._types; }
206 get sizes() { return this._sizes; }
207
208 addAPIPort(port) //FINISHDOC
209 {
210 // Add country if it is not already there
211 if ((this._portsAPI.find((obj) => { return obj.country === port.country; }) == undefined) && (this._portsUser.find((obj) => { return obj.country === port.country; }) == undefined))
212 {
213 this._countries.push(port.country);
214 }
215
216 // Add type if it is not already there
217 if (this._portsAPI.find((obj) => { return obj.type === port.type; }) == undefined && this._portsUser.find((obj) => { return obj.type === port.type; }) == undefined)
218 {
219 this._types.push(port.type);
220 }
221
222 // Add size if it is not already there
223 if (this._portsAPI.find((obj) => { return obj.size === port.size; }) == undefined && this._portsUser.find((obj) => { return obj.size === port.size; }) == undefined)
224 {
225 this._sizes.push(port.size);
226 }
227
228 this._portsAPI.push(port);
229 }
230
231 refreshList(filterCountry,filterType,filterSize) // FINISHDOC
232 {
233 // Create new array which contains both API and User Ports
234 let allPorts = [];
235
236 for (let i = 0;i < this._portsAPI.length;i++)
237 {
238 allPorts.push(this._portsAPI[i]);
239 }
240
241 for (let i = 0;i < this._portsUser.length;i++)
242 {
243 allPorts.push(this._portsUser[i]);
244 }
245
246 // Reset portsDisplay each time before refilling
247 this._portsDisplay = [];
248 for (let i =0;i < allPorts.length;i++)
249 {
250
251 let filtersPort = [0,0,0];
252
253 // Each filter follows the steps
254 // Check if the filter is not set, if so, say the instance passes the filter
255 // Else if the filter is set, only say an instance passes the filter if its value is the required value
256 if (filterCountry === "")
257 {
258 filtersPort[0] = 1;
259 }
260 else
261 {
262 if (allPorts[i].country == filterCountry)
263 {
264 filtersPort[0] = 1;
265 }
266 }
267
268 if (filterType === "")
269 {
270 filtersPort[1] = 1;
271 }
272 else
273 {
274 if (allPorts[i].type == filterType)
275 {
276 filtersPort[1] = 1;
277 }
278 }
279
280 if (filterSize === "")
281 {
282 filtersPort[2] = 1;
283 }
284 else
285 {
286 if (allPorts[i].size == filterSize)
287 {
288 filtersPort[2] = 1;
289 }
290 }
291
292 // If an instance passes all three filters, add it to portsDisplay
293 if (sumArray(filtersPort) == 3)
294 {
295 this._portsDisplay.push(allPorts[i]);
296 }
297 }
298 }
299
300 printCountriesDropdown() //FINISHDOC
301 {
302 let output = '<option value="" disabled selected>--Select--</option>';
303 for (let index in this._countries)
304 {
305 output += '<option value="' + this._countries[index] + '">' + this._countries[index] + '</option>';
306 }
307 return output;
308 }
309
310 printTypesDropdown() //FINISHDOC
311 {
312 let output = '<option value="" disabled selected>--Select--</option>';
313 for (let index in this._types)
314 {
315 output += '<option value="' + this._types[index] + '">' + this._types[index] + '</option>';
316 }
317 return output;
318 }
319
320 printSizesDropdown() //FINISHDOC
321 {
322 let output = '<option value="" disabled selected>--Select--</option>';
323 for (let index in this._sizes)
324 {
325 output += '<option value="' + this._sizes[index] + '">' + this._sizes[index] + '</option>';
326 }
327 return output;
328 }
329
330 printPortList() //FINISHDOC
331 {
332 let output = "<thead class='displayList'><tr>";
333
334 // Generate table head
335 let tableHead = ["Source","Name"];
336 for(let head in tableHead)
337 {
338 output += "<th>"+tableHead[head]+"</th>";
339 }
340 output += "</tr></thead><tbody class='displayList scrollList'>";
341
342 // Generate table body
343 for(let portIndex in this._portsDisplay)
344 {
345 output += "<tr><td>" + this._portsDisplay[portIndex].source + "</td>" +
346 "<td>" + this._portsDisplay[portIndex].name + "</td>" +
347 "<td><button onclick='enableSelectButton();showPortInfo(" + portIndex + ")' class='mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--accent'>View</button></td></tr>";
348 }
349 output += "</div></tbody>";
350
351 return output;
352 }
353}
354
355class Waypoint
356{
357 constructor(lat,lng)
358 {
359 this._lat = lat;
360 this._lng = lng;
361 }
362
363 get lat() { return this._lat; }
364 get lng() { return this._lng; }
365}
366
367class Route
368{
369 constructor(portSource,waypoints,portDestination,ship,dateStart)
370 {
371 this._portSource = portSource;
372 this._waypoints = waypoints;
373 this._portDestination = portDestination;
374 this._ship = ship;
375 this._dateStart = dateStart;
376
377 this._distances = [];
378 this._durations = [];
379 this._cost;
380 this._dateEnd;
381
382 this.calculateAttributes();
383 }
384
385 get portSource() { return this._portSource; }
386 get waypoints() { return this._waypoints; }
387 get portDestination() { return this._portDestination; }
388 get ship() { return this._ship; }
389 get dateStart() { return this._dateStart; } //milliseconds from 0, use Date()?
390 get durations() { return this._durations; } //milliseconds
391 get dateEnd() { return this._dateEnd; } //milliseconds from 0, use Date()?
392 get distances() { return this._distances; } //km
393 get cost() { return this._cost; } //units
394
395 set portSource(port) { this._portSource = port; }
396 set waypoints(waypoints) { this._waypoints = waypoints; }
397 set portDestination(port) { this._portDestination = port; }
398 set ship(ship) { this._ship = ship; }
399 set dateStart(date) { this._dateStart = date; }
400
401 calculateAttributes() //FINISHDOC
402 {
403 if (this._portSource != undefined && this._portDestination)
404 {
405 this._constructDistances();
406 }
407
408 if (this._distances.length != 0 && this._ship != undefined)
409 {
410 this._constructDurationsCost();
411 }
412
413 if (this._durations.length != 0 && this._dateStart != undefined)
414 {
415 this._constructDateEnd();
416 }
417 }
418
419 _constructDistances() // FINISHDOC
420 {
421 //Initialising variables
422 let points = [];
423
424 //Filling points array
425 points.push(this._portSource);
426
427 if (this._waypoints != undefined)
428 {
429 for (let i = 0;i < this._waypoints.length;i++)
430 {
431 points.push(this._waypoints[i]);
432 }
433 }
434
435 points.push(this._portDestination);
436
437 //Calculating distances between points
438 for (let i = 0; i < points.length - 1;i++)
439 {
440 let lat1 = points[i].lat;
441 let lng1 = points[i].lng;
442 let lat2 = points[i+1].lat;
443 let lng2 = points[i+1].lng;
444 this._distances[i] = this._haversine(lat1,lng1,lat2,lng2);
445 }
446 }
447
448 _haversine(lat1,lng1,lat2,lng2) // FINISHDOC
449 {
450 let radiusEarth = 6371e3;
451 let phi1 = degreesToRadians(lat1);
452 let phi2 = degreesToRadians(lat2);
453 let deltaPhi = degreesToRadians((lat2-lat1));
454 let deltaLambda = degreesToRadians((lng2-lng1));
455
456 let a = Math.sin(deltaPhi/2) * Math.sin(deltaPhi/2) + Math.cos(phi1) * Math.cos(phi2) * Math.sin(deltaLambda/2) * Math.sin(deltaLambda/2);
457 let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
458
459 let distance = radiusEarth * c * FACTOR_M_TO_KM;
460
461 return distance;
462 }
463
464 _constructDurationsCost() // FINISHDOC
465 {
466 //Calculating durations between points
467 for (let i = 0; i < this._distances.length;i++)
468 {
469 this._durations[i] = FACTOR_HOURS_TO_MILLISECONDS * this._distances[i] / this._ship.maxSpeed;
470 }
471
472 //Calculating cost
473 this._cost = sumArray(this._distances) * this.ship.cost;
474 }
475
476 _constructDateEnd() // FINISHDOC
477 {
478 this._dateEnd = this._dateStart + sumArray(this._durations); //CHECK & FINISH
479 }
480
481 isTheSame(otherRoute) //CHECK FINISHDOC
482 {
483 return ((otherRoute.portSource === this.portSource) && (otherRoute.waypoints === this.waypoints) && (otherRoute.portDestination === this.portDestination) && (otherRoute.ship === this.ship) && (otherRoutedateStart === this.dateStart));
484 }
485
486 printRouteInfoTable() // FINISH FINISHDOC
487 {
488 let output = "";
489 let points = [];
490 let timeCumNum = this._dateStart;
491 let timeCumDate = new Date();
492 timeCumDate.setTime(timeCumNum);
493
494 points.push(this._portSource);
495 for (let waypoint in this._waypoints)
496 {
497 points.push(this._waypoints[waypoint])
498 }
499 points.push(this._portDestination);
500
501 // Generate table head
502 let tableHead = ["","Port","Position","Time","Weather"];
503 for(let head in tableHead)
504 {
505 output += "<th>"+tableHead[head]+"</th>";
506 }
507
508 for (let pointIndex in points)
509 {
510 getPointWeather(points[pointIndex].lat,points[pointIndex].lng,timeCumNum);
511
512 output += '<tr><td></td>';
513
514 if (points[pointIndex] instanceof Port)
515 {
516 output += '<td>' + points[pointIndex].name + '</td>'
517 }
518 else
519 {
520 output += '<td></td>'
521 }
522
523 output += '<td>' + points[pointIndex].lat + ',' + points[pointIndex].lng + '</td>' +
524 '<td>' + timeCumNum + '</td>' +
525 '<td>' + tempWeather + '</td></tr>'; //FINISH
526
527 timeCumNum += this._durations[pointIndex];
528 timeCumDate.setTime(timeCumNum);
529 }
530
531 return output;
532 }
533
534 printRouteOtherInfo() //FINISH FINISHDOC
535 {}
536}
537
538class Routes
539{
540 constructor()
541 {
542 this._routes = [];
543 }
544
545 get routes() { return this._routes; }
546
547 _routeExists(route)
548 {
549 for (let i = 0;i < this._routes.length;i++)
550 {
551 if (route.isTheSame(this._routes[i]) == true)
552 {
553 return true;
554 }
555 }
556
557 return false;
558 }
559
560 addRoute(routeAdd)
561 {
562 //Checking route does not already exist
563 if (this._routeExists(routeAdd) == false)
564 {
565 //Add route to array
566 this._routes.push(routeAdd);
567 }
568 else
569 {
570 //Give user feedback via snackbar
571 //FINISH
572 }
573
574 storeToLocalStorage();
575 }
576}
577
578/* Functions */
579//* Ship and Port Creation */
580function loadShipsAPI()
581{
582 let url = "https://eng1003.monash/api/v1/ships/";
583 let shipData =
584 {
585 callback: "createShipsFromAPI",
586 };
587
588 webServiceRequest(url,shipData);
589}
590
591function createShipsFromAPI(data)
592{
593 let source = 'AuHumane';
594
595 for (let i = 0; i < data.ships.length;i++)
596 {
597 let shipData = data.ships[i];
598
599 let name = shipData.name;
600 let maxSpeed = shipData.maxSpeed;
601 let range = shipData.range;
602 let desc = shipData.desc;
603 let cost = shipData.cost;
604 let status = shipData.status;
605 let comments = shipData.comments;
606
607 //Create instance of Ship and push to list of API ships
608 let newShip = new Ship(name,maxSpeed,range,desc,cost,status,comments,source);
609 myShips.addAPIShip(newShip);
610 }
611}
612
613function loadPortsAPI()
614{
615 let url = "https://eng1003.monash/api/v1/ports/";
616 let data =
617 {
618 callback: "createPortsFromAPI",
619 };
620
621 webServiceRequest(url,data);
622}
623
624function createPortsFromAPI(data)
625{
626 let source = 'AuHumane';
627
628 for (let i = 0; i < data.ports.length;i++)
629 {
630 let portData = data.ports[i];
631
632 let name = portData.name;
633 let country = portData.country;
634 let type = portData.type;
635 let size = portData.size;
636 let locPrecision = portData.locPrecision;
637 let lat = portData.lat;
638 let lng = portData.lng;
639
640 //Create instance of Port and push to list of API ports
641 let newPort = new Port(name,country,type,size,locPrecision,lat,lng,source);
642 myPorts.addAPIPort(newPort);
643 }
644}
645//* General Purpose */
646function degreesToRadians(degrees)
647{
648 var pi = Math.PI;
649 return degrees * (pi/180);
650}
651
652function sumArray(array)
653{
654 return array.reduce(function(total,num) { return total + num; });
655}
656
657//* Ship and Port Selection */
658function showShipSelect() //FINISH FINISHDOC
659{
660 let dialogBox = "";
661 dialogBox += '<dialog class="mdl-dialog">' +
662 '<h2 class="mdl-dialog__title">Select Ship</h2>' +
663 '<div class="mdl-dialog__content">' +
664 '<div class="mdl-grid">' +
665
666 // Ship list section
667 '<div class="mdl-cell mdl-cell--8-col mdl-cell--6-col-tablet mdl-cell--4-col-phone">' +
668 '<div class="dropdown">' +
669 '<label>Sort Ship By: </label>'+
670 '<select id="sortShipBy" onchange="refreshShipsList()">' +
671 '<option value="" disabled selected>Sort by</option>' +
672 '<option value="name">Name A-Z</option>' +
673 '<option value="speed">Highest speed</option>' +
674 '<option value="range">Highest range</option>' +
675 '<option value="cost">Lowest cost</option>' +
676 '</select>' +
677 '</div>' +
678 '<label for="onlyAvailableShips" class="mdl-checkbox mdl-js-checkbox">' +
679 '<span class="mdl-checkbox__label">Show only available ships</span>' +
680 '<input type="checkbox" id="onlyAvailableShips" class="mdl-checkbox__input" onchange="refreshShipsList()">' +
681 '</label>' +
682 '<table class="mdl-data-table mdl-js-data-table mdl-shadow--2dp" id="shipsList"></table>' +
683 '<a class="mdl-navigation__link" href="pageAddToRepository.html">' +
684 '<br><br><button class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--accent">Add New Ship</button>' +
685 '</a>' +
686 '</div>' +
687
688 // Ship detailed information section
689 '<div class="mdl-cell mdl-cell--4-col mdl-cell--4-col-tablet mdl-cell--4-col-phone">' +
690 '<div class="mdl-dialog__actions">' +
691 '<button type="button" class="mdl-button select mdl-button--raised mdl-js-ripple-effect mdl-button--accent" id="select" disabled>Select</button>' +
692 '<button type="button" class="mdl-button cancel mdl-button--raised mdl-js-ripple-effect">Cancel</button>' +
693
694 '</div>' +
695 '<br><br><br><div id="shipInfoArea"></div>' +
696 '</div>' +
697 '</div>' +
698 '</div>' +
699
700
701 '</dialog>';
702
703 document.getElementById("hiddenDialog").innerHTML = dialogBox;
704 refreshShipsList();
705
706 let dialog = document.querySelector('dialog');
707 let showDialogButton = document.querySelector('#show-dialog');
708 if (!dialog.showModal) {
709 dialogPolyfill.registerDialog(dialog);
710 }
711 dialog.showModal();
712
713
714 dialog.querySelector('.select').addEventListener('click', function() {
715 let shipSelectionRef = document.getElementById('shipSelection');
716 let shipViewed = document.getElementById('shipViewed').innerText;
717 shipSelectionRef.innerText = shipViewed;
718 updateTempRoute("ship");
719 dialog.close();
720 });
721
722 dialog.querySelector('.cancel').addEventListener('click', function() {
723 dialog.close();
724 });
725}
726
727function refreshShipsList()
728{
729 // Getting filters and sortion criterion
730 let onlyAvailable = document.getElementById('onlyAvailableShips').checked;
731 let criterion = document.getElementById('sortShipBy').value;
732 let shipsListRef = document.getElementById('shipsList');
733
734 // Calling class methods to filter and sort myShips.shipDisplay
735
736 myShips.refreshList(onlyAvailable);
737 myShips.sortBy(criterion);
738 shipsListRef.innerHTML = myShips.printShipList();
739}
740
741function showShipInfo(shipIndex)
742{
743 let outputRef = document.getElementById('shipInfoArea');
744 let output = myShips.shipsDisplay[shipIndex].printShipInfo();
745
746 outputRef.innerHTML = output;
747}
748
749function showPortSelect(port) //FINISH FINISHDOC
750{
751 let dialogBox = "";
752 dialogBox += '<dialog class="mdl-dialog">' +
753 '<h2 class="mdl-dialog__title">Select Port</h2>' +
754 '<div class="mdl-dialog__content">' +
755 '<div class="mdl-grid">' +
756
757 // Port list section
758 '<div class="mdl-cell mdl-cell--6-col mdl-cell--6-col-tablet mdl-cell--4-col-phone">' +
759 '<div class="dropdown">' +
760 '<label>Filter By Country:</label>'+
761 '<select onchange="refreshPortsList()" id="portCountrySelection" style="width: 80px;"></select>' +
762 '</div>' +
763 '<div class="dropdown">' +
764 '<label>Filter By Type:</label>'+
765 '<select onchange="refreshPortsList()" id="portTypeSelection" style="width: 80px;"></select>' +
766 '</div>' +
767 '<div class="dropdown">' +
768 '<label>Filter By Size:</label>'+
769 '<select onchange="refreshPortsList()" id="portSizeSelection" style="width: 80px;"></select>' +
770 '</div>' +
771 '<table class="mdl-data-table mdl-js-data-table mdl-shadow--2dp" id="portsList"></table>' +
772 '<a class="mdl-navigation__link" href="pageAddToRepository.html">' +
773 '<br><br><button class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--accent">Add New Port</button>' +
774 '</a>' +
775 '</div>' +
776
777 // Port detailed information & map section
778 '<div class="mdl-cell mdl-cell--6-col mdl-cell--4-col-tablet mdl-cell--4-col-phone">' +
779 '<div class="mdl-dialog__actions">' +
780 '<button type="button" class="mdl-button select mdl-button--raised mdl-js-ripple-effect mdl-button--accent" id="select" disabled>Select</button>' +
781 '<button type="button" class="mdl-button cancel mdl-button--raised mdl-js-ripple-effect">Cancel</button>' +
782 '</div><br><br>' +
783
784 '<div id="portInfoArea"></div>' +
785 '<div id="portMapArea"></div>' +
786 '</div>' +
787 '</div>' +
788 '</div>' +
789
790 '</dialog>';
791
792 document.getElementById("hiddenDialog").innerHTML = dialogBox;
793
794 let dialog = document.querySelector('dialog');
795 let showDialogButton = document.querySelector('#show-dialog');
796 if (!dialog.showModal) {
797 dialogPolyfill.registerDialog(dialog);
798 }
799 dialog.showModal();
800
801 let countrySelectionRef = document.getElementById('portCountrySelection');
802 let typeSelectionRef = document.getElementById('portTypeSelection');
803 let sizeSelectionRef = document.getElementById('portSizeSelection');
804 countrySelectionRef.innerHTML = myPorts.printCountriesDropdown();
805 typeSelectionRef.innerHTML = myPorts.printTypesDropdown();
806 sizeSelectionRef.innerHTML = myPorts.printSizesDropdown();
807 refreshPortsList();
808
809 let portSelectionRef;
810 dialog.querySelector('.select').addEventListener('click', function() {
811 if (port == 'portSource')
812 {
813 portSelectionRef = document.getElementById('portSourceSelection');
814 }
815 else if (port == 'portDestination')
816 {
817 portSelectionRef = document.getElementById('portDestinationSelection');
818 }
819
820 let portViewed = document.getElementById('portViewed').innerText
821 portSelectionRef.innerText = portViewed;
822 updateTempRoute(port);
823 dialog.close();
824 });
825
826 dialog.querySelector('.cancel').addEventListener('click', function() {
827 dialog.close();
828 });
829}
830
831function refreshPortsList() // FINISHDOC
832{
833 // Getting filters
834 let filterCountry = document.getElementById('portCountrySelection').value;
835 let filterType = document.getElementById('portTypeSelection').value;
836 let filterSize = document.getElementById('portSizeSelection').value;
837
838 // Calling class methods to filter myPorts.portsDisplay
839 myPorts.refreshList(filterCountry,filterType,filterSize);
840
841 let portsListRef = document.getElementById('portsList');
842 portsListRef.innerHTML = myPorts.printPortList();
843}
844
845function showPortInfo(portIndex) //FINISHDOC
846{
847 let outputRef = document.getElementById('portInfoArea');
848 let output = myPorts._portsDisplay[portIndex].printPortInfo();
849
850 outputRef.innerHTML = output;
851}
852
853function enableSelectButton() //FINISHDOC
854{
855 document.getElementById('select').disabled = false;
856}
857
858//* New Route */
859
860function updateTempRoute(change) // FINISHDOC
861{
862 if (change == "portSource")
863 {
864 let portSourceName = document.getElementById('portSourceSelection').innerText;
865
866 // Check API then User ports for port with same name
867 let portSource = myPorts.portsAPI.find((obj) => { return obj.name === portSourceName; });
868 if (portSource == undefined)
869 {
870 portSource = myPorts.portsUser.find((obj) => { return obj.name === portSourceName; });
871 }
872
873 // Mutate tempRoute's portSource
874 tempRoute.portSource = portSource;
875 }
876 else if (change == "waypoints")
877 {
878 let waypoints = tempWaypoints;
879 tempRoute.waypoints = waypoints;
880 }
881 else if (change == "portDestination")
882 {
883 let portDestinationName = document.getElementById('portDestinationSelection').innerText;
884
885 // Check API then User ports for port with same name
886 let portDestination = myPorts.portsAPI.find((obj) => { return obj.name === portDestinationName; });
887 if (portDestination == undefined)
888 {
889 portDestination = myPorts.portsUser.find((obj) => { return obj.name === portDestinationName; });
890 }
891
892 // Mutate tempRoute's portDestination
893 tempRoute.portDestination = portDestination;
894 }
895 else if (change == "ship")
896 {
897 let shipName = document.getElementById('shipSelection').innerText;
898
899 // Check API then User ships for ship with same name
900 let ship = myShips.shipsAPI.find((obj) => { return obj.name === shipName; });
901 if (ship == undefined)
902 {
903 ship = myShips.shipsUser.find((obj) => { return obj.name === shipName; });
904 }
905
906 // Mutate tempRoute's ship
907 tempRoute.ship = ship;
908 }
909 else if (change == "dateStart")
910 {
911 let dateStartSelectionRef = document.getElementById('dateStartSelection');
912 let dateStartDate = new Date(dateStartSelectionRef.value);
913 dateStartDate.setTime(Date.parse(String(dateStartSelectionRef.value)));
914 let dateStart = Number(dateStartDate);
915 tempRoute.dateStart = dateStart;
916 }
917
918 tempRoute.calculateAttributes();
919 enableDoneButton();
920}
921
922function enableDoneButton() // FINISHDOC
923{
924 let portSourceDefined = tempRoute.portSource instanceof Port;
925 let portDestinationDefined = tempRoute.portDestination instanceof Port;
926 let shipDefined = tempRoute.ship instanceof Ship;
927 let dateStartDefined = (typeof(tempRoute.dateStart) == "number") && (tempRoute.dateStart !== NaN);
928
929 if (portSourceDefined && portDestinationDefined && shipDefined && dateStartDefined)
930 {
931 document.getElementById('done').disabled = false;
932 }
933 else
934 {
935 document.getElementById('done').disabled = true;
936 }
937}
938
939function getPointWeather(lat,lng,time)
940{
941 let data =
942 {
943 callback: "setPointWeather"
944 }
945 timeSeconds = Math.round(time/1000);
946 darkSkyRequest(KEY_DARKSKY,lat,lng,data,timeSeconds)
947}
948
949function setPointWeather(pointData)
950{
951 let pointWeather = pointData.currently.summary;
952 tempWeather = pointWeather;
953}
954
955function showNewRouteDetail() // FINISH FINISHDOC
956{
957 let dialogBox = "";
958 dialogBox += '<dialog class="mdl-dialog">' +
959 '<h2 class="mdl-dialog__title">Select Port</h2>' +
960 '<div class="mdl-dialog__content">' +
961 '<div class="mdl-grid">' +
962
963 // Route Info Table
964 '<div class="mdl-cell mdl-cell--6-col mdl-cell--4-col-tablet mdl-cell--4-col-phone">' +
965 '<table class="mdl-data-table mdl-js-data-table mdl-shadow--2dp" id="routeInfoTable"></table>' +
966 '</div>' +
967
968 // Other Route Info and Map
969 '<div class="mdl-cell mdl-cell--6-col mdl-cell--4-col-tablet mdl-cell--4-col-phone">' +
970 '<div id="routeOtherInfoArea"></div>' +
971 '<div id="routeMapArea"></div>' +
972 '</div>' +
973 '</div>' +
974 '</div>' +
975
976 '<div class="mdl-dialog__actions">' +
977 '<button type="button" class="mdl-button confirm mdl-button--raised mdl-js-ripple-effect mdl-button--accent">Confirm Route</button>' +
978 '<button type="button" class="mdl-button cancel mdl-button--raised mdl-js-ripple-effect">Cancel</button>' +
979 '</div>' +
980 '</dialog>';
981
982 document.getElementById("hiddenDialog").innerHTML = dialogBox;
983
984 let routeInfoTableRef = document.getElementById('routeInfoTable');
985 let routeOtherInfoAreaRef = document.getElementById('routeOtherInfoArea');
986
987 routeInfoTableRef.innerHTML = tempRoute.printRouteInfoTable();
988 routeOtherInfoAreaRef.innerHTML = tempRoute.printRouteOtherInfo();
989
990 let dialog = document.querySelector('dialog');
991 let showDialogButton = document.querySelector('#show-dialog');
992 if (!dialog.showModal) {
993 dialogPolyfill.registerDialog(dialog);
994 }
995
996 dialog.querySelector('.confirm').addEventListener('click', function() {
997 myRoutes.addRoute(tempRoute);
998 dialog.close();
999 });
1000
1001 dialog.showModal();
1002 dialog.querySelector('.cancel').addEventListener('click', function() {
1003 dialog.close();
1004 });
1005}
1006
1007//* Web Service Requests */
1008function webServiceRequest(url,data)
1009{
1010 // Build URL parameters from data object.
1011 let params = "";
1012 // For each key in data object...
1013 for (let key in data)
1014 {
1015 if (data.hasOwnProperty(key))
1016 {
1017 if (params.length == 0)
1018 {
1019 // First parameter starts with '?'
1020 params += "?";
1021 }
1022 else
1023 {
1024 // Subsequent parameter separated by '&'
1025 params += "&";
1026 }
1027
1028 let encodedKey = encodeURIComponent(key);
1029 let encodedValue = encodeURIComponent(data[key]);
1030
1031 params += encodedKey + "=" + encodedValue;
1032 }
1033 }
1034 let script = document.createElement('script');
1035 script.src = url + params;
1036 document.body.appendChild(script);
1037}
1038
1039function darkSkyRequest(key,lat,lng,data,time)
1040{
1041 // Build URL parameters from data object.
1042 let params = "";
1043 // For each key in data object...
1044 for (let key in data)
1045 {
1046 if (data.hasOwnProperty(key))
1047 {
1048 if (params.length == 0)
1049 {
1050 // First parameter starts with '?'
1051 params += "?";
1052 }
1053 else
1054 {
1055 // Subsequent parameter separated by '&'
1056 params += "&";
1057 }
1058
1059 let encodedKey = encodeURIComponent(key);
1060 let encodedValue = encodeURIComponent(data[key]);
1061
1062 params += encodedKey + "=" + encodedValue;
1063 }
1064 }
1065 let script = document.createElement('script');
1066 if (time == undefined)
1067 {
1068 script.src = "https://api.darksky.net/forecast/"+key+"/"+lat+","+lng+ params;
1069 }
1070 else
1071 {
1072 script.src = "https://api.darksky.net/forecast/"+key+"/"+lat+","+lng+","+time+ params;
1073 }
1074
1075 document.body.appendChild(script);
1076}
1077
1078//* Local Storage */
1079function retrieveFromLocalStorage() // FINISH FINISHDOC
1080{}
1081
1082function storeToLocalStorage() // FINISH FINISHDOC
1083{}
1084
1085/* Global Code */
1086//* Keys */
1087mapboxgl.accessToken = "pk.eyJ1IjoiMTlzMnRlYW0wNjYiLCJhIjoiY2sxNGY3Z3E4MGpvcjNjcDk0aDJzaTNheiJ9.pYZaYmkv1rTvmcc3oaUeOQ";
1088const KEY_DARKSKY = "9760bb0ba264bc44105e76ab1f64a517";
1089
1090//* Conversion Factors */
1091const FACTOR_KNOTS_TO_KMPERH = 1.852;
1092const FACTOR_M_TO_KM = 1e-3;
1093const FACTOR_HOURS_TO_MILLISECONDS = 60 * 60 * 1000;
1094
1095//* Instantiating Container Classes */
1096let myShips = new Ships();
1097let myPorts = new Ports();
1098let myRoutes = new Routes();
1099
1100//FINISH, REMOVE LATER
1101loadShipsAPI();
1102loadPortsAPI();
1103
1104//* Local Storage */ // FINISH
1105if (typeof(Storage) !== "undefined")
1106{
1107 retrieveFromLocalStorage();
1108}
1109
1110//* Temporary Route */
1111let tempRoute = new Route();
1112let tempWaypoints = [];
1113
1114let tempWeather;
1115
1116//* Map */
1117let map = new mapboxgl.Map({
1118 container: 'mapArea', // container id
1119 style: 'mapbox://styles/mapbox/streets-v11', // stylesheet location
1120 center: [0,0], // starting position [lng, lat]
1121 zoom: 0 // starting zoom
1122});
1123
1124map.on('click', function (e) {
1125 document.getElementById('waypointsSelection').innerHTML =
1126 // e.lngLat is the longitude, latitude geographical position of the event
1127 JSON.stringify(e.lngLat.wrap());
1128 tempWaypoints.push(new Waypoint(e.lngLat.lat,e.lngLat.lng));
1129});