Trying to eliminate closure error in google map eventListener - ruby-on-rails

I have a google map with a load of markers on it, each corresponding to a different post in the html. Each marker id is the same as each post id. Inside the map initialize = function() {... I have the following code (I'm using gon to pass info from rails to javascript):
for (m = 0; m < gon.markers.length; m++) {
marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(gon.markers[m].lat, gon.markers[m].lng),
icon: image,
infowindow: gon.markers[m].infowindow,
id: gon.markers[m].id
});
google.maps.event.addListener(marker, 'mouseover', function() {
var image = $("#map-canvas").data('marker2');
this.setIcon(image);
// console.log("marker.id: " + marker.id);
// console.log("this.id" + this.id);
$('#' + marker.id).css('background', 'red');
});
google.maps.event.addListener(marker, 'mouseout', function() {
var image = $("#map-canvas").data('marker1');
this.setIcon(image);
$('#' + marker.id).css('background', 'white');
});
markers[markers.length] = marker;
}
Uncommenting the console.log lines demonstrates that it is the classic closure problem (marker.id always has the same value no matter which marker is hovered on).
My question is, how do I code it properly so it does as intended? I just can't get the code right now matter what I try. I've tried stuff like this but is just doesn't work:
marker.on('mouseover', noticeHover(marker.id));
function noticeHover(id) {
var image = $("#map-canvas").data('marker2');
this.setIcon(image);
$('#' + id).css('background', 'gainsboro');
}

Wrap the entire code that handles the marker-creation into a function and pass the items inside the loop as argument to this function:
for (m = 0; m < gon.markers.length; m++) {
//anonymous,self-executing function
(function(props){
var goo = google.maps,
marker = new goo.Marker({
map: map,
position: new goo.LatLng(props.lat,
props.lng),
icon: image,
infowindow: props.infowindow,
id: props.id
});
goo.event.addListener(marker, 'mouseover', function() {
var image = $("#map-canvas").data('marker2');
this.setIcon(image);
$('#' + marker.id).css('background', 'red');
});
goo.event.addListener(marker, 'mouseout', function() {
var image = $("#map-canvas").data('marker1');
this.setIcon(image);
$('#' + marker.id).css('background', 'white');
});
markers.push(marker);
}(
gon.markers[m]//pass current loop-item as argument
));
}

Related

Get term for selected autocomplete when multiple are on one page

