Compare data collected with jquery each function - javascript

What I want to do is compare each element offset to each other and get the one that is closer to the top of the window, then do something with that specific element
$(".slide").each(function(index, el) {
var $this = $(this);
var offset = $this.offset().top - $(window).scrollTop();
});
so basically, if I print the offset via console.log and I have for each element having the slide class,
I currently get these values :
slide1 = -875
slide2 = 250
slide2 = 850
slide4 = 1375
Slide 2 is the one currently closest to 0 so slide 2 would be the div I would want to do something with...
Hope i am clear enough!

You were already quite close from your goal
var found=null;
var found_top=0;
$(".slide").each(function(index, el) {
var $this = $(this);
var offset = $this.offset().top - $(window).scrollTop();
if( ( found == null ) || ( ( offset >= 0 ) && ( offset < found_top ) ) ){
found=this;
found_top=offset:
}
});
/** do something with found here **/

Related

Finding structure with highest energy screeps

So I have this creep role called storer that is supposed to go fetch energy from containers and bring it to the storage. However, currently, it finds the container closest by Path and with an energy level greater to a certain threshold so that it doesn't wait there for hours every time a miner refills the container.
The problem I have is if I lower the threshold, the storer will run back and forth to the same containers, ignoring any containers further in the room and letting them fill up.
And raising the threshold will make him sit out and wait for too long, not giving him enough time to empty containers and thus the storage will be empty almost all the time.
I need a way for the creep to determine the container with the highest energy and fill up from there.
Here's the code its running:
if ((source = creep.pos.findClosestByPath(FIND_STRUCTURES, {filter: (s) => {return (s.structureType == STRUCTURE_CONTAINER && s.store[RESOURCE_ENERGY] >= 150)}})) != undefined) {
if (creep.withdraw(source, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
creep.moveTo(source);
}
}
EDIT: here's the code I tried, but I feel like it is using too much CPU power and can be done in a better way:
for (let i = 2000; i>=0; i=i-100) {
source = creep.pos.findClosestByPath(FIND_STRUCTURES, {filter: (s) => {return s.structureType == STRUCTURE_CONTAINER && s.store[RESOURCE_ENERGY] >= i}});
if (source != undefined) {
break;
}
}
if (creep.withdraw(source, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
creep.moveTo(source);
}
}
What you can do is loop trough all the containers once, get their energy level and pick the highest one. Set a value when the creep is working so the creep dosen't move to another container if he get higher.
This is the code i made for the storer role:
module.exports = {
run: function( creep ) {
// Setting the working variable so the creep focus
// on getting the ressource or returning it.
if ( creep.memory.working && creep.carry.energy == 0 ) {
creep.memory.working = false;
}
if ( ! creep.memory.working && creep.carry.energy == creep.carryCapacity ) {
creep.memory.working = true;
creep.memory.targetContainer = false;
}
if ( creep.memory.working ) {
// Bring the ressources to the storage.
var theStorage = creep.pos.findClosestByRange(FIND_MY_STRUCTURES, {
filter: (structure) => {
return (structure.structureType == STRUCTURE_STORAGE );
}
});
if ( creep.transfer( theStorage, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
creep.moveTo( theStorage );
}
} else {
// If the creep have a target.
if ( creep.memory.targetContainer ) {
// Go to the container.
var theContainer = Game.getObjectById( creep.memory.targetContainer );
if ( creep.withdraw( theContainer, RESOURCE_ENERGY ) == ERR_NOT_IN_RANGE ) {
creep.moveTo( theContainer );
}
} else {
// Find the container with the most energy.
var target = creep.room.find( FIND_STRUCTURES, {
filter: (structure) => {
return (structure.structureType == STRUCTURE_CONTAINER );
}
});
if ( target.length ) {
var allContainer = [];
// Calculate the percentage of energy in each container.
for ( var i = 0; i < target.length; i++ ) {
allContainer.push( { energyPercent: ( ( target[i].store.energy / target[i].storeCapacity ) * 100 ), id: target[i].id } );
}
// Get the container containing the most energy.
var highestContainer = _.max( allContainer, function( container ){ return container.energyPercent; });
console.log( 'Going for the container id "' + highestContainer.id + '" at ' + highestContainer.energyPercent + '% full.' );
// set the target in memory so the creep dosen't
// change target in the middle of the room.
creep.memory.targetContainer = highestContainer.id;
}
}
}
}
};
I do not know if this method uses more CPU, but it is much simpler to use JavaScript's built in sort method. It allows for the objects in an array to be sorted based on any property or calculation involving it. If you'd like to see the full syntax and some examples: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
This code should work for your purposes. A and B are the two pieces of the array it compares. The return portion tells it the comparison to do on the array elements.
var sources = creep.pos.findClosestByPath(FIND_STRUCTURES,
{filter: (s) => {return (s.structureType == STRUCTURE_CONTAINER &&
s.store[RESOURCE_ENERGY] >= 150)
}});
sources.sort(function(a, b) {return b.store[RESOURCE_ENERGY] - a.store[RESOURCE_ENERGY]});
Then just run your normal code to take energy from the sources. If it starts taking energy from the one with the least amount of energy, I probably got the order of a and b wrong in the return portion so just flip them.
Instead of having the filter do everything for you, why not return a list of structures that match your criteria and then figure out which structure in the list has the most energy? Something like this will find all containers, figure out which has the most energy, and if you have a tie for energy pick the closest one (direct line, doesn't account for obstacles).
var sources = creep.room.find(FIND_STRUCTURES, {
filter: (structure) => {
return (structure.structureType == STRUCTURE_CONTAINER);
}
});
var maxAmount = -1;
var maxSource = null;
var maxRange = 100;
for (var i = 0; i < sources.length; i++) {
if (sources[i].store[RESOURCE_ENERGY] >= maxAmount) {
var range = creep.pos.getRangeTo(sources[i]);
if (sources[i].store[RESOURCE_ENERGY] > maxAmount || range < maxRange) {
maxAmount = sources[i].store[RESOURCE_ENERGY];
maxSource = sources[i];
maxRange = range;
}
}
}
console.log(maxAmount);
console.log(maxSource);
console.log(maxRange);

return a value via function math result that is stored in a variable

i was trying to get a result of the browsers window width and trying to put the result of math and condition in a variable , this is the code
var MyWidth = 1900;
var MyHeight = 900;
var height = $(window).height();
var width = $(window).width();
var AutoW = function () {
if ( (MyWidth / width).toFixed(2) > 0.95 )
return 1;
if ( (MyWidth / width).toFixed(2) < 1.05 )
return 1;
else return (MyWidth / width).toFixed(2);
};
alert(AutoW);
the problem is i don't know the right syntax or structure of the function assigned to the variable
what is the right way to code this ?
alert(AutoW());
AutoW() returns the value of function assigned to the variable.
fiddle : http://jsfiddle.net/V2esf/
var AutoW = function () {
// don't calculate ratio 3 times! Calculate it once
var ratio = (MyWidth / width).toFixed(2);
if (ratio > 0.95)
return 1;
if (ratio < 1.05)
return 1;
else return ratio;
};
// alert(AutoW); - this was a problem, AutoW is a function, not a variable
// so, you should call it
alert(AutoW());
<script>
var MyWidth = 1900;
var MyHeight = 900;
var height = $(window).height();
var width = $(window).width();
var AutoW = function () {
if ((MyWidth / width).toFixed(2) > 0.95)
return 1;
if ((MyWidth / width).toFixed(2) < 1.05)
return 1;
else return (MyWidth / width).toFixed(2);
};
var val = AutoW();
alert(val)
</script>
You should try this way:
(function(){
var MyWidth = 1900,
MyHeight = 900,
height = $(window).height(),
width = $(window).width(),
result;
var AutoW = function () {
var rel = (MyWidth / width).toFixed(2);
return ( ( rel > 0.95 ) && ( rel < 1.05 )) ? 1 : rel;
};
result = AutoW();
alert(result);
})();
But remember the function you wrote always returns 1, that is why I changed it for (&&) condition to make it a filter.
if you make alert of function, you will return the entire function. you have to asign the cast of a function "()" to a variable so the return will be asigned to it.
var result = f_name();
And remember, try not to use global variables, wrap everything in a function.
You should put {} after if, and cache values that you are using many times like when I cached "(MyWidth / width).toFixed(2)" into rel.
The sintax I used instead of if >> (condition) ? (return if match) : (return else);

Parsing a number of pixels to an integer

In my code i'm trying to compare the height with the position of an element, to ensure that the element doesn't leave the game's div.
First I get the position of my element, snake. and if the cursor is too close then i move it. Then at the end I do a check that it is at least 20 pixels away from the top and bottom. For some reason everything is working except the when it reaches the bottom of the screen (which is the else if statement in the end block of code)
var posL = $("#snake").position().left;
var posT = $("#snake").position().top;
if((e.pageX-200 < posL) && (posL < e.pageX-50)){
if(posL > 20){
posL = posL - 5;
}else{
posT = posT + 5;
}
...
if(posT < 20){
posT = 20;
}else if(posT > parseInt($("#game").height)){
posT = parseInt($("#game").height) - 20;
}
You forgot the () after .height ...twice! ;-)
if(posT < 20) {
posT = 20; // ------------------------v
} else if(posT > parseInt($("#game").height)){
posT = parseInt($("#game").height) - 20;
} // -----------------^

javascript / jquery - finding the closest value in an array

I'm modifying the jquery ui slider. I have certain "stops" I want the user to be able to slide to, expressed as a percentage of the slider's overall width. So, for example, if I have 3 stops, they will be distributed evenly at 0, 50, and 100 (%). I store these in an array [0,50,100].
When the user drags the slider and releases, I capture the slider's current value. So if he scrolled 56% of the way across the bar, his stopVal is 56.
How do I write a function that will then determine which number in the array this stopVal is closest to? Here's my code:
var optValArr = [0,50,100];
function slideStop( event, ui ) {
var stopVal = ui.value;
//NOW NEED TO FIND CLOSEST ARRAY VALUE TO stopVal
}
This function will let you do that:
Array.prototype.closest = function(value) {
var i;
function diff(n) {
var diff = n - value;
return diff < 0 ? -diff : diff;
}
var found = this[0],
mindiff = diff(found);
for (i = 1 ; i < this.length ; i++) {
var currentdiff = diff(this[i]);
if (currentdiff < mindiff) {
found = this[i];
mindiff = diff(found);
}
}
return found;
}
Now you can do this:
var optValArr = [0,50,100];
function slideStop( event, ui ) {
var stopVal = ui.value;
//NOW NEED TO FIND CLOSEST ARRAY VALUE TO stopVal
stopVal = optValArr.closest(stopVal);
}
NOTE: Some people consider defining prototypes for native types as dangerous as it can cause conflicts if two libraries do the same (just like global variable). If you are writing a public library you should therefore avoid adding to the prototypes of native types.
Try This:
var optValArr = [0,50,100];
function slideStop( event, ui ) {
var stopVal = ui.value;
var diff=101;
var val =0;
for(var i =0; i < optValArr.length; i++){
var tmpDiff = Math.abs(stopVal - optValArr[i]);
if(tmpDiff < diff){
diff=tmpDiff;
val = optValArr[i]
}
}
}
slideStop("something", {"value":20});
Demo: http://jsfiddle.net/ggzZj/
var optValArr = [0,50,100];
function slideStop( event, ui ) {
var stopVal = ui.value;
var closestVal = optValArr.reduce(function (memo, curr) {
var currDiff = Math.abs(curr - stopVal),
memoDiff = Math.abs(memo - stopVal)
return memoDiff < currDiff ? memoDiff : currDif
})
}
Another common definition of "closer" is based on the square of the difference. But, you could do that by simply adding the number that you want in your original array like this:
[10,40,50, my_number]
Then, sort your array and then you choice if you want the closest position from the right or the left.
What do you think?

Having trouble using jQuery to change a class dependent on scroll position

Some very helpful folks wrote and then modified a script to change the class on a nav item when scrolling the page to a related section. Here's the original post: Use jQuery to change a class dependent on scroll position.
My first issue is that the last section of the array is being ignored. Someone else had this question and a solution was offered, which worked for them, but not for me: jQuery class change based on scroll ignoring last section.
The second issue is that even setting aside that the last section in my array is not ever getting selected, the new class name is only getting added to my nav items, but never removed, so that by the time I scroll to the bottom of the page, every item except the last in my nav has "selected" as a class. I'd really appreciate any insight. Here's my code, which is virtually identical to the modified version, except I'm using headings rather than sections (which is maybe significant?):
var $anchs = $('.content h1');
var $navs = $('#zone-submenu div .content > .item-list > ul > li');
topsArray = $anchs.map(function(){
return $(this).position().top - 100;
}).get(),
topsArray.push(window.height);
var len = topsArray.length;
var currentIndex = 0;
var getCurrent = function( top ) { // take the current top position, and see which
for( var i = 0; i < len; i++ ) { // index should be displayed
if( top > topsArray[i] && topsArray[i+1] && top < topsArray[i+1] ) {
return i;
}
}
};
$(document).scroll(function(e) {
var scrollTop = $(this).scrollTop();
var checkIndex = getCurrent( scrollTop );
if( checkIndex !== currentIndex ) {
currentIndex = checkIndex;
$navs.eq( currentIndex ).addClass("selected").siblings(".selected").removeClass(".selected");
}
});
I'm afraid I can't post the site itself - it's in development and I can't reveal it before it goes live. Thanks for any help, though!
This looks a bit odd:
currentIndex = checkIndex;
$navs.eq( currentIndex ).addClass("selected").siblings(".selected").removeClass(".selected");
From what I can tell in your code, it should be:
$navs.eq( currentIndex ).removeClass('selected'); // no dot
currentIndex = checkIndex;
$navs.eq( currentIndex ).addClass("selected");
UPDATED
Fixing the "not displaying the last index item" ...
You are referencing an invalid array element in your getCurrent function - [i+1] is invalid when i == len-1. You need to just return the last element if that happens.
var getCurrent = function( top ) { // take the current top position, and see which
for( var i = 0; i < len-1; i++ ) { // index should be displayed
if( top > topsArray[i] && topsArray[i+1] && top < topsArray[i+1] ) {
return i;
}
}
return len-1;
};

Categories