Google Maps Marker Filtering - javascript

I have the following jsfiddle:
http://jsfiddle.net/inkedraskal/zeLon7cs/2/
You'll notice when the map loads all the points are showing, and filtering on its own seems to work correctly. However, when you click a filter, (project for example), it will show only projects, but if you click it again, it wont reset the markers. As well as, if you say click News and then Stuff, then click Stuff again, it wont show the markers only applying to news again (still shows markers that apply to both News and Stuff, instead of just News).
Any tips would greatly be appreciated.
I have create a list-items to filter the markers on click
<div class="filters">
<ul>
<li>
Projects
</li>
<li>
News
</li>
<li>
stuff
</li>
</ul>
<ul>
<li>
Jan
</li>
<li>
Feb
</li>
<li>
Mar
</li>
</ul>
</div>
<div class="clear"></div>
at the bottom my JS you'll see the following:
$(document).on('click', '.filters a', function (event) {
event.preventDefault();
var $target = $(event.target);
var type = $target.data('filterby');
var value = $target.data('filtervalue');
$(this).toggleClass('active');
$.each(map.markers, function () {
if (this.filter[type] && this.filter[type].indexOf(value.toString()) >= 0) {
if (this.map == null) {
this.setMap(map);
}
} else {
this.setMap(null);
}
});
});

In your loop to hide/show each marker, for each individual marker you are only checking if that marker has the clicked on filter value. You need to check each marker against every active filter.
$(document).on('click', '.filters a', function(event) {
event.preventDefault();
$(this).toggleClass('active');
// create an array of active filters
var activeFilters = [];
$(".filters a.active").each(function() {
activeFilters.push({
by: $(this).data("filterby"),
value: $(this).data("filtervalue").toString()
});
});
if (activeFilters.length === 0) { // if there are no active filters, show all markers
for (var i = 0; i < map.markers.length; i++) {
map.markers[i].setMap(map);
}
} else {
for (var i = 0; i < map.markers.length; i++) { // for each marker
var marker = map.markers[i]; // just to make the next code easier
var missingActiveFilter = false;
// check if marker has every active filter
for (var j = 0; j < activeFilters.length; j++) {
var filter = activeFilters[j];
if (filter.by === "type" && marker.filter.type.indexOf(filter.value) === -1 || filter.by === "date" && marker.filter.date.indexOf(filter.value) === -1) {
missingActiveFilter = true;
break;
}
}
if (missingActiveFilter) {
marker.setMap(null);
} else {
marker.setMap(map);
}
}
}
});
});
Updated JSFiddle

Related

How can I add two JavaScript functions to this HTML element

