slow loop on google maps markers - javascript

i have a question about google maps markers and javascript.
i have a page that only has a div (map_canvas) that creates a marker when you click on it, and a textfield where you input the name of a marker and the marker starts bouncing ...
to keep track of the markers i have an array of all the markers added. The problem is that when it gets to 20+ markers the UI tends to become unresponsive while its looping...
here is the loop that i have, its inside a function that takes the marker id as a parameter
for (var i=0; i < markers.length; i++) {
if(markers[i].id == id)
{
if(markers[i].getAnimation() != null)
{
markers[i].setAnimation(null);
}
else
{
markers[i].setAnimation(google.maps.Animation.BOUNCE);
}
}
else
markers[i].setAnimation(null);
}
please let me know if this is a re-post or if i should provide more information ... this is my first question here!

I would suggest using id as the index in your markers array so that you can access each marker directly rather than looping to find it. Once you have a "current" marker, make a note of which it is in order that you know which one to stop bouncing when you start the next one bouncing.
var lastmarker;
...
if (lastmarker) {markers[lastmarker].setAnimation(null)}
markers[id].setAnimation(google.maps.Animation.BOUNCE);
lastmarker=id;
Of course, the viability of this suggestion depends on the rest of your code, of which we know nothing.

I would suggest adding steps/breakpoints in your code, not sure what coding environment you are in.....if you are just using straight html I would suggest using firebug to step through your code using breakpoints as this will allow you to see the issue in your code. I am guessing it is code related.
If you have already done so, I am pretty perplexed on your issue as to why it would just stop working at 20 or more markers....if it is not code related I would venture to guess that it has something to do with Google's api as I have run into some real odd occurrences once you get past their maxes on certain things although I haven't experienced a max on marker placement before, I have done something like what you are doing but in asp environment with many more markers.

Related

Leaflet layer controls for array properties mess up results, how to fix? better solution for large amounts of geoJSON data and several filters?

My end goal is to show a map with several hundred markers, each containing some information in a popup. Those markers are fairly close and some are in the very same spot, so they should be clustered and must be separately clickable for the popup. I also want to be able to filter them by several properties, starting with two array properties (phases and tags).
I actually managed to set all of that up quite nicely by using the MarkerCluster and MarkerCluster-LayerSupport plugins. I have 19 different tags and 4 different phases with corresponding FeatureGroups, all the markers are added to the respective groups, and there are two controls with checkboxes on the map. You can check it out here if you like.
However, these controls act a little weirdly, or rather, not quite the way I'd like them to. All markers are on at least two layers, so when I uncheck "Tag #2", the FeatureGroup with all the markers with tag #2 is removed. That includes markers with tag #3 and tag #6, which are still checked and which therefore I'd like to keep on the map… so when you check and uncheck boxes in both controls, the results become quite unpredictable.
Is there a way to fix this, by somehow reevaluating all the checked layers? Or should I go a completely different route with the filtering? For example this seems to be a jQuery filter. I find it hard to gauge performance issues though – I'm importing all the data into a separate geoJSON file with PHP, and I expect to get several hundred markers at some point, possibly more. I'm fairly new to Leaflet and handling large amounts of data in JS.
I will of course post my code if you'd like to see it, but since it's all working as intended and it's quite a lot, I'm not sure it's useful at this point.
Any pointers, ideas and best practice tips are most appreciated!
I have worked a little with Leaflet. In my experience, you need to have in mind that you need to group the common markers in a single layer, but the geo-JSON files put all markers in a single layer, no matter with properties has.
I did something similar to you, but I preprocessed all added markers to group them by specific properties. It is good because it can give you more control and do whatever you need, but that needs more initial time to preprocess all the info (and more if you are planning to have thousands of markers).
To check and manage all possible points you can use the pointToLayer method in the geoJSON loading:
const tagCategories = {};
.
.
.
L.geoJSON(someGeojsonFeature, {
pointToLayer: function (feature, latlng) {
const tagName = feature.properties.tagName;
const marker = L.circleMarker(latlng, geojsonMarkerOptions);
if (!tagCategories[tagName]) {
tagCategories[tagName] = [];
}
tagCategories[tagName].push({marker, feature});
return marker;
}
}).addTo(map);
.
.
.
function myFilterFunction({feature}) {
return feature.properties.year === '1981';
}
document.querySelector('.tag1Btn').addEventListener('click', () => {
const places = tagCategories[tagName].filter(myFilterFunction);
// Do whatever you need with places.
})
My best advice is to try to use vanilla js to reduce the overhead of preprocessing because libraries like jQuery, lodash and underscore do the same and in some cases are fast, but generally, Vanilla JS is faster if is used properly.

