Is it possible to add weight to images in a generator? - javascript

I wish to make a random image generator (which is working fine), however, I was wondering is there a way to add weight to certain images which won't appear as much as others?
I have attached the code below:
<script language="JavaScript">
function random_imglink(){
var myimages=new Array()
myimages[1]="Blue_Car.png"
myimages[2]="Red_Car.png"
myimages[3]="White_Car.png"
myimages[4]="Black_Car.png"
var ry=Math.floor(Math.random()*myimages.length)
if (ry==0)
ry=1
document.write('<img src="'+myimages[ry]+'" border=0>')
}
random_imglink()
function confirmRefresh() {
var okToRefresh = confirm("Do you really want to refresh the page?");
if (okToRefresh)
{
setTimeout("location.reload(true);",10);
}
}
</script>
<input type="button" value="Generate a new player" onClick="document.location.reload(true)">
</script>
</a></p>
I do have a SMALL amount of knowledge regarding JavaScript, however, I'm no pro.

var myimages=new Array();
myimages[0]="Blue_Car.png";
myimages[1]="Red_Car.png";
myimages[2]="White_Car.png";
myimages[3]="Black_Car.png";
// myimages[4] = ...
// All values summed up must equal 1
var probabilities=new Array();
probabilities[0]=0.1; // 10%
probabilities[1]=0.1; // 10%
probabilities[2]=0.25; // 25%
probabilities[3]=0.55; // 55%
// probabilities[4] = ... (also need to change the other probability values)
function getImage() {
var rand = Math.random();
var probabilitiy_sum = 0;
for(var i=0; i < probabilities.length; i++) {
probabilitiy_sum += probabilities[i];
if(rand <= probabilitiy_sum ) {
return myimages[i];
}
}
return myimages[myimages.length];
}
// Just for testing:
for(var i=0; i < 10; i++) {
document.getElementById("textbox").innerHTML += getImage() + "<br />";
}
<div id="textbox"></div>

To extend #ByteHamster's response (accept his, not mine), you can do the same thing with an array of objects to easier keep track of the possibilities.
var myimages = [{
image: "Blue_Car.png",
probability: 0.1
}, {
image: "Red_Car.png",
probability: 0.1
}, {
image: "White_Car.png",
probability: 0.25
}, {
image: "Black_Car.png",
probability: 0.55
}];
function getImage() {
var rand = Math.random();
var probabilitiy_sum = 0;
for (var i = 0; i < myimages.length; i++) {
probabilitiy_sum += myimages[i].probability;
if (rand <= probabilitiy_sum) {
return myimages[i].image;
}
}
return myimages[myimages.length].image;
}
// Just for testing:
for (var i = 0; i < 10; i++) {
document.getElementById("textbox").innerHTML += getImage() + "<br />";
}
<div id="textbox"></div>

Easy way would just to be to increase the length of your array, and then add the images with more probability to hit more times, and the images with less probability less times. You can use a for loop for each.
for (i=0;i<15;i++) {
myimages[i] = "Blue_Car.png";
}
for (i=15;i<40;i++) {
myimages[i] = "Red_Car.png";
}
for (i=40;i<80;i++) {
myimages[i] = "White_Car.png";
}
for (i=80;i<100;i++) {
myimages[i] = "Black_Car.png";
}

You already have an answer, but I'll post mine anyway.
<script language="JavaScript">
var counter = 0; // this is just to show that something happens when you randomly get the same car as the previous car.
function random_imglink() {
var myimages = [
{weight: 3, url: "http://insideevs.com/wp-content/uploads/2012/07/bollare-bluecar.jpg"}, // blue
{weight: 10, url: "http://4.bp.blogspot.com/-UKeEILt_8nw/UZOCIEMrMVI/AAAAAAAAAvI/X5i-HaJRnTc/s400/red+car10.jpg"}, // red
{weight: 5, url: "http://i.telegraph.co.uk/multimedia/archive/02661/Audi-A5-Sportback_2661284b.jpg"}, // white
{weight: 2, url: "http://1.bp.blogspot.com/-mojnxHJlWVA/UZ1KShiKMeI/AAAAAAAAHMo/oO7qMo7PJq4/s400/Best-Black-Car-2009_j2bq.gif"} // black
];
// calculate total weigt
// this example: totalWeight = 20
// Then we search a random number from 0 to 19. 0,1,2 belongs to blue; 3 to 12 is red; 13 to 17 is white; 18 to 19 is black
// we add min and max range to the image object, so we can easily return the good one.
var totalWeight = 0;
for (var i=0; i<myimages.length; i++) {
myimages[i].min = totalWeight;
myimages[i].max = totalWeight + myimages[i].weight - 1; // example: if the first weight is 3; the max is 3-1 = 2
totalWeight += myimages[i].weight;
}
var ry = Math.floor(Math.random() * totalWeight);
for (var i=0; i<myimages.length; i++) {
if (ry >= myimages[i].min && ry <= myimages[i].max) {
var index = i; // we've got a winner
break;
}
}
document.getElementById('image').innerHTML = '<img src="' + myimages[index].url + '">';
document.getElementById('counter').innerHTML = counter++;
}
window.onload = function() {
random_imglink();
}
</script>
<input type="button" value="New random car" onClick="random_imglink()">
<div id="counter"></div>
<div id="image"></div>

