whenever I try to load the google map asynchronously it fails to load until I reload the page multiple times.after Removing async from the the code runs well.
I have used knockout.js and Foursquare API for the work.
//strict
//JavaScript file
$(document).ready(function() {
//initialize map
var map;
//if no error occours
if (typeof google != "undefined") {
map = new google.maps.Map(document.getElementById('display-area'), {
center: new google.maps.LatLng(30.4100, 77.98000),
zoom: 11,
});
} //else the error message will be displayed
else {
$('#error').css('display', 'block'); //error handling if map loading fails
$('#error').css('color', 'red'); //error handling color set to red
$('#display_area').css('display', 'none'); //map loading fails
}
//display list of places
$('#view-list-toggle').click(function() {
var list = $('#view-list');
//view-list is initially set to display:none, when any marker is clicked it has to be displayed
list.css('display', 'block');
});
//array of locations where the markers are to be created
//loc is the location
var locDetails = [{
loc: new google.maps.LatLng(30.416333, 77.968585),
title: "UPES Dehradun",
details: '<b>University of Petroleum and Energy Studies, Dehradun. My place!:)</b><br><img src="images/upes.jpg" width=100%>',
venues: "4e61e0d1e4cdf1e2bf0ddd66",
searchOptions: ['college', 'petroleum']
}, //venues are used in foursquareURL to get the location and rating of the place.
//searchOptions provide a easier search,
{
loc: new google.maps.LatLng(30.34266547538908, 78.0602590943995),
title: "Silver City Multiplex",
details: '<b>Silver City Multiplex</b><br>A perfect shopping and movie hall for fun<br><img src="images/sc.jpg" width=100%>',
venues: "4efad823469012b8c3fcad8c",
searchOptions: ['mall', 'shopping']
},
{
loc: new google.maps.LatLng(30.33308670383727, 77.99534667810693),
title: "Forest research institute",
details: '<b>The Forest Research Institute</b><br> It is an institute of the Indian Council of Forestry Research and Education and is a premier institution in the field of forestry research in India.<br><img src="images/fri.jpg" width=100%>',
venues: "56c95d90cd10173286d99b0c",
searchOptions: ['institute', 'places']
},
{
loc: new google.maps.LatLng(30.3572660, 78.0166512),
title: "Tapkeshwar Mandir",
details: '<b>Tapkeshwar Mandir</b><br>Water drips from the cave walls of this famous, tranquil Hindu temple honoring Lord Shiva<br><img src="images/tap.jpg" width=100%>',
venues: "516fc256e4b03bca88777ab4",
searchOptions: ['places', 'temple']
},
{
loc: new google.maps.LatLng(30.334597469681178, 77.98139035061027),
title: "IMA",
details: '<b>The Indian Military Academy</b><br> Dehradun is the officer training Academy of the Indian Army. IMA was established in 1932<br><img src="images/ima.jpg" width=100%>',
venues: "4d8f0723835b530cbf6fa5b6",
searchOptions: ['acedemy', 'army']
},
{
loc: new google.maps.LatLng(30.340292, 77.952410),
title: "Uttaranchal University",
details: '<b>Uttaranchal University</b><br>It is a State Private university established by the Government of Uttarakhand and approverd by UGC.<br><img src="images/uti.jpg" width=100%>',
venues: "57f4b07d498e1f07ac71068e",
searchOptions: ['university', 'study']
},
{
loc: new google.maps.LatLng(30.322101132963066, 78.00289561203648),
title: "Big Cinemas",
details: '<b>Carnival Cinemas-Vikas mall</b><br>A mall, where you can easily find fun stuffs like food and movies<br><img src="images/car.png" width=100%>',
venues: "50cc6304e4b0af445c617e6f",
searchOptions: ['movie', 'shop']
},
{
loc: new google.maps.LatLng(30.409601848936052, 77.97009795321478),
title: "Sai Mandir",
details: '<b>Temple</b><br>A hindu temple near university of petroleum and energy studies',
venues: "513886f1e4b019e1c4745c8b",
searchOptions: ['temple', 'temples']
},
{
loc: new google.maps.LatLng(30.488112761304816, 78.03671992371376),
title: "Kempty Fall",
details: '<b>Kempty Fall</b><br>A very Calm and Soothing place as a family picnic destination.<br><img src="images/kempty.jpg" width=100%>',
venues: "4e8fe25d02d5ee38b690c60c",
searchOptions: ['water', 'fall']
},
{
loc: new google.maps.LatLng(30.459536, 78.020681),
title: "George everest",
details: '<b>George everest</b><br>Beautiful location peace of mind relaxing place worth a visit<br><img src="images/ge.jpg" width=100%>',
venues: "4fba04bce4b09a2fd4f5b957",
searchOptions: ['hill', 'mountains']
}
];
function MVM() {
var temp = []; //will be used to store the markers
var self = this;
for (var j = 0; j < locDetails.length; j++)
temp.push(new finalMarker(locDetails[j], self)); //
self.query = ko.observable('');
self.markers = ko.observableArray(temp);
self.fName = ko.observable('');
self.fRating = ko.observable('');
self.kill = function() {
for (var i = 0; i < self.markers().length; i++)
self.markers()[i].startState();
};
self.searchMarkers = function() {
// find a list of markers that match the string
var search_matches = [];
//a list of markers that do not matches and needs to be hidden
var search_not_match = [];
var query = self.query();
for (var k = 0; k < self.markers().length; k++) {
var mrkr = self.markers()[k];
if (mrkr.matches(query))
search_matches.push(mrkr);
else
search_not_match.push(mrkr);
}
for (i = 0; i < search_matches.length; i++)
search_matches[i].matchesSearch();
//if search matches then the list is set to be visible;
for (i = 0; i < search_not_match.length; i++)
search_not_match[i].doNotMatch();
//all the remaining is set to be hidden
};
self.selectItem = function(item) {
item.selected();
};
}
function finalMarker(marker_info, model) {
var self = this;
self.model = model;
self.title = marker_info.title;
self.venues = marker_info.venues;
self.text = ko.observable(marker_info.details);
self.searchOptions = marker_info.searchOptions;
var infoParts = self.text().split(" "); //splits the infopart and add it to searchOptions, it will help in making the search more easier to users.
for (var i = 0; i < infoParts.length; i++)
self.searchOptions.push(infoParts[i].toLowerCase());
var titleParts = self.title.split(" "); //splits the title and add it to searchOptions, it will help in making the search more easier to users.
for (i = 0; i < titleParts.length; i++)
self.searchOptions.push(titleParts[i].toLowerCase());
self.infowindow = new google.maps.InfoWindow({
content: self.text()
});
self.googleMarker = new google.maps.Marker({
position: marker_info.loc,
title: marker_info.title,
map: map,
animation: google.maps.Animation.DROP
});
//when any one of the markers on the map is clicked then this function is called.
google.maps.event.addListener(self.googleMarker, 'click', function() {
self.selected();
self.toggleBounce();
//animate the markers when loaded.
function toggleBounce() {
if (marker.getAnimation() !== null) {
marker.setAnimation(null);
} else {
marker.setAnimation(google.maps.Animation.BOUNCE);
}
}
});
self.selected = function() {
// kills/closes all the other window popups
model.kill();
self.clicked();
$('#four-view').css('display', 'block');
//url for foursquare
var foursquareUrl = 'https://api.foursquare.com/v2/venues/' + self.venues + '?v=20170503&' + 'client_id=' + 'I5E3UJKIUR03YMFPIC0DEML402JJLEH2ZBN2MJMVY1CERFZA' + '&client_secret=' + 'J10CMGOLXC24EJTBBMW5DUD3O5DDXJ5E5Y134MAFQG15AYNQ';
model.fRating('');
//foursquare api settingz
//id = "I5E3UJKIUR03YMFPIC0DEML402JJLEH2ZBN2MJMVY1CERFZA";
//Secret = "J10CMGOLXC24EJTBBMW5DUD3O5DDXJ5E5Y134MAFQG15AYNQ";
model.fName('');
//ajax async. loads the data when the marker is clicked
$.ajax({
url: foursquareUrl
}).done(
function(response) {
var res = response.response.venue;
model.fName(res.name);
model.fRating(res.rating);
if (!res.rating) {
model.fRating('not yet rated');
} else
model.fRating('rated as ' + res.rating);
})
.error(function() {
model.fName('error');
model.fRating('error');
});
};
self.matches = function(q) {
return $.inArray(q.toLowerCase(), self.searchOptions) != -1;
};
self.matchesSearch = function() {
self.isHidden(false);
self.googleMarker.setVisible(true);
self.infowindow.open(map, self.googleMarker);
$('#four-view').css('display', 'none');
};
self.startState = function() {
self.isHidden(false);
self.googleMarker.setVisible(true);
self.infowindow.close();
$('#four-view').css('display', 'none');
};
self.doNotMatch = function() {
self.isHidden(true);
self.googleMarker.setVisible(false);
self.infowindow.close();
$('#four-view').css('display', 'none');
};
self.clicked = function() {
self.isHidden(false);
self.googleMarker.setVisible(true);
self.googleMarker.setAnimation(google.maps.Animation.BOUNCE);
setTimeout(function() {
self.googleMarker.setAnimation(null);
}, 1400);
self.infowindow.open(map, self.googleMarker);
};
self.isHidden = ko.observable(false);
}
ko.applyBindings(new MVM());
});
html,
body {
height: 99%;
margin: 0px;
padding-left: 10px;
padding-right: 10px;
background: linear-gradient(27deg, #151515 5px, transparent 5px) 0 5px, linear-gradient(207deg, #151515 5px, transparent 5px) 10px 0px, linear-gradient(27deg, #222 5px, transparent 5px) 0px 10px, linear-gradient(207deg, #222 5px, transparent 5px) 10px 5px, linear-gradient(90deg, #1b1b1b 10px, transparent 10px), linear-gradient(#1d1d1d 25%, #1a1a1a 25%, #1a1a1a 50%, transparent 50%, transparent 75%, #242424 75%, #242424);
background-color: #131313;
background-size: 20px 20px;
}
input {
width: 20%;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45), 0 1px 3px rgba(0, 0, 0, 0.44);
border: 1px solid black;
position: relative;
padding-bottom: 2px;
margin-bottom: 2px;
}
h1 {
color: white;
}
#media only screen and (min-width: 506px) {
#view-list {
display: block !important;
}
}
#display-area {
height: 100%;
width: 100%;
margin: 5px;
padding: 5px;
}
#view-list {
top: 30%;
right: 0px;
position: absolute;
font-weight: bold;
color: white;
background: linear-gradient(27deg, #151515 5px, transparent 5px) 0 5px, linear-gradient(207deg, #151515 5px, transparent 5px) 10px 0px, linear-gradient(27deg, #222 5px, transparent 5px) 0px 10px, linear-gradient(207deg, #222 5px, transparent 5px) 10px 5px, linear-gradient(90deg, #1b1b1b 10px, transparent 10px), linear-gradient(#1d1d1d 25%, #1a1a1a 25%, #1a1a1a 50%, transparent 50%, transparent 75%, #242424 75%, #242424);
background-color: #131313;
background-size: 20px 20px;
box-shadow: 10px 4px 13px rgba(0, 0, 0, 0.45), 5px 10px 10px rgba(0, 0, 0, 0.64);
border: 1px solid black;
}
#four-view {
padding: 5px;
color: grey;
display: none;
text-align: center;
-ms-transform: translateY(-50%);
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
.hidden {
display: none;
}
.list-item:hover {
background-color: grey;
}
#view-list-toggle {
display: none;
background-color: grey;
padding: 5px;
}
#media only screen and (max-width: 528px) {
h1 {
display: none;
}
#display-area {
height: 100%;
}
#four-view {
padding-top: 10px;
margin-top: 10px;
}
#view-list {
font-size: 10px;
}
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Neighbourhood</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="css/main.css" />
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDy2Gh9s53u0nitvdqECa5cevawqiBwkP0&callback=initMap"></script>
</head>
<body bgcolor="grey">
<h1 align="center">Neighbourhood Project - Udacity</h1>
<form action="/" align="right">
<input data-bind="value: query" maxlength="100" />
<button data-bind="click: searchMarkers">Search List</button>
</form>
<div id="four-view" class="rating">
<strong data-bind="text: fName"></strong> is <strong data-bind="text: fRating" style="color: white;"></strong> by foursquare.
</div>
<div id="view-list-toggle">List View</div>
<div id="display-area"></div>
<div id="view-list">
<table>
<tbody data-bind="foreach: markers()">
<tr data-bind="click: $root.selectItem">
<td data-bind="text: title, css : { hidden : isHidden() }" class='list-item'></td>
</tr>
</tbody>
</table>
</div>
<div id="error" style="display : none; color : green">Oops!! The map could not be loaded. Please check your connection.</div>
<script type='text/javascript' src='js/knockout-3.3.0.js'></script>
<script type='text/javascript' src='js/jquery-2.1.3.min.js'></script>
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>
If you are using jQuery, you can asynchronously load google maps using jQuery's $.getScript() method.
Here is an example of how you would do this:
function initMap() {
// logic for creating map
}
var mapsUrl = "https://maps.googleapis.com/maps/api/js?key=" + "Your_API_KEY" + "&v=3";
$.getScript(mapsUrl)
.done(function() {
initMap();
})
.fail(function() {
console.log('Error: Map failed to load.');
});
Related
I am using noUiSlider, but in fact any range slider library would work.
I have a small widget (here: https://codepen.io/chapkovski/pen/pobRwZj) where people have to split the range into three sections:
var slider = document.getElementById('slider-color');
noUiSlider.create(slider, {
start: [6000, 12000],
connect: [true, true, true],
range: {
'min': [2000],
'max': [20000]
}
});
var connect = slider.querySelectorAll('.noUi-connect');
var classes = ['c-1-color', 'c-2-color', 'c-3-color'];
for (var i = 0; i < connect.length; i++) {
connect[i].classList.add(classes[i]);
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/14.6.2/nouislider.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/14.6.2/nouislider.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
.c-1-color {
background: red;
}
.c-2-color {
background: yellow;
}
.c-3-color {
background: green;
}
</style>
<div id='slider-color'></div>
What I can't figure is how to add a text within the ranges. For instance for the mid-range (yellow one) would be something like 'Second category: XX%' (depending on the handles position. When I do something like:
.c-3-color::after {
content:'my text goes here';
}
it ends up completely deformed.
On the parent you are having scale so this is why it is growing. You need to compensate that with child or pseudo child Please have a look as below:
.c-3-color::after {
content:'my text goes here';
display: block;
position: absolute;
top: 50%;
left: 33%;
transform: translateY(-50%) scale(4,2);
}
DEMO (with adjustment of the code above because line is smaller
var slider = document.getElementById('slider-color');
noUiSlider.create(slider, {
start: [6000, 12000],
connect: [true, true, true],
range: {
'min': [2000],
'max': [20000]
}
});
var connect = slider.querySelectorAll('.noUi-connect');
var classes = ['c-1-color', 'c-2-color', 'c-3-color'];
for (var i = 0; i < connect.length; i++) {
connect[i].classList.add(classes[i]);
}
.c-3-color::after {
content:'my text goes here';
display: block;
position: absolute;
top: 50%;
left: 33%;
transform: translateY(-50%) scale(3,2);
font-size:12px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/14.6.2/nouislider.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/noUiSlider/14.6.2/nouislider.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
.c-1-color {
background: red;
}
.c-2-color {
background: yellow;
}
.c-3-color {
background: green;
}
</style>
<div id='slider-color'></div>
I am new to Vue.js and I am stuck. I have pulled in API data from Github jobs via Vanilla JavaScript and now I want to create a user filter. I am starting out with a filter for job "type" meaning Full time, part time, etc. Also, this code in being put into a plugin in WordPress called Shortcoder. I have watched tutorials and looked at three other posts on Stackoverflow that are similar but cannot figure out why I am getting this error: "unexpected SyntaxError:Unexpected token: on the line that states selectedType="Full Time". Maybe I have just stared at it for too long and need a fresh set eyes. I would really appreciate someone else reviewing it. Thanks in advance. Here is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- VUE.JS CDN -->
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.22/dist/vue.js"></script>
<title>Github Jobs API</title>
<style>
* {
box-sizing: border-box
}
html {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-family: 'Dosis', sans-serif;
line-height: 1.6;
color: #696969;
background: white;
}
#root {
max-width: 1200px;
margin: 0 auto;
}
h1 {
text-align: center;
padding: 1.5rem 2.5rem;
background-color: #b0bac6;
margin: 0 0 2rem 0;
font-size: 1.5rem;
color: #696969;
}
p {
padding: 0 2.5rem 2.5rem;
margin: 0;
}
.container1{
display: flex;
flex-wrap: wrap;
}
.card {
margin: 1rem;
background: #bobac6;
box-shadow: 2px 4px 25px rgba(0, 0, 0, .1);
border-radius: 12px;
overflow: hidden;
transition: all .2s linear;
}
.card:hover {
box-shadow: 2px 8px 45px rgba(0, 0, 0, .15);
transform: translate3D(0, -2px, 0);
}
#media screen and (min-width: 600px) {
.card {
flex: 1 1 calc(50% - 2rem);
}
}
#media screen and (min-width: 900px) {
.card {
flex: 1 1 calc(33% - 2rem);
}
}
.card:nth-child(2n) h1 {
background-color: #b0bac6;
color: #696969;
}
.card:nth-child(4n) h1 {
background-color: #b0bac6;
color: #696969;
}
.card:nth-child(5n) h1 {
background-color #b0bac6;
color: #696969;
}
.container2 {
padding: 20px;
width: 90%;
max-width: 400px;
margin: 0 auto;
}
label {
display: block;
line-height: 1.5em;
}
ul {
margin-left: 0;
padding-left: 0;
list-style: none;
}
li {
padding: 8px 16px;
border-bottom: 1px solid #eee;
}
</style>
</head>
<body>
<!-- DIV for Vue.js filter -->
<div class="container2" id="jobs">
<div class="filter">
<label><input type="radio" v-model="selectedType" value="Full Time"/>Full Time</label>
<label><input type="radio" v-model="selectedType" value="Part Time"/>Part Time</label>
</div>
<ul class="job-list">
<li v-for="job in filteredJobs">{{ job.title }}</li>
</ul>
</div>
<!-- DIV FOR API DATA CARD DISPLAY -->
<div id="root"></div>
<script>
// USED STRICT MODE TO SOLVE: “UNCAUGHT SYNTAX ERROR: UNEXPECTED TOKEN
U IN JSON # POSITION 0”
'use strict';
// INITIATING APIDATA AS GLOBAL VARIABLE
var apiData= " ";
const app = document.getElementById('root');
const container1 = document.createElement('div');
container1.setAttribute('class', 'container1');
app.appendChild(container1);
var request = new XMLHttpRequest();
//GET REQUEST WITH USE OF HEROKU AS A PROXY TO SOLVE CORS ERROR
request.open('GET','https://cors-anywhere.herokuapp.com/https://jobs.github.com/positions.json?&markdown=true&page=1',
true);
request.onload = function () {
//CONVERT JSON DATA TO JAVASCRIPT OBJECTS USING JSON.PARSE
var apiData = JSON.parse(this.response);
if (request.status >= 200 && request.status < 400) {
apiData.forEach(job => {
const card = document.createElement('div');
card.setAttribute('class', 'card');
const h1 = document.createElement('h1');
h1.textContent = job.title;
const p = document.createElement('p');
job.description = job.description.substring(0, 300);
p.textContent = `${job.description}...`;
container1.appendChild(card);
card.appendChild(h1);
card.appendChild(p);
});
// ERROR HANDLING
} else {
const errorMessage = document.createElement('marquee');
errorMessage.textContent = `It's not working!`;
app.appendChild(errorMessage);
}
}
request.send();
// APPLY FILTER TO API DATA USING VUE.JS
var vm = new Vue({
el: "#jobs",
data() {
return {
apiData:[],
search: ' ',
filterJobs: [ ]},
selectedType:"Full Time"
},
computed: {
filteredJobs: function() {
vm = this;
var category = vm.selectedType;
if(type === "part time") {
return vm.jobs;
} else {
return vm.jobs.filter(function(job) {
return job.type === type;
});
}
}
}
});
</script>
</body>
</html>
The syntax errors are in data():
data() {
return {
apiData: [],
search: ' ',
filterJobs: []}, // <-- FIXME: unexpected '}'
selectedType: "Full Time"
// <-- FIXME: missing '}' for the return statement
},
computed: {
...
Here's the code corrected:
data() {
return {
apiData: [],
search: ' ',
filterJobs: [], // <-- fixed
selectedType: "Full Time"
} // <-- fixed
},
computed: {
...
var vm = new Vue({
el: "#jobs",
data() {
return {
apiData: [],
search: " ",
jobs: [],
selectedType: "full time"
};
},
computed: {
filteredJobs: function() {
vm = this;
var type = vm.selectedType;
if (type === "part time") {
return vm.jobs;
} else {
return vm.jobs.filter(function(job) {
return job.type === type;
});
}
}
},
mounted() {
this.jobs = [
{id: 1, type: 'part time'},
{id: 2, type: 'full time'},
{id: 3, type: 'part time'},
{id: 4, type: 'full time'},
{id: 5, type: 'part time'},
]
}
});
<script src="https://unpkg.com/vue#2.6.1/dist/vue.min.js"></script>
<div id="jobs">
<ul>
<li v-for="job in filteredJobs" :key="job.id">
type: {{job.type}}
</li>
</ul>
</div>
<!DOCTYPE>
<html>
<body>
<img id="traffic" src="assets/red.gif">
<button type="button" onclick="ChangeLights()">Change Lights</button>
<script>
var lights = [
"assets/red.gif",
"assets/yellow.gif",
"assets/green.gif",
"assets/yellow.gif",
];
var index = 0;
function ChangeLights() {
setInterval(function () {ChangeLights();}, 1000);
index = index + 1;
if (index == lights.length) index = 0;
var image = document.getElementById('traffic');
image.src=lights[index];
}
</script>
</body>
</html>
Hi, I am trying to make an animation script using JavaScript so that a traffic light sequence changes from red - yellow - green - yellow on a timer once a button is pressed. I only want the sequence to loop once. However, when I implemented the setInterval function into the function, the lights only change from red - yellow - green - red.
Thank you for any help!
var lights = {
red: "https://upload.wikimedia.org/wikipedia/commons/thumb/4/45/Traffic_lights_red.svg/200px-Traffic_lights_red.svg.png",
yellow: "https://upload.wikimedia.org/wikipedia/commons/thumb/1/19/Traffic_lights_yellow.svg/200px-Traffic_lights_yellow.svg.png",
green: "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Traffic_lights_dark_green.svg/200px-Traffic_lights_dark_green.svg.png"
};
var sequence = ['red', 'yellow', 'green', 'yellow'];
function startChangeLights() {
for (var index = 0; index < sequence.length; index++) {
changeLight(index, sequence[index]);
}
function changeLight(index, color) {
setTimeout(function() {
var image = document.getElementById('traffic');
image.src = lights[color];
}, index * 1000);
}
}
<div>
<img height=100px id="traffic" src="https://upload.wikimedia.org/wikipedia/commons/thumb/4/45/Traffic_lights_red.svg/200px-Traffic_lights_red.svg.png">
</div>
<div>
<button type="button" onclick="startChangeLights()">Change Lights</button>
</div>
https://codepen.io/anon/pen/VbKQNj?editors=1011
If you are looking for one time sequence, you have to use "setTimeout" method in javascript and besides, define an inner function like the following:
var lights = [
"assets/red.gif",
"assets/yellow.gif",
"assets/green.gif",
"assets/yellow.gif",
];
var index = 0;
function ChangeLights() {
function innerChangeLight(){
index = index + 1;
if (index == lights.length) index = 0;
var image = document.getElementById('traffic');
image.src=lights[index];
}
innerChangeLight();
setTimeout(function () {
innerChangeLight();
}, 1000);
}
<!DOCTYPE>
<html>
<body>
<img id="traffic" src="assets/red.gif">
<button type="button" onclick="ChangeLights()">Change Lights</button>
</body>
</html>
Try this:
var lights = [
"assets/red.gif",
"assets/yellow.gif",
"assets/green.gif",
"assets/yellow.gif",
];
var index = 0;
function ChangeLights(){
setInterval(function() {
if(index == lights.length) {
return;
}
var image = document.getElementById('traffic');
image.src=lights[index];
index = index + 1;
}, 1000);
}
<img id="traffic" src="assets/red.gif"><br>
<button onclick="ChangeLights()">Change Lights</button>
New instance of 'Traffic Light':
Traffic Lights can't always be the same duration in every light....
So, i started to expand this html code..
The improved code with different seconds in every light:
// Traffic Light
// Improved with different durations in every light!
// But in this html code, i will use input tag instead
var TrafficLights = (function() {
// The image
var imageTag = document.getElementById("lightImg");
// Keep track of whether the sequence is running
var running = false;
// Different stages of the traffic light (Also defines the light)
var stages = [
{
"name": "red",
"path": "https://upload.wikimedia.org/wikipedia/commons/thumb/4/45/Traffic_lights_red.svg/200px-Traffic_lights_red.svg.png",
},
{
"name": "green",
"path": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Traffic_lights_dark_green.svg/200px-Traffic_lights_dark_green.svg.png"
},
{
"name": "yellow",
"path": "https://upload.wikimedia.org/wikipedia/commons/thumb/1/19/Traffic_lights_yellow.svg/200px-Traffic_lights_yellow.svg.png"
}
];
// Different amount of seconds in every light change (Must be an positive integer!)
var seconds_every_step = [
18,
24,
3
];
// Current stage of the traffic light
var stage = 0;
// Current steps of the traffic light
var steps = 0;
// Timer for automatically changing light
var timer = null;
/** * Start the traffic light sequence * */
function start() {
// Mark that the light sequence is running
running = true;
// Tell the light to change
changeLight();
}
/** * Stop the sequence from running * */
function stop() {
// Mark that the sequence is not running
running = false;
// Stop the automatic timer from running
clearInterval(timer);
}
/** * Change the light to the next one in the sequence * */
function changeLight() {
// If the timer is not running, this function does not need to do anything
if (running === false) {
clearInterval(timer);
return;
} else {};
// If the current stage gets higher than the number of stages there are, reset to 0
if (stage >= stages.length) {
stage = 0;
} else {};
// If the current steps gets higher than the number of seconds in a step there are, reset to 0
if (steps >= seconds_every_step.length) {
steps = 0;
} else {};
// Get the image from the list of stages
var image = stages[stage];
var wait_seconds = seconds_every_step[steps];
// Update the image tag and defines the light name
imageTag.src = image.path;
imageTag.alt = String("Traffic light color is " + image.name + ".");
// Increase the current stage by 1
stage++;
// Increase the current steps by 1
steps++;
// Set a timeout to change the light at the next interval
timer = setTimeout(changeLight, wait_seconds * 1000);
}
// These functions will be available on the `TrafficLights` object to allow interaction
return {
start: start,
stop: stop
}
})();
<input type="image" width="20px" id="lightImg" src="" alt="">
<br/>
<p>
<button type="button" onclick="TrafficLights.start()">Start Sequence</button> <button type="button" onclick="TrafficLights.stop()">Stop Sequence</button>
</p>
You may see an error code. Just ignore it...
var red = document.getElementById("red");
var yellow = document.getElementById("yellow");
var green = document.getElementById("green");
var btn = document.createElement("BUTTON");
btn.innerHTML = "CLICK ME";
document.body.appendChild(btn);
red.style.opacity = "1";
yellow.style.opacity = "0.2";
green.style.opacity = "0.2";
btn.onclick = function () {
setTimeout(function(){red.style.opacity = "0.2";yellow.style.opacity = "1"; setTimeout(function(){yellow.style.opacity = "0.2";green.style.opacity = "1"; setTimeout(function(){green.style.opacity = "0.2";red.style.opacity = "1"}, 1000);}, 1000);
}, 1000);
}
html{
background: linear-gradient(#08f, #fff);
padding: 40px;
width: 170px;
height: 100%;
margin: 0 auto;
}
.trafficlight{
background: #222;
background-image: linear-gradient(transparent 2%, #111 2%, transparent 3%, #111 30%);
width: 170px;
height: 400px;
border-radius: 20px;
position: relative;
border: solid 5px #333;
}
#red{
background: red;
background-image: radial-gradient(brown, transparent);
background-size: 5px 5px;
width: 100px;
height: 100px;
border-radius: 50%;
position: absolute;
top: 20px;
left: 35px;
animation: 13s red infinite;
border: dotted 2px red;
box-shadow:
0 0 20px #111 inset,
0 0 10px red;
}
#yellow{
background: yellow;
background-image: radial-gradient(orange, transparent);
background-size: 5px 5px;
width: 100px;
height: 100px;
border-radius: 50%;
border: dotted 2px yellow;
position: absolute;
top: 145px;
left: 35px;
animation: 13s yellow infinite;
box-shadow:
0 0 20px #111 inset,
0 0 10px yellow;
}
#green{
background: green;
background-image: radial-gradient(lime, transparent);
background-size: 5px 5px;
width: 100px;
height: 100px;
border-radius: 50%;
border: dotted 2px lime;
position: absolute;
top: 270px;
left: 35px;
box-shadow:
0 0 20px #111 inset,
0 0 10px lime;
animation: 13s green infinite;
}
<div class="trafficlight">
<div id="red"></div>
<div id="yellow"></div>
<div id="green"></div>
</div>
I make a simple HTML and CSS Traffic light from an online example. Then I just create the condition for it to loop red-yellow-green-red.
I have 2 button (the unsmile and smile).
1. When i click to unsmile the img "flies" to left side.
2. When i click to smile the img is "flies" to right side.
But i need to do the following:
When i click on the img and drag it to the left, the img + description should "fly" to the left side and show a js alert - "You don't like this".
When i click on the img and drag it to right, the img + description should "fly" to the right side and show an alert - "You like this".
When i click on the img and drag it under the img, the img + description should "fly" down and show an alert - "You add this to favorite".
This should be done in javascript/html5/css.
It will be compiled using intelXDK to android platform.
HTML
<div id="food"></div>
<div id="control">
<div class="button no">
</div>
<div class="button yes">
</div>
</div>
</div>
JS Code
$('a[href*=#]').click(function(){
return false;
});
var animationEndEvent = "webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend";
var Food = {
wrap: $('#food'),
selectFood: [
{
name: 'Hamburger',
locaction: 'Poland, Warsaw, FoocCap',
img: "images/photo/1.jpg"
},
{
name: 'Chiness something',
locaction: 'Poland, Warsaw, FoocKnajp',
img: "images/photo/2.jpg"
},
{
name: 'Nuggets',
locaction: 'Japan, Tokyo, Yorazowa',
img: "images/photo/3.jpg"
},
{
name: 'Burger',
locaction: 'Japan, Nagasaki, Nogoiau',
img: "images/photo/4.jpg"
},
{
name: 'Chicken pice',
locaction: 'Russia, Moskow, Karmino',
img: "images/photo/5.jpg"
}
],
add: function(){
var random = this.selectFood[Math.floor(Math.random() * this.selectFood.length)];
this.wrap.append("<div class='foodChoose'><img alt='" + random.name + "' src='" + random.img + "' /><span><strong>" + random.name + "</strong>, " + random.locaction + "</span></div>");
}
}
var App = {
yesButton: $('.button.yes .trigger'),
noButton: $('.button.no .trigger'),
blocked: false,
like: function(liked){
var animate = liked ? 'animateYes' : 'animateNo';
var self = this;
if (!this.blocked) {
this.blocked = true;
$('.foodChoose').eq(0).addClass(animate).one(animationEndEvent, function() {
$(this).remove();
Food.add();
self.blocked = false;
});
}
}
};
App.yesButton.on('mousedown', function() {
App.like(true);
});
App.noButton.on('mousedown', function() {
App.like(false);
});
$(document).ready(function() {
Food.add();
});
CSS
#keyframes yes {
0% {
transform: scale(1) rotateZ(0deg);
left: 0;
}
30% {
transform: scale(1.05) rotateZ(0deg);
left: 0;
}
100% {
transform: rotateZ(45deg);
left: 400px;
}
}
.animateYes {
animation-fill-mode: both;
animation: yes 0.6s linear;
}
#keyframes no {
0% {
transform: rotateZ(360deg);
right: 0;
}
30% {
transform: scale(1.05) rotateZ(360deg);
right: 0;
}
100% {
transform: rotateZ(315deg);
right: 400px;
}
}
.animateNo {
animation-fill-mode: both;
animation: no 0.6s linear;
}
#control {
position: relative;
margin: 0 auto;
width: 250px;
top: -55%;
}
#control .button {
width: 65px;
height: 65px;
background: #fff;
position: absolute;
top: 5px;
border-radius: 50%;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
}
#control .button .trigger:active {
transform: translateY(-50%) scale(0.75);
transition: all .05s linear;
}
#control .button .trigger:before {
position: absolute;
top: 50%;
left: 50%;
transform: translateY(-50%) translateX(-50%);
font-family: 'FontAwesome';
}
#control .no {
left: 38px;
}
#control .no .trigger:before {
content: "\2639";
font-size: 40px;
color: #c33;
}
#control .yes {
right: 38px;
}
#control .yes .trigger:before {
content: "\263A";
font-size: 40px;
color: #3b7;
}
Current working version can be found here.
It's beed a while since I worked with jquery- let me know if it's a bad way to handle it so I can update/delete it?
You have already implemented an animationEnd handler
var App = {
yesButton: $('.button.yes .trigger'),
noButton: $('.button.no .trigger'),
blocked: false,
like: function(liked){
var animate = liked ? 'animateYes' : 'animateNo';
var self = this;
if (!this.blocked) {
this.blocked = true;
$('.foodChoose').eq(0).addClass(animate).one(animationEndEvent, function() {
$(this).remove();
Food.add();
self.blocked = false;
});
}
}
};
just pass the required arguments to your handler, e.g.
$('.foodChoose').eq(0).addClass(animate).one(animationEndEvent,
function(e) {
function(liked) {
$(this).remove();
alert(liked);
Food.add();
self.blocked = false;
}.bind(e.target, liked);
}
);
I'm passing the jquery custom event target here which should be identical to $('.foodChoose').eq(0)
^^ this means you will not need the original event and can remove the outer function like:
$('.foodChoose').eq(0).addClass(animate).one(animationEndEvent,
function(liked) {
$(this).remove();
alert(liked);
Food.add();
self.blocked = false;
}.bind($('.foodChoose').eq(0), liked);
);
added a fiddle including the code: https://jsfiddle.net/jLugv92t/1/ - slightly modified to bind to App. Thiy way we get rid of
var self = this;
I am using JWplayer 7 (HTML5 render mode) in my site.
I created a player with custom playlist, but cannot highlight current playing video when it has been clicked.
Is there any solution to add a custom class, like .active when click on a item of list.
This is my code to setup JWplayer.
var playerInstance = jwplayer("videoCont");
playerInstance.setup({
image: "{PLAYLIST_IMAGE}",
autostart: false,
aspectratio: "16:9",
playlist : "{NV_BASE_SITEURL}{MODULE_NAME}/player/{RAND_SS}{PLAYLIST_ID}-{PLIST_CHECKSS}-{RAND_SS}{FAKE_ID}/",
controls: true,
displaydescription: true,
displaytitle: true,
flashplayer: "{NV_BASE_SITEURL}themes/default/modules/{MODULE_NAME}/jwplayer/jwplayer.flash.swf",
primary: "html5",
repeat: false,
skin: {"name": "stormtrooper"},
stagevideo: false,
stretching: "uniform",
visualplaylist: true,
width: "100%"
});
And following code to generate custom player
var list = document.getElementById("show-list");
var html = list.innerHTML;
html +="<ul class='list-group'>"
playerInstance.on('ready',function(){
var playlist = playerInstance.getPlaylist();
for (var index=0;index<playlist.length;index++){
var playindex = index +1;
html += "<li class='list-group-item'><span>"+playlist[index].title+"</span><span class='pull-right'><label onclick='javascript:playThis("+index+")' title='Phát "+playlist[index].title+"' class='btn btn-default btn-xs'><i class='fa fa-play'></i></label><label class='btn btn-default btn-xs' href='"+playlist[index].link+"' title='Xem ở cửa sổ mới' target='_blank'><i class='fa fa-external-link-square'></i></label></span></li>"
list.innerHTML = html;
}
html +="</ul>"
});
function playThis(index) {
playerInstance.playlistItem(index);
}
SOLUTION : Based on an idea of #zer00ne
Add following code :
playerInstance.on('playlistItem', function() {
var playlist = playerInstance.getPlaylist();
var index = playerInstance.getPlaylistIndex();
var current_li = document.getElementById("play-items-"+index);
for(var i = 0; i < playlist.length; i++) {
$('li[id^=play-items-]').removeClass( "active" )
}
current_li.classList.add('active');
});
before
function playThis(index) {
playerInstance.playlistItem(index);
}
And edit html generate like this :
html += "<li id='play-items-"+index+"' class='list-group-item'><span>"+playlist[index].title+"</span><span class='pull-right'><label onclick='javascript:playThis("+index+")' title='"+lang_play+" "+playlist[index].title+"' class='btn btn-primary btn-xs mgr_10'><i class='fa fa-play'></i></label><a href='"+playlist[index].link+"' title='"+lang_new_window+"' target='_blank'><label class='btn btn-default btn-xs'><i class='fa fa-external-link-square'></i></label></a></span></li>"
With adding id='play-items-"+index+"' to identify unique class for each item of list.
Thanks for idea of #zer00ne !
Your code not total works with my site but it give a solution.
playerInstance.on('playlistItem', function() {
var playlist = playerInstance.getPlaylist();
var index = playerInstance.getPlaylistIndex();
var current_li = document.getElementById("play-items-"+index);
for(var i = 0; i < playlist.length; i++) {
$('li[id^=play-items-]').removeClass( "active" )
}
current_li.classList.add('active');
});
This code will remove all "active" from each li element and find the ID is correct with current playing Index, then add "active" class.
UPDATE
Firefox has a problem with li[i], since it's a HTMLCollection (nodeList) and not live coming from querySelectorAll(). One extra step needs to be added in order to convert li[i] to a true Array. The update involves a function called nodeList2Array(sel).
UPDATE
I misinterpreted the OP's request:
Is there any solution to add a custom class, like .active when click on a item of list.
So what is needed is manipulation of the generated <li>s of the custom playlist.
SOLUTION
Add this after the the rest of the script:
jw.on('playlistItem', function() {
var playlist = jw.getPlaylist();
var idx = jw.getPlaylistIndex();
//var li = document.querySelectorAll('.group-list-item');
var li = nodeList2Array('.group-list-item');
for(var i = 0; i < playlist.length; i++) {
if(i === idx) {
li[i].classList.add('active');
}
else {
li[i].classList.remove('active');
}
}
});
function nodeList2Array(sel) {
var li = Array.prototype.slice.call(document.querySelectorAll(sel));
return li;
}
DEMO
!!!IMPORTANT PLEASE READ THIS!!!
The following demo DEFINITELY WORKS, but you need to enter your own key in order for it to function. JW7 does not have a free version like JW6 does.
var jw = jwplayer("media1");
jw.setup({
playlist: "https://content.jwplatform.com/feeds/13ShtP5m.rss",
displaytitle: false,
width: 680,
height: 360
});
var list = document.querySelector(".group-list");
var html = list.innerHTML;
jw.on('ready', function() {
var playlist = jw.getPlaylist();
for (var idx = 0; idx < playlist.length; idx++) {
html += "<li class='group-list-item' title='" + playlist[idx].title + "'><a href='javascript:playThis(" + idx + ");'><img height='75' width='120' src='" + playlist[idx].image + "'><figcaption>" + playlist[idx].title + "</figcaption></a></li>";
list.innerHTML = html;
}
});
//SOLUTION~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
jw.on('playlistItem', function() {
var playlist = jw.getPlaylist();
var idx = jw.getPlaylistIndex();
var li = document.querySelectorAll('.group-list-item');
for (var i = 0; i < playlist.length; i++) {
if (i === idx) {
li[i].classList.add('active');
} else {
li[i].classList.remove('active');
}
}
});
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function playThis(idx) {
jw.playlistItem(idx);
}
html {
box-sizing: border-box;
font: 400 16px/2 small-caps"Trebuchet MS";
height: 100vh;
width: 100vw;
}
*,
*:before,
*:after {
box-sizing: inherit;
margin: 0;
padding: 0;
border: 0 solid transparent;
outline: 0;
text-indent: 0;
}
body {
height: 100%;
width: 100%;
background: #000;
color: #FFF;
position: relative;
}
#main {
margin: auto;
width: 680px;
}
#frame1 {
position: absolute;
top: 12.5%;
left: 25%;
}
.jwp {
position: relative;
}
.group-list {
position: relative;
list-style-type: none;
list-style-position: inside;
}
.group-list li {
list-style: none;
display: inline-block;
float: left;
padding: 15px 0 0 11px;
line-height: 2;
}
.group-list a {
text-decoration: none;
display: inline-block;
background: #000;
border: 1px solid #666;
border-radius: 8px;
height: 75px;
width: 120px;
text-align: center;
}
.group-list a:hover,
.group-list a:active {
border: 1px solid #ff0046;
border-radius: 8px;
color: #FFF;
background: hsla(180, 60%, 50%, .4);
}
img {
display: block;
}
.active {
background: hsla(180, 60%, 50%, .4);
outline: 3px solid #0FF;
}
.active figcaption {
color: #000;
}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JWplayer 7 - Add active class to current playing video</title>
<meta name="SO33252950" content="http://stackoverflow.com/questions/33252950/jwplayer-7-add-active-class-to-current-playing-video">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://d1jtvmpy1cspce.cloudfront.net/lib/jw/7/jwplayer.js"></script>
<script>
jwplayer.key = "/*........::::::45_Alphanumerics::::::........*/"
</script>
</head>
<body>
<main id="main">
<section id="frame1" class="frame">
<div id="media1" class="jwp">Loading...</div>
<ul id="list1" class="group-list"></ul>
</section>
</main>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
</body>
</html>
OLD
Sure it's possible to add a class such as .active then apply styles that way, but JW7 has extensive CSS Skin documentation. I styled the skin using the technique detailed here:
http://support.jwplayer.com/customer/en/portal/articles/2092249-sample-css-file
DEMO
https://glpro.s3.amazonaws.com/_util/smpte/jwp.html
/* Allows you to adjust the color of the playlist item when hovering and has a different active style.*/
.jw-skin-stormtrooper .jw-playlist-container .jw-option:hover,
.jw-skin-stormtrooper .jw-playlist-container .jw-option.jw-active-option {
background-color: hsla(210,100%,20%,1);
}
/* Changes the color of the label when hovering.*/
.jw-skin-stormtrooper .jw-playlist-container .jw-option:hover .jw-label {
color: #0080ff;
}
/* Sets the color of the play icon of the currently playing playlist item.*/
.jw-skin-stormtrooper .jw-playlist-container .jw-label .jw-icon-play {
color: #0080ff;
}
/* Sets the color of the playlist title */
.jw-skin-stormtrooper .jw-tooltip-title {
background-color: #000;
color: #fff
}
/* Style for playlist item, current time, qualities, and caption text.*/
.jw-skin-stormtrooper .jw-text {
color: #aed4ff;
}
/* Color for all buttons when they are inactive. This is over-ridden with the
inactive configuration in the skin block.*/
.jw-skin-stormtrooper .jw-button-color {
color: #cee2ec;
}
/* Color for all buttons for when they are hovered on. This is over-ridden with the
active configuration in the skin block.*/
.jw-skin-stormtrooper .jw-button-color:hover {
color: #00e;
}
/* Color for when HD/CD icons are toggled on. */
.jw-skin-stormtrooper .jw-toggle {
color: #0080ff;
}
/* Color for when HD/CD icons are toggled off. */
.jw-skin-stormtrooper .jw-toggle.jw-off {
color: #ffffff;
}