I am trying to create 'previous' and 'next' buttons that cycle through different locations on an embedded Google Maps image, but have the 'previous' button hidden at the first location, and have the 'next' button disappear once the last location shows.
I know adding a CSS class called 'hidden' would do the trick, however I'm not sure where to place it, and how to place it.
Here is my HTML code. The iframe element is the google maps, and I gave it an id of 'mappy', to select it easier in JavaScript. Below the map are the two buttons.
Here is my JavaScript code. Currently, the next and previous buttons just cycle through each location.
var main_map = document.getElementById('mappy');
var maps = [
'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d106094.85581787785!2d-118.22632098885458!3d33.80033081467724!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x80c2cae84099d759%3A0xa1003afac42a8faa!2sLong%20Beach%2C%20CA!5e0!3m2!1sen!2sus!4v1598942170840!5m2!1sen!2sus',
'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d7961373.37326689!2d96.9825121578134!3d13.010860368647212!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x304d8df747424db1%3A0x9ed72c880757e802!2sThailand!5e0!3m2!1sen!2sus!4v1598948055475!5m2!1sen!2sus',
'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d12436315.314415561!2d166.3019164867038!3d-40.448493377535335!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x6d2c200e17779687%3A0xb1d618e2756a4733!2sNew%20Zealand!5e0!3m2!1sen!2sus!4v1598944334239!5m2!1sen!2sus',
'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d29616594.651652496!2d115.15555667021819!3d-25.02365472591425!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x2b2bfd076787c5df%3A0x538267a1955b1352!2sAustralia!5e0!3m2!1sen!2sus!4v1598944469264!5m2!1sen!2sus'
];
var i = 0; // Current Image Index
var a;
function prev() {
if (i <= 0) i = maps.length;
i--;
return setImg();
}
function next() {
if (i >= maps.length - 1) i = -1;
i++;
return setImg();
}
function setImg() {
return main_map.setAttribute('src', maps[i]);
}
<p><iframe id="mappy" src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d106094.85581787785!2d-118.22632098885458!3d33.80033081467724!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x80c2cae84099d759%3A0xa1003afac42a8faa!2sLong%20Beach%2C%20CA!5e0!3m2!1sen!2sus!4v1598942170840!5m2!1sen!2sus"
width="600" height="450" frameborder="0" style="border:0;" allowfullscreen="" aria-hidden="false" tabindex="0"></iframe></p>
<div class="buttons">
<button class="button" id="prev" onclick="prev()">← Previous</button>
<button class="button" id="next" onclick="next()">Next →</button>
</div>
You can check the index, if it is 0 make the previous button hide, and if the index of is 4 you make the next button hide. You can use toggleclass to hide the buttons
if (i = 0) { //if index is 0, toggle class hide
classList.toggle("hide");
else {
classList.toggle(“show”); //if the index is not 0, toggle class show
}
}
if (i = 4) { //if index is 4, toggle class hide
classList.toggle("hide");
else {
classList.toggle(“show”); //if the index is not 4, toggle class show
}
}
Edit: added a nested else statement to toggle class show if the index isn’t 0 or 4.
There are definitely better ways to do this, but this is probably the least convoluted method so you can see how it's done and probably rewrite it better!
var main_map = document.getElementById('mappy');
var previousBtn = document.getElementById('btn-prev');
var nextBtn = document.getElementById('btn-next')
var maps = [
'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d106094.85581787785!2d-118.22632098885458!3d33.80033081467724!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x80c2cae84099d759%3A0xa1003afac42a8faa!2sLong%20Beach%2C%20CA!5e0!3m2!1sen!2sus!4v1598942170840!5m2!1sen!2sus',
'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d7961373.37326689!2d96.9825121578134!3d13.010860368647212!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x304d8df747424db1%3A0x9ed72c880757e802!2sThailand!5e0!3m2!1sen!2sus!4v1598948055475!5m2!1sen!2sus',
'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d12436315.314415561!2d166.3019164867038!3d-40.448493377535335!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x6d2c200e17779687%3A0xb1d618e2756a4733!2sNew%20Zealand!5e0!3m2!1sen!2sus!4v1598944334239!5m2!1sen!2sus',
'https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d29616594.651652496!2d115.15555667021819!3d-25.02365472591425!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x2b2bfd076787c5df%3A0x538267a1955b1352!2sAustralia!5e0!3m2!1sen!2sus!4v1598944469264!5m2!1sen!2sus'];
var i = 0; // Current Image Index
var a;
function prev() {
if (i <= 0) i = maps.length;
i--;
viewButtons(i);
return setImg();
}
function next() {
if (i >= maps.length - 1) i = -1;
i++;
viewButtons(i);
return setImg();
}
function viewPrevious(index) {
if (index === 0) {
previousBtn.classList.add('hidden');
} else {
previousBtn.classList.remove('hidden');
}
}
function viewNext(index) {
if (index === maps.length - 1) {
nextBtn.classList.add('hidden');
} else {
nextBtn.classList.remove('hidden');
}
}
function viewButtons(index) {
viewPrevious(index);
viewNext(index);
}
function setImg() {
return main_map.setAttribute('src', maps[i]);
}
previousBtn.addEventListener('click', prev);
nextBtn.addEventListener('click', next);
viewButtons(i);

Index not being counted on click

