Stopping a Finite State Machine - javascript

I have an application that I have written that adds a set of traffic lights on the screen upon the press of a button. The traffic light automatically cycles from red to yellow after 10 seconds, then on to green after two seconds, then back to yellow after 10 seconds and finally back to red. I have added a control which allows the user to start each traffic light individually. I am trying to figure out how to enable the user to permanently stop each traffic light, without it stopping all the others.
Here is my updated code so far - note the addition of the 'this.stop()' function inside of var Red. I would like the code to stop the rotation there, rather than continue to yellow and green.
Thanks,
Rob
var i = 1;
var TrafficLight = function(i) {
var count = 0;
var light_container = document.getElementById('light-container-' + i);
var currentState = new Red(this, light_container);
this.change = function(state) {
currentState = state;
currentState.go();
}
this.start = function() {
currentState.go();
}
this.stop = function() {
currentState.stop();
}
}
var Red = function(light, light_container) {
this.light = light;
this.go = function() {
light_container.querySelector('.inner-circle-red').style.backgroundColor = '#d8412c';
console.log(light_container);
setTimeout(function() {
light.change(new Yellow(light, 'red', light_container))
}, 12000);
}
this.stop = function() {
light_container.querySelector('.inner-circle-red').style.backgroundColor = '#111111';
light_container.querySelector('.inner-circle-yellow').style.backgroundColor = '#111111';
light_container.querySelector('.inner-circle-green').style.backgroundColor = '#111111';
// Switch all the lights off.
return;
}
}
var Yellow = function(light, origin, light_container) {
this.light = light;
this.go = function() {
light_container.querySelector('.inner-circle-yellow').style.backgroundColor = '#fad201';
setTimeout(function() {
if (origin == 'red') {
light.change(new Green(light, light_container));
light_container.querySelector('.inner-circle-red').style.backgroundColor = '#111111';
light_container.querySelector('.inner-circle-yellow').style.backgroundColor = '#111111';
} else if (origin == 'green') {
light.change(new Red(light, light_container));
light_container.querySelector('.inner-circle-yellow').style.backgroundColor = '#111111';
}
}, 2000);
}
}
var Green = function(light, light_container) {
this.light = light;
console.log('here');
this.go = function() {
light_container.querySelector('.inner-circle-green').style.backgroundColor = '#33A532';
setTimeout(function() {
light.change(new Yellow(light, 'green', light_container))
light_container.querySelector('.inner-circle-green').style.backgroundColor = '#111111';
}, 14000);
}
};
function initiate() {
var light_container = document.createElement('div');
light_container.id = "light-container-" + i;
light_container.className = "light-container";
light_container.innerHTML = '<div class="outer-circle-red"><div class="inner-circle-red"></div></div><div class="outer-circle-yellow"><div class="inner-circle-yellow"></div></div><div class="outer-circle-green"><div class="inner-circle-green"></div></div><label class="switch"><input type="checkbox" class="off" onclick="toggleRun(this, ' + i + ');"><span class="slider round"></span></label>';
document.getElementById("container").appendChild(light_container);
i++;
}
function toggleRun(item, i) {
if (item.className == "off") {
item.className = "on";
run(i);
} else {
item.className = "off";
stop(i);
}
}
function run(i) {
var light = new TrafficLight(i);
light.start();
}
function stop(i) {
var light = new TrafficLight(i);
light.stop();
}
function exit(status) {
var i;
if (typeof status === 'string') {
alert(status);
}
window.addEventListener('error', function(e) {
e.preventDefault();
e.stopPropagation();
}, false);
var handlers = [
'copy', 'cut', 'paste',
'beforeunload', 'blur', 'change', 'click', 'contextmenu', 'dblclick', 'focus', 'keydown', 'keypress', 'keyup', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'resize', 'scroll',
'DOMNodeInserted', 'DOMNodeRemoved', 'DOMNodeRemovedFromDocument', 'DOMNodeInsertedIntoDocument', 'DOMAttrModified', 'DOMCharacterDataModified', 'DOMElementNameChanged', 'DOMAttributeNameChanged', 'DOMActivate', 'DOMFocusIn', 'DOMFocusOut', 'online', 'offline', 'textInput',
'abort', 'close', 'dragdrop', 'load', 'paint', 'reset', 'select', 'submit', 'unload'
];
function stopPropagation(e) {
e.stopPropagation();
// e.preventDefault(); // Stop for the form controls, etc., too?
}
for (i = 0; i < handlers.length; i++) {
window.addEventListener(handlers[i], function(e) {
stopPropagation(e);
}, true);
}
if (window.stop) {
window.stop();
}
throw '';
}
#button {
width: 200px;
height: 20px;
padding: 10px;
background-color: blue;
color: #ffffff;
cursor: pointer;
}
.button {
width: 15px;
height: 20px;
padding: 10px;
background-color: red;
color: #ffffff;
cursor: pointer;
margin: 20px auto;
text-align: center;
text-transform: uppercase;
font-weight: bold;
}
.outer-circle-red,
.outer-circle-yellow,
.outer-circle-green {
background-color: #696969;
margin: 0 auto;
border: 2px solid black;
width: 50px;
height: 40px;
border-radius: 15px;
display: table;
}
.light-container {
margin: 20px 30px 0 30px;
margin-top: 20px;
float: left;
}
.inner-circle-red,
.inner-circle-yellow,
.inner-circle-green {
width: 20px;
height: 20px;
border-radius: 25px;
border: 2px solid #111111;
margin: 0 auto;
margin-top: 7.5px;
background-color: #111111;
}
/* The switch - the box around the slider */
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
margin-top: 20px;
}
/* Hide default HTML checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}
/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
input:checked+.slider {
background-color: #2196F3;
}
input:focus+.slider {
box-shadow: 0 0 1px #2196F3;
}
input:checked+.slider:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
/* Rounded sliders */
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
<div id="button" onclick="initiate()">+ Add a new traffic light</div>
<div id="container">
</div>

