I have the bellow code checking if a map marker is inside or outside of a geofence.
i am going to make it alert detected out of the bounds.
My problem is the map markers a refreshing constantly and i do not want the alert to be repeated over an over.
I need to set something when the alarm is played. Then only do the alert if that thing is unset.
When the user is detected back inside the bounds it will unset it also.
if (name === f.contact) {
var fence = new google.maps.LatLng(f.lat, f.lng);
var dist = google.maps.geometry.spherical.computeDistanceBetween(posi, fence);
// check if in/out of fence
if (dist > f.radius) {
console.log(f.contact+" : "+dist+" meters - outside the fence");
// OMG outside the fence play an alarm
} else {
console.log(f.contact+" : "+dist+" meters - inside the fence");
// Back inside the fence, reset the alarm
}
}
i was thinking possibly making an array like this
var alertSent = [];
and then if outside the geofence adding the users name to it
alertSent.push(name);
how would i check if the name exists in the array?
and how would i delete the name from the array when back inside the fence?
You could use an Object as an asociative array and use the names as keys and a boolean value for sent / not sent. alertSent[name] also evaluates to a falsy value if it doesn't contain name at all.
var alertSent = {};
// if user outside: check
if (!alertSent[name]) {
// show alert
// remember that alert was shown
alertSent[name] = true;
}
// remove name from alertSent:
alertSent[name] = false;
If you end up using array, then you have search it for every index till you find the string like
How do I check if an array includes an object in JavaScript?
or
Best way to find if an item is in a JavaScript array?
You can also think about, registering events and eventlisteners for handling this problem, it would be a better design.
Or you can also use hashmap kind of javascript implementation like using
alertSent["driver1"]=true;,
Lookup will be simple in this case just use ,
alertSent["driver1"]
to get the boolean value. But take care of array space in this case.
Related
I have an array of 100 “XYCoordinate” objects, and I want to randomly select 25 of them and assign them to 25 "Cube" objects so I can present those cubes on the screen in different locations.
Obviously I need to make sure that I don’t accidentally randomly select the same XYCoordinate twice and assign it to two different Cube objects - cause then they’ll sit right on top of each other.
I thought the following code would work, but I’m still getting duplicates:
// I first declare an array to store the randomly selected XYCoordinate objects:
var selectedCoordObjectsArray = [];
// I then declare a second array to store just the INDEXES of the Coords that
// were already randomly selected:
var selectedCoordIDNumbersArray = [];
// Next I make a function to randomly select one XYCoordinate object:
function selectRandomXYCoordinateObject() {
let randomCoordNumber = Math.floor(Math.random() * 100);
// Check if this Coord-number was already selected:
if(selectedCoordIDNumbersArray.includes(randomCoordNumber)) {
// A Coord of this ID was already selected!
console.log(“Duplicate!”);
// Immediately call this function again:
selectRandomXYCoordinateObject();
}
else {
// Grab this Coord from my previously declared “coordsArray”:
let chosenCoord = coordsArray[randomCoordNumber];
// Add the INDEX of this Coord to the “selectedCoordIDNumbersArray”:
selectedCoordIDNumbersArray.push(randomCoordNumber);
// Finally, return the actual “chosenCoord” object:
return chosenCoord;
}
}
Here’s where I call this function:
function makeCubes() {
for(var cubeCounter = 0; cubeCounter < 25; cubeCounter++) {
let tempCube = cubesArray[cubeCounter];
// prep the Cube, give it different Width & Height, Color, etc.
// Then, assign to it a random coordinate:
tempCube.coords = selectRandomXYCoordinateObject();
// an then display the “tempCube” at those coords:
. . .
}
}
So what’s happening is that every time the selectRandomXYCoordinateObject function comes upon a duplicate - the App crashes!
The function does recognize when it’s got a duplicate on it's hands - and it does call itself again - but the makeCubes function seems to not be able to wait for that second execution. It seems as though it’s already moved along, and it's trying to display the tempCube at it's would-be coords.
I tried solving this using async and await but that didn't work - and I really don't wanna go barking up the Promises tree - just feels like I'm missing something here and that there should be a straight-forward solution...?
This is partly a guess, but you don't return the value that the recursive call to selectRandomXYCoordinateObject() returned:
// Check if this Coord-number was already selected:
if(selectedCoordIDNumbersArray.includes(randomCoordNumber)) {
// A Coord of this ID was already selected!
console.log(“Duplicate!”);
// Immediately call this function again:
selectRandomXYCoordinateObject();
}
Instead of:
// Check if this Coord-number was already selected:
if(selectedCoordIDNumbersArray.includes(randomCoordNumber)) {
// A Coord of this ID was already selected!
console.log(“Duplicate!”);
// Immediately call this function again:
return selectRandomXYCoordinateObject();
}
So the first call to selectRandomXYCoordinateObject() returns undefined, and assuming you're trying to access properties of the returned object in the callee, you'll get a TypeError and crash.
Edit: By the way, this is not the best method to sample an array uniquely - see Unique (non-repeating) random numbers in O(1)?.
I'm trying to clear all local storage when the user either completes the game loop or starts a new game, but also keep some values.
I can do this already with my sound values for volume:
// inside a conditional statement that fires when the user chooses to start a new game.
if (newGameBool === '1') {
var tst = myAu;
//myAu is the stored value that the user sets as sound using a range type input
localStorage.clear();
localStorage.setItem("Au", tst);//A newly cleared localStorage just got a new value, and it's the same as it was before.
UI.myLoad();//reload the function that uses LS to do things.
}
How do I do this for key's that have an iterating number attached to them?
Here is how I save them:
var i = +v + +1;
localStorage.setItem("v", i);
var vv = localStorage.getItem("v");
localStorage.setItem("LdrBrd_" + vv, JSON.stringify(LdrBrd));//saves all data with the iterating key name.
Calling them the way i did the sound function:
var gv = v + 1;//v calls the value from LS and adjusted for off-by-one error. gv is a local variable.
if (newGameBool === '1') {
var ldd, vg;
for (var ii = 0; ii < gv; ii++) {
var ld = localStorage.getItem("LdrBrd_" + ii);
if (ld != null) {
//these are the values that i want to pass beyond the clear point
ldd = JSON.parse(ld);//JSON string of data saved
vg = ii;//how many of them.
}
}
localStorage.clear();
for (var xx = 0; xx < vg; xx++) {
var nld = localStorage.getItem("LdrBrd_" + xx);
if (nld != null) {
localStorage.setItem("LdrBrd_" + ii, JSON.stringify(ldd));
}
}
localStorage.setItem("v", vg);
UI.myLoad();
}
I have been using console.log() in various spots to see what is going on. I comment-out the clear function just to see if the values were wrong and they don't save all all. I tried to make a fiddle, but the local storage wasn't working at all there. In visual studio, it works fine but the script to this file is almost 2000 lines long, so i tried to dress it up the best i knew how.
Thanks in advance for any help or guidance.
I was stuck on this for a few days, but i think i found something that will work, so i'll answer my own question in case there is value in posterity.
locatStorage.clear();
/* ^LS clear() function is above all new setItem codes, some variables are declared globally and some are declared at the top of the functional scope or as param^ */
var itemClass = document.querySelectorAll(".itemClass");//the strings are here
if (itemClass) {//make sure some exist
for (var p = 0; p < itemClass.length; p++) {//count them
mdd = JSON.parse(itemClass[p].innerText);//parse the data for saving
localStorage.setItem("v", v);//this is the LS item that saves the amount of items i have, it's declared at the top of the functions timeline.
localStorage.setItem("LdrBrd_" + p, JSON.stringify(mdd));//this setItem function will repeat and increment with 'p' and assign the right string back to the key name it had before.
}
}
The key is to keep the strings physically attached to an element, then call the class name. The i ran a loop counting them. 'mdd' will spit back each item i want. So then all that is left to do is re-set the item back to it's original status.
This has allowed me to create a way for my users to collect trophies and keep them even after clearing the localStorage when the he/she decides to start a new game.
I use CSS to hide the text from the string.
color:transparent;
In my gameLoop, i have a function that will read the saved strings and show them as cards just below the hidden strings.
Since you want to keep some values I recommend one of two things:
Don't call localStorage.clear() and instead only wipe out the values that you want using localStorage.removeItem('itemName'). Since you said the item names have a numeric component, maybe you can do this in a loop to reduce code.
Pull item(s) that you want saved first and restore them after calling clear(). This option is best if there are way more items that you want removed rather than saved (see below)
function mostlyClear() {
var saveMe = {};
saveMe['value1'] = localStorage.getItem('value1');
saveMe['anotherValue'] = localStorage.getItem('anotherValue');
localStorage.clear();
for(var prop in saveMe) {
if(!saveMe.hasOwnProperty(prop)) continue;
localStorage.setItem(prop, saveMe[prop]);
}
}
I am using a JS library for facetracking/emotion detection called CLMtracker.
http://auduno.github.io/clmtrackr/examples/clm_emotiondetection.html
Note: Seems to work best in chrome for those trying to use it.
Is the example I am using, I am wondering how I can access the values for each emotion. For instance, I want check every 10 seconds what the values are and print to console. From this I would also like to compare the values to find the highest and find the emotion that is attached to that. I think I am right in saying that the max() function will give me the highest out of an array?
What I have tried:
I have tried to get emotionData[0].emotion and emotionData[0].value which should print Angry and the value, but it only prints 0. I have also tried the same method with data which does not seem to return anything.
EDIT
emotionData gets me:
however it does not seem to show any update/change as I make my expression change
ec.meanPredict(ctrack.getCurrentParameters()) returns an object containing all the current scores for all emotions.
To get the current score of "Angry", for example, you would do :
ec.meanPredict(ctrack.getCurrentParameters())[0].value
So, in order to get the current most probable emotion, you could do this :
function getCurrentEmotion()
{
if(!ec.meanPredict(ctrack.getCurrentParameters())){setTimeout(getCurrentEmotion,1000);return;}
var currentData = ec.meanPredict(ctrack.getCurrentParameters());
var currentScores = [];
//Gather all scores in an array
for(var i=0;i<currentData.length;i++)
{
currentScores.push(currentData[i].value);
}
//Get the biggest score
var max = Math.max.apply(null,currentScores);
//Calculate its index
var indexOfScore = currentScores.indexOf(max);
//Get the associated emotion
var emotion = currentData[indexOfScore].emotion;
console.log(emotion);
//Set up a loop (did not add 'var', to allow stopping it from outside)
currentEmotionLoop = setTimeout(getCurrentEmotion,3000);
}
To stop the loop at any time, do this :
clearTimeout(currentEmotionLoop);
By the way, the ec variable is declared privately, so in order for this to work, either remove var where it is declared :
var ec = new emotionClassifier();
or write this code in the same file, under the same scope.
example can be found at:
http://projects.snowshtechnologies.com/findhrr/_admin/_geolocate/content.php
view the source for the full idea.
I am trying to get the JS to populate the long/lat fields as soon as a text search result has re-positioned the map.
The linked Map script has a submit feature which returns the long lat back to a parent form (not included in this link - so don't worry about that!)
There are two main methods here:
First is the text search - which is used to determine the map location buy entering an address. The required fix lies here, after the user clicks search, the map returns the position - all good. But I also now need the long/lat to appear in the text areas and enable the submit button.. you can see that functionality in the next method:
The second method simply allows the user to drag the map, the last clicked position will populate the lon/lat fields.
The txt search function:
function FindLoc(numResults)
{
try
{
results = map.Find(document.getElementById('txtWhat').value,
document.getElementById('txtWhere').value,
null,
null,
index,
numResults,
true,
true,
true,
true,
MoreResults);
index = parseInt(index)+9;
}
catch(e)
{
alert(e.message);
}
map.AttachEvent("onchange", DisplayCoords);
}
I have a function displayCoords that will output the clicked long/lat position to the page, I have included it in the text search function but no joy.
map.AttachEvent("onchange", DisplayCoords);
Any ideas?
I can't change your sources so I can't test this to be sure, however, I believe you want to do the following:
1) Get rid of the "map.AttachEvent" in FindLoc, because this will attach a new event each time the user performs a find, and anyway it's not a correct event name for the map type so it won't be triggered. The list of valid events is here.
2) Change your MoreResults callback so that it reads the resultsArray parameter, which is an array of find results, and reads the LatLong property from an array element. This class is documented here. For example, something like:
var pos;
if (resultsArray && resultsArray.length > 0) {
pos = resultsArray[0].LatLong;
if (pos) {
document.getElementById("mapLatitude").value = pos.Latitude;
document.getElementById("mapLongitude").value = pos.Longitude;
document.getElementById('getLongLat').style.display='block';
}
}
Edit: The resultsArray always seems to be null, so you need to use the places array instead. Add this to the beginning of MoreResults:
if (places && places.length > 0) {
document.getElementById("mapLatitude").value = places[0].LatLong.Latitude;
document.getElementById("mapLongitude").value = places[0].LatLong.Longitude;
document.getElementById('getLongLat').style.display='block';
}
I tested this alternative, and it does work for me.
I'm building a simple puzzle app for and iPad using a JavaScript library for dragging and dropping the pieces. I can't figure out how to check if all the pieces are in the right place however.
What I've got so far is
// create the draggable puzzle piece
var p1=document.getElementById('piece1');
new webkit_draggable(p1);
p1.className = 'ps1';
// create an array to count the pieces placed correctly
var countArray = new Array();
// create the dropspot, link it to the puzzle piece and add an element to the array to count. Finally kill the dropspot
var p1p1 = webkit_drop.add('droppiece1',{accept : ['ps1'], onDrop : function(){countArray.push("a");webkit_drop.remove('droppiece1')}});
// piece has been placed correctly.
if(countArray.length = 1){
alert('Piece placed correctly');
};
The problem I'm having is that the alert from the counting function fires immediately.
How can I fix this?
Change your last three lines to:
// piece has been placed correctly.
if(countArray.length == 1){
alert('Piece placed correctly');
};
You were trying to assign, instead of checking for equality.
Edit: So, it's still not working for you? It seems to me you are setting up a listener on onDrop but then directly after you have done that (presumably before the onDrop event ever gets triggered) you are checking if anything has been "dropped". See how that won't work?
If you just want to see that the event is actually getting triggered, and that the "a" is in fact pushed onto your array you could move the last three lines inside your callback. Like so:
// create the draggable puzzle piece
var p1 = document.getElementById('piece1');
new webkit_draggable(p1);
p1.className = 'ps1';
// create an array to count the pieces placed correctly
var countArray = new Array();
// create the dropspot, link it to the puzzle piece and add an element to the array to count. Finally kill the dropspot
var p1p1 = webkit_drop.add('droppiece1', {accept: ['ps1'], onDrop: function() {
countArray.push("a");
webkit_drop.remove('droppiece1');
// piece has been placed correctly.
if (countArray.length == 1) {
alert('Piece placed correctly');
}
}});
I haven't really tested that, but here is a version with all the webkit stuff taken out and the drop replaced with a simple click: http://jsfiddle.net/kajic/snJMr/1/
If you click the red box, is that what you expected to happen on your ipad app when you drop the piece?
You should change this
if(countArray.length = 1){
to
if(countArray.length == 1){
// ^^ use comparison, not assignment
The first line assigns 1 to countArray.length, which resolves to 1, which is truthy.