mirror of
https://github.com/KeymonSoft/Ruteador-NonUI.git
synced 2026-04-17 21:06:16 +00:00
- Cambios en el Algoritmo Genetico.
- Se agregó el HASH al JSON que regresa cuando se genera el ruteo.
This commit is contained in:
21
Files/LICENSE
Normal file
21
Files/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Muyang Ye
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
1033
Files/OSMTools.js
Normal file
1033
Files/OSMTools.js
Normal file
File diff suppressed because it is too large
Load Diff
60
Files/README.md
Normal file
60
Files/README.md
Normal file
@@ -0,0 +1,60 @@
|
||||

|
||||
|
||||
# 🌎 Travelnetics ([demo](https://muyangye.github.io/Traveling_Salesman_Solver_Google_Maps/))
|
||||
The Traveling Salesman Problem statement is as follows:
|
||||
```Given a list of cities and the distances between each pair of cities, what is the shortest possible route that visits each city exactly once and returns to the origin city?```
|
||||
|
||||
This problem is **NP-hard** because it is as hard as a NP-Complete problem Hamilton Cycle and doesn't have an efficient certifier (not necessarily need this to be NP-Hard though). It can not be solved within polynomial time. The reason is this:
|
||||
Suppose there are 19 cities in total, then I have 19 choices of which city should I travel first, 18 choices of which
|
||||
city should I travel second, ..., 1 choice of which city should I travel at last. In total, that is **19!** possibilities,
|
||||
out of the **19!** possibilities, I pick the one that has the shortest total distance.
|
||||
|
||||
If my computer can test **one billion** tours per second. It is going to take **19!/1,000,000,000** seconds ~ **3.85 years**
|
||||
to finish. Therefore, it is unfeasible to enumerate all possibilities. This project proposes a partial solution using
|
||||
`Genetic Algorithm` and calls `Google Maps API` to visualize. You can also utilize this project to plan your travel over 100+ places with ease.
|
||||
|
||||
### You can see a demo [here](https://muyangye.github.io/Traveling_Salesman_Solver_Google_Maps/)
|
||||
(please note that I am using my personal Google Maps API key to host the demo. So I've set up restrictions of daily usage limit.
|
||||
If you see Google Map does not load correctly. It means the daily limit was exceeded. The settings for the demo site are
|
||||
`population` of 128, `numIterations` of 10000, and `mutChance` of 0.2)
|
||||
|
||||
## ▶️ Steps to Run Locally
|
||||
1. Replace `apiKey` attribute in `config.js` with your own Google Maps API Key. If you do not have
|
||||
one, here is the [link](https://developers.google.com/maps/documentation/javascript/get-api-key)
|
||||
to create one (❗❗❗ Note: Fees charged by Google may apply ❗❗❗)
|
||||
2. Open `index.html`, type an address in the search bar and Google Maps' Autocomplete API will
|
||||
show you a list of addresses. click on one will add a waypoint, the **first** waypoint added is the origin
|
||||
3. Check `Return To Origin?` or not, which means whether the solution should include going back to the origin
|
||||
3. Click `Calculate Best Route!` at the bottom of `index.html`, enjoy!
|
||||
|
||||
## ⚙️ Customize Yourself
|
||||
### Edit `config.js`, which contains the following fields:
|
||||
- `popSize`: An `integer` == Population size == The total number of individual routes
|
||||
- `numIterations`: A `number` > `0` == How many iterations the Genetic Algorithm should run. Generally the
|
||||
more iterations, the more GA converges
|
||||
- `mutChance`: A `float` between `0` and `1` == Mutation chance, as explained in `How Does It Work?`
|
||||
|
||||
## 💡 How Does It Work?
|
||||
### [Medium Article](https://medium.com/@realymyplus/introduction-to-genetic-algorithm-with-a-website-to-watch-it-solve-traveling-salesman-problem-live-a21105a3251a)
|
||||
|
||||
## ⚠️Known Defects
|
||||
- This project solely calculates the distance between 2 waypoints using **Haversine distance**.
|
||||
However, this approach has 2 major disadvantages:
|
||||
- **Shortest distance** is not always equal to **shortest time**
|
||||
- **Haversine distance** calculates the distance of a straight line between 2 waypoints,
|
||||
whereas there are other factors involved in the **shortest distance** such as the
|
||||
**existence/straightness of a road** and/or **elevation**
|
||||
- All of the above 2 problems can be solved by simply querying [Google Maps' Directions API](https://developers.google.com/maps/documentation/directions/overview),
|
||||
but again, Google Maps charges very high for this API. In future versions, will add
|
||||
support to let the user decide whether to use [Google Maps' Directions API](https://developers.google.com/maps/documentation/directions/overview)
|
||||
or **Haversine distance** for calculating distances
|
||||
- Genetic Algorithm **does not gurantee** to generate the **global optimal solution** since
|
||||
Genetic Algorithm may converge fairly quickly. This is why we want `mutChance` for mutation
|
||||
to add a little bit of randomness here
|
||||
|
||||
## 🏆Acknowledgments && Disclaimers
|
||||
- This project's idea originates from `ITP 435-Professional C++` taught at the
|
||||
`University of Southern California` designed by [Sanjay Madhav](https://viterbi.usc.edu/directory/faculty/Madhav/Sanjay)
|
||||
- This is the first time I ever touched Javascript. I am a lifelong C++|Python|Java|PHP developer.
|
||||
So please bear with me if my Javascript coding style is a mess. Any suggestions are
|
||||
more than welcome!
|
||||
6
Files/config.js
Normal file
6
Files/config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
config = {
|
||||
"apiKey": "AIzaSyDYUOIGHUNDHrkdsU2B-WT7loUGdqGgCfg", // REPLACE WITH YOUR_API_KEY HERE
|
||||
"popSize": 128,
|
||||
"numIterations": 5000,
|
||||
"mutChance": 0.4,
|
||||
};
|
||||
BIN
Files/cover.png
Normal file
BIN
Files/cover.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 409 KiB |
270
Files/genetic-algorithm.js
Normal file
270
Files/genetic-algorithm.js
Normal file
@@ -0,0 +1,270 @@
|
||||
const CONVERT_TO_RADIAN_CONST = 1; // 0.0174533;
|
||||
|
||||
function loadScript() {
|
||||
var script = document.createElement("script");
|
||||
script.type = "text/javascript";
|
||||
script.src = "https://maps.googleapis.com/maps/api/js?key=" + config["apiKey"] + "&callback=initMap&v=weekly";
|
||||
script.defer = true;
|
||||
document.body.appendChild(script);
|
||||
}
|
||||
|
||||
function initMap() {
|
||||
let waypointsJSON = localStorage.getItem("waypoints");
|
||||
|
||||
// let waypointsJSON = [{"name":"Lago Chalco 47, Anáhuac I Secc, Miguel Hidalgo, 11320 Ciudad de México, CDMX, Mexico","lat":0.33943361448716003,"lon":-1.73094628692019},{"name":"C. Lago Chapala 47, Anáhuac I Secc., Anáhuac I Secc, Miguel Hidalgo, 11320 Ciudad de México, CDMX, Mexico","lat":0.33939502873152005,"lon":-1.73093370832688},{"name":"Lago Texcoco, Anáhuac I Secc, Ciudad de México, CDMX, Mexico","lat":0.33941341578307005,"lon":-1.73099749490239},{"name":"Lago Cuitzeo, Anáhuac I Secc., 11320 Ciudad de México, CDMX, Mexico","lat":0.33936825362399003,"lon":-1.73091535792726}]
|
||||
let returnToOrigin = localStorage.getItem("returnToOrigin");
|
||||
let waypoints = JSON.parse(waypointsJSON);
|
||||
// console.log(">>>>>> ga/waypoints", waypointsJSON);
|
||||
// console.log(waypoints);
|
||||
|
||||
const map = new google.maps.Map(document.getElementById("map"), {
|
||||
center: { lat: waypoints[0].lat / CONVERT_TO_RADIAN_CONST, lng: waypoints[0].lon / CONVERT_TO_RADIAN_CONST},
|
||||
zoom: 8,
|
||||
});
|
||||
|
||||
class Waypoint{
|
||||
constructor(name, location) {
|
||||
this.name = name;
|
||||
this.lat = location.lat();
|
||||
this.lon = location.lng();
|
||||
}
|
||||
}
|
||||
|
||||
var poly = new google.maps.Polyline({
|
||||
editable: true,
|
||||
path: []
|
||||
});
|
||||
|
||||
let popSize = config["popSize"];
|
||||
let numIterations = config["numIterations"];
|
||||
let mutChance = config["mutChance"];
|
||||
|
||||
// Fisher-Yates shuffle algorithm
|
||||
function shuffle(individual) {
|
||||
let i = individual.length;
|
||||
while (--i > 0) {
|
||||
let temp = Math.floor(Math.random() * (i + 1));
|
||||
[individual[temp], individual[i]] = [individual[i], individual[temp]];
|
||||
}
|
||||
}
|
||||
|
||||
// Generate initial population
|
||||
function genInitialPopulation(population) {
|
||||
let individual = []; //Arrego con los puntos a visitar.
|
||||
let zero = [0];
|
||||
for(i=0; i < waypoints.length; ++i){
|
||||
individual.push(i); // Agregamos el primer individuo con el orden original de los puntos.
|
||||
}
|
||||
population.push(individual)
|
||||
for (let i = 0; i < popSize; ++i) { // Agregamos a la poblacion el numero de individuos establecido (popSize).
|
||||
individual = [...Array(waypoints.length - 1).keys()].map(j => ++j); // Quitamos el 0 (punto de origen) porque es el inicio de la ruta, solo barajeamos los demas y luego lo regresamos.
|
||||
shuffle(individual); // Barajeamos los puntos del individuo para tener un individuo random.
|
||||
//console.log(">>>>> ga/individual ", i, [...Array(waypoints.length - 1).keys()].map(j => ++j), individual)
|
||||
population.push(zero.concat(individual)); // Regresamos el 0 (punto de origen) al inicio de la ruta.
|
||||
}
|
||||
// console.log(">>>>> ga/population ", population)
|
||||
}
|
||||
|
||||
// Calculate the Haversine distance between two waypoints
|
||||
function getHaversineDistance(waypoint1, waypoint2) {
|
||||
let dlon = waypoint2.lon - waypoint1.lon;
|
||||
let lat1 = waypoint1.lat;
|
||||
let lat2 = waypoint2.lat;
|
||||
let dlat = lat2 - lat1;
|
||||
let a = Math.pow(Math.sin(dlat/2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(dlon/2), 2);
|
||||
let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
|
||||
return 3961 * c;
|
||||
}
|
||||
|
||||
function calcTotalDistance(waypoints, individual) {
|
||||
let totalDistance = 0;
|
||||
for (let i = 0; i < individual.length - 1; ++i) {
|
||||
totalDistance += getDistanceFromLatLonInKm(waypoints[individual[i]], waypoints[individual[i+1]]);
|
||||
}
|
||||
// Add distance back to origin if returnToOrigin is set to true
|
||||
return returnToOrigin === "true" ? totalDistance + getHaversineDistance(waypoints[0], waypoints[individual[individual.length - 1]]) : totalDistance;
|
||||
}
|
||||
|
||||
function getDistanceFromLatLonInKm(waypoint1, waypoint2) {
|
||||
let lat1 = waypoint1.lat;
|
||||
let lon1 = waypoint1.lon;
|
||||
let lat2 = waypoint2.lat;
|
||||
let lon2 = waypoint2.lon;
|
||||
var R = 6371; // Radius of the earth in km
|
||||
var dLat = deg2rad(lat2-lat1); // deg2rad below
|
||||
var dLon = deg2rad(lon2-lon1);
|
||||
var a =
|
||||
Math.sin(dLat/2) * Math.sin(dLat/2) +
|
||||
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
|
||||
Math.sin(dLon/2) * Math.sin(dLon/2)
|
||||
;
|
||||
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
|
||||
var d = R * c; // Distance in km
|
||||
return d;
|
||||
}
|
||||
|
||||
function deg2rad(deg) {
|
||||
return deg * (Math.PI/180)
|
||||
}
|
||||
|
||||
function normalize(probabilities) {
|
||||
let sum = probabilities.reduce(function(a, b) { //Suma todos los valores del arreglo.
|
||||
return a + b;
|
||||
}, 0);
|
||||
// let x = 0;
|
||||
// probabilities.forEach((probability, index) => {
|
||||
// x += probabilities[index];
|
||||
// });
|
||||
// console.log("##### SUM: ",sum, x);
|
||||
probabilities.forEach((probability, index) => { // Cambia cada valor del arreglo con su valor dividido entre SUM.
|
||||
probabilities[index] /= sum;
|
||||
});
|
||||
}
|
||||
|
||||
function getRandomInclusive() { // Genera un numero ramdom entro 0 y 1, PERO si resulta 0, entonces regresa 1.
|
||||
return Math.random() == 0 ? 1 : Math.random();
|
||||
}
|
||||
|
||||
function getRandomIntInclusive(min, max) {
|
||||
min = Math.ceil(min); // Redondeamos hacia arriba.
|
||||
max = Math.floor(max); // Redondeamos hacia abajo.
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min; // Redondeamos hacia abajo (random * (max - min + 1)).
|
||||
}
|
||||
|
||||
function genNewPopulation(newPopulation, crossoverIndex, individual1, individual2) {
|
||||
let newIndividual = [];
|
||||
++crossoverIndex;
|
||||
for (let i = 0; i < crossoverIndex; ++i) {
|
||||
newIndividual.push(individual1[i]);
|
||||
}
|
||||
for (let i = 0; i < individual2.length; ++i) {
|
||||
if (!newIndividual.includes(individual2[i])) {
|
||||
newIndividual.push(individual2[i]);
|
||||
}
|
||||
}
|
||||
let random = getRandomInclusive();
|
||||
//console.log(random);
|
||||
if (random <= mutChance) {
|
||||
let index1 = getRandomIntInclusive(1, newIndividual.length - 1);
|
||||
let index2 = getRandomIntInclusive(1, newIndividual.length - 1);
|
||||
[newIndividual[index1], newIndividual[index2]] = [newIndividual[index2], newIndividual[index1]];
|
||||
}
|
||||
newPopulation.push(newIndividual);
|
||||
}
|
||||
|
||||
function addToPath(polyPath, latlng, count) {
|
||||
polyPath.push(latlng);
|
||||
if (count != waypoints.length+1) {
|
||||
new google.maps.Marker({
|
||||
position: latlng,
|
||||
label: {text: count.toString(), color: "#00FF00"},
|
||||
animation: google.maps.Animation.DROP,
|
||||
map: map,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function startNewCalculation() {
|
||||
window.location.href = "index.html";
|
||||
}
|
||||
document.getElementById("goto-index").addEventListener("click", startNewCalculation);
|
||||
let waypointsList = document.getElementById("waypoints-list");
|
||||
|
||||
/*
|
||||
INICIAMOS LOS CALCULOS
|
||||
*/
|
||||
let population = [];
|
||||
|
||||
// let fitTemp = [];
|
||||
let sortedIndexTemp = [];
|
||||
genInitialPopulation(population); // Mandamos population en blanco y regresamos 128 (popSize) variaciones.
|
||||
for (let i = 0; i <= numIterations; ++i) {
|
||||
// fitness[i] <==> the ith route's total distance
|
||||
let fitness = [];
|
||||
population.forEach(individual => {
|
||||
fitness.push(calcTotalDistance(waypoints, individual)); // Ponemos en fitness la distancia total entre los puntos de este individuo en particular.
|
||||
});
|
||||
// fitTemp = fitness;
|
||||
// console.log(">>>>> ga/fitness", fitness)
|
||||
let sortedIndexes = [...Array(popSize).keys()].sort((index1, index2) => {
|
||||
return fitness[index1] < fitness[index2] ? -1 : 1;
|
||||
});
|
||||
// console.log(sortedIndexes);
|
||||
|
||||
let probabilities = new Array(popSize).fill(1.0 / popSize); // No se que haga este arreglo de probabilidades, pero se usa en algoritmos geneticos.
|
||||
probabilities[sortedIndexes[0]] *= 6; // Al parecer tiene que ver con las posibiliddes de que un individuo se escoja para la siguiente generación.
|
||||
probabilities[sortedIndexes[1]] *= 6;
|
||||
for (let j = 0; j < popSize / 2; ++j) {
|
||||
probabilities[sortedIndexes[j]] *= 3;
|
||||
}
|
||||
// console.log(">>>>> ga/probabilities", probabilities);
|
||||
// let probs = [] = probabilities;
|
||||
normalize(probabilities);
|
||||
|
||||
// console.log(calcTotalDistance(waypoints, population[sortedIndexes[0]]))
|
||||
|
||||
// console.log(">>>>> ga/probabilities normalizadas", probabilities);
|
||||
if (i == numIterations) { // Si ya completamos el numero de iteraciones especificadas (numIterations), entonces salimos.
|
||||
let solution = population[sortedIndexes[0]];
|
||||
// console.log(">>>>> POPULATION: ", population)
|
||||
console.log(">>>>> FITNESS: ", fitness)
|
||||
// console.log(">>>>> SORTED INDEXES: ", sortedIndexes)
|
||||
// console.log(">>>>> PROBS: ", probs);
|
||||
// console.log(">>>>> PROBABILITIES: ", probabilities)
|
||||
console.log(">>>>> GA/SOLUTION:", solution);
|
||||
console.log(calcTotalDistance(waypoints, solution))
|
||||
let polyPath = [];
|
||||
let count = 0;
|
||||
let waypointElement = null;
|
||||
solution.forEach(waypointIndex => { // Generamos la polilinea para Google Maps.
|
||||
waypoint = waypoints[waypointIndex];
|
||||
waypointElement = document.createElement("li");
|
||||
waypointElement.append(waypoint.name);
|
||||
waypointsList.appendChild(waypointElement);
|
||||
addToPath(polyPath, new google.maps.LatLng(waypoint.lat / CONVERT_TO_RADIAN_CONST, waypoint.lon / CONVERT_TO_RADIAN_CONST), ++count);
|
||||
});
|
||||
if (returnToOrigin === "true") {
|
||||
addToPath(polyPath, new google.maps.LatLng(waypoints[0].lat / CONVERT_TO_RADIAN_CONST, waypoints[0].lon / CONVERT_TO_RADIAN_CONST), ++count);
|
||||
}
|
||||
poly.setPath(polyPath);
|
||||
poly.setMap(map);
|
||||
break;
|
||||
}
|
||||
let index1 = 0;
|
||||
let index2 = 0;
|
||||
let random = 0;
|
||||
let currSum = 0;
|
||||
let crossoverIndex = 0;
|
||||
let aGoesFirst = 0;
|
||||
let newPopulation = [];
|
||||
for (let j = 0; j < popSize; ++j) {
|
||||
currSum = 0;
|
||||
random = getRandomInclusive();
|
||||
for (let k = 0; k < popSize; ++k) { // Generamos index1.
|
||||
currSum += probabilities[k];
|
||||
if (currSum >= random) {
|
||||
index1 = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
currSum = 0;
|
||||
random = getRandomInclusive();
|
||||
for (let k = 0; k < popSize; ++k) { // Generamos index2.
|
||||
currSum += probabilities[k];
|
||||
if (currSum >= random) {
|
||||
index2 = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
crossoverIndex = getRandomIntInclusive(1, waypoints.length - 2);
|
||||
aGoesFirst = getRandomIntInclusive(0, 1);
|
||||
//console.log("****************** ",crossoverIndex, aGoesFirst)
|
||||
// Si aGoesFirst = 0 o 1, entonces obtenemos nueva poblacion de una u otra forma!
|
||||
aGoesFirst ? genNewPopulation(newPopulation, crossoverIndex, population[index1], population[index2])
|
||||
: genNewPopulation(newPopulation, crossoverIndex, population[index2], population[index1]);
|
||||
}
|
||||
population = newPopulation;
|
||||
}
|
||||
//console.log(">>>>> FITNESS TEMP: ", fitTemp)
|
||||
//console.log(">>>>> SORTED INDEXES TEMP: ", sortedIndexTemp)
|
||||
}
|
||||
51
Files/index.html
Normal file
51
Files/index.html
Normal file
@@ -0,0 +1,51 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Travelnetics</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="./style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="pac-card" id="pac-card">
|
||||
<div>
|
||||
<div id="title">Search for Waypoints</div>
|
||||
<br />
|
||||
</div>
|
||||
<div id="pac-container">
|
||||
<input id="pac-input" type="text" placeholder="Enter a location" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="map"></div>
|
||||
|
||||
<!-- Searched data -->
|
||||
<ul id="waypoints-list">
|
||||
</ul>
|
||||
<div id="infowindow-content">
|
||||
<span id="place-name" class="title"></span><br />
|
||||
<span id="place-address"></span>
|
||||
</div>
|
||||
|
||||
<div id="return-to-origin-div">
|
||||
<label>Return to Origin?
|
||||
<input id="return-to-origin" type="checkbox" checked>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div id="button-div">
|
||||
<button id="goto-result">Calculate Best Route!</button>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
The `defer` attribute causes the callback to execute after the full HTML
|
||||
document has been parsed. For non-blocking uses, avoiding race conditions,
|
||||
and consistent behavior across browsers, consider loading using Promises
|
||||
with https://www.npmjs.com/package/@googlemaps/js-api-loader.
|
||||
-->
|
||||
<script src="./config.js"></script>
|
||||
<script src="./map.js"></script>
|
||||
<script defer>
|
||||
window.initMap = initMap;
|
||||
window.onload = loadScript;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
140
Files/map.js
Normal file
140
Files/map.js
Normal file
File diff suppressed because one or more lines are too long
9
Files/osm.html
Normal file
9
Files/osm.html
Normal file
@@ -0,0 +1,9 @@
|
||||
<script type="text/javascript" src="OSMTools.js"></script>
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
at.quelltextlich.osm.embedMapMarkedLocation( 47.07655, 15.43683, 11, 500, 300 );
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
test
|
||||
</body>
|
||||
24
Files/r2.html
Normal file
24
Files/r2.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Travelnetics</title>
|
||||
<link rel="stylesheet" type="text/css" href="./style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<h2 style="text-align: center;">Results:</h2>
|
||||
<ol style="text-align: center; list-style-position: inside;" id="waypoints-list">
|
||||
</ol>
|
||||
|
||||
<div id="button-div">
|
||||
<button id="goto-index" style="cursor: pointer;">Start a New Calculation!</button>
|
||||
</div>
|
||||
|
||||
<script src="./config.js"></script>
|
||||
<script src="./genetic-algorithm.js"></script>
|
||||
|
||||
<script defer>
|
||||
window.onload = loadScript;
|
||||
window.initMap = initMap;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
24
Files/result.html
Normal file
24
Files/result.html
Normal file
@@ -0,0 +1,24 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Travelnetics</title>
|
||||
<link rel="stylesheet" type="text/css" href="./style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<h2 style="text-align: center;">Results:</h2>
|
||||
<ol style="text-align: center; list-style-position: inside;" id="waypoints-list">
|
||||
</ol>
|
||||
|
||||
<div id="button-div">
|
||||
<button id="goto-index" style="cursor: pointer;">Start a New Calculation!</button>
|
||||
</div>
|
||||
|
||||
<script src="./config.js"></script>
|
||||
<script src="./genetic-algorithm.js"></script>
|
||||
|
||||
<script defer>
|
||||
window.onload = loadScript;
|
||||
window.initMap = initMap;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
95
Files/style.css
Normal file
95
Files/style.css
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Always set the map height explicitly to define the size of the div element
|
||||
* that contains the map.
|
||||
*/
|
||||
#map {
|
||||
height: 80%;
|
||||
}
|
||||
|
||||
/*
|
||||
* Optional: Makes the sample page fill the window.
|
||||
*/
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#infowindow-content .title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#infowindow-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#map #infowindow-content {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.pac-card {
|
||||
background-color: #fff;
|
||||
border: 0;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 1px 4px -1px rgba(0, 0, 0, 0.3);
|
||||
margin: 10px;
|
||||
padding: 0 0.5em;
|
||||
font: 400 18px Roboto, Arial, sans-serif;
|
||||
overflow: hidden;
|
||||
font-family: Roboto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#pac-container {
|
||||
padding-bottom: 12px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
#pac-input {
|
||||
background-color: #fff;
|
||||
font-family: Roboto;
|
||||
font-size: 15px;
|
||||
font-weight: 300;
|
||||
margin-left: 12px;
|
||||
padding: 0 11px 0 13px;
|
||||
text-overflow: ellipsis;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
#pac-input:focus {
|
||||
border-color: #4d90fe;
|
||||
}
|
||||
|
||||
#title {
|
||||
color: #fff;
|
||||
background-color: #4d90fe;
|
||||
font-size: 25px;
|
||||
font-weight: 500;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
#button-div {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#return-to-origin-div {
|
||||
text-align: center;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
#goto-result {
|
||||
border: 2px solid coral;
|
||||
height: 50px;
|
||||
width: 200px;
|
||||
margin-bottom: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#goto-index {
|
||||
border: 2px solid coral;
|
||||
height: 50px;
|
||||
width: 200px;
|
||||
margin-bottom: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
Reference in New Issue
Block a user