Should this For-Loop, in theory, work?

I have a question over at collision-detection about a similar issue, but it's not exactly the same. I had an issue with a new game project (I'm trying to learn more about HTML5 Canvases and Socket.io) in which my collisions weren't working. I thought that my issue was centered on collisions, but now I'm starting to think something different. The reason I have a different issue posted here at the for-loop area is because I'm not sure if my issue is for-loop related or collision-detection related. Either way, I'd be happy to take one of my questions down.
This code is looping every frame to get the active positions of bullets and ships. If the bullet touches the ship, it'll be removed and some health points will be removed from the ship.
Tutorial I was using: http://jlongster.com/Making-Sprite-based-Games-with-Canvas
That aside, here's my checkCollisions code. It seems that the collision function is working, because when I started to log all the positions every time we had an iteration, it seemed that the position of my object was changing every single time. Is this one of those for-loop issues where I'm going to need a callback?
Thank you so much in advance for all your help. I'll be sure to upvote/select every response that helps out! :)
SOLVED! Turns out one of my arrays wasn't being passed in correctly. I'd like to thank you guys for telling me to always split it into multiple functions, that really helped me figure that one out!
// Let's start out here: I have a players[] array
//that's essentially a list of all players on the server
// and their positions. I omitted server connection functionality since that's not my error
// source.
function checkCollisions() {
for (var i = 0; i < players.length; i++) { // Iterating through all players
var pos = [players[i].posX, players[i].posY];
var size = [SHIP_WIDTH, SHIP_HEIGHT]; // This is the size of each player, it's a ship game. So these are constants.
if (players[i].userId != PLAYER.userId) { // Each player has a userId object, this is just doublechecking if we're not uselessly iterating
for (var j = 0; j < bullets.length; j++) { // We're now looping through bullets, an array of all the bullets being shot by players
var pos2 = bullets[j].pos;
var size2 = BULLET_SIZE;
var sender = bullets[j].sender;
if (boxCollides(pos, size, pos2, size2)) { // Collision code
if (sender != players[i].userId) {
bullets.splice(j, 1);
i--; // Tried here with j--, and by removing the entire line. Unfortunately it doesn't work :(
break;
}
}
}
}
}
}
Have you tried using console.log to see where the program is breaking? This might help you determine if there are multiple bugs or if it's just this one. If there's something wrong in a previous statement, you may not know it if you've fixed the i-- / j-- ...?
Edit: AH I see that you've fixed things, after I'd posted this. Well congrats and good job!

Detecting collisions between two moving objects

