Forming a Grid With a JS Matrix - javascript

A friend and I are making a God-like Game for the browser. It is VERY early stages, but I already have problems with my code!
It was suggested by someone on Stack Overflow to use a 'matrix' (I think that is what he called it) for organizing the tiles that you can build on. I now have a system for reading and editing the contents of a tile, but I am not sure how I can lay out the matrix in a grid format like this:
tile 1, tile 2, tile 3
tile 4, tile 5, tile 6
tile 7, tile 8, tile 9
It would be ideal if this would work no matter how many rows and columns there were.
Here is my code so far:
var WoodHut = "Woodcutter's hut";
var TownHall = "TownHall";
var Mine = "Iron Mine";
var tiles = [];
var rowCount = 15;
var columnCount = 15;
// Assign the none string to all tiles.
for (var r = 0; r < rowCount; r++)
{
tiles[r] = [];
for (var c = 0; c < columnCount; c++)
{
var currentRow = tiles[r];
currentRow[c] = "--none--";
}
}
// NOTE TO SELF: Arrays are 0-based!
// access row 4, column 2.
// console.log(tiles[3][1]);
// Assign something to row 5 column 3.
// tiles[4][2] = WoodHut
function Build(locX, locY, type){
this.locX = X
this.locY = Y
this.type = type;
tiles[X][Y] = type;
}
function TownMap(){
// HOW DO I DO THIS???????
}
So in summary, I want to be able to call TownMap() and have a grid of tile values displayed in an alert or a console log.
Any Feedback would be great! Thanks in advance!

Wow I'm doing the same thing, only that I started 2 weeks ago.
Any way we could get in contact?
I'll show you how I did the grid:
function setup() {
// Create Grid
var grid = $('#grid');
for (var i = 0; i < tileCount; i++) {
var tile = document.createElement('div');
tile.id = "t" + (i + 1);
tile.className = "tile";
tile.onclick = function () {
deselect();
activeTile = $(this);
$(this).addClass("active");
tilePopup(this);
};
grid.append(tile);
}
//Create Menu
var menu = $('#menu');
for (var i = 0; i < buildings; i++) {
var building = document.createElement('div');
building.id = "b" + (i + 1);
//building.className = "building";
building.innerHTML = "Building " + (i + 1);
building.style.background = "url('images/buildings/" + building.id + ".png') 0 26px / 100% auto no-repeat";
building.onclick = function () {
build(this.id);
};
menu.append(building);
}
}
CSS:
#grid {
position: absolute;
width: 800px;
height: 800px;
left: 400px;
-moz-transform: rotate(-45deg) skew(15deg, 15deg);
-webkit-transform: rotate(-45deg) skew(15deg, 15deg);
-ms-transform: rotate(-45deg) skew(15deg, 15deg);
transform: rotate(-45deg) skew(15deg, 15deg);
background-image: url("images/ground.jpg");
background-size: 100% 100%;
}
.tile {
float: left;
width: 10%;
height: 10%;
outline: 1px ridge rgba(121, 121, 121, 0.8);
transition: 1s;
}

Related

Generating buttons in a grid

I'm working on a drum machine and I am not sure how to approach making the squares clickable. How can I alter the color of a specific square to crimson upon being clicked?
const drums = ["Crash", "CHiHat", "OHiHat", "Tom3", "Tom2", "Tom1", "Snare", "Kick"];
for (let i = 0; i < 8; i++) {
for (let v = 0; v < 16; v++) {
var block = document.getElementById('canvas');
var context = block.getContext('2d');
context.strokeRect(100 + (55 * v), (55 * i), 50, 50);
context.fillStyle = 'crimson';
context.fillRect(100 + (55 * v), (55 * i), 50, 50);
}
}
<canvas id="canvas" width="1920" height="1080"></canvas>
I tried addEventListener, but that returned an error.
A canvas is just a grid of pixels. You can't assign a click handler to a canvas shape, because that shape is just some pixels. If you aren't restricted to using canvas, try using regular elements, like this:
var drumMachine = document.getElementById("drumMachine");
var nRows = 8;
var nCols = 16;
for (let i = 0; i < nRows; i++) {
var row = document.createElement("tr");
for (let j = 0; j < nCols; j++) {
let cell = document.createElement("td");
cell.className = "clickable";
cell.addEventListener("click", function () {
this.classList.toggle("activated");
});
row.appendChild(cell);
}
drumMachine.appendChild(row);
}
#drumMachine {
margin-left: 100px;
}
.clickable {
width: 50px;
height: 50px;
background-color: black;
cursor: pointer;
margin-right: 5px;
margin-bottom: 5px;
display: inline-block;
}
.clickable.activated {
background-color: crimson;
}
<table id="drumMachine"></table>
This does a few things.
First, it defines the grid dimensions and then creates the elements in a two-dimensional loop.
It then adds an click event listener to each element (here is where HTML elements shine against HTML canvas!)
After which, the elements are assembled into a regular table setup. CSS is used to mimic your canvas setup.
If you have any questions don't hesitate to ask in the comments.