I have a page where I am adding jquery-ui autocompletes dynamically
My .autocomplete() code includes a $.getJSON('my_url', my_payload) where, in my_payload,' I am trying to send the request.term (what I typed into the jqueryui textbox) as well as the id of the jquery ui text box.
The problem is, for all the dynamically added textboxes, they were just picking up the term and id of the original autocomplete.
I managed to find a way to get the id of the added (not original) autocomplete by wrapping the autocomplete in a function that has the added field passed in as a parameter, but because the 'term' is in the request, which comes from .autocomplete, I do not know how to get this for the new ones.
https://jsfiddle.net/amchugh89/1L8jvea5/4/
//=======dynamic formset script from https://medium.com/all-about-
django/adding-forms-dynamically-to-a-django-formset-375f1090c2b0======
function updateElementIndex(el, prefix, ndx) {
var id_regex = new RegExp('(' + prefix + '-\\d+)');
var replacement = prefix + '-' + ndx;
if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
if (el.id) el.id = el.id.replace(id_regex, replacement);
if (el.name) el.name = el.name.replace(id_regex, replacement);
}
function cloneMore(selector, prefix) {
var newElement = $(selector).clone(true);
var total = $('#id_' + prefix + '-TOTAL_FORMS').val();
newElement.find(':input:not([type=button]):not([type=submit]):not([type=reset])').each(function() {
if ($(this).attr('name')){
var name = $(this).attr('name').replace('-' + (total-1) + '-', '-' + total + '-');
var id = 'id_' + name;
$(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
if($(this).attr('id').includes('gl')){
console.log($(this).attr('id'))
make_autocomplete($(this))
}
}
});
newElement.find('label').each(function() {
var forValue = $(this).attr('for');
if (forValue) {
forValue = forValue.replace('-' + (total-1) + '-', '-' + total + '-');
$(this).attr({'for': forValue});
}
});
total++;
$('#id_' + prefix + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
var conditionRow = $('.form-row:not(:last)');
conditionRow.find('.btn.add-form-row')
.removeClass('btn-success').addClass('btn-danger')
.removeClass('add-form-row').addClass('remove-form-row')
.html('<span class="glyphicon glyphicon-minus" aria-hidden="true"></span>');
return false;
}
function deleteForm(prefix, btn) {
var total = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
if (total > 1){
btn.closest('.form-row').remove();
var forms = $('.form-row');
$('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
for (var i=0, formCount=forms.length; i<formCount; i++) {
$(forms.get(i)).find(':input').each(function() {
updateElementIndex(this, prefix, i);
});
}
}
return false;
}
$(document).on('click', '.add-form-row', function(e){
e.preventDefault();
cloneMore('.form-row:last', 'form');
return false;
});
$(document).on('click', '.remove-form-row', function(e){
e.preventDefault();
deleteForm('form', $(this));
return false;
});
//====================
//AUTOCOMPLETE==(that allows for multiple ACs
https://stackoverflow.com/questions/24656589/using-jquery-ui-autocomplete-
with-multiple-input-fields)===================================
function make_autocomplete(ee) {
ee.on("focus", function(){ //.autocomplete({
$(this).autocomplete({
minLength: 2,
source: function( request, response ) {
var term = request.term;
//with the formset, I want to get the row for which I am typing in the
'term'
var this_formset_row_autocomplete_id
=ee.attr('id');//$(this.element).prop("id");//
$(this).attr('id');
console.log(this_formset_row_autocomplete_id);
var corresponding_branch_html_id =
this_formset_row_autocomplete_id.replace('gl_account','branch');
var this_formset_row_branch_sym_id =
$('#'+corresponding_branch_html_id).val();
//console.log(corresponding_branch_html_id, this_formset_row_branch_sym_id)
var appended_data={term:term,
this_formset_row_branch_sym_id:this_formset_row_branch_sym_id};
console.log(appended_data);
$.getJSON( "{% url 'dashapp:account_autocomplete' %}", appended_data,
function( data,
status, xhr ) {
//cache[ term ] = data;
response( data );
});
}
});
});
}//end function make_autocomplete
var ee =$( ".account_autocomplete" )
make_autocomplete(ee)
//===============
You may want to try to make it more simple for testing. Something like:
function make_autocomplete(obj) {
obj.autocomplete({
minLength: 2,
source: function(req, resp) {
var myData = {
term: req.term,
original_form_branch_id: $(this).closest("form").attr("id"),
this_formset_row_branch_sym_id: $(this).closest(".row").find("select").val()
}
$.getJSON("myurl", myData, function(results) {
resp(results);
});
}
});
}
Fiddle: https://jsfiddle.net/Twisty/pywb9nhv/23/
This uses .closest() to gather details from the relative objects. Also I do not see any benefit to initializing Autocomplete on focus event.
If you would like further help, please provide Example Data that can be used in a working example.
Hope that helps a little.

Konva converting stage toDataUrl() do not work in chrome browser,but work well in safari browser

I have Konva Stage with few layers, when I try convert to image all stage - result is OK in safari browser , when I try convert stage in chrome ,firefox etc. - result is failed. I think that toDataUrl() method does
not work well in chrome browser ,firefox browser etc except for safari browser
<button id="save" type="button">save</button>
<div id="container"></div>
<script>
var width = window.innerWidth;
var height = window.innerHeight;
function downloadURI(uri, name) {
var link = document.createElement('a');
link.download = name;
link.href = uri;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
delete link;
}
function drawImage(imageObj) {
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
var layer = new Konva.Layer();
// darth vader
var darthVaderImg = new Konva.Image({
image: imageObj,
x: stage.getWidth() / 2 - 200 / 2,
y: stage.getHeight() / 2 - 137 / 2,
width: 200,
height: 137,
name: 'myimg',
draggable: true
});
// add cursor styling
darthVaderImg.on('mouseover', function () {
document.body.style.cursor = 'pointer';
});
darthVaderImg.on('mouseout', function () {
document.body.style.cursor = 'default';
});
layer.add(darthVaderImg);
stage.add(layer);
stage.on('click tap', function (e) {
// if click on empty area - remove all transformers
if (e.target === stage) {
stage.find('Transformer').destroy();
layer.draw();
return;
}
// do nothing if clicked NOT on our rectangles
if (!e.target.hasName('myimg')) {
return;
}
// remove old transformers
// TODO: we can skip it if current rect is already selected
stage.find('Transformer').destroy();
// create new transformer
var tr = new Konva.Transformer();
layer.add(tr);
tr.attachTo(e.target);
layer.draw();
})
document.getElementById('save').addEventListener(
'click',
function () {
var dataURL = stage.toDataURL({ pixelRatio: 3 });
downloadURI(dataURL, 'stage.png');
},
false
);
}
var imageObj = new Image();
imageObj.onload = function () {
drawImage(this);
};
imageObj.src = 'https://www.decanterchina.com/assets/images/article/550/136031_decanter-cava-tasting-1.jpg';
</script>
Any possible reasons or solutions ? Thanks!!
If you look into the console you will see a message:
Konva warning: Unable to get data URL. Failed to execute 'toDataURL'
on 'HTMLCanvasElement': Tainted canvases may not be exported.
You have CORS issue. Take a look here for solutions:
Tainted canvases may not be exported
https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image

Check if image is valid

I want to check, if a given image file is valid (means displayable in a browser window and not getting a indicating, that the image cannot be displayed. This is the code I tried:
var bWindow;
bWindow = new electron.BrowserWindow({"show": false});
bWindow.loadURL("file://defect.png");
bWindow.webContents.on("did-fail-load", function (event, errCode, errDescription) {
console.log("error", errDescription);
});
bWindow.webContents.on("did-finish-load", function () {
console.log("success");
});
expecting to get "error". But I always get "success". How can I achieve what I want?
Try-
function checkImage(imageSrc, good, bad) {
var img = new Image();
img.onload = good;
img.onerror = bad;
img.src = imageSrc;
}
checkImage("foo.gif", function(){ alert("good"); }, function(){ alert("bad"); } );

Add more markers to markerCluster without removing previous

I build a map and add markers. When I'm calling AJAX , Some more records are coming from db and updating the location to map without reloading the map. But the problem is it is making new cluster for new records.
Here is code :
var marker, i;
var markers=[]
for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map,
icon: locations[i][4]
});
google.maps.event.addListener(marker, 'mouseover', (function (marker, i) {
return function () {
infowindow.setContent("<img src="+locations[i][5]+" width='100%'><br> <strong>"+locations[i][0]+"</strong>");
infowindow.open(map, marker);
}
})(marker, i));
// assuming you also want to hide the infowindow when user mouses-out
marker.addListener('mouseout', function() {
infowindow.close();
});
google.maps.event.addListener(marker, 'click', (function (marker, i) {
return function () {
infowindow.setContent("<img src="+locations[i][5]+" width='100%'><br> <strong>"+locations[i][0]+"</strong>");
infowindow.open(map, marker);
}
})(marker, i));
markers.push(marker);
}
var markerCluster = new MarkerClusterer(map, markers,{
imagePath: 'https://cdn.rawgit.com/googlemaps/js-marker-clusterer/gh-pages/images/m'
});
You can Add markers
var markers = []
var marker = new google.maps.Marker({position: center});
markers.push(marker);
markerClusterer.addMarkers(markers);
Note that here I have added only one.
You can remove all markers
markerClusterer.clearMarkers();
markers = [];
Note that for tidiness I have also unset the markers array here.
you can go through
http://google-maps-utility-library-v3.googlecode.com/svn/trunk/markerclusterer/docs/reference.html

on() doesn't work with live data using jQuery, how to?

i have some dynamic data that gets appended to a list and any links in that data doesnt seem to work.
i am using jquery 1.8.3 and on() should account for the live method, i think
setInterval(function () {
getNot();
}, 2000);
function getNot() {
var data = {
t1: 'test1',
t2: 'test2',
t3: 'test3'
};
var size = 0,
li = '';
$.each(data, function (k, v) {
li += '<li>' +
'<a href="#" class="add" data-listid="' + k + '">' +
'<h2>load data - ' + k + '</h2>' +
'</a>' +
'</li>';
size++;
});
var but = $('#not'),
ul = $('#not_ul');
but.find('span').text(size + ' Notifications');
ul.html(li);
ul.listview().listview("refresh");
}
// this doesn't seem to work
$('.add').on("click", function () {
var listId = $(this).data('listid');
console.log(listId);
return false;
});
see full example here
any ideas on this issue?
$('.add').on("click", function () {
You need to pass a selector to make on generate a delegate event:
$('#{containerId}').on("click", '.add', function () {
var listId = $(this).data('listid');
console.log(listId);
return false;
});
containerId should be the closest static element to the dynamic created .adds elements.

Resources