I've got a basic Space Invaders type game going, and I can't get it to recognise when the shot from the player hits the alien. (I'm only checking Alien2 atm, the one second from the left). Since they're both moving, I've decided the only way to check for collisions is with either a range-based if statement (with 2 top coordinates and one left coordinate), or directly comparing the positions along the Y axis with Jquery.
I'm using the range-based solution at the moment, but so far it hasn't worked (not sure why).
My code so far:
if (key == "87"/*&& document.getElementById('BarrelOne').id=='BarrelOne'*/){
var Invader2 = document.getElementById('Alien2');
var Shot1 = document.getElementById('ShortShot');
Shot1.style.webkitAnimationPlayState="running";
setTimeout(function(){
Shot1.style.webkitAnimationPlayState="paused";
}, 1200);
if(document.elementFromPoint(625.5, 265.5) == Shot1){
Invader2.style.visibility="hidden";
}
};
Jsfiddle:
http://jsfiddle.net/ZJxgT/2/
I did something similar, and i found that it was much easier to achieve using gameQuery.
to test for collisions:
var collided = $("#div1").collision("#div2");
you can see full working example here
EDIT
If you're having trouble check out the API. For example, to find out how to use collisions check this part of the API.
the collision works in the following way:
This method returns the list of elements collisioning with the selected one but only those that match with the filter given as parameter. It takes two optional arguments (their order is not important). The filter is a string filtering element used to detect collision, it should contain all the elements the function should search collision into. For example if you look for collision with element of the class ‘foo’ that may be contained in a group you will use the filter ".group,.foo".
So, write something like this:
$("#ShortShot").collision("#Alien2").hide();
// will return the alien if it collides with ShortShot
or, to hide them both:
if (($("#ShortShot").collision("#Alien2")).length) {
$("#ShortShot").remove();
$("#Alien2").remove();
}
Instead of losing hours reinventing the wheel, I would suggest to switch (if still possible, depending on your time deadline) to a real 2D game engine for Javascript, with easy collision detection.
Check as well: 2D Engines for Javascript

How to make infinite polyline in google directions and fit draggable markers to the line?

I discovered that is possible to add only eight waypoints in google api directions, you know how to bypass this limitation? I've tried to display direction api, but gave up this idea. Now my solution is based on own polyline, each click adds marker that should stick to that line, next together with it should move as you drag and here occurred is that if there are more than 8 points polyline with markers is no longer compatible. Maybe my approach is completly bad? How to fix this?
Current code: jsfiddle
Markers are not on the polyline:
One way to avoid markers being placed in the middle of the block is to place one at the end of the generated polyline, for example, inside one of your loops, instead of where the click was.
for (k = 0; k < next.length; k++) {
polyline.getPath().push(next[k]);
if (z == steps.length-1 && k == next.length-1) {
var roadMarker = new google.maps.Marker( {
map: map,
position: next[k],
icon: "http://labs.google.com/ridefinder/images/mm_20_green.png"
});
}
}
You will have to also change the first marker to be placed at the start of the polyline
This applies the code above http://jsfiddle.net/T79as/3/
So, my solution is to create render DirectionRenderner between each important waypoint (with marker?):
http://jsfiddle.net/9T7Vg/
draggable markers that look exactly like original ones
draggable polyline with immediately calculation
custom markers with letters (A, B, etc.) - this was difficult
route computation in long distance is much faster
route can have more than 8 waypoints (you can improve script to automate split the route when user want to place 9th waypoint between markers)
So this solution is in fact better than original in Google Maps, especially with long routes.

Jquery/Javascript only running a custom function once after CSS changes

I'm using Jquery to draw lines between the cells in a web-based spreadsheet application. I accomplish this with a mixture of background-image, background-position and background-repeat. The entire system is working very nicely, and allows me to map between different cells in the application.
However, I'm having some trouble with my Jquery/Javascript code.
function draw_line(start_row, start_col, finish_row, finish_col){
//Change CSS background properties
}
function loadData(){
for (i = 0; i < values; i++){
//Add element to spreadsheet - change CSS properties.
//Draw line between the two cells
draw_line(start_row, start_column, line, column);
}
}
loadData();
The problem is that although the for loop should run several times for all the elements involved, it will actually only run once. However, if I comment out the draw_line function, the for loop executes the correct number of times, and all of the elements get placed on the spreadsheet.
I've also tried running setTimeout, but that didn't help. Anyone every experienced this sort of behavior before? (Just for reference, I'm running JQuery v1.6.4, on FF)
Hope someone can help. Thanks!
I have no idea if this is actually causing your problem, but it's bad and risky code so you should fix it. This line of your code:
for (i = 0; i < values; i++)
is using an implicitly declared global variable as i. If any other code you are running is also doing that, then the value of i will get trounced and wreck your for loop.
Change that line to this to make i a local variable so nothing else can trounce it:
for (var i = 0; i < values; i++)

Categories