How to go from x++ to x-- in interval when reaching a specific number in javascript?

I am building a small javascript program.
The program runs when the windows loads. I set an interval to make the function starts. So I would like to know how can I change from increment to decrement from x++ to i-- when a certain number has been reached in a for loop which goes through each element of an array defined in the beginning of the script ?
here is my script :
// we create the patterns array
var pattern = [
[1, 0, 1],
[0, 1, 0],
[1, 0, 1]
];
var stage = document.querySelector("#stage");
// here we assign the width of the cell divs and space margin between them
var WIDTH = 30;
var SPACE = 10;
// here we get the number of rows in an array
var ROWS = pattern.length;
// here we get the number of columns in an array
var COLUMNS = pattern[0].length;
var previousColorNum = 0;
setInterval(render, 2000);
function render() {
for (var row = 0; row < ROWS; row++) {
for (var column = 0; column < COLUMNS; column++) {
// here we create a div element
var cell = document.createElement("div");
// here we set the attribute class with the name cell
cell.setAttribute("class", "cell");
// here we append this new div to stage div
stage.appendChild(cell);
// now we check if the element of the array is 1 we give it a background of black
// if the element is 0 it is white
if (pattern[row][column] === 1) {
cell.style.backgroundColor = "black";
} else if (pattern[row][column] === 2) {
cell.style.backgroundColor = "red";
} else if (pattern[row][column] === 3) {
cell.style.backgroundColor = "green";
}
previousColorNum = pattern[row][column];
//pattern[row][column] += 1;
if (previousColorNum === 3) {
pattern[row][column] -= 1;
} else if (previousColorNum === 0) {
pattern[row][column] += 1;
}
// now we make the arrangement of margins for each div cell
// it is a mathematical formula
cell.style.top = row * (WIDTH + SPACE) + "px";
cell.style.left = column * (WIDTH + SPACE) + "px";
console.log("previous " + previousColorNum);
console.log("current " + pattern[row][column]);
}
}
}
.stage {
position: relative;
}
.cell {
position: absolute;
width: 30px;
height: 30px;
border: 1px solid black;
background-color: white;
}
/* smaller console */
.as-console-wrapper { max-height: 2.5em !important; }
<div id="stage"></div>

Visualize JSON data containing XY coordinate location

