JavaScript: cycle through an array (rather than pop)? - javascript

I'm creating map markers, and I want to assign a different colour to each county on the map.
I don't know in advance how many counties there will be showing on the map, so I need to figure out a way to assign an unlimited number of colours.
At the moment, I'm assigning a colour to each county using the following code, but I run into a problem when I pop() the list too many times:
var colours = ['6183A6', '3A66A7', '3B4990', '5B59BA'];
var h_colours = []; // associative array
function addMarker(county, colour) {
if (colour==undefined) {
if (h_colours[hundred]==undefined) {
h_colours[hundred] = colours.pop();
} } }
Is there a way I could cycle through the list without actually deleting items, and continuing from the start of the list when I reach the end?
thanks!

Yes.
var getNextColour = (function() {
var colours = ['6183A6', '3A66A7', '3B4990', '5B59BA'];
var cc = 0;
return function() {
var rv = colours[cc];
cc = (cc + 1) % colours.length;
return rv;
};
})();
Now you can just say:
if (colour == undefined) colour = getNextColour();
or simply
colour = colour || getNextColour();
Of course, applying the colors to the elements of the map such that you don't color adjacent areas with the same color is a considerably more interesting problem.

You can use a counter for the index in the array.
Increment whenever you fetch a color, reset it to 0 when it is the size of the array -1.

Related

Problems with immutable array

Recently i started working with D3.js to plot a sunburn graph. The data is provided in JSON. For some design stuff i wanted to swap some items (called childrens in D3 doc).
I know in JS arrays are objects...so something like this:
var buffer = myarray[2];
is just a reference. Therefore a buffer for swapping has no effect (?).
Thus i invented a second array (childrens_final) in my code which adopt the items while the swapping process. Its just iterating through every item, a second iteration is looking for an item with the same name to set items with same name in a row. Therefore the swap.
var childrens = response_data.data.data['children'];
var childrens_final = []
for (var child = 0; child < childrens.length; child++) {
var category = childrens[child];
var found = false;
var i = child+1
while (!(found) && (i < childrens.length)) {
if (childrens[i]['name'] == category['name']) {
var childrens = swapArrayElements(childrens, child+1, i);
var one = childrens[child];
var two = childrens[child+1]
found = true;
}
i++;
}
if (found) {
childrens_final.push(one);
childrens_final.push(two);
child++;
}
else {
childrens_final.push(childrens[child])
}
}
response.data.data['children'] = childrens_final;
return response.data.data;
The function swapArrayElements() is just using splice:
function swapArrayElements(list, x, y) {
if (list.length ==1) return list;
list.splice(x, 1, list.splice(y,1, list[x])[0]);
return list;
}
The problem is that there is still no effect from the swap in the graph. But when logging the childrens_final. There is something like that in the console:
Array [ Object, Object, Object, Object, Object, Object, Object, Object, Object ]
The objects are in the right order! But in the array there is still the old order.
Thats actually so basic, but i dont see a solution.
Btw...the code is working under AngularJS.
Found the problem. It's a D3.js problem. D3 is sorting the data itself. You have to set explicitly:
d3.layout.partition.sort(null)
Otherwise every pre sorting process has no effect.

Get selected point(s) indices on zoom in Highcharts

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.

Switching id names in javascript

Working on chess board using html and javascript. I am trying to add a function so that the user can flip the perspective of the board and running into a glitch that I understand, but can't figure out how to solve. Code as below....
function flipBoard(){
document.getElementById("a8").id = "h1";
document.getElementById("a7").id = "h2";
document.getElementById("a6").id = "h3";
document.getElementById("a5").id = "h4";
document.getElementById("a4").id = "h5";
document.getElementById("a3").id = "h6";
document.getElementById("a2").id = "h7";
document.getElementById("a1").id = "h8";
document.getElementById("h8").id = "a1";
document.getElementById("h7").id = "a2";
document.getElementById("h6").id = "a3";
document.getElementById("h5").id = "a4";
document.getElementById("h4").id = "a5";
document.getElementById("h3").id = "a6";
document.getElementById("h2").id = "a7";
document.getElementById("h1").id = "a8";
}
So.... I thought this would work just fine, but discovered that this wreaks havoc on my board by position half white, half black pieces on both sides of the board. The problem of course is that after the original "a1" square is renamed to "h8", there are now TWO "h8" squares, and at the end of the code it switches both back to "a1".
I have no idea how to get the id names to switch at the same time, otherwise I'd have to add a whole lot of code switching the id names to some third name as a place holder before switching them over to the desired name. Possible, but tedious and I feel there has to be a simpler way to do this.
Any ideas?
You can reduce the repetition of your current code by generating the id values programmatically in a loop:
function flipBoard(){
var a, h, aVal, hVal, aEl, hEl;
for(a = 8, h = 1; a > 0; --a, ++h) {
aVal = 'a' + a;
hVal = 'h' + h;
// Store off the current values
aEl = document.getElementById(aVal);
hEl = document.getElementById(hVal);
// swap them
aEl.id = hVal;
hEl.id = aVal;
}
}
demo fiddle
Save the reference to the element in variable. For example:
function flip(){
var aEight = document.getElementById("a8"),
hOne = document.getElementById("h1");
aEight.id = "h1";
hOne.id = "a8";
}
By separating out the steps of finding your elements and changing their ids, you'll easily be able to keep track of the flipped elements.