The solution to this is to save the id returned by var id = setTimeout(), so you can use clearTimeout( id ); later on to completely stop the timeout function from triggering again.
So something like: this.timeout = setInterval(function(){ /* insert the color changing code */ }, 10000 );.
If you opt for such a solution, it would be handy to put the timeout code into a single timeout instead of having a separate class for each color. But you can always use an array to store all timeouts and loop over that to cancel if you like having different timeouts for each color.

Related

Collision detection in nuxt.js. code is running without errors. But some functionalities not working

I am working with collision detection in vue.js using nuxt.js framework. I have done a similar program from this source
https://codepen.io/dropinks/pen/MrzPXB
I have converted this js code in vue friendly template and script. Only problem is that the the collision is not being detected . Please take a look at my code and tell where i made mistake.
Here is the link for codesandbox online editor where i have the code
https://codesandbox.io/s/wispy-hill-466s7?file=/pages/index.vue
template code:
<template>
<div class="container">
<div class="rectangle-1" id="rect">Hover Me</div>
<div class="rectangle-2" id="dragMe">Drag Me</div>
</div>
</template>
styles:
<style scoped>
container {
position: relative;
}
.rectangle-1 {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background: #4CAF50;
width: 180px;
height: 150px;
border-radius: 5px;
transition: 0.3s all ease;
color: #fff;
text-align: center;
line-height: 150px;
font-size: 25px;
}
.rectangle-1.collide {
background: #EF5350;
}
.rectangle-1:after {
content: ":-)";
position: absolute;
bottom: -50px;
left: 50%;
transform: translateX(-50%);
}
.rectangle-1.collide:after {
content: ":-(";
}
.rectangle-2 {
position: absolute;
background: #F5B041;
width: 100px;
height: 100px;
border-radius: 5px;
z-index: 10;
cursor: move;
transition: 0.5s box-shadow ease, 0.5s transform ease;
transform: translate(0, 0);
top: 40%;
left: 30%;
text-align: center;
line-height: 100px;
font-size: 17px;
}
.rectangle-2.onDrag {
box-shadow: 5px 5px 25px 0px rgba(0, 0, 0, 0.2);
transform: translate(-3px, -3px);
}
</style>
script
<script>
export default {
data() {
return {
dragMe: "",
rect: "",
};
},
created: function () {
if (process.client) {
this.myFunction();
}
},
methods: {
myFunction: function () {
this.rect = document.getElementById("rect");
this.dragMe = document.getElementById("dragMe");
this.initDrag({
element: this.dragMe,
drag: function () {
this.isCollapsed(this.dragMe, this.rect);
},
});
},
isCollapsed: function (dragMe, rect) {
var object_1 = this.dragMe.getBoundingClientRect();
var object_2 = this.rect.getBoundingClientRect();
if (
object_1.left < object_2.left + object_2.width &&
object_1.left + object_1.width > object_2.left &&
object_1.top < object_2.top + object_2.height &&
object_1.top + object_1.height > object_2.top
) {
rect.classList.add("collide");
document.getElementById('dragMe').style.background = 'blue';
} else {
rect.classList.remove("collide");
}
},
initDrag: function (options) {
var element = options.element;
var mousedown,
mouseup,
mousemove,
dragStart,
initX,
initY,
offsetLeft,
offsetTop;
function mouseMove(ev) {
if (dragStart) {
var newX = offsetLeft + (ev.pageX - initX);
var newY = offsetTop + (ev.pageY - initY);
element.style.top = newY + "px";
element.style.left = newX + "px";
options.drag.call();
}
}
function mouseUp(ev) {
dragStart = false;
document.removeEventListener("mousemove", mouseMove, false);
document.removeEventListener("mouseup", mouseUp, false);
options.stop.call();
}
function mouseDown(ev) {
initX = ev.pageX;
initY = ev.pageY;
dragStart = true;
offsetLeft = element.offsetLeft;
offsetTop = element.offsetTop;
document.addEventListener(
"mousemove",
function (ev) {
mouseMove(ev);
},
false
);
document.addEventListener(
"mouseup",
function (ev) {
mouseUp(ev);
},
false
);
options.start.call();
}
element.addEventListener(
"mousedown",
function (ev) {
mouseDown(ev);
},
false
);
},
},
};
</script>

Add delay to show loading GIF on button, then close div (to load results)

I would like to have a button, that when clicked shows a pre-loading gif for 1-second, and then closes the div #sidefilter, that the user has open.
I have been able to get both of them working independently, but they are not working as intended, I think I need to add a delay to #dismissiefilter, and then end the loading GIF when executed.
What needs to be added to enable the above to happen?
$('.showloader').button();
$('.showloader').click(function() {
$(this).html('<img src="http://www.bba-reman.com/images/fbloader.gif" />');
});
$('#dismisssidefilter, .overlay').on('click', function() {
$('#sidefilter').removeClass('active');
$('.overlay').removeClass('active');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
See results
Working link:
https://clearing.co.uk/dev/universities/
Filter button next to 'search for a university' input field
I've updated my answer with a demo representing your site
$(function() {
var devActions = function(str, clear) {
let output = $('#dev-output');
if (typeof clear === 'boolean' && clear === true) {
output.empty();
}
output.append(' - ' + str + '<br />');
console.log('devActions:', str);
}
$('#sidefilterCollapse').on('click', function() {
var sidebar = $('#sidefilter');
if (!sidebar.hasClass('active')) {
sidebar.addClass('active');
devActions('#sidefilterCollapse clicked', true);
devActions('Adding .active class to #sidefilter');
if ($('#sidefilter').hasClass('active')) {
devActions('#sidefilter now has .active class');
} else {
devActions('somethings went wrong #sidefilter doesn\'t have .active class');
}
} else {
devActions('#sidefilter already has .active class');
}
})
$('.showloader').on('click', function(e) {
e.preventDefault();
var btn = $(this);
// add .loading class so we can prevent spam click
if (!btn.hasClass('loading')) {
btn.addClass('loading');
var saveOriginalText = $(this).html();
var duration = 3000;
btn.html('<img src="http://www.bba-reman.com/images/fbloader.gif" />');
if (btn.children('img').length) {
devActions('.showloader clicked and image was added.');
}
btn.stop(true).animate({
opacity: 1
}, {
duration: duration,
start: function() {
devActions('animation started');
},
complete: function() {
devActions('animation done');
// remove .loading class so we can make the button available again
btn.removeClass('loading');
btn.html(saveOriginalText);
if ($(this).html() == saveOriginalText) {
devActions('original button content was added on .showloader');
}
// do custom stuff after 1000ms
$('#sidefilter').removeClass('active');
if (!$('#sidefilter').hasClass('active')) {
devActions('.active class has been removed from #sidefilter');
}
}
})
} else {
devActions('---- don\'t spam click, currently loading ---');
}
});
})
body {
overflow-x: hidden;
font-family: "Segoe UI";
}
#sidefilterCollapse,
.showloader {
padding: 3px 5px;
line-height: 1rem;
width: 100px;
background: red;
color: white;
display: inline-block;
text-align: center;
border-radius: 20px;
cursor: pointer;
text-decoration: none;
}
#sidefilter {
text-align: center;
position: fixed;
right: -200px;
top: 0;
padding: 15px 10px;
box-sizing: border-box;
width: 200px;
height: 100%;
border-left: 1px solid lightgrey;
box-shadow: -2px 0 13px 2px grey;
transition: right 0.2s ease-in-out;
}
#sidefilter.active {
right: 0;
transition: right 0.2s ease-in-out;
}
#sidefilter p {
text-align: left;
margin-bottom: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="sidefilterCollapse">
Filter Button
</div>
<div id="sidefilter">
<p>
text text text text text text text text text
</p>
See results
</div>
<div id="dev-output"></div>