I have JSON data which includes X-Y grid location, quantity, and color.
[{"x":1,"y":2,"qty":5,"color":"red"},
{"x":2,"y":4,"qty":10,"color":"green"},
{"x":3,"y":1,"qty":15,"color":"green"},
{"x":4,"y":3,"qty":20,"color":"red"}]
I would like to visualize the JSON like this:
Preference is to use something in the Google Visualization API, but I'm open to other solutions. I'm familiar enough with Javascript but wanted something that was a bit more plug/play.
Any ideas on where to begin?
Thanks as always!
My solution is not very elegant, but the idea was just to show how you can use basic Javascript with no additional libraries and just a bare bit of CSS to achieve this. I threw in a couple of additional values with a blue background to test out additional data. You can make it look better with additional CSS - and expand on the feature set here, but just wanted to throw something up that would reproduce the chart in your image.
var data = [{"x":1,"y":2,"qty":5,"color":"red"},
{"x":2,"y":4,"qty":10,"color":"green"},
//{"x":1,"y":4,"qty":8,"color":"blue"},
{"x":3,"y":1,"qty":15,"color":"green"},
//{"x":3,"y":2,"qty":77,"color":"purple"},
//{"x":5,"y":3,"qty":66,"color":"purple"},
//{"x":2,"y":1,"qty":22,"color":"blue"},
{"x":4,"y":3,"qty":20,"color":"red"}];
var chart = document.getElementById('chart');
var rows = 0;
var cols = 0;
// loop through and figure out how many rows and columns we will have
for (var i = 0; i < data.length; i++) {
if (data[i].x > rows) rows = data[i].x;
if (data[i].y > cols) cols = data[i].y;
if (rows > cols) cols = rows;
if (cols > rows) rows = cols;
yCt = rows;
}
drawChart(rows,cols);
function drawChart(rows,cols) {
var e = 0;
var f = 0;
while (e < rows) {
var square = '<div class="square"><div class="header">'+yCt+'</div></div>';
yCt--;
chart.innerHTML = chart.innerHTML + square;
addColumn(e);
e++;
}
if ( e == rows ) {
addHeader()
addValues()
}
}
function addHeader() {
var sq = document.getElementsByClassName('squareCol');
var ct = 0;
for (var i = 0; i < sq.length; i++) {
var element = sq[i];
if (element.getAttribute('data-y') == 1) {
ct++;
var heading = document.getElementById('heading');
heading.innerHTML = heading.innerHTML + '<div class="headerCol">'+ct+'</div>';
}
}
}
function addColumn(rowNumber) {
var row = document.getElementsByClassName('square')[rowNumber]
for (var i = 0; i < cols; i++) {
var x = i +1;
var y = rows - (rowNumber);
var squareCol = '<div class="squareCol" data-x="'+x+'" data-y="'+y+'"></div>';
row.innerHTML = row.innerHTML + squareCol;
}
}
function addValues() {
for (var i = 0; i < data.length; i++) {
var xVal = data[i].x;
var yVal = data[i].y;
var qty = data[i].qty;
var color = data[i].color;
var squares = document.getElementsByClassName('squareCol')
for (var j = 0; j < squares.length; j++) {
var element = squares[j];
if (element.getAttribute('data-x') == xVal && element.getAttribute('data-y') == yVal) {
element.innerHTML = '<div class="qty"><div class="inner">'+qty+'</div></div>'
element.className += ' '+ color;
}
} // end loop squares
}
}
#heading {
position:absolute;
margin-bottom:150px;
margin-left:100px;
width: 100%;
}
.header {
position:absolute;
line-height:4;
vertical-align:text-bottom;
text-align: center;
margin-left:-50px;
font-family:arial;
font-size:1.2rem;
font-weight:bold;
}
.headerCol {
display:inline-block;
border-width: 0;
line-height:3;
text-align: center;
font-family:arial;
font-size:1.2rem;
width: 50px;
font-weight:bold;
}
.square {
height: 50px;
}
.qty {
position: relative;
text-align:center;
line-height:3;
}
.inner {
position:absolute;
text-align:center;
margin:0;
width: 100%;
}
.squareCol {
width: 50px;
height: 50px;
box-shadow: inset 0 0 0 1px black;
display:inline-block;
font-family:arial;
font-size:1.2rem;
font-weight:bold;
}
#chart {
width: 600px;
margin-left:100px;
}
.blue {
background-color: lightblue;
}
.green {
background-color: #92D050;
}
.red {
background-color: #FF0000;
}
.purple {
background-color: violet;
}
<div id="chart"></div>
<div id="heading"></div>

Meeting Calendar | How to take care of the overlapping meetings to show in the calendar?

