aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--static/css/style.css107
-rw-r--r--static/js/map.js35
-rw-r--r--static/js/prediction.js25
-rw-r--r--static/js/search.js5
-rw-r--r--static/js/timeline-slider.js315
-rw-r--r--templates/index.html78
6 files changed, 553 insertions, 12 deletions
diff --git a/static/css/style.css b/static/css/style.css
index 79584dd..db964d1 100644
--- a/static/css/style.css
+++ b/static/css/style.css
@@ -1,3 +1,110 @@
#map {
height: 100%;
}
+
+.range {
+ position: relative;
+ width: 550px;
+ height: 5px;
+}
+
+.range input {
+ width: 100%;
+ position: absolute;
+ top: 2px;
+ height: 0;
+ -webkit-appearance: none;
+}
+.range input::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ width: 18px;
+ height: 18px;
+ margin: -8px 0 0;
+ border-radius: 50%;
+ background: #37adbf;
+ cursor: pointer;
+ border: 0 !important;
+}
+.range input::-moz-range-thumb {
+ width: 18px;
+ height: 18px;
+ margin: -8px 0 0;
+ border-radius: 50%;
+ background: #37adbf;
+ cursor: pointer;
+ border: 0 !important;
+}
+.range input::-ms-thumb {
+ width: 18px;
+ height: 18px;
+ margin: -8px 0 0;
+ border-radius: 50%;
+ background: #37adbf;
+ cursor: pointer;
+ border: 0 !important;
+}
+.range input::-webkit-slider-runnable-track {
+ width: 100%;
+ height: 2px;
+ cursor: pointer;
+ background: #b2b2b2;
+}
+.range input::-moz-range-track {
+ width: 100%;
+ height: 2px;
+ cursor: pointer;
+ background: #b2b2b2;
+}
+.range input::-ms-track {
+ width: 100%;
+ height: 2px;
+ cursor: pointer;
+ background: #b2b2b2;
+}
+.range input:focus {
+ background: none;
+ outline: none;
+}
+.range input::-ms-track {
+ width: 100%;
+ cursor: pointer;
+ background: transparent;
+ border-color: transparent;
+ color: transparent;
+}
+
+.range-labels {
+ margin: 18px -41px 0;
+ padding: 0;
+ list-style: none;
+}
+.range-labels li {
+ position: relative;
+ float: left;
+ width: 90.25px;
+ text-align: center;
+ color: #b2b2b2;
+ font-size: 14px;
+ cursor: pointer;
+}
+.range-labels li::before {
+ position: absolute;
+ top: -25px;
+ right: 0;
+ left: 0;
+ content: "";
+ margin: 0 auto;
+ width: 9px;
+ height: 9px;
+ background: #b2b2b2;
+ border-radius: 50%;
+}
+.range-labels .active {
+ color: #37adbf;
+}
+.range-labels .selected::before {
+ background: #37adbf;
+}
+.range-labels .active.selected::before {
+ display: none;
+}
diff --git a/static/js/map.js b/static/js/map.js
index a197fdb..843449b 100644
--- a/static/js/map.js
+++ b/static/js/map.js
@@ -10,13 +10,13 @@ function InitializeMap(city) {
displayMap(map, city);
}
-function reRenderMap(city) {
+function reRenderMap(city, style={}) {
map.remove();
map = L.map('map').setView([city.latitude, city.longitude], 12);
- displayMap(map, city);
+ displayMap(map, city, style);
}
-function displayMap(map, city) {
+function displayMap(map, city, style = {}) {
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
accessToken: 'pk.eyJ1IjoibHVjaWZlcmNyIiwiYSI6ImNrNGx0amIzejJkaHIzZm8yODB2dGx2cXYifQ.sopB-tKzpX_qXc30bv_puQ'
}).addTo(map);
@@ -40,8 +40,14 @@ function displayMap(map, city) {
type: 'FeatureCollection',
features: lines
};
-
+ var fg = L.featureGroup().addTo(map);
var gs = L.geoJSON(geoJSON).addTo(map);
+
+ if (style.fillColor) {
+ fg.clearLayers();
+ gs.setStyle(style);
+ }
+
try {
map.fitBounds(gs.getBounds());
} catch (e) {
@@ -76,4 +82,23 @@ function getBoundaries(city) {
}).catch(function () {
return false;
});
-} \ No newline at end of file
+}
+
+function getColors(temperature) {
+ // Generate relevant colors from temperature values for the map and return them
+ // Set hex values to 0.3 opacity
+ return temperature > 40 ? '#ff0000' : temperature > 30 ? '#ff4000' : temperature > 20 ? '#ff8000' : temperature > 10 ? '#ffbf00' : temperature > 0 ? '#ffff00' : temperature > -10 ? '#bfff00' : temperature > -20 ? '#80ff00' : temperature > -30 ? '#40ff00' : temperature > -40 ? '#00ff00' : '#00ff40';
+}
+
+// Function to change color of the map geoJSON based on provided temperature input
+function changeColor(city, temperature) {
+ var color = getColors(temperature);
+ var style = {
+ fillColor: color,
+ fillOpacity: 0.3,
+ color: color,
+ weight: 1
+ };
+ reRenderMap(city, style);
+}
+
diff --git a/static/js/prediction.js b/static/js/prediction.js
index 499cba9..7a8e2bf 100644
--- a/static/js/prediction.js
+++ b/static/js/prediction.js
@@ -1,5 +1,5 @@
var displayDataButton = document.getElementById('displayData');
-
+var temperatureData = [];
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth() + 1; //January is 0!
@@ -38,10 +38,14 @@ displayDataButton.addEventListener('click', e => {
e.preventDefault();
var cityId = document.getElementById('citySearch').getAttribute('data-city-id');
var cityName = document.getElementById('citySearch').value;
- predictData(startDate, endDate, cityId, cityName);
+ var latitude = document.getElementById('citySearch').getAttribute('latitude');
+ var longitude = document.getElementById('citySearch').getAttribute('longitude');
+ predictData(startDate, endDate, cityId, cityName, latitude, longitude);
})
-function predictData(startDate, endDate, cityId, cityName) {
+function predictData(startDate, endDate, cityId, cityName, latitude, longitude) {
+ latitude ? latitude : latitude = 42.8864;
+ longitude ? longitude : longitude = -78.8784;
var startDateValue = startDate;
var endDateValue = endDate;
if (startDateValue == '' || endDateValue == '') {
@@ -57,13 +61,13 @@ function predictData(startDate, endDate, cityId, cityName) {
end_date: endDateValue,
city_id: cityId
}, data => {
- console.log(data);
var x = data.x_data;
var y = data.y_data.map(function (item) {
return Math.round(item * 100) / 100;
});
+ temperatureData = y;
var upperBound = data.upper_bound.map(function (item) {
return Math.round(item * 100) / 100;
@@ -79,7 +83,7 @@ function predictData(startDate, endDate, cityId, cityName) {
mode: "lines",
name: "Lower Bound",
type: "scatter",
- line: { color: "rgb(0,100,80)" }
+ line: { color: "#ffbf00" }
};
var trace2 = {
@@ -89,7 +93,7 @@ function predictData(startDate, endDate, cityId, cityName) {
fillcolor: "rgba(231,107,243,0.0)",
mode: "lines",
fill: "tozerox",
- line: { color: "rgb(31, 119, 180)" },
+ line: { color: "#ff8000" },
name: "Prediction"
};
@@ -100,7 +104,7 @@ function predictData(startDate, endDate, cityId, cityName) {
mode: "lines",
name: "Upper Bound",
type: "scatter",
- line: { color: "rgb(0,176,246)" }
+ line: { color: "#ff4000" }
};
var data = [trace1, trace2, trace3];
@@ -120,6 +124,13 @@ function predictData(startDate, endDate, cityId, cityName) {
document.getElementById("processingButton").classList.add('hidden');
displayDataButton.classList.remove('hidden');
+
+ document.getElementById('rangeContainer').classList.remove('hidden');
+ changeColor({
+ city: cityName,
+ latitude: latitude,
+ longitude: longitude
+ }, temperatureData[0])
});
}
} \ No newline at end of file
diff --git a/static/js/search.js b/static/js/search.js
index c96e003..28dbd15 100644
--- a/static/js/search.js
+++ b/static/js/search.js
@@ -28,6 +28,8 @@ citySearch.addEventListener('keyup', (e) => {
citySearch.removeAttribute('data-city-id');
citySearch.value = e.target.innerText;
citySearch.setAttribute('data-city-id', e.target.getAttribute('cityId'));
+ citySearch.setAttribute('data-latitude', e.target.getAttribute('latitude'));
+ citySearch.setAttribute('data-longitude', e.target.getAttribute('longitude'));
resultContainer.classList.add('hidden');
resultContainer.innerHTML = "";
city = {
@@ -36,6 +38,9 @@ citySearch.addEventListener('keyup', (e) => {
longitude: e.target.getAttribute('longitude')
};
reRenderMap(city);
+ document.getElementById('rangeContainer').classList.add('hidden');
+ $rangeInput = $('.range input');
+ $rangeInput.val(1).trigger('input');
});
document.getElementById('results').appendChild(listElement);
}
diff --git a/static/js/timeline-slider.js b/static/js/timeline-slider.js
new file mode 100644
index 0000000..eb1f710
--- /dev/null
+++ b/static/js/timeline-slider.js
@@ -0,0 +1,315 @@
+// TODO: parameterize timeline colors, overall length, and length between points (css styles)
+L.Control.TimeLineSlider = L.Control.extend({
+
+ options: {
+ position: 'bottomright',
+ timelineItems: ["Today", "Tomorrow", "The Next Day"],
+
+ changeMap: function({label, value, map}) {
+ console.log("You are not using the value or label from the timeline to change the map.");
+ },
+ extraChangeMapParams: {},
+ initializeChange: true,
+
+ thumbHeight: "4.5px",
+ labelWidth: "80px",
+ betweenLabelAndRangeSpace: "20px",
+
+ labelFontSize: "14px",
+ activeColor: "#37adbf",
+ inactiveColor: "#8e8e8e",
+
+ backgroundOpacity: 0.75,
+ backgroundColor: "#ffffff",
+
+ topBgPadding: "10px",
+ bottomBgPadding: "0px",
+ rightBgPadding: "30px",
+ leftBgPadding: "30px",
+
+ },
+
+ initialize: function (options) {
+ if (typeof options.changeMap != "function") {
+ options.changeMap = function ({label, value, map}) {
+ console.log("You are not using the value or label from the timeline to change the map.");
+ };
+ }
+
+ if (parseFloat(options.thumbHeight) <= 2) {
+ console.log("The nodes on the timeline will not appear properly if its radius is less than 2px.")
+ }
+
+ L.setOptions(this, options);
+ },
+ onAdd: function(map) {
+ this.map = map;
+ this.sheet = document.createElement('style');
+ document.body.appendChild(this.sheet);
+
+ this.container = L.DomUtil.create('div', 'control_container');
+
+ /* Prevent click events propagation to map */
+ L.DomEvent.disableClickPropagation(this.container);
+
+ /* Prevent right click event propagation to map */
+ L.DomEvent.on(this.container, 'control_container', function (ev)
+ {
+ L.DomEvent.stopPropagation(ev);
+ });
+
+ /* Prevent scroll events propagation to map when cursor on the div */
+ L.DomEvent.disableScrollPropagation(this.container);
+
+ /* Create html elements for input and labels */
+ this.slider = L.DomUtil.create('div', 'range', this.container);
+ this.slider.innerHTML = `<input id="rangeinputslide" type="range" min="1" max="${this.options.timelineItems.length}" steps="1" value="1"></input>`
+
+ this.rangeLabels = L.DomUtil.create('ul', 'range-labels', this.container);
+ this.rangeLabels.innerHTML = this.options.timelineItems.map((item) => { return "<li>" + item + "</li>" }).join('');
+
+ this.rangeInput = L.DomUtil.get(this.slider).children[0];
+ this.rangeLabelArray = Array.from(this.rangeLabels.getElementsByTagName('li'));
+ this.sliderLength = this.rangeLabelArray.length;
+
+ this.thumbSize = parseFloat(this.options.thumbHeight) * 2;
+ // double the thumb size when its active
+ this.activeThumbSize = this.thumbSize * 2;
+
+ // make the width of the range div holding the input the number of intervals * the label width and add the thumb size on either end of the range
+ this.rangeWidthCSS = parseFloat(this.options.labelWidth) * (this.options.timelineItems.length-1) + (this.thumbSize*2);
+
+ // move labels over to the left so they line up; move half the width of the label and adjust for thumb radius
+ this.rlLabelMargin = parseFloat(this.options.labelWidth)/2 - (parseFloat(this.options.thumbHeight)/2);
+
+ // 2.5 because that is half the height of the range input
+ this.topLabelMargin = parseFloat(this.options.betweenLabelAndRangeSpace) - parseFloat(this.options.thumbHeight) - 2.5;
+
+ this.backgroundRGBA = this.hexToRGBA(this.options.backgroundColor, this.options.backgroundOpacity);
+ this.coverBackgroundRGBA = this.hexToRGBA(this.options.backgroundColor, 0);
+
+ that = this;
+
+ this.sheet.textContent = this.setupStartStyles();
+
+ /* When input gets changed change styles on slider and trigger user's changeMap function */
+ L.DomEvent.on(this.rangeInput, "input", function() {
+
+ curValue = this.value;
+
+ that.sheet.textContent += that.getTrackStyle(this, that.sliderLength);
+ var curLabel = that.rangeLabelArray[curValue-1].innerHTML;
+
+ // Change map according to either current label or value chosen
+ mapParams = {value: curValue, label: curLabel, map: map}
+ allChangeMapParameters = {...mapParams, ...that.options.extraChangeMapParams};
+ that.options.changeMap(allChangeMapParameters);
+ });
+
+ // Add click event to each label so it triggers input change for corresponding value
+ for (li of this.rangeLabelArray) {
+ L.DomEvent.on(li, "click", function (e) {
+ var targetli = e.target;
+ var index = that.rangeLabelArray.indexOf(targetli);
+ that.rangeInput.value = index + 1;
+
+ var inputEvent = new Event('input');
+ that.rangeInput.dispatchEvent(inputEvent);
+
+ });
+ };
+
+ // Initialize input change at start
+ if (this.options.initializeChange) {
+ var inputEvent = new Event('input');
+ this.rangeInput.dispatchEvent(inputEvent);
+ }
+
+ return this.container;
+
+ },
+
+ onRemove: function() {
+ // remove control html element
+ L.DomUtil.remove(this.container);
+ },
+
+ hexToRGBA: function(hex, opacity){
+ // from https://stackoverflow.com/questions/21646738/convert-hex-to-rgba
+ var c;
+ if(/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)){
+ c= hex.substring(1).split('');
+ if(c.length== 3){
+ c= [c[0], c[0], c[1], c[1], c[2], c[2]];
+ }
+ c= '0x'+c.join('');
+ return 'rgba('+[(c>>16)&255, (c>>8)&255, c&255].join(',')+','+opacity+')';
+ }
+ throw new Error('Bad Hex');
+ },
+
+ setupStartStyles: function() {
+ style = `
+ .control_container {
+ background-color: ${that.backgroundRGBA};
+ padding: ${that.options.topBgPadding} ${that.options.rightBgPadding} ${that.options.bottomBgPadding} ${that.options.leftBgPadding};
+ }
+
+ .range {
+ position: relative;
+ left: -${that.thumbSize}px;
+ height: 5px;
+ width: ${that.rangeWidthCSS}px;
+ }
+
+ .range input {
+ width: 100%;
+ position: absolute;
+ height: 0;
+ -webkit-appearance: none;
+ }
+
+ /* -1 because the height is 2 (half the height) */
+ .range input::-webkit-slider-thumb {
+ background: ${that.options.activeColor};
+ margin: -${that.thumbSize - 1}px 0 0;
+ width: ${that.activeThumbSize}px;
+ height: ${that.activeThumbSize}px;
+ -webkit-appearance: none;
+ border-radius: 50%;
+ cursor: pointer;
+ border: 0 !important;
+ }
+ .range input::-moz-range-thumb {
+ background: ${that.options.activeColor};
+ margin: -${that.thumbSize - 1}px 0 0;
+ width: ${that.activeThumbSize}px;
+ height: ${that.activeThumbSize}px;
+ border-radius: 50%;
+ cursor: pointer;
+ border: 0 !important;
+ }
+ .range input::-ms-thumb {
+ background: ${that.options.activeColor};
+ margin: -${that.thumbSize - 1}px 0 0;
+ width: ${that.activeThumbSize}px;
+ height: ${that.activeThumbSize}px;
+ border-radius: 50%;
+ cursor: pointer;
+ border: 0 !important;
+ }
+
+
+ .range input::-webkit-slider-runnable-track {
+ background: ${that.options.backgroundColor};
+ width: 100%;
+ height: 2px;
+ cursor: pointer;
+ }
+ .range input::-moz-range-track {
+ background: ${that.options.backgroundColor};
+ width: 100%;
+ height: 2px;
+ cursor: pointer;
+ }
+ .range input::-ms-track {
+ background: ${that.options.backgroundColor};
+ width: 100%;
+ height: 2px;
+ cursor: pointer;
+ background: transparent;
+ border-color: transparent;
+ color: transparent;
+ }
+
+ .range input:focus {
+ background: none;
+ outline: none;
+ }
+
+ . range input[type=range]::-moz-focus-outer {
+ border: 0;
+ }
+
+ .range-labels {
+ margin: ${that.topLabelMargin}px -${that.rlLabelMargin}px 0;
+ padding: 0;
+ list-style: none;
+ }
+
+ .range-labels li {
+ color: ${that.options.inactiveColor};
+ width: ${that.options.labelWidth};
+ font-size: ${that.options.labelFontSize};
+ position: relative;
+ float: left;
+ text-align: center;
+ cursor: pointer;
+ }
+ .range-labels li::before {
+ background: ${that.options.inactiveColor};
+ width: ${that.thumbSize}px;
+ height: ${that.thumbSize}px;
+ position: absolute;
+ top: -${that.options.betweenLabelAndRangeSpace};
+ right: 0;
+ left: 0;
+ content: "";
+ margin: 0 auto;
+ border-radius: 50%;
+ }
+ .range-labels .active {
+ color: ${that.options.activeColor};
+ }
+ .range-labels .selected::before {
+ background: ${that.options.activeColor};
+ }
+ .range-labels .active.selected::before {
+ display: none;
+ }
+ `;
+
+
+ return style;
+
+ },
+
+ getTrackStyle: function (el, sliderLength) {
+ prefs = ['webkit-slider-runnable-track', 'moz-range-track', 'ms-track'];
+
+ var curVal = el.value,
+ labelIndex = curVal - 1,
+ val = (labelIndex) * (100/(sliderLength-1)),
+ coverVal = (parseFloat(that.thumbSize)/that.rangeWidthCSS) * 100;
+ style = '';
+
+ // Remove active and selected classes from all labels
+ for (li of that.rangeLabelArray) {
+ L.DomUtil.removeClass(li, 'active');
+ L.DomUtil.removeClass(li, 'selected');
+ }
+
+ // Find label that should be active and give it appropriate classes
+ var curLabel = that.rangeLabelArray[labelIndex];
+ L.DomUtil.addClass(curLabel, 'active');
+ L.DomUtil.addClass(curLabel, 'selected');
+
+ // For labels before active label, add selected class
+ for (i = 0; i < curVal; i++) {
+ L.DomUtil.addClass(that.rangeLabelArray[i], 'selected');
+ }
+
+ // Change background gradient
+ for (var i = 0; i < prefs.length; i++) {
+ style += `.range {background: linear-gradient(to right, ${that.coverBackgroundRGBA} 0%, ${that.coverBackgroundRGBA} ${coverVal}%, ${that.options.activeColor} ${coverVal}%, ${that.options.activeColor} ${val}%, ${that.coverBackgroundRGBA} 0%, ${that.coverBackgroundRGBA} 100%)}`;
+ style += '.range input::-' + prefs[i] + `{background: linear-gradient(to right, ${that.coverBackgroundRGBA} 0%, ${that.coverBackgroundRGBA} ${coverVal}%, ${that.options.activeColor} 0%, ${that.options.activeColor} ${val}%, ${that.options.inactiveColor} ${val}%, ${that.options.inactiveColor} ${100-coverVal}%, ${that.coverBackgroundRGBA} ${100-coverVal}%, ${that.coverBackgroundRGBA} 100%)}`;
+ }
+
+ return style;
+ }
+
+})
+
+L.control.timelineSlider = function(options) {
+ return new L.Control.TimeLineSlider(options);
+} \ No newline at end of file
diff --git a/templates/index.html b/templates/index.html
index 789babf..2e6d325 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -66,6 +66,30 @@
<div class="h-3/4 mx-auto">
<div class="border-4 border-dashed border-gray-200 rounded-lg h-full">
<div id="map"></div>
+ <div id="rangeContainer" class="rangeContainer hidden" style=" position: relative;
+ top: -12vh;
+ z-index: 1000;
+ right: 0vw;
+ background: white;
+ padding: 30px 30px 30px 30px;
+ width: 615px;">
+ <p style="position: relative;
+ top: -20px;
+ left: -15px;">Temperature Visualization:</p>
+ <div class="range">
+ <input id="changeDate" type="range" min="1" max="7" steps="1" value="1">
+ </div>
+
+ <ul class="range-labels">
+ <li class="active selected">Today</li>
+ <li>2 days</li>
+ <li>3 days</li>
+ <li>4 days</li>
+ <li>5 days</li>
+ <li>6 days</li>
+ <li>7 days</li>
+ </ul>
+ </div>
</div>
</div>
<div class="mx-auto px-3 py-6 text-center">
@@ -89,6 +113,7 @@
</body>
<script src="https://cdn.plot.ly/plotly-2.6.3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
+<script src="../static/js/timeline-slider.js" defer></script>
<script type="text/javascript">
const cities = JSON.parse('{{cities_list | tojson}}');
</script>
@@ -96,5 +121,58 @@
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script src="../static/js/search.js" defer></script>
<script src="../static/js/prediction.js" defer></script>
+<script>
+ var sheet = document.createElement('style'),
+ $rangeInput = $('.range input'),
+ prefs = ['webkit-slider-runnable-track', 'moz-range-track', 'ms-track'];
+
+ document.body.appendChild(sheet);
+
+ var getTrackStyle = function (el) {
+ var curVal = el.value,
+ val = (curVal - 1) * 16.666666667,
+ style = '';
+
+ // Set active label
+ $('.range-labels li').removeClass('active selected');
+
+ var curLabel = $('.range-labels').find('li:nth-child(' + curVal + ')');
+
+ curLabel.addClass('active selected');
+ curLabel.prevAll().addClass('selected');
+
+ // Change background gradient
+ for (var i = 0; i < prefs.length; i++) {
+ style += '.range {background: linear-gradient(to right, #37adbf 0%, #37adbf ' + val + '%, #fff ' + val + '%, #fff 100%)}';
+ style += '.range input::-' + prefs[i] + '{background: linear-gradient(to right, #37adbf 0%, #37adbf ' + val + '%, #b2b2b2 ' + val + '%, #b2b2b2 100%)}';
+ }
+
+ return style;
+ }
+
+ $rangeInput.on('input', function () {
+ sheet.textContent = getTrackStyle(this);
+ });
+
+ // Change input value on label click
+ $('.range-labels li').on('click', function () {
+ var index = $(this).index();
+
+ $rangeInput.val(index + 1).trigger('input');
+ var currentCityName = document.getElementById('citySearch').value || 'Buffalo';
+ var latitude = document.getElementById('citySearch').getAttribute('latitude') || '42.8864';
+ var longitude = document.getElementById('citySearch').getAttribute('longitude') || '-78.8784';
+ changeColor({ city: currentCityName, latitude: latitude, longitude: longitude }, temperatureData[index]);
+
+ });
+
+ document.getElementById('changeDate').addEventListener('change', (e) => {
+ var currentCityName = document.getElementById('citySearch').value || 'Buffalo';
+ var latitude = document.getElementById('citySearch').getAttribute('latitude') || '42.8864';
+ var longitude = document.getElementById('citySearch').getAttribute('longitude') || '-78.8784';
+ changeColor({ city: currentCityName, latitude: latitude, longitude: longitude }, temperatureData[e.target.value - 1]);
+ })
+
+</script>
</html> \ No newline at end of file