Simple javascript game, hide / show random square

I'm working on a simple game and I need some help to improve my code
So here's the game:
Some square show and hide randomely for a few seconds and you have to clic on them.
I use RaphaelJS to draw the square and a few of JQuery ($.each() function)
I work in a div, that's how I draw my squares (6 squares), x y are random numbers.
var rec1 = paper.rect(x, y, 50, 50).attr({
fill: "blue",});
Can I use for() to build my squares with a different var name for each one ?
I try with var = varName+i but it didn't work.
To hide and show the square I use two functions call with two setTimeout:
function box1() {rec1.show();}
function hidebox1() {rec1.hide();}
var time1 = setTimeout(box1, 1000);
var time1 = setTimeout(hidebox1, 2000);
I know it looks crappy...
I'm sure there is a way to use a toggle, or something more fancy to do that if you could help me finding it :) Because right now I have to do that for every square...
Thanks a lot for your help.
Your instinct to try to use varName plus some i to identify which varName you want is spot on, and JavaScript (like most languages) has that idea built in through what's called an array.
A simple one looks something like this:
var foo = [1, 5, 198, 309];
With that array, you can access foo[0] which is 1, or foo[3] which is 309.
Note two things: First, we identify which element of the array we want using square brackets. Second, we start counting at 0, not 1.
You can create an empty array like var varName = []; and then add new elements to it using varName.push( newValueToPutIn );
With those tools, you can now get at what you wanted. Now you can do something like:
var recs = [];
for(var i = 0; i < 100; i++) {
var rec = paper.rect(x, y, 50, 50).attr({fill: 'blue'});
recs.push(rec);
}
And recs[0] and recs[1] and so forth will refer to your various boxes.
For the first question, an array is the way to go.
For the second part, you could encapsulate the square and its show/hide stuff into a new anonymous object, like this:
var recs = [];
var numberOfRecs = 6;
for (var i = 0; i < numberOfRecs; i++) {
//determine x and y?
recs.push({
box: paper.rect(x, y, 50, 50).attr({ fill: "blue" }),
showBriefly: function(timeFromNow, duration) {
window.setTimeout(this.box.show, timeFromNow);
window.setTimeout(this.box.hide, timeFromNow + duration);
}
});
}
//show the 3rd box 1000 ms from now, for a duration of 1000 ms
recs[2].showBriefly(1000, 1000);

Working with SVG polygon elements

I'm trying to work with an SVG polygon and javascript. I create a polygon and set its initial point list like this:
var polygon = document.createElementNS('http://www.w3.org/2000/svg','polygon');
polygon.setAttribute("points", "0,0 100,100 200,200");
now what do I do if I want to modify the 2nd point (100,100)? Right now I'm basically reconstructing the whole string again. But can we address "polygon.points" as an array somehow, or is it really just a plain simple string? This can work ok for very simple polygons, but if my polygon eventually has hundreds of point pairs, I'd hate to reconstruct the entire "points" attribute as a string every time I want to modify a single element.
Thanks
You can access the individual point values using the SVG DOM:
var p = polygon.points.getItem(1);
p.x = 150;
p.y = 300;
(Assuming that your UA implements this interface.) See SVGPolygonElement, SVGAnimatedPoints, SVGPointList and SVGPoint.
I find though that using these SVG DOM interfaces (at least for me in Batik, in which I do most of my SVG stuff) is often not faster than just updating the attribute with string manipulation.
No way around it I'm afraid. You have to reconstruct the string again. But it's not difficult to wrap the whole thing in an object, something like:
function Polygon () {
var pointList = [];
this.node = document.createElementNS('http://www.w3.org/2000/svg','polygon');
function build (arg) {
var res = [];
for (var i=0,l=arg.length;i<l;i++) {
res.push(arg[i].join(','));
}
return res.join(' ');
}
this.attribute = function (key,val) {
if (val === undefined) return node.getAttribute(key);
node.setAttribute(key,val);
}
this.getPoint = function (i) {return pointList[i]}
this.setPoint = function (i,x,y) {
pointList[i] = [x,y];
this.attribute('points',build(pointList));
}
this.points = function () {
for (var i=0,l=arguments.length;i<l;i+=2) {
pointList.push([arguments[i],arguments[i+1]]);
}
this.attribute('points',build(pointList));
}
// initialize 'points':
this.points.apply(this,arguments);
}
var polygon = new Polygon(0,0, 100,100, 200,200);
polygon.setPoint(0, 50,10); // set point and automatically re-build points
polygon.points(50,50, 50,100, 200,100); // set everything
polygon.node; // refer to the actual SVG element
* not the best implementation but you get the idea.
You need to use setAttributeNS. You'll probably want to cache that namespace in a variable somewhere so you don't have to keep typing it.
You need to set all points at once, the performance is pretty solid, what you may want to do is manage the array outside and merge it on the setAttribute calls

Categories

Resources