So to those who looked at my previous question, im building a chess board in complete JS and jQuery (or mostly at least).
So for my pieces to effectivly be restricted in the amount of squares they are allowed to move i need to know their position. (starting and ending position)
I wrote the code below to log the starting row (integer) and starting column (integer) and do that on both mousedown() and mouseup()
var piece;
$('div').mousedown(function(e) {
e.preventDefault();
var selectedRow = this.getAttribute("data-row");
var selectedColumn = this.getAttribute("data-column");
console.log(selectedRow, selectedColumn);
piece = $(this).find('.pawn');
})
.mouseup(function() {
var selectedRow = this.getAttribute("data-row");
var selectedColumn = this.getAttribute("data-column");
console.log(selectedRow, selectedColumn);
if (selectedRow === selectedRow++ || selectedColumn === selectedColumn++){
console.log('TRUE :D'); //Wont be true because both selectedRow's will be the same value
}
$(this).append(piece);
});
For as far as i can see i cant compare both values since both logs are in different events. (please keep in mind that im new to both languages and im still learning).
My question would be if its possible to collect both values (starting and ending) and then being able to compare them to each other.
The easiest approach is to make a selectedRow_down and selectedColumn_down
selectedRow_up and selectedColumn_up in global scope.
var selectedRow_down;
var selectedColumn_down;
var selectedRow_up;
var selectedColumn_up;
$('div').mousedown(function(e) {
e.preventDefault();
var selectedRow_down = this.getAttribute("data-row");
var selectedColumn_down = this.getAttribute("data-column");
piece = $(this).find('.pawn');
})
.mouseup(function() {
var selectedRow_up = this.getAttribute("data-row");
var selectedColumn_up = this.getAttribute("data-column");
console.log(selectedRow_up, selectedColumn_up);
$(this).append(piece);
});
then refer to its value as you do your mouse event
also you could make global 2 dimensional array first so could keep track of your chess pieces, see this thread how to create 2d arrays
How can I create a two dimensional array in JavaScript?
Related
I’ve found a great code which is built for finding peaks in arrays, which print the result in the console (Finding peaks and troughs in time series data in a 1D array - Javascript) . I would like to apply it on each pixel of an 8-day NDVI image collection. The result should be an image with the peak number in each pixel.
I tried to apply the .toArray() function to the image collection to obtain an array. Then I created a function “findPeaks” that should add a peak number Band to the image. Then I tried to apply this function to the array image using .map(findPeaks), but I get an error “array.map is not a function”
Here you find the code https://code.earthengine.google.com/32e78cc57f87c05a76665ed0e8b6c720.
var aoi =
ee.Geometry.Polygon(
[[[11.111455811313702, 46.3205838600638],
[11.111455811313702, 46.31527834569152],
[11.11800040131004, 46.31527834569152],
[11.11800040131004, 46.3205838600638]]], null, false);
var ndvi_IC=ee.ImageCollection("LANDSAT/LC08/C01/T1_8DAY_NDVI")
.filterDate('2020-04-01','2020-10-01')
.filter(ee.Filter.bounds(aoi))
var array=ndvi_IC.toArray()
print(array)
//code from https://stackoverflow.com/questions/43567335/finding-peaks-and-troughs-in-time-series-data-in-a-1d-array-javascript
//I would like to obtain a new image presenting the number of peaks found for each pixel.
var findPeaks=function(array) {
var start = 1; // Starting index to search
var end = array.length - 2; // Last index to search
var obj = { peaks: [], troughs: [] };// Object to store the indexs of peaks/thoughs
for(var i = start; i<=end; i++)
{
var current = array[i];
var last = array[i-1];
var next = array[i+1];
if(current > next && current > last)
obj.peaks.push(i);
else if(current < next && current < last)
obj.troughs.push(i);
}
var peaksNum=obj.peaks.size()
return array.addBands(peaksNum);
}
var arraywithpeaksBand=array.map(findPeaks)
print(arraywithpeaksBand)
Thank you for your help, I’m new to GEE and coding.
Davide
You cannot use javascript for loops, conditionals or even math on Earth Engine images. All the Earth Engine stuff happens somewhere else on a server, and all the javascript stuff happens in your browser. You have to essentially vectorize the code to work with earth engine operators.
What you want to know is, for each point in time, if it is higher than its previous or next neighbor. Then you count how many times that's true. You can do this with a technique called forward-differencing. See this article and this presentation.
// Count the number of peaks in a 1D array image.
var countPeaks = function(image) {
// Compute the forward and backwards difference.
// Note: these arrays are 1 smaller than the input
// because the first/last pt doesn't have a prev/next neighbor.
var left = image.arraySlice(0, 0, -1)
var right = image.arraySlice(0, 1)
var fwd = left.subtract(right)
var back = right.subtract(left)
// Test if each position is greater than its next/prev neighbor?
var next = fwd.gt(0)
var prev = back.gt(0)
// Test if the first/last point is itself a peak
var first = image.arrayGet([0]).gt(image.arrayGet([1])).toArray()
var last = image.arrayGet([-1]).gt(image.arrayGet([-2])).toArray()
// Reattach the end points.
next = next.arrayCat(last, 0)
prev = first.arrayCat(prev, 0)
// Count how many times both next and prev are greater than 0 (or an end peak)
// and get the result.
var peaks = next.and(prev).arrayReduce(ee.Reducer.sum(), [0]).arrayGet([0])
return peaks
}
var array = ee.Array([113,112,115,120,119,102,101,100,103,105,110,109,105,107])
var image = ee.Image.constant(array)
Map.addLayer(countPeaks(image))
https://code.earthengine.google.com/e3265400b32b3ade1d4df2a7f920d8a5
I want to be able to zoom upon one or more point and get the associated Y value(s) for that point. So far I have got this, but without any success: http://jsfiddle.net/animeshb/8rdkb7t4/3/
var pointValue = this.series[0].data[index].y
I am not able to find the index of the selected point or selected points. What am I missing here?
Okay, this might not be the best way, but I got it working for a single point by doing the following:
var pt = Math.ceil(event.xAxis[0].min)
pointValue = this.series[0].data[pt].y;
http://jsfiddle.net/animeshb/8rdkb7t4/5/
So, to capture multiple points, I have expanded the above a bit further like this:
var minpt = Math.ceil(event.xAxis[0].min);
var maxpt = Math.ceil(event.xAxis[0].max);
var distance = maxpt - minpt;
if (distance == 1) pointValues.push(this.series[0].data[minpt].y);
else {
for (var i = minpt; i < maxpt; i++) {
pointValues.push(this.series[0].data[i].y);
}
}
pointValues.forEach(function (item) {
console.log(item);
});
return false;
http://jsfiddle.net/animeshb/8rdkb7t4/7/
The problem with this is, I get values even if I drag the selector above or below the points/markers.
I will continue to explore this and will update here if I have a solution.
Okay, I hope you don't all facepalm when you see this - I'm still finding my way around javascript.
I am putting together an RSVP form for a wedding website.
I want the guests to be able to add their names to the RSVP form, but only have as many fields showing as required. To this end, after each name field, there is a link to click, which will, when clicked, show a name field for the next guest.
The code below works... but I am sure it can be tidier.
I have tried to insert a for() loop into the code in several different ways, I can see that the for() loop increments correctly to the last value - but when it does so, it leaves only the last addEventListener in place. I can only assume, that I should be using a different kind of loop - or a different approach entirely.
How should I tidy up the following?
<script>
function showNextGuest(i) {
document.getElementsByTagName(\'fieldset\')[i].style.display = \'block\';
}
function initiateShowNextGuest() {
document.getElementsByTagName('fieldset')[0].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(1);},false);
document.getElementsByTagName('fieldset')[1].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(2);},false);
document.getElementsByTagName('fieldset')[2].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(3);},false);
document.getElementsByTagName('fieldset')[3].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(4);},false);
document.getElementsByTagName('fieldset')[4].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(5);},false);
}
window.onload = initiateShowNextGuest();
</script>
Your intuition is right - a for loop could indeed simplify it and so could a query selector:
var fieldsSet = document.querySelectorAll("fieldset"); // get all the field sets
var fieldss = [].slice.call(asSet); // convert the html selection to a JS array.
fields.map(function(field){
return field.querySelector("a"); // get the first link for the field
}).forEach(function(link, i){
// bind the event with the right index.
link.addEventListener("click", showNextGuest.bind(null, i+1), false);
});
This can be shortened to:
var links = document.querySelectorAll("fieldset a:first-of-type");
[].forEach.call(links, function(link, i){
link.addEventListener("click", showNextGuest.bind(null, i+1), false);
});
function nextGuest () {
for(var i = 0; i < 5; i++){
document.getElementsByTagName('fieldset')[i]
.getElementsByTagName('a')[0]
.addEventListener('click',function(){
showNextGuest(parseInt(i + 1));
}, false);
}
}
Benjamin's answer above is the best given, so I have accepted it.
Nevertheless, for the sake of completeness, I wanted to show the (simpler, if less elegant) solution I used in the end, so that future readers can compare and contrast between the code in the question and the code below:
<script>
var initiateShowNextGuest = [];
function showNextGuest(j) {
document.getElementsByTagName('fieldset')[j].style.display = 'block';
}
function initiateShowNextGuestFunction(i) {
return function() {
var j = i + 1;
document.getElementsByTagName('fieldset')[i].getElementsByTagName('a')[0].addEventListener('click',function(){showNextGuest(j);},false);
};
}
function initiateShowNextGuests() {
for (var i = 0; i < 5; i++) {
initiateShowNextGuest[i] = initiateShowNextGuestFunction(i);
initiateShowNextGuest[i]();
}
}
window.onload = initiateShowNextGuests();
</script>
In summary, the function initiateShowNextGuests() loops through (and then executes) initiateShowNextGuestFunction(i) 5 times, setting up the 5 anonymous functions which are manually written out in the code in the original question, while avoiding the closure-loop problem.
Background
To learn Knockout JS, I'm (slowly) building a gradebook in the browser. My lastest issue involves dropping the lowest scores in an observable array. I have a student model, which has an observable array called scores. This array consists of observable scores, which are plain numbers.
My methodology for removing the lowest grades is as follows. First, I sort each array of scores, high-low, then, for now, splice the end of the array, such that the two lowest numbers are stored into a new array called low. The low variable will be used later when I calculate the mean.
The Problem(s)
First, my current dropLowestGrades method outright removes data from the dom, which I do not desire. Second, myObservableArray.sort() does not appear to do any sorting! I'm not sure where to go here. Relevant script follows.
JSBin: http://jsbin.com/fehoq/141/edit
JS
var StudentsViewModel = (function () {
function StudentsViewModel() {
var _this = this;
...
this.dropLowestScores = function() {
var low = [];
ko.utils.arrayForEach(_this.students(), function(student){
console.log(student.fullName());
student.scores().sort();
/*
student.scores().sort(function(a, b) {
return a() == b() ? 0 : (a() > b() ? 1 : -1);
});
*/
low = student.scores.splice((student.scores().length-2),student.scores().length);
console.log('low: ' + low);
return low;
});
};
HTML
I currently just bind the function to a button. For simplicity's sake, I'm hard-coding the drop to be two scores. I will later allow the user to pass in a value. Note that the button is named "Sort" right now because I was originally going to have a sort feature, then build my dropLowestScores method on top it.
<button data-bind="click: dropLowestScores">Sort</button>
Update
I have significantly updated my method after insights from the answers. The script below still suffers from cutting the values in my scores array, which I do not wish to change.
this.dropLowestScores = function() {
ko.utils.arrayForEach(_this.students(), function(student){
console.log(student.fullName());
var tmp = student.scores().sort();
console.log(tmp);
student.lowest = tmp.splice((tmp.length-2),tmp.length);
console.log('student lowest: ' + student.lowest);
});
};
Update 2
I changed my StudentModel such that it now has property lowest, which keeps track of the lowest scores when user drops grades.
var StudentModel = (function () {
function StudentModel(fullName) {
var _this = this;
this.fullName = ko.observable(fullName);
this.scores = ko.observableArray();
this.lowest = [];
...
You need to remember that functions like sort() return a sorted list of the array, they don't actually transform the array itself.
var studentScores = student.scores().sort();
or something like -
var sortedStudentScores(function () {
return student.scores().sort();
});
And if you are sorting on a property of the score you need to use something like -
var sortFunction = // Google a JavaScript sort function
var studentScores = student.scores().sort(sortFunction);
and if you are trying to remove items splicing is correct (it transforms the array itself) otherwise you need to use something like a computed to just not add the lowest in.
Updated
var sortedStudentScores(function () {
// Set a local var equal to the sorted scores
var theseScores = student.scores().sort().splice(0);
theseScores.splice(student.scores().length-2),student.scores().length);
});
I am learning jQuery and am having issues trying to figure out how to select elements in a multidimensional array. I have a select list with database IDs and I want to set a var with the cost field in the database according to the id that selected. I have all the pieces except for translating the selected ID to a cost. Can someone please help me with getting this right please?
var rangeListData = [{"idrange_list":"1","range_cost":"0","target_range_name":"Self Only"},{"idrange_list":"2","range_cost":"1","target_range_name":"1 Space"},{"idrange_list":"3","range_cost":"2","target_range_name":"2 Spaces"},{"idrange_list":"4","range_cost":"3","target_range_name":"3 Spaces"},{"idrange_list":"5","range_cost":"4","target_range_name":"4 Spaces"},{"idrange_list":"6","range_cost":"5","target_range_name":"5 Spaces"}];
$('#slctPowerTarget').change(function () {
var targetID = $('#slctPowerTarget').val();
var cost $.grep(rangeListData, function(e) { return e.idrange_list == targetID }); // this is the line that is wrong
$('#spanTotalEffectsCost').text(cost);
});
If I put targetID in where cost is it lists fine. But when I try to look this up nothing happens. It is not right somehow and I am not sure what else to try. I think I get how idrange_list == targetID is supposed to match them but not sure how to call the related range_cost.
Thanks for any help you can offer! I read through the docs at jquery.com but can't seem to wrap my head around them.
You can do this :-
// Get the Multidimensional Array first
var data = $.grep(rangeListData, function (e) {
return e.idrange_list === targetID
});
// Get the range cost from the array
var cost = data[0].range_cost;
// Check the value in console for debugging purpose
console.log(cost);
Here is the final code. I also added an IF clause in there in case they select the default setting. This way it will reset instead of tossing an error and keeping page calculations working no matter if they change the drop downs or go back to "Select..."
$('#slctPowerRange').change(function () {
var rangeID = $('#slctPowerRange').val();
if (rangeID > 0) {
var rdata = $.grep(rangeListData, function (e) {
return e.idrange_list === rangeID
});
var rcost = rdata[0].range_cost;
}
else {
var rcost = 0 ;
}
$('#hdnRangeCost').val(rcost);
});