Custom Media player design to scale when width changed

I am having a Trouble with this custom media player, Media player not functioning properly.
I have 2 problems:
When full-screen it goes back to the default HTML5 player
When i adjust the width of the video tag it throws all of the spacing out and ruins the player.
HTML
<!DOCTYPE HTML>
<html>
<head>
<title>Video/Audio</title>
<link rel='stylesheet' type='text/css' href='style.css' />
<style type="text/css">
</style>
<script src='jquery.js'></script>
<script src='javascript.js'></script>
<script type='text/javascript'>
$(document).ready(function() {
$('video').videoPlayer({
'playerWidth' : 1,
'videoClass' : 'video'
});
});
</script>
</head>
<body>
<div class="container" class="player">
<video width="700" height="400">
<source src="https://s3-eu-west-1.amazonaws.com/icevideos/151014+Cathodic+Protection+of+Highways/151014.PETERBOROUGH.CATHODICPROTECTION.HIGH1.mp4" type="video/mp4">
<source src="movie.webm" type="video/webm">
</video>
</div>
</body>
</html>
CSS
body {
font-size: 62.5%;
padding: 0;
margin: 0;
}
.player {
background: grey;
box-sizing: border-box;
height: 40px;
-moz-box-sizing: border-box;
float: left;
font-family: Arial, sans-serif;
position: absolute;
padding: 0;
bottom: 4px;
z-index: 2;
opacity: 1;
box-shadow: 0 0 10px rgba(0,0,0,0.3);
-webkit-transition: opacity 0.3s ease-in;
transition: opacity 0.3s ease-in;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
width: 100%;
}
.video {
position: relative;
margin: 0px auto;
}
.video:hover .player {
opacity: 1;
}
.player .progress {
width: 60%;
height: 20px;
border-radius: 5px;
background: #000;
box-shadow: inset 0 -5px 10px rgba(0,0,0,0.1);
float: left;
cursor: pointer;
margin: 12px 0 0 0;
padding: 0;
position: relative;
font-variant: normal;
margin-left: 20px;
}
.player .progress-bar {
background: #FF6600;
border-radius: 5px;
height: 100%;
position: relative;
z-index: 999;
width: 0;
}
.player .button-holder {
position: relative;
left: 10px;
}
.player .progress-button {
background: #00bdff;
box-shadow: 0 0 20px rgba(0,0,0,0.3);
border-radius: 30px;
width: 20px;
height: 20px;
position: absolute;
left: -20px;
text-decoration: overline;
}
.player [class^="buffered"] {
background: rgba(255,255,255,0.1);
position: absolute;
top: 0;
left: 30px;
height: 100%;
border-radius: 5px;
z-index: 1;
}
.player .play-pause {
display: inline-block;
font-size: 3em;
float: left;
text-shadow: 0 0 0 #fff;
color: #00bdff;
width: 4%;
padding: 4px 0 0 0;
margin-left: 15px;
cursor: pointer;
font-variant: small-caps;
}
.player .play, .player .pause-button {
-webkit-transition: all 0.2s ease-out;
}
.player .play .pause-button, .player .pause .play-button {
display: none;
}
.player .pause-button {
padding: 5px 2px;
box-sizing: border-box;
-moz-box-sizing: border-box;
height: 34px;
}
.player .pause-button span {
background: #FF6600;
width: 8px;
height: 24px;
float: left;
display: block;
}
.player .pause-button span:first-of-type {
margin: 0 4px 0 0;
}
.player .time {
color: #fff;
font-weight: bold;
font-size: 1.2em;
position: absolute;
width: 150px;
margin-left: 425px;
bottom: 3px;
}
.player .stime, .ttime {
color: #fff;
}
.player .play:hover {
text-shadow: 0 0 5px #fff;
}
.player .play:active, .pause-button:active span {
text-shadow: 0 0 7px #fff;
}
.player .pause-button:hover span {
box-shadow: 0 0 5px #fff;
} .player .pause-button:active span {
box-shadow: 0 0 7px #fff;
}
.player .volume {
position: relative;
float: left;
width: 7%;
height: 100%;
margin-left: 70px;
}
.player .volume-icon {
padding: 1.5%;
height: 100%;
cursor: pointer;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-transition: all 0.15s linear;
}
.player .volume-icon-hover {
background-color: grey;
}
.player .volume-holder {
height: 100px;
width: 80%;
position: absolute;
display: none;
background: grey;
left: 0;
border-radius: 5px 5px 0 0;
top: -100px;
}
.player .volume-bar-holder {
background: black;
width: 20px;
box-shadow: inset 0px 0px 5px rgba(0,0,0,0.3);
margin: 15px auto;
height: 80px;
border-radius: 5px;
position: relative;
cursor: pointer;
}
.player .volume-button {
background: #00bdff;
box-shadow: 0 0 20px rgba(0,0,0,0.3);
border-radius: 30px;
width: 20px;
height: 20px;
}
.player .volume-button-holder {
position: relative;
top: -10px;
}
.player .volume-bar {
background: #FF6600;
border-radius: 5px;
width: 100%;
height: 100%;
position: absolute;
bottom: 0;
}
.player .fullscreen {
width: 5%;
cursor: pointer;
float: left;
height: 100%;
}
.player .fullscreen a {
width: 25px;
height: 20px;
border-radius: 3px;
background: #00bdff;
display: block;
position: relative;
top: 10px;
margin: 0px auto;
}
.player .fullscreen a:hover {
background: #FF6600;
}
.player .volume-icon span {
width: 20%;
height: 23%;
background-color: #00bdff;
display: block;
position: relative;
z-index: 1;
font-weight: bold;
top: 40%;
color: #fff;
left: 22%;
}
.player .volume-icon span:before,
.player .volume-icon span:after {
content: '';
position: absolute;
}
.player .volume-icon span:before {
width: 0;
height: 0;
border: 1em solid transparent;
border-left: none;
border-right-color: #00bdff;
z-index: 2;
top: -2px;
left: 10%;
margin-top: -40%;
}
.player .volume-icon span:after {
width: 10%;
height: 4%;
border: 1px solid #00bdff;
left: 150%;
border-width: 0px 0px 0 0;
border-radius: 0 50px 0 0;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
font-variant: small-caps;
}
.player .v-change-11 span:after { border-width: 10px 10px 0 0; top: 0; }
.player .v-change-10 span:after { border-width: 9px 9px 0 0; top: 1px; }
.player .v-change-9 span:after { border-width: 8px 8px 0 0; top: 1px; }
.player .v-change-8 span:after { border-width: 7px 7px 0 0; top: 2px; }
.player .v-change-7 span:after { border-width: 6px 6px 0 0; top: 2px; }
.player .v-change-6 span:after { border-width: 5px 5px 0 0; top: 3px; }
.player .v-change-5 span:after { border-width: 4px 4px 0 0; top: 3px; }
.player .v-change-4 span:after { border-width: 3px 3px 0 0; top: 4px; }
.player .v-change-3 span:after { border-width: 2px 2px 0 0; top: 4px; }
.player .v-change-2 span:after { border-width: 1px 1px 0 0; top: 5px; }
.player .v-change-1 span:after { border-width: 0px 0px 0 0; top: 5px; }
.player .v-change-1 span:after {
content: '+';
-webkit-transform: rotate(45deg);
font-size: 20px;
top: -6px;
left: 25px;
color: #00bdff;
}
/* ------- IGNORE */
#header {
width: 100%;
margin: 0px auto;
}
#header #center {
text-align: center;
}
#header h1 span {
color: #000;
display: block;
font-size: 50px;
}
#header p {
font-family: 'Georgia', serif;
}
#header h1 {
color: #892dbf;
font: bold 40px 'Bree Serif', serif;
}
#travel {
padding: 10px;
background: rgba(0,0,0,0.6);
border-bottom: 2px solid rgba(0,0,0,0.2);
font-variant: normal;
text-decoration: none;
}
#travel a {
font-family: 'Georgia', serif;
text-decoration: none;
border-bottom: 1px solid #f9f9f9;
font-size: 20px;
color: #f9f9f9;
}
.container {
padding: 40px 0 0 0;
}
.logo {
margin-top: 9px;
float: left;
margin-left: 6px;
}
JS
(function($) {
$.fn.videoPlayer = function(options) {
var settings = {
playerWidth : '0.95', // Default is 95%
videoClass : 'video' // Video Class
}
// Extend the options so they work with the plugin
if(options) {
$.extend(settings, options);
}
// For each so that we keep chainability.
return this.each(function() {
$(this)[0].addEventListener('loadedmetadata', function() {
// Basic Variables
var $this = $(this);
var $settings = settings;
// Wrap the video in a div with the class of your choosing
$this.wrap('<div class="'+$settings.videoClass+'"></div>');
// Select the div we just wrapped our video in for easy selection.
var $that = $this.parent('.'+$settings.videoClass);
// The Structure of our video player
{
$( '<div class="player">'
+'<img class="logo" src="http://www.cpdonline.tv/ice-events/mediaplayer/icelogo.png" height="20px">'
+ '<div class="play-pause play">'
+ '<span class="play-button">►</span>'
+ '<div class="pause-button">'
+ '<span> </span>'
+ '<span> </span>'
+ '</div>'
+ '</div>'
+ '<div class="progress">'
+ '<div class="progress-bar">'
+ '<div class="button-holder">'
+ '<div class="progress-button"> </div>'
+ '</div>'
+ '</div>'
+ '<div class="time">'
+ '<span class="ctime">00:00</span>'
+ '<span class="stime"> / </span>'
+ '<span class="ttime">00:00</span>'
+ '</div>'
+ '</div>'
+ '<div class="volume">'
+ '<div class="volume-holder">'
+ '<div class="volume-bar-holder">'
+ '<div class="volume-bar">'
+ '<div class="volume-button-holder">'
+ '<div class="volume-button"> </div>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '<div class="volume-icon v-change-0">'
+ '<span> </span>'
+ '</div>'
+ '</div>'
+ '<div class="fullscreen"> '
+ ' '
+ '</div>'
+ '</div>').appendTo($that);
}
// Width of the video
$videoWidth = $this.width();
$that.width($videoWidth+'px');
// Set width of the player based on previously noted settings
$that.find('.player').css({'width' : ($settings.playerWidth*100)+'%', 'left' : ((100-$settings.playerWidth*100)/2)+'%'});
// Video information
var $spc = $(this)[0], // Specific video
$duration = $spc.duration, // Video Duration
$volume = $spc.volume, // Video volume
currentTime;
// Some other misc variables to check when things are happening
var $mclicking = false,
$vclicking = false,
$vidhover = false,
$volhover = false,
$playing = false,
$drop = false,
$begin = false,
$draggingProgess = false,
$storevol,
x = 0,
y = 0,
vtime = 0,
updProgWidth = 0,
volume = 0;
// Setting the width, etc of the player
var $volume = $spc.volume;
// So the user cant select text in the player
$that.bind('selectstart', function() { return false; });
// Set some widths
var progWidth = $that.find('.progress').width();
var bufferLength = function() {
// The buffered regions of the video
var buffered = $spc.buffered;
// Rest all buffered regions everytime this function is run
$that.find('[class^=buffered]').remove();
// If buffered regions exist
if(buffered.length > 0) {
// The length of the buffered regions is i
var i = buffered.length;
while(i--) {
// Max and min buffers
$maxBuffer = buffered.end(i);
$minBuffer = buffered.start(i);
// The offset and width of buffered area
var bufferOffset = ($minBuffer / $duration) * 100;
var bufferWidth = (($maxBuffer - $minBuffer) / $duration) * 100;
// Append the buffered regions to the video
$('<div class="buffered"></div>').css({"left" : bufferOffset+'%', 'width' : bufferWidth+'%'}).appendTo($that.find('.progress'));
}
}
}
// Run the buffer function
bufferLength();
// The timing function, updates the time.
var timeUpdate = function($ignore) {
// The current time of the video based on progress bar position
var time = Math.round(($('.progress-bar').width() / progWidth) * $duration);
// The 'real' time of the video
var curTime = $spc.currentTime;
// Seconds are set to 0 by default, minutes are the time divided by 60
// tminutes and tseconds are the total mins and seconds.
var seconds = 0,
minutes = Math.floor(time / 60),
tminutes = Math.round($duration / 60),
tseconds = Math.round(($duration) - (tminutes*60));
// If time exists (well, video time)
if(time) {
// seconds are equal to the time minus the minutes
seconds = Math.round(time) - (60*minutes);
// So if seconds go above 59
if(seconds > 59) {
// Increase minutes, reset seconds
seconds = Math.round(time) - (60*minutes);
if(seconds == 60) {
minutes = Math.round(time / 60);
seconds = 0;
}
}
}
// Updated progress width
updProgWidth = (curTime / $duration) * progWidth
// Set a zero before the number if its less than 10.
if(seconds < 10) { seconds = '0'+seconds; }
if(tseconds < 10) { tseconds = '0'+tseconds; }
// A variable set which we'll use later on
if($ignore != true) {
$that.find('.progress-bar').css({'width' : updProgWidth+'px'});
$that.find('.progress-button').css({'left' : (updProgWidth-$that.find('.progress-button').width())+'px'});
}
// Update times
$that.find('.ctime').html(minutes+':'+seconds)
$that.find('.ttime').html(tminutes+':'+tseconds);
// If playing update buffer value
if($spc.currentTime > 0 && $spc.paused == false && $spc.ended == false) {
bufferLength();
}
}
// Run the timing function twice, once on init and again when the time updates.
timeUpdate();
$spc.addEventListener('timeupdate', timeUpdate);
// When the user clicks play, bind a click event
$that.find('.play-pause').bind('click', function() {
// Set up a playing variable
if($spc.currentTime > 0 && $spc.paused == false && $spc.ended == false) {
$playing = false;
} else { $playing = true; }
// If playing, etc, change classes to show pause or play button
if($playing == false) {
$spc.pause();
$(this).addClass('play').removeClass('pause');
bufferLength();
} else {
$begin = true;
$spc.play();
$(this).addClass('pause').removeClass('play');
}
});
// Bind a function to the progress bar so the user can select a point in the video
$that.find('.progress').bind('mousedown', function(e) {
// Progress bar is being clicked
$mclicking = true;
// If video is playing then pause while we change time of the video
if($playing == true) {
$spc.pause();
}
// The x position of the mouse in the progress bar
x = e.pageX - $that.find('.progress').offset().left;
// Update current time
currentTime = (x / progWidth) * $duration;
$spc.currentTime = currentTime;
});
// When the user clicks on the volume bar holder, initiate the volume change event
$that.find('.volume-bar-holder').bind('mousedown', function(e) {
// Clicking of volume is true
$vclicking = true;
// Y position of mouse in volume slider
y = $that.find('.volume-bar-holder').height() - (e.pageY - $that.find('.volume-bar-holder').offset().top);
// Return false if user tries to click outside volume area
if(y < 0 || y > $(this).height()) {
$vclicking = false;
return false;
}
// Update CSS to reflect what's happened
$that.find('.volume-bar').css({'height' : y+'px'});
$that.find('.volume-button').css({'top' : (y-($that.find('.volume-button').height()/2))+'px'});
// Update some variables
$spc.volume = $that.find('.volume-bar').height() / $(this).height();
$storevol = $that.find('.volume-bar').height() / $(this).height();
$volume = $that.find('.volume-bar').height() / $(this).height();
// Run a little animation for the volume icon.
volanim();
});
// A quick function for binding the animation of the volume icon
var volanim = function() {
// Check where volume is and update class depending on that.
for(var i = 0; i < 1; i += 0.1) {
var fi = parseInt(Math.floor(i*10)) / 10;
var volid = (fi * 10)+1;
if($volume == 1) {
if($volhover == true) {
$that.find('.volume-icon').removeClass().addClass('volume-icon volume-icon-hover v-change-11');
} else {
$that.find('.volume-icon').removeClass().addClass('volume-icon v-change-11');
}
}
else if($volume == 0) {
if($volhover == true) {
$that.find('.volume-icon').removeClass().addClass('volume-icon volume-icon-hover v-change-1');
} else {
$that.find('.volume-icon').removeClass().addClass('volume-icon v-change-1');
}
}
else if($volume > (fi-0.1) && volume < fi && !$that.find('.volume-icon').hasClass('v-change-'+volid)) {
if($volhover == true) {
$that.find('.volume-icon').removeClass().addClass('volume-icon volume-icon-hover v-change-'+volid);
} else {
$that.find('.volume-icon').removeClass().addClass('volume-icon v-change-'+volid);
}
}
}
}
// Run the volanim function
volanim();
// Check if the user is hovering over the volume button
$that.find('.volume').hover(function() {
$volhover = true;
}, function() {
$volhover = false;
});
// For usability purposes then bind a function to the body assuming that the user has clicked mouse
// down on the progress bar or volume bar
$('body, html').bind('mousemove', function(e) {
// Hide the player if video has been played and user hovers away from video
if($begin == true) {
$that.hover(function() {
$that.find('.player').stop(true, false).animate({'opacity' : '1'}, 0.5);
}, function() {
$that.find('.player').stop(true, false).animate({'opacity' : '0'}, 0.5);
});
}
// For the progress bar controls
if($mclicking == true) {
// Dragging is happening
$draggingProgress = true;
// The thing we're going to apply to the CSS (changes based on conditional statements);
var progMove = 0;
// Width of the progress button (a little button at the end of the progress bar)
var buttonWidth = $that.find('.progress-button').width();
// Updated x posititon the user is at
x = e.pageX - $that.find('.progress').offset().left;
// If video is playing
if($playing == true) {
// And the current time is less than the duration
if(currentTime < $duration) {
// Then the play-pause icon should definitely be a pause button
$that.find('.play-pause').addClass('pause').removeClass('play');
}
}
if(x < 0) { // If x is less than 0 then move the progress bar 0px
progMove = 0;
$spc.currentTime = 0;
}
else if(x > progWidth) { // If x is more than the progress bar width then set progMove to progWidth
$spc.currentTime = $duration;
progMove = progWidth;
}
else { // Otherwise progMove is equal to the mouse x coordinate
progMove = x;
currentTime = (x / progWidth) * $duration;
$spc.currentTime = currentTime;
}
// Change CSS based on previous conditional statement
$that.find('.progress-bar').css({'width' : $progMove+'px'});
$that.find('.progress-button').css({'left' : ($progMove-buttonWidth)+'px'});
}
// For the volume controls
if($vclicking == true) {
// The position of the mouse on the volume slider
y = $that.find('.volume-bar-holder').height() - (e.pageY - $that.find('.volume-bar-holder').offset().top);
// The position the user is moving to on the slider.
var volMove = 0;
// If the volume holder box is hidden then just return false
if($that.find('.volume-holder').css('display') == 'none') {
$vclicking = false;
return false;
}
// Add the hover class to the volume icon
if(!$that.find('.volume-icon').hasClass('volume-icon-hover')) {
$that.find('.volume-icon').addClass('volume-icon-hover');
}
if(y < 0 || y == 0) { // If y is less than 0 or equal to 0 then volMove is 0.
$volume = 0;
volMove = 0;
$that.find('.volume-icon').removeClass().addClass('volume-icon volume-icon-hover v-change-11');
} else if(y > $(this).find('.volume-bar-holder').height() || (y / $that.find('.volume-bar-holder').height()) == 1) { // If y is more than the height then volMove is equal to the height
$volume = 1;
volMove = $that.find('.volume-bar-holder').height();
$that.find('.volume-icon').removeClass().addClass('volume-icon volume-icon-hover v-change-1');
} else { // Otherwise volMove is just y
$volume = $that.find('.volume-bar').height() / $that.find('.volume-bar-holder').height();
volMove = y;
}
// Adjust the CSS based on the previous conditional statmeent
$that.find('.volume-bar').css({'height' : volMove+'px'});
$that.find('.volume-button').css({'top' : (volMove+$that.find('.volume-button').height())+'px'});
// Run the animation function
volanim();
// Change the volume and store volume
// Store volume is the volume the user last had in place
// in case they want to mute the video, unmuting will then
// return the user to their previous volume.
$spc.volume = $volume;
$storevol = $volume;
}
// If the user hovers over the volume controls, then fade in or out the volume
// icon hover class
if($volhover == false) {
$that.find('.volume-holder').stop(true, false).fadeOut(100);
$that.find('.volume-icon').removeClass('volume-icon-hover');
}
else {
$that.find('.volume-icon').addClass('volume-icon-hover');
$that.find('.volume-holder').fadeIn(100);
}
})
// When the video ends the play button becomes a pause button
$spc.addEventListener('ended', function() {
$playing = false;
// If the user is not dragging
if($draggingProgress == false) {
$that.find('.play-pause').addClass('play').removeClass('pause');
}
});
// If the user clicks on the volume icon, mute the video, store previous volume, and then
// show previous volume should they click on it again.
$that.find('.volume-icon').bind('mousedown', function() {
$volume = $spc.volume; // Update volume
// If volume is undefined then the store volume is the current volume
if(typeof $storevol == 'undefined') {
$storevol = $spc.volume;
}
// If volume is more than 0
if($volume > 0) {
// then the user wants to mute the video, so volume will become 0
$spc.volume = 0;
$volume = 0;
$that.find('.volume-bar').css({'height' : '0'});
volanim();
}
else {
// Otherwise user is unmuting video, so volume is now store volume.
$spc.volume = $storevol;
$volume = $storevol;
$that.find('.volume-bar').css({'height' : ($storevol*100)+'%'});
volanim();
}
});
// If the user lets go of the mouse, clicking is false for both volume and progress.
// Also the video will begin playing if it was playing before the drag process began.
// We're also running the bufferLength function
$('body, html').bind('mouseup', function(e) {
$mclicking = false;
$vclicking = false;
$draggingProgress = false;
if($playing == true) {
$spc.play();
}
bufferLength();
});
// Check if fullscreen supported. If it's not just don't show the fullscreen icon.
if(!$spc.requestFullscreen && !$spc.mozRequestFullScreen && !$spc.webkitRequestFullScreen) {
$('.fullscreen').hide();
}
// Requests fullscreen based on browser.
$('.fullscreen').click(function() {
if ($spc.requestFullscreen) {
$spc.requestFullscreen();
}
else if ($spc.mozRequestFullScreen) {
$spc.mozRequestFullScreen();
}
else if ($spc.webkitRequestFullScreen) {
$spc.webkitRequestFullScreen();
}
});
});
});
}
})(jQuery);
I would also like to point out that this is someone else source code and cannot find where i got this from.
https://jsfiddle.net/f39huqpv/

