Calculate percentage from an array - javascript

I'm trying to fill a jqPlot Chart with percentage values for a stacked bar chart. I get the data via mysql and COUNT. For example, if I have 4 categories and 12 months, I am able to produce:
var s1 = [0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s2 = [0, 5, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, ];
var s3 = [0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s4 = [0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, ];
Which produces a stacked bar chart with numbers, every number of each variable is a months value.
Now I want to show a stacked bar chart where the values of each month are percentages. I must somehow be able to make a percentage calculation with the values of the array. For example: add all values from position two (February) (100/(2+5+3+3)) and then multiply with positon two.
I am nowhere near a solution.
EDIT: Well, thanks for the fast answers.
I will try to explain better. I get the data from the 'MySQL' query, then to a PHP array, then convert it to a string to paste it to the JavaScript for plotting:

Try a for loop to calculate the percent you wanted to get and put it inside an array again
$(document).ready(function(){
var s1 = [0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s2 = [0, 5, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, ];
var s3 = [0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s4 = [0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, ];
var s5 = new Array();
for (var i = 0; i < s1.length; i++){
//Or use your own formula on getting the value you wanted.
s5.push(100/(s1[i]+s2[i]+s3[i]+s4[i]);
}
// Can specify a custom tick Array.
// Ticks should match up one for each y value (category) in the series.
var ticks = ['January','February','March','April','May','June','July','August','September','October','November','December'];
var plot1 = $.jqplot('chart1', [s1, s2, s3, s4, s5], {
// The "seriesDefaults" option is an options object that will
// be applied to all series in the chart.
seriesDefaults:{
renderer:$.jqplot.BarRenderer,
rendererOptions: {fillToZero: true}
},
// Custom labels for the series are specified with the "label"
// option on the series option. Here a series option object
// is specified for each series.
series:[
{label:'Hotel'},
{label:'Event Regristration'},
{label:'Airfare'}
],
// Show the legend and put it outside the grid, but inside the
// plot container, shrinking the grid to accomodate the legend.
// A value of "outside" would not shrink the grid and allow
// the legend to overflow the container.
legend: {
show: true,
placement: 'outsideGrid'
},
axes: {
// Use a category axis on the x axis and use our custom ticks.
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: ticks
},
// Pad the y axis just a little so bars can get close to, but
// not touch, the grid boundaries. 1.2 is the default padding.
yaxis: {
pad: 1.05,
tickOptions: {formatString: '$%d'}
}
}
});
});

<script>
/* are there to be more than 4 arrays? */
var s1 = [0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s2 = [0, 5, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, ];
var s3 = [0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s4 = [0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, ];
/* add new arrays to this array */
var arrs=[s1,s2,s3,s4];
var pc=[];
for( var i=0; i < arrs[0].length; i++ ){
var a=0;
for( var j=0; j < arrs.length; j++ ){
if( !isNaN( arrs[ j ][ i ] ) ) a+=arrs[ j ][ i ];
}
console.log( 'i=%d, j=%d, a=%d', i, j, a );
/* confused by the `then multiply with positon two` */
pc.push( a > 0 ? Math.round( 100 / a ) : 0 );
}
alert( pc );
</script>

If I understood correctly, it will work in your case :
function getPercent(array){
var return_array = [];
var total_sum = 0; // total sum of data
for(var i = 0; i < array.length; i++){
total_sum += array[i].reduce(function(pv, cv) { return pv + cv; }, 0);
}
for( var i=0; i < array[0].length; i++ ){
var sum = 0; // month sum
for( var j=0; j < array.length; j++ ){
sum += array[j][i];
}
return_array[i] = sum*100/total_sum; // percent calculation of the month
}
return return_array;
}
var s1 = [0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s2 = [0, 5, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, ];
var s3 = [0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ];
var s4 = [0, 3, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, ];
var data=[s1,s2,s3,s4];
var percent = getPercent(data);
console.log(percent);
And results are :
[0, 61.904761904761905, 4.761904761904762, 4.761904761904762, 19.047619047619047, 9.523809523809524, 0, 0, 0, 0, 0, 0]

Related

Items in javascript array suddenly changed without any reason

I've been working on a tile-based game, but after playing it for about a minute or so, some tiles just change to a different value. I have found that the code responsible for the sudden change is this part:
console.table(field);
console.table(ct);
var xcoord = x;
var ycoord = y;
if(y < 0) {
redrawField();
gameOver();
return;
}
for(var i = 0; i < ct.length; i++) {
for(var j = 0; j < ct[0].length; j++) {
if(ct[i][j] == 1) {
field[ycoord+i][xcoord+j] = index;
}
}
}
console.table(field);
the field variable is a two-dimensional array containing the 'status' of every tile. the ct variable has to be copied into the field on the x and y coordinates. (The field its vertical so the first index is the y-coordinate (or the row) and the second the x-coordinate (or the column)).
Usually this works fine, so when field is
0, 0, 0, 0, 0
0, 0, 0, 0, 0
0, 0, 0, 0, 0
0, 0, 0, 0, 0
ct is
0, 0, 1
1, 1, 1
and x and y are 2 and index = 3,
the result is:
0, 0, 0, 0, 0
0, 0, 0, 0, 0
0, 0, 0, 0, 3
0, 0, 3, 3, 3
But sometimes it randomly gives this:
0, 0, 0, 0, 3
0, 0, 0, 0, 3
0, 0, 0, 0, 3
0, 0, 3, 3, 3
I really can't think of any reason why it would do this, can someone help me?
Thanks in advance.

Practicing 2D Arrays

I'm writing a script that will generate a square room within a larger map. The code looks like this:
var mapSize = 10;
var map = [];
for (var x = 0; x < mapSize; x++) {
map[x] = [];
for (var y = 0; y < mapSize; y++) {
map[x][y] = 0
};
};
//Make square room within map
var roomSize = 3;
var roomType = "Kitchen"
var paintRoom = function(mapX, mapY) {
for (var j = 0; j < roomSize; j++) {
map[mapX + j][mapY] = roomType;
map[mapX][mapY + j] = roomType;
};
};
paintRoom(3, 4);
console.log(map);
The result that I want is this:
[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, "Kitchen", "Kitchen", "Kitchen", 0, 0, 0],
[0, 0, 0, 0, "Kitchen", "Kitchen", "Kitchen", 0, 0, 0],
[0, 0, 0, 0, "Kitchen", "Kitchen", "Kitchen", 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
But instead I end up with this:
[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, "Kitchen", "Kitchen", "Kitchen", 0, 0, 0],
[0, 0, 0, 0, "Kitchen", 0, 0, 0, 0, 0],
[0, 0, 0, 0, "Kitchen", 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]
What am I missing here? I'm just starting out, and would like to figure out as much as possible on my own, so if anyone could give me a hint instead of answering outright, I would really appreciate it.
It is doing what you've asked, if you follow the code carefully. It just needs an extra loop. Since what you're doing is 2 dimensional then you'll need 2 loops as well...
var paintRoom = function(mapX, mapY) {
for (var x = 0; x < roomSize; x++) {
for (var y = 0; y < roomSize; y++) {
map[mapX + x][mapY + y] = roomType;
}
};
};
you a missing 1 loop:
var mapSize = 10;
var map = [];
for (var x = 0; x < mapSize; x++) {
map[x] = [];
for (var y = 0; y < mapSize; y++) {
map[x][y] = 0
};
};
//Make square room within map
var roomSize = 3;
var roomType = "Kitchen"
var paintRoom = function(mapX, mapY) {
for (var j = 0; j < roomSize; j++) {
for (var k = 0; k < roomSize; k++) {
map[mapX + j][mapY + k] = roomType;
}
};
};
paintRoom(3, 4);
console.log(map);
https://jsfiddle.net/nfnpesmd/

Rendering a tile map on html5 canvas using and array and fillRect

I'm very much an amateur enthusiast trying to make a basic 2d game map with html canvas. I've done this before by using arrays to create div/img tags and position them. I'm now trying to do this with canvas, not with images but simply drawing squares with fillRect().
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var map =
[0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 1, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 1, 0, 0]
[1, 1, 1, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0];
window.addEventListener("load", function()
{
update();
}, false);
function update()
{
window.requestAnimationFrame(update, canvas);
render();
}
function render()
{
ctx.clearRect(0, 0, canvas.width, canvas.height);
for(var row = 0; row < map.length; row++)
{
for(var column = 0; column < map[0].length; column++)
{
switch(map[row][column])
{
case 0:
ctx.fillStyle = #ffffff;
ctx.fillRect
(
row * 64, column * 64, 64, 64
);
break;
case 1:
ctx.fillStyle = #009900;
ctx.fillRect
(
row * 64, column * 64, 64, 64
);
break;
}
}
}
}
I'm getting the error: 'Uncaught SyntaxError: Unexpected token ILLEGAL' on line 46 which is 'ctx.fillStyle = #ffffff;'.
I'm a bit stuck as to why it's giving this error, I'm wondering if you can't use the context methods in this way with an array but I can't understand why.
If anyone has any advice, I would be very grateful.

Adding characters to a two-dimentional array in Javascript

I am really having a hard time trying to fill my two dimensional array in Javascript.
I have a different array with lots of letters that I want to add to my 'board' but even the board dose not seem to be working correctly. Whenever I try to print board to the web page using the draw Board method I get NaN for the place where the letter A is. The rest is displaying the number 0.
var ROW = 10;
var COLUMN = 10;
var board = [['A', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
function drawBoard(board) {
var str = '';
for (var x = 0; x < ROW; x++){
str += '<div class="row">';
for (var y = 0; y < COLUMN; y++){
str += '<div class="column">' +
+ board[x][y] + '</div>' + '</div>';
}
str += '</div>';
}
$('#board').append(str);
}
$(function(){
drawBoard(board);
});
What I want to do is have this string:
var Letters = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M'];
make a for loop to just board[x][y] = Letters.pop(). And then display the board with the new letters.
Are there any better ways to add an array to a two dimentional array than just running two for loops?
Why dose my board display NaN and not the letter. I have tried many different things.
To answer the first question. If you look at your code:
str += '<div class="column">' +
+ board[x][y] + '</div>' + '</div>';
you can see that you have a + +board[x][y], not a + when adding board[x][y]. The unary + tries to convert the value of board[x][y] to a number before concatenating giving you the NaN error( as #Bergi pointed out).
To add an element to the end of an array you can use the push() method (in your caseboard.push(Letters)). This will place the element, which can be an array, at the end of the array.
If you want to replace a line in the array you can use board[x] = Letters.

HTML5 Canvas drawImage only draws after second refresh

OK, I have a HTML5 canvas... and it draws images from .png tiles (32x32). It works. Sort of. It only draws on the canvas after the second refresh. For example, if you were to load it up... al you would see is a red canvas (the background for #canvas is red) then if you were to refresh it... it would be successfully draw the images... why is that?
Here is the code. (All you need is two images. t0.png and t1.png in line_tiles folder) But I am sure you can spot the error right away that I can't :P
game.js
// HTML5 JS Tile Example
var canvas, context, board, imageObj, tiles;
var currentMap = 1;
var upMap = 0;
var rightMap = 0;
var leftMap = 0;
var downMap = 3;
var NUM_OF_TILES = 1; // starting from ZERO
// Set return 2D array of map
function loadMap(map) {
if (map == 1) {
return [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]];
}
}
// On load...
window.onload = function () {
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
imageObj = new Image();
tiles = [];
board = loadMap(1);
canvas.width = 512;
canvas.height = 352;
// 2. SET UP THE MAP TILES
for (x = 0; x <= NUM_OF_TILES; x++) {
imageObj = new Image(); // new instance for each image
imageObj.src = "line_tile/t" + x + ".png";
tiles.push(imageObj);
}
var theX;
var theY;
// 3. DRAW MAP BY ROWS AND COLS
for (x = 0; x <= 10; x++) {
for (y = 0; y <= 15; y++) {
theX = x * 32;
theY = y * 32;
context.drawImage(tiles[board[x][y]], theY, theX, 32, 32);
}
}
};
index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
<title>HTML5</title>
<script type="text/javascript" src="game.js"></script>
<style type="text/css">
<!--
#canvas {
background:red;
z-index:0;
position:relative;
}
.container {
width: 512px;
position: relative;
}
-->
</style>
</head>
<body>
<div class="container">
<canvas id="canvas"></canvas>
</div>
</body>
</html>
You need to add onload hooks on your images (the tiles) and draw only when all images are loaded.
Here's a suggestion :
// HTML5 JS Tile Example
var canvas, context, board, imageObj, tiles;
var currentMap = 1;
var upMap = 0;
var rightMap = 0;
var leftMap = 0;
var downMap = 3;
var NUM_OF_TILES = 1; // starting from ZERO
// Set return 2D array of map
function loadMap(map) {
if (map == 1) {
return [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]];
}
}
// On load...
window.onload = function () {
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
imageObj = new Image();
tiles = [];
board = loadMap(1);
canvas.width = 512;
canvas.height = 352;
var draw = function() {
var theX;
var theY;
// 3. DRAW MAP BY ROWS AND COLS
for (x = 0; x <= 10; x++) {
for (y = 0; y <= 15; y++) {
theX = x * 32;
theY = y * 32;
context.drawImage(tiles[board[x][y]], theY, theX, 32, 32);
}
}
}
var loadedImagesCount = 0;
// 2. SET UP THE MAP TILES
for (x = 0; x <= NUM_OF_TILES; x++) {
var imageObj = new Image(); // new instance for each image
imageObj.src = "line_tile/t" + x + ".png";
imageObj.onload = function() {
loadedImagesCount++;
if (loadedImagesCount==NUM_OF_TILES) draw();
};
tiles.push(imageObj);
}
};
And be careful not to forget the var keyword (look at the loop).

Categories

Resources