I have a slider where I want to keep track of the current position of the slider. The function that runs when the ('next') and ('prev') are being clicked, is supposed to log the current position of the slider.
Unfortunately it skips the first child and starts the count on the second item in the slider. Instead of the first item being index 0, the second item is index 0
$(document).foundation()
$('.bullet').first().addClass('active');
//sets first item to active
$('.slider-item').first().addClass('active');
function dec() {
var $this = $(this);
var current = $('.slider-items').find('.active');
var position = $('.slider-items').children().index(current);
console.log(position)
}
$('.next, .prev').click(function() {
dec();
var $this = $(this);
var current = $('.slider-items').find('.active');
var position = $('.slider-items').children().index(current);
var numItems = $('.slider-item').length;
if ($this.hasClass('next')) {
if (position < numItems - 1) {
$('.active').removeClass('active').next().addClass('active');
} else {
$('.slider-item').removeClass('active').first().addClass('active');
$('.bullet').removeClass('active').first().addClass('active');
} //else
} else {
if (position === 0) {
$('.slider-item').removeClass('active').last().addClass('active');
$('.bullet').removeClass('active').last().addClass('active');
} else {
$('.active').removeClass('active').prev().addClass('active');
}
}
}); // click function
The code seems to work when I run it against a simple bullet list example. It correctly states that the first bullet point is index 0. Are you simply calling the dec() function in the wrong place? Note that when you click next, you are logging the current position before the change is made to the position. I updated the dec() code to accept a parameter to show what I mean.
$(document).ready(function() {
//sets first item to active
$('.slider-item').first().addClass('active');
function dec(prefix) {
var $this = $(this);
var current = $('.slider-items').find('.active');
var position = $('.slider-items').children().index(current);
console.log(prefix + position);
}
$('.next, .prev').click(function() {
dec("before click handled: ");
var $this = $(this);
var current = $('.slider-items').find('.active');
var position = $('.slider-items').children().index(current);
var numItems = $('.slider-item').length;
if ($this.hasClass('next')) {
if (position < numItems - 1) {
$('.active').removeClass('active').next().addClass('active');
} else {
$('.slider-item').removeClass('active').first().addClass('active');
$('.bullet').removeClass('active').first().addClass('active');
} //else
} else {
if (position === 0) {
$('.slider-item').removeClass('active').last().addClass('active');
$('.bullet').removeClass('active').last().addClass('active');
} else {
$('.active').removeClass('active').prev().addClass('active');
}
}
dec("after click handled: ");
})}); // click function
li.active {
color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="slider-items">
<li class="slider-item">A</li>
<li class="slider-item">B</li>
<li class="slider-item">C</li>
<li class="slider-item">D</li>
</ul>
<button class="prev">Prev</button>
<button class="next">Next</button>

Jquery tab is not working

I have one problem with click function. I have created this demo from jsfiddle.net.
In this demo you can see there are smile buttons. When you click those buttons then a tab will be opening on that time. If you click the red button from tab area then the tab is not working there are something went wrong.
Anyone can help me here what is the problem and what is the solution?
The tab is normalize like this working demo
var response = '<div class="icon_b">
<div class="clickficon"></div>
<div class="emicon-menu MaterialTabs">
<ul>
<li class="tab active"> TAB1</li>
<li class="tab"> TAB2</li>
<li class="tab"> TAB3<span></span></li>
</ul>
<div class="panels">
<div id="starks-panel1" class="panel pactive"> a </div>
<div id="lannisters-panel1" class="panel"> b </div>
<div id="targaryens-panel1" class="panel"> c </div>
</div>
</div>
</div>';
$(document).ready(function () {
function showProfileTooltip(e, id) {
//send id & get info from get_profile.php
$.ajax({
url: '/echo/html/',
data: {
html: response,
delay: 0
},
method: 'post',
success: function (returnHtml) {
e.find('.user-container').html(returnHtml).promise().done(function () {
$('.emoticon').addClass('eactive');
});
}
});
}
$('body').on('click', '.emoticon', function(e) {
var id = $(this).find('.emoticon_click').attr('data-id');
showProfileTooltip($(this), id);
});
$(this).on( "click", function() {
$(this).find('.user-container').html("");
});
var componentHandler = function() {
'use strict';
var registeredComponents_ = [];
var createdComponents_ = [];
function findRegisteredClass_(name, opt_replace) {
for (var i = 0; i < registeredComponents_.length; i++) {
if (registeredComponents_[i].className === name) {
if (opt_replace !== undefined) {
registeredComponents_[i] = opt_replace;
}
return registeredComponents_[i];
}
}
return false;
}
function upgradeDomInternal(jsClass, cssClass) {
if (cssClass === undefined) {
var registeredClass = findRegisteredClass_(jsClass);
if (registeredClass) {
cssClass = registeredClass.cssClass;
}
}
var elements = document.querySelectorAll('.' + cssClass);
for (var n = 0; n < elements.length; n++) {
upgradeElementInternal(elements[n], jsClass);
}
}
function upgradeElementInternal(element, jsClass) {
if (element.getAttribute('data-upgraded') === null) {
element.setAttribute('data-upgraded', '');
var registeredClass = findRegisteredClass_(jsClass);
if (registeredClass) {
createdComponents_.push(new registeredClass.classConstructor(element));
} else {
createdComponents_.push(new window[jsClass](element));
}
}
}
function registerInternal(config) {
var newConfig = {
'classConstructor': config.constructor,
'className': config.classAsString,
'cssClass': config.cssClass
};
var found = findRegisteredClass_(config.classAsString, newConfig);
if (!found) {
registeredComponents_.push(newConfig);
}
upgradeDomInternal(config.classAsString);
}
return {
upgradeDom: upgradeDomInternal,
upgradeElement: upgradeElementInternal,
register: registerInternal
};
}();
function MaterialTabs(element) {
'use strict';
this.element_ = element;
this.init();
}
MaterialTabs.prototype.Constant_ = {
MEANING_OF_LIFE: '42',
SPECIAL_WORD: 'HTML5',
ACTIVE_CLASS: 'pactive'
};
MaterialTabs.prototype.CssClasses_ = {
SHOW: 'materialShow',
HIDE: 'materialHidden'
};
MaterialTabs.prototype.initTabs_ = function(e) {
'use strict';
this.tabs_ = this.element_.querySelectorAll('.tab');
this.panels_ = this.element_.querySelectorAll('.panel');
for (var i=0; i < this.tabs_.length; i++) {
new MaterialTab(this.tabs_[i], this);
}
};
MaterialTabs.prototype.resetTabState_ = function() {
for (var k=0; k < this.tabs_.length; k++) {
this.tabs_[k].classList.remove('pactive');
}
};
MaterialTabs.prototype.resetPanelState_ = function() {
for (var j=0; j < this.panels_.length; j++) {
this.panels_[j].classList.remove('pactive');
}
};
function MaterialTab (tab, ctx) {
if (tab) {
var link = tab.querySelector('a');
link.addEventListener('click', function(e){
e.preventDefault();
var href = link.href.split('#')[1];
var panel = document.querySelector('#' + href);
ctx.resetTabState_();
ctx.resetPanelState_();
tab.classList.add('pactive');
panel.classList.add('pactive');
});
}
};
MaterialTabs.prototype.init = function() {
if (this.element_) {
this.initTabs_();
}
}
window.addEventListener('load', function() {
componentHandler.register({
constructor: MaterialTabs,
classAsString: 'MaterialTabs',
cssClass: 'MaterialTabs'
});
});
});
There is updated and working version.
What we have to do, is to move the target on the same level as the icon is (almost like tab and content). Instead of this:
<div class="emoticon">
<div class="emoticon_click" data-id="1">
<img src="http://megaicons.net/static/img/icons_sizes/8/178/512/emoticons-wink-icon.png" width="30px" height="30px">
<div class="user-container" data-upgraded></div>
</div>
</div>
We need this
<div class="emoticon">
<div class="emoticon_click" data-id="1">
<img src="http://megaicons.net/static/img/icons_sizes/8/178/512/emoticons-wink-icon.png" width="30px" height="30px">
// not a child
<!--<div class="user-container" data-upgraded></div>-->
</div>
// but sibling
<div class="user-container" data-upgraded></div>
</div>
And if this is new HTML configuration, we can change the handlers
to target click on div "emoticon_click"
change the content of the sibling (not child) div "user-container"
The old code to be replaced
$('body').on('click', '.emoticon', function(e) {
var id = $(this).find('.emoticon_click').attr('data-id');
showProfileTooltip($(this), id);
});
$(this).on( "click", function() {
$(this).find('.user-container').html("");
});
will now be replaced with this:
//$('body').on('click', '.emoticon', function(e) {
$('body').on('click', '.emoticon_click', function(e) {
// clear all user container at the begining of this click event
$('body').find('.user-container').html("");
// find id
var id = $(this).attr('data-id');
// find the parent, which also contains sibling
// user-container
var parent = $(this).parent()
// let the target be initiated
showProfileTooltip($(parent), id);
});
$(this).on( "click", function() {
//$(this).find('.user-container').html("");
});
Check it in action here
NOTE: the really interesting note was in this Answer by pinturic
If we want to extend the first and complete answer with a feature:
close all tabs if clicked outside of the area of tabs or icons
we just have to
add some event e.g. to body
and do check if the click was not on ".emoticon" class elements
There is a working example, containing this hook:
$('body').on( "click", function(e) {
// if clicked in the EMOTICON world...
var isParentEmotion = $(e.toElement).parents(".emoticon").length > 0 ;
if(isParentEmotion){
return; // get out
}
// else hide them
$('body').find('.user-container').html("");
});
I have been debugging your code and this is the result:
you are adding the "tab" under ; any time you click within that div this code is intercepting it:
$('body').on('click', '.emoticon', function(e) {
var id = $(this).find('.emoticon_click').attr('data-id');
showProfileTooltip($(this), id);
});
and thus the "tab" are built again from scratch.

Number elements by class and get placement of specific div

I have a list like this:
<div class="list"></div>
<div class="list"></div>
<div class="list on"></div>
<div class="list"></div>
... etc
I get the total like this:
var count = $('.list').length; // 4 in this case
But I want to write a function that selects the next div with the down arrow, and I can't figure out how to get the next div, select it, and deselect the current div. This is what I have now, but it doesn't work:
var visible = $('.list:visible');
var on = $('.list.on:visible');
if (e.keyCode == 40) { // down key
if(on.length == 0) {
visible.first().addClass("on"); // this works
}
else if( // div placement // < count) {
var next = on.next(); // this part doesn't work
on.removeClass("on"); // :(
next.addClass("on"); // :(
}
else { // if its the last div
// do nothing
}
}
You can do:
if (e.keyCode == 40) { // down key
if(on.length == 0) {
visible.first().addClass("on");
}
else if(on.length && on.next("div.list").length > 0) {
var next = on.next("div.list");
on.removeClass("on");
next.addClass("on");
}
else { // if its the last div
// do nothing
}
}
A quick demo: http://jsfiddle.net/GL7tA/
You can work with .index() to see which item is currently "selected":
var $items = $('.list:visible'),
$selectedItem = $items.filter('.on'),
selectedIndex = $items.index($selectedItem);
if (selectedIndex == -1) {
$items.eq(0).addClass('on');
} else if (selectedIndex + 1 < $items.length) {
$selectedItem.next().andSelf().toggleClass('on');
}
You have a syntax error in the else if ( part, where you say it doesn't work.
It doesn't work because the else if is expecting a condition to evaluate but you are not even closing the parenthesis of that if condition, neither have you openned the brackets for its block.

How to make random selector only pick shown items?

Yeah not very familiar with JQuery and I'm trying to make a random lunch picker for our web team.
http://jsfiddle.net/vy8RL/1/
I want to hide certain items. For example when you hit the "Quick Eats" button it only displays 4 options and when you hit "EAT ME" it still selects the LI's that are hidden. Is there any way to allow it only to select options that are visible?
$(document).ready(function() {
$("#button").click(function(){
random();
});
$("#unhealthy-food").click(function(){
$(".unhealthy").hide();
});
$("#all").click(function(){
$("li").show();
});
$("#fast-food").click(function(){
$(".food").hide();
$(".fast").show();
});
});
function random() {
$("li.selected").removeClass("selected");
var menuItems = $("ul#list li");
var numItems = menuItems.length;
if(window.sessionStorage && window.sessionStorage.getItem("selected")) {
previous = Number(window.sessionStorage.getItem("selected"));
} else {
previous = -1;
}
var selected = Math.floor(Math.random()*numItems);
while(selected === previous && numItems > 1) {
selected = Math.floor(Math.random()*numItems);
}
if(window.sessionStorage) window.sessionStorage.setItem("selected", selected);
$("ul#list li:nth-child("+(selected+1)+")").addClass("selected");
}
You can use the :visible selector:
function random() {
$("li.selected").removeClass("selected");
var menuItems = $("#list li").filter(':visible');
var numItems = menuItems.length;
// ...
menuItems.eq(selected).addClass("selected");
}
Please note that I have replaced the $("ul#list li:nth-child("+(selected+1)+")") with the cached collection + eq() method.
http://jsfiddle.net/3n9ex/
here you go. I just added tracking of menu preference. Also added $(".food").show(); in line 9 to correct a bug.
$(document).ready(function() {
var user_choice = ".food";
$("#button").click(function(){
random(user_choice);
});
$("#unhealthy-food").click(function(){
user_choice = "li:not(.unhealthy)";
$(".food").show();
$(".unhealthy").hide();
});
$("#all").click(function(){
$("li").show();
user_choice = ".food";
});
$("#fast-food").click(function(){
$(".food").hide();
$(".fast").show();
user_choice = ".fast";
});
});
function random(user_choice) {
$("li.selected").removeClass("selected");
var menuItems = $(user_choice);
console.log(menuItems);
var numItems = menuItems.length;
if(window.sessionStorage && window.sessionStorage.getItem("selected")) {
previous = Number(window.sessionStorage.getItem("selected"));
} else {
previous = -1;
}
var selected = Math.floor(Math.random()*numItems);
while(selected === previous && numItems > 1) {
selected = Math.floor(Math.random()*numItems);
}
if(window.sessionStorage) window.sessionStorage.setItem("selected", selected);
$(menuItems[selected]).addClass("selected");
}
http://jsfiddle.net/vy8RL/19/

Categories