How volume button is generated [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
Hello i've gotten this code from codepen and i was wondering if anybody could explain me how and where in the code the volume button is generated not the track but the megaphone symbol.
HTML
<h1>Youtube Volume Control</h1>
<div class='bsp-volume-wrap'>
<button id='bsp-volume'>
<span class='fa fa-volume-up'></span>
</button>
<div class='bsp-volume-panel'>
<div class='bsp-volume-slider'>
<div class='bsp-volume-slider-track'>
<div class='bsp-volume-slider-progress'>
<div class='bsp-volume-slider-handle'></div>
</div>
</div>
</div>
</div>
</div>
CSS
#import "//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css";
#import "//fonts.googleapis.com/css?family=Roboto:700";
html, body {
font-family: 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif;
color: #333333;
text-align: center;
background: #1a1a1a;
}
h1 {
margin: 70px 0 50px;
font-size: 40px;
}
button {
background: none;
border: none;
color: #cccccc;
font-size: 20px;
padding: 0 10px;
height: 40px;
outline: none;
transition: color 0.2s;
cursor: pointer;
float: left;
}
button:hover {
color: white;
}
.bsp-volume-wrap {
padding: 0 10px 0 0;
display: inline-block;
}
.bsp-volume-wrap #bsp-volume {
float: left;
}
.bsp-volume-wrap.bsp-volume-show button {
color: white;
}
.bsp-volume-wrap.bsp-volume-show .bsp-volume-panel {
width: 73px;
}
.bsp-volume-wrap .bsp-volume-panel {
float: left;
height: 40px;
width: 0;
overflow: hidden;
transition: width 0.2s;
cursor: pointer;
}
.bsp-volume-wrap .bsp-volume-panel .bsp-volume-slider {
position: relative;
height: 100%;
}
.bsp-volume-wrap .bsp-volume-panel .bsp-volume-slider-track {
height: 2px;
width: 70px;
position: absolute;
top: 50%;
right: 0;
margin-top: -1px;
background: gray;
}
.bsp-volume-wrap .bsp-volume-panel .bsp-volume-slider-progress {
height: 100%;
width: 0%;
background: red;
position: relative;
}
.bsp-volume-wrap .bsp-volume-panel .bsp-volume-slider-handle {
height: 12px;
width: 3px;
position: absolute;
top: -5px;
right: 0;
background: white;
}
Javascript
(function () {
var VolumeControl, control, getElementPercentage, bind = function (fn, me) {
return function () {
return fn.apply(me, arguments);
};
};
getElementPercentage = function (click, elm) {
var rect;
rect = elm.getBoundingClientRect();
return (click.pageX - rect.left) / rect.width * 100;
};
VolumeControl = function () {
function VolumeControl() {
this.volumeMute = bind(this.volumeMute, this);
this.volumeStopHandler = bind(this.volumeStopHandler, this);
this.volumeMoveHandler = bind(this.volumeMoveHandler, this);
this.volumeDrag = bind(this.volumeDrag, this);
this.volumeClick = bind(this.volumeClick, this);
this.volumeHoverOut = bind(this.volumeHoverOut, this);
this.volumeHoverIn = bind(this.volumeHoverIn, this);
this.video = new Audio('http://garethweaver.com/codepen/media/bensound-jazzcomedy.mp3');
this.video.volume = 0;
this.video.play();
this.elm = {
volumeWrap: document.getElementsByClassName('bsp-volume-wrap')[0],
volumeSlider: document.getElementsByClassName('bsp-volume-slider')[0],
volumeProgress: document.getElementsByClassName('bsp-volume-slider-progress')[0]
};
this.elm.volumeWrap.addEventListener('mouseenter', this.volumeHoverIn);
this.elm.volumeWrap.addEventListener('mouseleave', this.volumeHoverOut);
this.elm.volumeSlider.addEventListener('click', this.volumeClick);
this.elm.volumeSlider.addEventListener('mousedown', this.volumeDrag);
document.getElementById('bsp-volume').addEventListener('click', this.volumeMute);
}
VolumeControl.prototype.volumeHoverIn = function (e) {
if (this.volumeHoverTimout) {
clearTimeout(this.volumeHoverTimout);
}
return this.elm.volumeWrap.classList.add('bsp-volume-show');
};
VolumeControl.prototype.volumeHoverOut = function (e) {
return this.volumeHoverTimout = setTimeout(function (_this) {
return function () {
return _this.elm.volumeWrap.classList.remove('bsp-volume-show');
};
}(this), 300);
};
VolumeControl.prototype.volumeClick = function (e) {
var percent;
percent = getElementPercentage(e, this.elm.volumeSlider);
return this.volumeSet(percent);
};
VolumeControl.prototype.volumeSet = function (percent) {
this.elm.volumeProgress.style.width = percent + '%';
return this.lastVolume = this.video.volume = percent / 100;
};
VolumeControl.prototype.volumeDrag = function (e) {
e.preventDefault();
document.addEventListener('mousemove', this.volumeMoveHandler);
return document.addEventListener('mouseup', this.volumeStopHandler);
};
VolumeControl.prototype.volumeMoveHandler = function (e) {
var percent;
percent = getElementPercentage(e, this.elm.volumeSlider);
if (percent < 0) {
percent = 0;
} else if (percent > 100) {
percent = 100;
}
return this.volumeSet(percent);
};
VolumeControl.prototype.volumeStopHandler = function (e) {
document.removeEventListener('mousemove', this.volumeMoveHandler);
return document.removeEventListener('mouseup', this.volumeStopHandler);
};
VolumeControl.prototype.volumeMute = function () {
var vol;
vol = this.video.volume > 0 ? 0 : this.lastVolume || 1;
this.video.volume = vol;
return this.elm.volumeProgress.style.width = vol * 100 + '%';
};
return VolumeControl;
}();
control = new VolumeControl();}.call(this));
For and easier way to read here is the link: http://codepen.io/garethdweaver/pen/EjqNxO
That is Font Awesome:
https://fortawesome.github.io/Font-Awesome/icons/
Go there and search (ctrl+F) for "volume".
Font Awesome is loaded on the first line of the CSS file:
#import "//maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css";
If you want to know more, visit the fa's home page: https://fortawesome.github.io/Font-Awesome/
edit:
Besides CSS, the HTML file needs to use this simple line to show the megaphone:
<span class='fa fa-volume-up'></span>