Sorry for the long question.
I have tried to create a meetings on a calendar for a day. I need help to take care of the overlapping intervals.
The code I have written in following :
HTML
<body>
<div id="timeline"></div>
<div id="calendar" class="calendar">
</div>
</body>
CSS
.calendar {
border: 1px solid black;
position: absolute;
width: 600px;
height: 1440px;
left: 60px;
}
.event {
position: absolute;
float: left;
width: 100%;
overflow: auto;
border: 0px solid red;
}
#timeline {
position: absolute;
float: left;
}
JS
function getRandomColor() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function creatTimeline(tl) {
var i = 0;
while (i < tl.length) {
var divEl = document.createElement('div');
divEl.style.width = '50px';
divEl.style.height = '120px';
divEl.style.border = '0px solid yellow';
divEl.innerHTML = tl[i];
var timeLine = document.getElementById('timeline');
timeLine.appendChild(divEl);
i++;
}
}
function appendEventDivs(eventArr) {
var i = 0;
while (i < eventArr.length) {
var eventEl = document.createElement('div');
eventEl.className = 'event';
eventEl.style.height = eventArr[i].height;
eventEl.style.top = eventArr[i].top;
eventEl.style.background = eventArr[i].color;
eventEl.style.width = eventArr[i].width;
eventEl.style.left = eventArr[i].left;
eventEl.innerHTML = 'Meeting' + eventArr[i].id;
var cl = document.getElementById('calendar');
cl.appendChild(eventEl);
i++;
}
}
function collidesWith(a, b) {
return a.end > b.start && a.start < b.end;
}
function checkCollision(eventArr) {
for (var i = 0; i < eventArr.length; i++) {
eventArr[i].cols = [];
for (var j = 0; j < eventArr.length; j++) {
if (collidesWith(eventArr[i], eventArr[j])) {
eventArr[i].cols.push(i);
}
}
}
return eventArr;
}
function updateEvents(eventArr) {
eventArr = checkCollision(eventArr);
var arr = [];
arr = eventArr.map(function(el) {
//just to differentiate each event with different colours
el.color = getRandomColor();
el.height = (el.end - el.start) * 2 + 'px';
el.top = (el.start) * 2 + 'px';
el.width = (600 / el.cols.length) + 'px';
return el;
});
return arr;
}
var events = [{
id: 123,
start: 60,
end: 150
}, {
id: 124,
start: 540,
end: 570
}, {
id: 125,
start: 555,
end: 600
}, {
id: 126,
start: 585,
end: 660
}];
var timeline = ['9AM', '10AM', '11AM', '12Noon', '1PM', '2PM', '3PM', '4PM', '5PM', '6PM', '7PM', '8PM', '9PM'];
function getEvents (eventArr) {
eventArr.sort(function(a, b) {
return a.start - b.start;
});
eventArr = updateEvents(eventArr);
appendEventDivs(eventArr);
console.log(eventArr);
//PART 1 - function returning the eventArr with all the required attributes
return eventArr;
};
creatTimeline(timeline);
getEvents(events);
Working fiddle here
Can anybody guide me how to take care of the overlapping intervals so that they appear side-by-side and not on top of each other.
Thanks in advance.
You need to figure out in which column each of the events should be before you can determine their width or left-position. To do this, you need to also store which of the colliding events came before each event:
function checkCollision(eventArr) {
for (var i = 0; i < eventArr.length; i++) {
eventArr[i].cols = [];
eventArr[i].colsBefore=[];
for (var j = 0; j < eventArr.length; j++) {
if (collidesWith(eventArr[i], eventArr[j])) {
eventArr[i].cols.push(j);
if(i>j) eventArr[i].colsBefore.push(j); //also list which of the conflicts came before
}
}
}
return eventArr;
}
Now, we can figure out the column of each event. Once we've done that, we can figure out how wide they should be, and with that, the horizontal positioning should be easy. This should be done inside your updateEvents function. I've got more detailed explanation commented in the comments of the code below.
function updateEvents(eventArr) {
eventArr = checkCollision(eventArr);
var arr=eventArr.slice(0); //clone the array
for(var i=0; i<arr.length; i++){
var el=arr[i];
el.color = getRandomColor();
el.height = (el.end - el.start) * 2 + 'px';
el.top = (el.start) * 2 + 'px';
if(i>0 && el.colsBefore.length>0){ //check column if not the first event and the event has collisions with prior events
if(arr[i-1].column>0){ //if previous event wasn't in the first column, there may be space to the left of it
for(var j=0;j<arr[i-1].column;j++){ //look through all the columns to the left of the previous event
if(el.colsBefore.indexOf(i-(j+2))===-1){ //the current event doesn't collide with the event being checked...
el.column=arr[i-(j+2)].column; //...and can be put in the same column as it
}
}
if(typeof el.column==='undefined') el.column=arr[i-1].column+1; //if there wasn't any free space, but it ito the right of the previous event
}else{
var column=0;
for(var j=0;j<el.colsBefore.length;j++){ //go through each column to see where's space...
if(arr[el.colsBefore[el.colsBefore.length-1-j]].column==column) column++;
}
el.column=column;
}
}else el.column=0;
}
//We need the column for every event before we can determine the appropriate width and left-position, so this is in a different for-loop:
for(var i=0; i<arr.length; i++){
arr[i].totalColumns=0;
if(arr[i].cols.length>1){ //if event collides
var conflictGroup=[]; //store here each column in the current event group
var conflictingColumns=[]; //and here the column of each of the events in the group
addConflictsToGroup(arr[i]);
function addConflictsToGroup(a){
for(k=0;k<a.cols.length;k++){
if(conflictGroup.indexOf(a.cols[k])===-1){ //don't add same event twice to avoid infinite loop
conflictGroup.push(a.cols[k]);
conflictingColumns.push(arr[a.cols[k]].column);
addConflictsToGroup(arr[a.cols[k]]); //check also the events this event conflicts with
}
}
}
arr[i].totalColumns=Math.max.apply(null, conflictingColumns); //set the greatest value as number of columns
}
arr[i].width=(600/(arr[i].totalColumns+1))+'px';
arr[i].left=(600/(arr[i].totalColumns+1)*arr[i].column)+'px';
}
return arr;
}
Working Fiddle: https://jsfiddle.net/ilpo/ftbjan06/5/
I added a few other events to test different scenarios.
Oh, and by the way, absolutely positioned elements can't float.
You already know the top and height of every event, so you could map the calendar and check an event already exist within the area it will occupy, then offset the left value by the number of existing events.