Related

Using jQuery to choose two grids randomly in my table

I am trying to append enemy_1 and enemy_2 in the <td> tags on my 6x7 table randomly.
I don't know how to solve this with random method or any other way.
// target -> all <td>
$('table').find('td');
// two individual enemies
var enemy_1 = $('<span>enemy_1</span>');
var enemy_2 = $('<span>enemy_2</span>');
here is my table
for (var i = 0; i < 7; i++) {
$("table").append("<tr></tr>");
}
for (var i = 0; i < 6; i++) {
$("table tr").append("<td style='background:#DDDDDD;height:50px;width:50px;'></td>");
}
$('table').prepend('<div>Start</div');
$('table').append('<div>End</div');
$('table div:last-child').css({
position :'absolute',
right: '0'
});
Here is a logic using Math.random() which will generate a random number, then we multiply it by 100 and round it, then if its a multiple of 2, we will get enemy_1 span else enemy_2.
Random logic taken from the below link.
SO Answer
// target -> all <td>
// $('table').find('td');
// two individual enemies
var enemy_1 = '<span>enemy_1</span>';
var enemy_2 = '<span>enemy_2</span>';
for (var i = 0; i < 7; i++) {
$("table").append("<tr></tr>");
}
for (var i = 0; i < 6; i++) {
$("table tr").append("<td style='background:#DDDDDD;height:50px;width:50px;'></td>");
}
$('table').prepend('<div>Start</div');
$('table').append('<div>End</div');
$('table div:last-child').css({
position: 'absolute',
right: '0'
});
//generate random number 1
var numberOne = 1,
numberTwo = 1;
do {
numberOne = Math.floor(Math.random() * 42) + 1;
} while (numberOne === numberTwo);
do {
numberTwo = Math.floor(Math.random() * 42) + 1;
} while (numberTwo === numberOne);
$('td').each(function(index) {
if (index === numberOne) {
$(this).append(enemy_1);
}
if (index === numberTwo) {
$(this).append(enemy_2);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table></table>

Is it possible to show interpolated data using dygraphs?

I have been working for the last months with dygraphs. It is a incredible library and I have got great results but I´m having some problems to find the way of interpolating data from different signals to be shown in the same chart.
The data I received from different sensors have not the same timestamp for the different samples, so for the most of the points of the x axe timestamps I have only the value of one signal. The chart is plotted perfectly, but I would like to see the interpolated value of the rest of the signals in that x point I am pointing over. Below I have the chart I get.
Reading on the dygraph documentation I have seen that when you have independent series, it is possible to see at least the value "undefined" for the signals without data in that point of the x axe.
The csv I use to plot the data is shown below. It has the same structure indicated in the dygraph documentation but I don´t get this undefined label neither.
TIME,LH_Fuel_Qty,L_Left_Sensor_NP
1488801288048,,1.4411650490795007
1488801288064,0.478965502446834,
1488801288133,,0.6372882768113235
1488801288139,1.131315227899919,
1488801288190,1.847605177130475,
1488801288207,,0.49655791428536067
1488801288258,0.45488168748987334,
1488801288288,,1.3756073145270766
1488801288322,0.5636921255908185,
1488801288358,,1.1193344122758362
Thanks in advance.
This is an approach that does not add any data to your csv data and still provides interpolated values for all the columns as you move your mouse around. It adds a listener to the mousemove event within dygraph and interpolates the closest points for all of the data. At the moment I have simply shown it in an extra DIV that is after the graph but you can display it however you like:
function findNextValueIndex(data, column, start) {
var rows = data.length;
for (var i = start; i < rows; i++) {
if (data[i][column] != null) return (i);
}
return (-1);
}
function findPrevValueIndex(data, column, start) {
for (var i = start; i >= 0; i--) {
if (data[i][column] != null) return (i);
}
return (-1);
}
function interpolate(t0, t1, tmid, v0, v1) {
return (v0 + (tmid - t0) / (t1 - t0) * (v1 - v0));
}
function showValues(headers, colors, vals) {
var el = document.getElementById("info");
var str = "";
for (j = 1; j < headers.length; j++) {
str += '<p style="color:' + colors[j] + '";>' + headers[j] + ": " + vals[j] + "</p>";
}
el.innerHTML = str;
document.getElementById("hiddenDiv").style.display = "none";
}
function movecustom(event, dygraph, point) {
var time = dygraph.lastx_;
var row = dygraph.lastRow_;
var vals = [];
var headers = [];
var colors = [];
var cols = dygraph.rawData_[0].length;
// draw a line on the chart showing the selected location
var canvas = dygraph.canvas_;
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = "rgba(0,200,200,0.1)";
ctx.moveTo( dygraph.selPoints_[0].canvasx, 0);
ctx.lineTo( dygraph.selPoints_[0].canvasx, 1000);
ctx.stroke();
for (var j = 1; j < cols; j++) {
colors[j] = dygraph.colors_[j - 1];
if (dygraph.rawData_[row][j] == null) {
var prev = findPrevValueIndex(dygraph.rawData_, j, row - 1);
var next = findNextValueIndex(dygraph.rawData_, j, row + 1);
if (prev < 0)
vals[j] = dygraph.rawData_[next][j];
else if (next < 0)
vals[j] = dygraph.rawData_[prev][j];
else {
vals[j] = interpolate(dygraph.rawData_[prev][0], dygraph.rawData_[next][0], time, dygraph.rawData_[prev][j], dygraph.rawData_[next][j]);
}
} else {
vals[j] = dygraph.rawData_[row][j];
}
}
headers = Object.keys(dygraph.setIndexByName_);
showValues(headers, colors, vals);
}
window.onload = function() {
new Dygraph(
document.getElementById('graph'), document.getElementById('csvdata').innerHTML, {
connectSeparatedPoints: true,
drawPoints: true,
labelsDiv: "hiddenDiv",
interactionModel: {
'mousemove': movecustom
}
}
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.js"></script>
<div id="graph" style="height:120px;"></div>
<div id="info"></div>
<div id="hiddenDiv" style="display:none"></div>
<pre id="csvdata" style="display:none">
TIME,LH_Fuel_Qty,L_Left_Sensor_NP
1488801288048,,1.4411650490795007
1488801288064,0.478965502446834,
1488801288133,,0.6372882768113235
1488801288139,1.131315227899919,
1488801288190,1.847605177130475,
1488801288207,,0.49655791428536067
1488801288258,0.45488168748987334,
1488801288288,,1.3756073145270766
1488801288322,0.5636921255908185,
1488801288358,,1.1193344122758362
</pre>
It seems that the best way to do this is to massage the data before submitting it to the dygraph call. This means the following steps:
1) parse the csv file into an array of arrays.
2) go through each line of the array to find where the holes are
3) interpolate to fill those holes
4) modify the constructed arrays to be displayed by dygraph
5) call dygraph
Not the most attractive code, but seems to work...
function findNextValueIndex(data, column, start) {
var rows = data.length;
for(var i=start;i<rows;i++) {
if(data[i][column].length>0) return(i);
}
return(-1);
}
function interpolate(t0, t1, tmid, v0, v1) {
return((v0 + (tmid-t0)/(t1-t0) * (v1-v0)).toString());
}
function parseCSV(string) {
var data = [];
// first get the number of lines:
var lines = string.split('\n');
// now split the first line to retrieve the headings
var headings = lines[0].split(",");
var cols = headings.length;
// now get the data
var rows=0;
for(var i=1;i<lines.length;i++) {
if(lines[i].length>0) {
data[rows] = lines[i].split(",");
rows++;
}
}
// now, fill in the blanks - start by finding the first value for each column of data
var vals = [];
var times = [];
for(var j=1;j<cols;j++) {
var index = findNextValueIndex(data,j,0);
vals[j] = parseFloat(data[index][j]);
}
// now put those start values at the beginning of the array
// there is no way to calculate the previous value of the sensor missing from the first sample
// so we use the first reading and duplicate it
for(var j=1;j<cols;j++) {
data[0][j] = vals[j].toString();
times[j] = parseInt(data[0][0]);
}
// now step through the rows and interpolate the missing values
for(var i=1;i<rows;i++) {
for(var j=1;j<cols;j++) {
if(data[i][j].length>0) {
vals[j] = parseFloat(data[i][j]);
times[j] = parseInt(data[i][0]);
}
else {
var index = findNextValueIndex(data,j,i);
if(index<0) // no more data in this column
data[i][j] = vals[j].toString();
else
data[i][j] = interpolate(times[j],parseInt(data[index][0]),parseInt(data[i][0]),vals[j],data[index][j]);
}
}
}
// now convert from strings to integers and floats so dygraph can handle it
// I've also changed the time value so that it is relative to the first element
// it will be shown in milliseconds
var time0 = parseInt(data[0][0]);
for(var i=0;i<rows;i++) {
data[i][0] = parseInt(data[i][0]) - time0;
for(var j=1;j<cols;j++) {
data[i][j] = parseFloat(data[i][j]);
}
}
var obj = {
labels: headings,
data: data
}
return(obj);
}
window.onload = function () {
var data_obj = parseCSV(document.getElementById('csvdata').innerHTML);
new Dygraph(
document.getElementById('graph'), data_obj.data,
{
labels: data_obj.labels,
connectSeparatedPoints: true,
drawPoints: true
}
);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.js"></script>
<div id="graph" style="height:200px;"></div>
<pre id="csvdata" style="display:none">
TIME,LH_Fuel_Qty,L_Left_Sensor_NP
1488801288048,,1.4411650490795007
1488801288064,0.478965502446834,
1488801288133,,0.6372882768113235
1488801288139,1.131315227899919,
1488801288190,1.847605177130475,
1488801288207,,0.49655791428536067
1488801288258,0.45488168748987334,
1488801288288,,1.3756073145270766
1488801288322,0.5636921255908185,
1488801288358,,1.1193344122758362
</pre>
Does
connectSeparatedPoints: true
Not do what you need?

Nested for loop incrementation producing inconsistent result

I'm trying to use the variable of the current iteration of the loop in the nested loop.
However when I execute the following code the loop incorrectly starts at f = 6, and then it correctly iterates over the nested loop.
I've removed all the other code and then it works normally. However I have no clue what could possibly be interfering with the loop. There probably is a reason for it and I wish you guys could help me figure this out - and probably learn something more about why this behaviour occurs the way it does.
for (var f = 0; f < 6; f++) {
var JSONURL = "http://blabla.com/json";
$.ajax( JSONURL, {
dataType: "json"
})
.done(function(json) {
for (var i = 0; i < json.timeslots.length; i++) {
var StartHour = json.timeslots[i].begintijd.split(":")[0];
var StartMinute = json.timeslots[i].begintijd.split(":")[1];
var EndHour = json.timeslots[i].eindtijd.split(":")[0];
var EndMinute = json.timeslots[i].eindtijd.split(":")[1];
//Calculate top distance of block in pixels
if (StartHour < 20) {
var TopDistance = ((parseInt(StartHour) - 9) * 240) + (parseInt(StartMinute) * 4);
}
//Calculate height of block in pixels
var BlockHeight = ((((parseInt(EndHour) * 60) + (parseInt(EndMinute))) - ((parseInt(StartHour) * 60) + (parseInt(StartMinute)))) * 4) - 2.5;
//Generate HTML for blocks
var html_first = '<div data-ix="show-pop-up" class="w-clearfix time-block event-block" style="height:'+BlockHeight+'px; top:'+TopDistance+'px; background-color:'+json.timeslots[i].achtergrondkleur+';">';
if (json.timeslots[i].afbeelding.length > 0) {
var html_mid = '<div class="avatar" style="background-image:url('+json.timeslots[i].afbeelding+');"></div>';
}
else {
html_mid = "";
}
var html_last = '<h4 class="card-title">'+json.timeslots[i].naam+'</h4><div class="time-indication">'+json.timeslots[i].begintijd+'</div><div class="speaker-description">'+json.timeslots[i].functie+'</div><div class="hidden-content"><div class="pop-up-wrapper" style="background-color:'+json.timeslots[i].achtergrondkleur+';"><div class="w-clearfix pop-up-header-background"><div data-ix="hide-pop-up" class="close-icon" id="PopupClose"></div><h3 class="white pop-up-title">'+json.timeslots[i].naam+'</h3><div class="pop-up-subtitle">'+json.timeslots[i].functie+'</div></div><div class="w-clearfix pop-up-body"><div class="pop-up-avatar" style="background-image:url('+json.timeslots[i].afbeelding+');"></div><div class="w-clearfix"><div class="pop-up-card-detail-wrap"><div class="time-label">Begint om</div><div class="pop-up-time-text">'+json.timeslots[i].begintijd+'</div></div><div class="pop-up-card-detail-wrap"><div class="time-label">Eindigt om</div><div class="pop-up-time-text">'+json.timeslots[i].eindtijd+'</div></div><div class="pop-up-card-detail-wrap"><div class="time-label">plek</div><div class="pop-up-time-text">Zaal 1</div></div></div><p class="pop-up-paragraph">'+json.timeslots[i].beschrijving_lang+'</p></div><div class="pop-up-footer">Meer over deze spreker</div></div></div></div>';
var html = html_first+html_mid+html_last;
var TargetDiv = "#Locatie"+f+"Column";
alert("Parent loop increment: "+f);
alert("Child loop increment: "+i);
$(TargetDiv).append(html);
}
});
}
It starts at f = 6 because your callback doesn't get called until after f equals 6
What you may do is something to the effect of:
for (var f = 0; f < 6; f++) {
var JSONURL = "http://blabla.com/json";
$.ajax( JSONURL, {
dataType: "json"
})
.done(handleResponse.bind(null, f));
}
function handleResponse(f, json) {
for (var i = 0; i < json.timeslots.length; i++) {
var StartHour = json.timeslots[i].begintijd.split(":")[0];
var StartMinute = json.timeslots[i].begintijd.split(":")[1];
var EndHour = json.timeslots[i].eindtijd.split(":")[0];
var EndMinute = json.timeslots[i].eindtijd.split(":")[1];
//Calculate top distance of block in pixels
if (StartHour < 20) {
var TopDistance = ((parseInt(StartHour) - 9) * 240) + (parseInt(StartMinute) * 4);
}
//Calculate height of block in pixels
var BlockHeight = ((((parseInt(EndHour) * 60) + (parseInt(EndMinute))) - ((parseInt(StartHour) * 60) + (parseInt(StartMinute)))) * 4) - 2.5;
//Generate HTML for blocks
var html_first = '<div data-ix="show-pop-up" class="w-clearfix time-block event-block" style="height:'+BlockHeight+'px; top:'+TopDistance+'px; background-color:'+json.timeslots[i].achtergrondkleur+';">';
if (json.timeslots[i].afbeelding.length > 0) {
var html_mid = '<div class="avatar" style="background-image:url('+json.timeslots[i].afbeelding+');"></div>';
}
else {
html_mid = "";
}
var html_last = '<h4 class="card-title">'+json.timeslots[i].naam+'</h4><div class="time-indication">'+json.timeslots[i].begintijd+'</div><div class="speaker-description">'+json.timeslots[i].functie+'</div><div class="hidden-content"><div class="pop-up-wrapper" style="background-color:'+json.timeslots[i].achtergrondkleur+';"><div class="w-clearfix pop-up-header-background"><div data-ix="hide-pop-up" class="close-icon" id="PopupClose"></div><h3 class="white pop-up-title">'+json.timeslots[i].naam+'</h3><div class="pop-up-subtitle">'+json.timeslots[i].functie+'</div></div><div class="w-clearfix pop-up-body"><div class="pop-up-avatar" style="background-image:url('+json.timeslots[i].afbeelding+');"></div><div class="w-clearfix"><div class="pop-up-card-detail-wrap"><div class="time-label">Begint om</div><div class="pop-up-time-text">'+json.timeslots[i].begintijd+'</div></div><div class="pop-up-card-detail-wrap"><div class="time-label">Eindigt om</div><div class="pop-up-time-text">'+json.timeslots[i].eindtijd+'</div></div><div class="pop-up-card-detail-wrap"><div class="time-label">plek</div><div class="pop-up-time-text">Zaal 1</div></div></div><p class="pop-up-paragraph">'+json.timeslots[i].beschrijving_lang+'</p></div><div class="pop-up-footer">Meer over deze spreker</div></div></div></div>';
var html = html_first+html_mid+html_last;
var TargetDiv = "#Locatie"+f+"Column";
alert("Parent loop increment: "+f);
alert("Child loop increment: "+i);
$(TargetDiv).append(html);
}
}
What this does is call handleResponse by passing in the value of f at the time that the loop is run.
The problem is not the nested loop, but the asynchronous call inside the loop. To resolve this issue you can use an immediately-invoked-anonymous-function to pass the correct value to your function, like so :
for (var f = 0; f < 6; f++) {
(function(foo) {
//ajax call
//your ajax call will now have the correct number
})(f);
}

Javascript NaN function

This function receive values for another one (the generation parameter). My objective is return onde array in cloneGene variable, although it appears like NaN and I do not know why.
function SampleWithReposition(generation, newGeneration) {
newGeneration = [];
generation = Starting_generation;
var randomGeneration = Math.floor(Math.random() * pop_size) + 0;
for(i=0;i<pop_size;i++){
newGeneration = generation[i] = generation[randomGeneration];
}
return newGeneration;
GenerationStep(newGeneration);
//document.write(newGeneration + ' <br />' + ' <br />');
}
//Mutation and recombination rate
function GenerationStep (mutation_rate, recombination_rate, generation, cloneGene) {
//var generation = [1, 2, 1, 54, 1, 1, 1];
generation = SampleWithReposition();
mutation_rate = recombination_rate = 0.1;
for(var i=0; i<pop_size; i++){
for(var j=0;j<gene_size; j++){
random_number = random();
var max_individual = Math.max.apply(Math, generation);
//mutation_rate
if(random_number < mutation_rate){
var cloneGene = 1;
cloneGene=generation[i][j]=generation[max_individual][j]+1;
document.write(cloneGene);
}
}
}

Drawing multiple random canvas images in a loop

I'm trying to draw a grid with random images assigned to each square. I'm having trouble with the draw sequence and potentially closure issues with the Javascript variables. Any help is appreciated.
var tileSize = 30;
var drawCanvasImage = function(ctx,tile,x,y) {
return function() {
ctx.drawImage(tile,x,y);
console.log("x = " + x + "/ y = " + y);
}
}
function textures(ctx) {
var grass = new Image();
var sea = new Image();
var woods = new Image();
for (var i=0; i<=10; i++) {
for (var j=0; j<=20; j++) {
rand = Math.floor(Math.random()*3 + 1);
x = i * tileSize;
y = j * tileSize;
if (rand == 1) {
grass.onload = drawCanvasImage(ctx,grass,x,y);
} else if (rand == 2) {
sea.onload = drawCanvasImage(ctx,sea,x,y);
} else {
woods.onload = drawCanvasImage(ctx,woods,x,y);
}
}
}
grass.src = "textures/grass.png";
sea.src = "textures/sea.png";
woods.src = "textures/woods.png";
}
//function called by the onload event in the html body tag
function draw() {
var ctx = document.getElementById("grid").getContext('2d');
grid(ctx); //a function to draw the background grid - works fine
textures(ctx);
}
The current result is three drawn tiles, all at the position of x = 300 (equivalent to the i loop of 10 * the tileSize of 30) and a random y position.
After following a lead and accounting for (maybe?) closure issues by creating the variable drawCanvasImage, I at least got those three tiles to draw.
----Edit----
Working Code - Revision 2:
function randomArray() {
for (var i=0; i<=(xValue/tileSize); i++) {
terrainArray[i] = [];
for (var j=0; j<=(yValue/tileSize); j++) {
rand = Math.floor(Math.random()*4 + 1);
if (rand == 1) {
terrainArray[i][j] = 3;
} else if (rand == 2) {
terrainArray[i][j] = 2;
} else if (rand == 3) {
terrainArray[i][j] = 1;
} else {
terrainArray[i][j] = 0;
}
}
}
}
var drawTerrain = function(ctx,tile,landUseValue) {
return function() {
for (var i=0; i<=(xValue/tileSize); i++) {
for (var j=0; j<=(yValue/tileSize); j++) {
if (terrainArray[i][j] == landUseValue) {
ctx.drawImage(tile,i*tileSize,j*tileSize);
}
}
}
}
}
function textures(ctx) {
var grass = new Image();
var sea = new Image();
var woods = new Image();
var desert = new Image();
grass.onload = drawTerrain(ctx,grass,3);
sea.onload = drawTerrain(ctx,sea,0);
woods.onload = drawTerrain(ctx,woods,2);
desert.onload = drawTerrain(ctx,desert,1);
grass.src = "textures/grass.png";
sea.src = "textures/sea.png";
woods.src = "textures/woods.png";
desert.src = "textures/desert.png";
}
You're rewriting the onloads of the three images in every iteratiom. So, it will only execute the last-added onload f or every image.
Suggestion: run your drawing method only after the thred are loaded(and them just call drawCanvasImage every iteration without an .onload=)
Even better:store the randoms in an array, have each image independantly walk through the array on load and add copies of only itself wherever applicable .
Improvement to rev 2
function randomArray() {
for (var i=0; i<=(xValue/tileSize); i++) {
terrainArray[i] = [];
for (var j=0; j<=(yValue/tileSize); j++) {
rand = Math.floor(Math.random()*4 + 1);
terrainArray[i][j] = 4-rand;
//OR: replace above two lines with terrainArray[i][j]=Math.floor(Math.random()*4 + 1);. There's no need to have them in exactly reverse order.
}
}
}
var drawTerrain = function(ctx,tile,landUseValue) {
return function() {
for (var i=0; i<=(xValue/tileSize); i++) {
for (var j=0; j<=(yValue/tileSize); j++) {
if (terrainArray[i][j] == landUseValue) {
ctx.drawImage(tile,i*tileSize,j*tileSize);
}
}
}
}
}
function textures(ctx) {
var grass = new Image();
var sea = new Image();
var woods = new Image();
var desert = new Image();
grass.onload = drawTerrain(ctx,grass,3);
sea.onload = drawTerrain(ctx,sea,0);
woods.onload = drawTerrain(ctx,woods,2);
desert.onload = drawTerrain(ctx,desert,1);
grass.src = "textures/grass.png";
sea.src = "textures/sea.png";
woods.src = "textures/woods.png";
desert.src = "textures/desert.png";
}
To make it even more flexible, you could use an array to store the images, and then use length. This way, if you want to add another image, all you have to do is modify the array.
var srcArray=["textures/grass.png","textures/sea.png","textures/woods.png","textures/desert.png"];
var imgArray=[];
var terrainArray=[];
function textures(ctx){
randomArray();
for(var i=0;i<srcArray.length;i++){
imgArray[i]=new Image();
imgArray[i].src=srcArray[i];
imgArray[i].onload=drawTerrain(ctx,i);
}
}
function randomArray() {
for (var i=0; i<=(xValue/tileSize); i++) {
terrainArray[i] = [];
for (var j=0; j<=(yValue/tileSize); j++) {
terrainArray[i][j]=Math.floor(Math.random()*srcArray.length);
}
}
}
var drawTerrain = function(ctx,index) {
return function() {
for (var i=0; i<=(xValue/tileSize); i++) {
for (var j=0; j<=(yValue/tileSize); j++) {
if (terrainArray[i][j] == index) {
ctx.drawImage(imgArray[index],i*tileSize,j*tileSize);
}
}
}
}
}
So now, all you have to do is call terrain(ctx) when you want to load all the images. And, whenever you want to add an image to the list of images, just add it to the array up top. You won't have to dig deeper and modify the random values and whatnot.
It's because every time you do a loop, you assign a new function to [image].onload, overwriting the previous one. That's how you end up with only three images.
This should work:
if (rand == 1) {
grass.addEventlistener('load', drawCanvasImage(ctx,grass,x,y), false);
} else if (rand == 2) {
sea.addEventlistener('load', drawCanvasImage(ctx,sea,x,y), false);
} else {
woods.addEventlistener('load', drawCanvasImage(ctx,woods,x,y), false);
}
Here you just add a new listener for every loop.

Categories

Resources