google places api autocomplete - adding click event

I'm appending a Search Results to the google places javascript api autocomplete.
So far I'm doing this:
var autocomplete;
function initialize() {
var myLatlng = new google.maps.LatLng(40.738793, -73.991402);
autocomplete = new google.maps.places.Autocomplete(document.getElementById('autocomplete'));
}
later on I have this:
$('.pac-container').append( '<div class="j-search pac-item-refresh">Search Results</div>' );
$(document.body).on('click', '.pac-container .j-search', function(e) {
console.log('click fired');
});
The problem? The click event never fires...
Any idea why? Anything wrong with my code?
It seems that the click-event for .pac-container is cancelled by the Autocomplete-instance. Use mousedown instead.
You can follow the this article.
Implement and Optimize Autocomplete with Google Places API
Specifically Autocompletion using the AutocompleteService:
link: JS Filddle Of AutocompletionService
function debounce(func, wait, immediate) {
let timeout;
return function() {
let context = this,
args = arguments;
let later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
let callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
function initAutocomplete() {
let map = new google.maps.Map(document.getElementById('map'), {
center: {
lat: 48,
lng: 4
},
zoom: 4,
disableDefaultUI: true
});
// Create the search box and link it to the UI element.
let inputContainer = document.querySelector('autocomplete-input-container');
let autocomplete_results = document.querySelector('.autocomplete-results');
let service = new google.maps.places.AutocompleteService();
let serviceDetails = new google.maps.places.PlacesService(map);
let marker = new google.maps.Marker({
map: map
});
let displaySuggestions = function(predictions, status) {
if (status != google.maps.places.PlacesServiceStatus.OK) {
alert(status);
return;
}
let results_html = [];
predictions.forEach(function(prediction) {
results_html.push(`<li class="autocomplete-item" data-type="place" data-place-id=${prediction.place_id}><span class="autocomplete-icon icon-localities"></span> <span class="autocomplete-text">${prediction.description}</span></li>`);
});
autocomplete_results.innerHTML = results_html.join("");
autocomplete_results.style.display = 'block';
let autocomplete_items = autocomplete_results.querySelectorAll('.autocomplete-item');
for (let autocomplete_item of autocomplete_items) {
autocomplete_item.addEventListener('click', function() {
let prediction = {};
const selected_text = this.querySelector('.autocomplete-text').textContent;
const place_id = this.getAttribute('data-place-id');
let request = {
placeId: place_id,
fields: ['name', 'geometry']
};
serviceDetails.getDetails(request, function(place, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
if (!place.geometry) {
console.log("Returned place contains no geometry");
return;
}
var bounds = new google.maps.LatLngBounds();
marker.setPosition(place.geometry.location);
if (place.geometry.viewport) {
bounds.union(place.geometry.viewport);
} else {
bounds.extend(place.geometry.location);
}
map.fitBounds(bounds);
}
autocomplete_input.value = selected_text;
autocomplete_results.style.display = 'none';
});
})
}
};
let autocomplete_input = document.getElementById('my-input-autocomplete');
autocomplete_input.addEventListener('input', debounce(function() {
let value = this.value;
value.replace('"', '\\"').replace(/^\s+|\s+$/g, '');
if (value !== "") {
service.getPlacePredictions({
input: value
}, displaySuggestions);
} else {
autocomplete_results.innerHTML = '';
autocomplete_results.style.display = 'none';
}
}, 150));
}
document.addEventListener("DOMContentLoaded", function(event) {
initAutocomplete();
});
#map {
height: 100%;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
.autocomplete-input-container {
position: absolute;
z-index: 1;
width: 100%;
}
.autocomplete-input {
text-align: center;
}
#my-input-autocomplete {
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08);
font-size: 15px;
border-radius: 3px;
border: 0;
margin-top: 10px;
width: 290px;
height: 40px;
text-overflow: ellipsis;
padding: 0 1em;
}
#my-input-autocomplete:focus {
outline: none;
}
.autocomplete-results {
margin: 0 auto;
right: 0;
left: 0;
position: absolute;
display: none;
background-color: white;
width: 320px;
padding: 0;
list-style-type: none;
margin: 0 auto;
border: 1px solid #d2d2d2;
border-top: 0;
box-sizing: border-box;
}
.autocomplete-item {
padding: 5px 5px 5px 35px;
height: 26px;
line-height: 26px;
border-top: 1px solid #d9d9d9;
position: relative;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.autocomplete-icon {
display: block;
position: absolute;
top: 7px;
bottom: 0;
left: 8px;
width: 20px;
height: 20px;
background-repeat: no-repeat;
background-position: center center;
}
.autocomplete-icon.icon-localities {
background-image: url(https://images.woosmap.com/icons/locality.svg);
}
.autocomplete-item:hover .autocomplete-icon.icon-localities {
background-image: url(https://images.woosmap.com/icons/locality-selected.svg);
}
.autocomplete-item:hover {
background-color: #f2f2f2;
cursor: pointer;
}
.autocomplete-results::after {
content: "";
padding: 1px 1px 1px 0;
height: 18px;
box-sizing: border-box;
text-align: right;
display: block;
background-image: url(https://maps.gstatic.com/mapfiles/api-3/images/powered-by-google-on-white3_hdpi.png);
background-position: right;
background-repeat: no-repeat;
background-size: 120px 14px
}
<div class="autocomplete-input-container">
<div class="autocomplete-input">
<input id="my-input-autocomplete" placeholder="AutocompleteService" autocomplete="off" role="combobox">
</div>
<ul class="autocomplete-results">
</ul>
</div>
<div id="map"></div>
<!-- Replace the value of the key parameter with your own API key. -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&libraries=places&callback"></script>

Categories