Gradient only on one section

On my previous post I asked how I'd get the gradient set up. Now the problem is that the gradient "spreads" out. Here's What I'm using
function generateCSSGradient(colours) {
var l = colours.length, i;
for( i=0; i<l; i++) colours[i] = colours[i].join(" ");
return "linear-gradient( to right, "+colours.join(", ")+")";
}
var cols = [
["red","0%"],
["red","40%"],
["yellow","40%"],
["yellow","60%"],
["green","60%"],
["green","80%"]
];
yourElement.style.background = generateCSSGradient(cols);
With this. What I want to do is say you fill in one input. And the bar goes to 33%, then that could be a red color. Then the next would be a blue and so fourth. Not like this. Any ideas? I'd also avoid using div
I think you want it like this ... See the source code
HTML
I'v edited the HTML code and added another div called colors inside the div top ...
<div class="top">
<div class="colors"></div>
</div>
CSS
Also I edited the CSS of .top and added to it overflow:hidden; and create .colors style
.top{
/*background: #009dff;*/
background:linear-gradient(to right,#009dff 0,#00c8ff 100%);
position:fixed;
z-index:1031;
top:0;
left:0;
height:4px;
transition:all 1s;
width:0;
overflow: hidden;
}
.colors{
width: 100%;
height: 4px;
}
JavsScript
Then edited the JavaScript and made the CSSGradient to colors not top , and let the JavaScript set the width of colors to fit the window width , and changed the colors percentage..
document.querySelector(".colors").style.background = generateCSSGradient(cols);
var window_width = window.innerWidth + "px";
document.querySelector(".colors").style.width = window_width;
var cols = [
["red","0%"],
["red","33.3%"],
["yellow","33.3%"],
["yellow","66.6%"],
["green","66.6%"],
["green","100%"]
];
Hope this will help you ...
Update
if you want to change the color of the bar like this , See the source code ...
just edit the JavaScript to be like this
function cback(e) {
var t = [];
for (var n = inputs.length; n--;) {
if (!inputs[n].value.length) t.push(inputs[n]);
}
var r = t.length;
var i = inputs.length;
var s = document.querySelectorAll(".top");
for (var o = s.length; o--;) {
s[o].style.width = 100 - r / i * 100 + "%";
s[o].style.background = cols[i-r-1];
}
}
var forms = document.querySelectorAll(".form"),
inputs = [];
for (var i = forms.length; i--;) {
var els = forms[i].querySelectorAll("input, textarea, select");
for (var j = els.length; j--;) {
if (els[j].type != "button" && els[j].type != "submit") {
inputs.push(els[j]);
els[j].addEventListener("input", cback, false);
}
}
}
var cols = ["red","yellow","green"];

Categories

Resources