I've been trying to make a little neural network. It plays a copy of the No-Wifi Google dinosaure game. It is not the most efficient (and probably has a tons of leaks), but it works after a hundred generations more or less. But I've notived something: the best elements of the previous generations do not copy to the next or don't act as before, shown by how the best before always jumped and then the next generation doesn't jump at all. Where is the problem? Btw it is a large code but I don't know how to attach files, can you comment on how?
HTML file:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" name="viewport" content="width=device-width,initial-scale=1">
<title>Dino</title>
<script type="text/javascript" src="genetic.js" defer></script>
<script type="text/javascript" src="dino.js" defer></script>
<script type="text/javascript" src="population_dino.js" defer></script>
<link rel="stylesheet" href="dino.css">
</head>
<body>
<div id="score">Score: 0</div>
<div id="line"></div>
<div id="test"></div>
</body>
</html>
genetic.js:
function sigmoid(t) {
return 1/(1+Math.pow(Math.E, -t));
}
function weightedRand(spec) {
var i, j, table=[];
for (i in spec) {
for (j=0; j<spec[i]*10; j++) {
table.push(i);
}
}
//console.log(table,spec)
return table[Math.floor(Math.random() * table.length)];
}
function randomfromminustoone(){
return Math.random()*2-1;
}
class Connection {
constructor(weight) {
if (weight==null){
this.weight=randomfromminustoone();
} else{
this.weight = weight;
}
}
get_weight() {
return this.weight;
}
set_weight(weight) {
return this.weight = weight;
}
}
class Neuron {
constructor(numOuputs = 0, neuronIndex, weights = []) {
this.outputWeights = [];
this.outputVal = null;
this.neuronIndex = neuronIndex;
for (let c = 0; c < numOuputs; c++) {
var weight = weights[c] || null;
this.outputWeights.push(new Connection(weight));
}
}
setOutputVal(outputVal) {
this.outputVal = outputVal;
}
getOutputVal(inputs,inputWeights) {
this.outputVal=0;
for (var i = inputs.length - 1; i >= 0; i--) {
this.outputVal+=inputs[i]*inputWeights[i];
}
this.outputVal=sigmoid(this.outputVal);
return this.outputVal;
}
getNeuronIndex() {
return this.neuronIndex;
}
getOuputWeight(i){
return this.outputWeights[i].get_weight();
}
updateInputWeights(prevLayer) {
for (let n = 0; n < prevLayer.length-1; n++) {
let neuron = prevLayer[n];
// neuron.outputWeights[this.neuronIndex].weight += ;
}
}
}
class Net {
constructor(topology = [],model=false) {
if (model){
this.layers=model.layers;
//console.log("flag");
} else {
this.topology = topology;
// number of layers
this.numLayers = topology.length;
this.layers = [];
for (let layerNum = 0; layerNum < this.numLayers; layerNum++) {
var layer = [];
var numOuputs = topology[layerNum + 1] ? topology[layerNum + 1] : 0;
for (let neuronNum = 0; neuronNum < topology[layerNum]; neuronNum++) {
let neuron = new Neuron(numOuputs, neuronNum);
layer.push(neuron);
}
this.layers.push(layer);
}
}
}
/*
getResults() {
this.resultVals = [];
var lastLayer = this.layers[this.layers.length-1];
for (let n = 0; n < lastLayer.length-1; n++) {
this.resultVals.push(lastLayer[n].getOutputVal());
}
return this.resultVals;
}*/
feedLayer(inputs,layerNum){
let layer=this.layers[layerNum];
let outputs=[];
for (let i = 0; i < layer.length; i++) {
let neuron = layer[i];
let neuronWeights=[];
for (let a = 0; a < this.layers[layerNum-1].length; a++) {
neuronWeights.push(this.layers[layerNum-1][a].getOuputWeight(i));
}
outputs.push(neuron.getOutputVal(inputs,neuronWeights));
}
return outputs;
}
feedAll(inputs){
let prevOutputs=inputs;
for (let i = 1; i < this.layers.length; i++) {
prevOutputs=this.feedLayer(prevOutputs,i);
}
return prevOutputs;
}
};
class Population{
constructor (PopNumber,topology,bestResults=[]){
if (bestResults.length>1){
this.population=[];
for (var i = 0; i < bestResults.length; i++) {
this.population.push(bestResults[i][1]);
console.log(bestResults[i][1].feedAll([0.05,0]))
}
for (var i = 0; i < PopNumber-bestResults.length; i++) {
let addNet= this.choose(bestResults);
/*if (randomfromminustoone()>0.5){
addNet=this.mix_elements(addNet,this.choose(bestResults));
}*/
addNet=this.mutate_values(addNet);
this.population.push(addNet);
}
} else {
this.population=[];
for (var i = 0; i < PopNumber; i++) {
let addNet= new Net(topology);
this.population.push(addNet);
}
}
}
choose(results){
let dic={};
for (var i = 0; i < results.length; i++) {
dic[i]=results[i][0];
}
return results[weightedRand(dic)][1];
}
mix_elements(elem1,elem2){
var output= new Net();
output.topology = elem2.topology;
output.numLayers = elem2.numLayers;
output.layers = elem2.layers;
for (var i = 0; i < elem1.layers.length; i++) {
for (var a = 0; a < elem1.layers[i].length; a++) {
if (randomfromminustoone()>0.5){
output.layers[i][a]=elem1.layers[i][a];
}
}
}
return output;
}
mutate_values(model){
if (model==null){
return [];
}
var output= new Net();
output.topology = model.topology;
output.numLayers = model.numLayers;
output.layers = model.layers;
for (var layer = 0; layer < output.layers.length; layer++) {
for (var neuron = 0; neuron < output.layers[layer].length; neuron++) {
for (var i = 0; i < output.layers[layer][neuron].outputWeights.length; i++) {
if (randomfromminustoone()>0.75){
output.layers[layer][neuron].outputWeights[i].weight =output.layers[layer][neuron].outputWeights[i].get_weight()+randomfromminustoone()/5;
}
}
}
}
return output;
}
};
dino.js:
function getRndInteger(min, max) {
return Math.floor(Math.random() * (max - min + 1) ) + min;
};
function Dino(brain,pop){
this.cooldown=0;
this.score=0;
this.alive=true;
this.y=300;
this.before_jump=this.y;
this.inertia=0;
this.population=pop;
this.div = document.createElement('div');
this.div.className="Dino";
this.div.main=this;
this.div.style.top=this.y+"px";
document.body.appendChild(this.div);
this.brain = brain;
};
Dino.prototype.jump = function(dino){
if (dino.y==dino.before_jump){
//dino.y=dino.before_jump;
dino.inertia=3;
dino.jumpInterval=setInterval( jump => {
dino.y-=dino.inertia
dino.div.style.top=dino.y+"px";
dino.inertia -= 0.05;
if (dino.y>dino.before_jump){
dino.inertia=0;
clearInterval(dino.jumpInterval);
dino.y=dino.before_jump;}
});
}
};
Dino.prototype.down = function(dino){
if (dino.y<dino.before_jump && dino.inertia>-5){
dino.inertia-=1.5;
}
};
Dino.prototype.lost =function(dino){
dino.alive=false;
dino.div.remove();
dino.score=dino.population.score;
dino.population.still_alive-=1;
dino.population.records.push(dino.brain);
delete dino;
};
Dino.prototype.check_collision = function(dino) {
cactuses=document.getElementsByClassName("cactus");
for (var i = cactuses.length - 1; i >= 0; i--) {
if (cactuses[i].main.x<=280 && dino.y>=280 && dino.alive){
dino.lost(dino);
}
};
};
Dino.prototype.smart = function(dino){
var cactuses=Array.from(document.getElementsByClassName("cactus"));
cactuses.sort(function(cactus){
return cactus.main.x;
});
if (cactuses.length>0){
var distance_nearest_cactus=(cactuses[0].main.x-240)/660;
} else{
var distance_nearest_cactus=1;
};
let results = dino.brain.feedAll([distance_nearest_cactus,(300-dino.y)/100*(-dino.inertia/3)]);
let high_score=results.indexOf(Math.max.apply(Math,results))
if (high_score==0){
dino.jump(dino);
} else if (high_score==1){
dino.down(dino);
};
};
function Dot(height){
this.y=height
this.x=900
//-- cree le DIV
this.div = document.createElement('div');
this.div.className = 'dot';
this.div.style.top=this.y+"px";
this.div.style.left=this.x+"px";
this.div.main=this;
document.body.appendChild(this.div);
};
Dot.prototype.delete =function(leave_div)
{
if (leave_div == false){
this.div.remove();
}
delete this;
};
function CreateDot(){
new Dot(getRndInteger(346,350));
};
function Cactus(){
this.x=900
this.div = document.createElement('div');
this.div.style.left=this.x+"px";
this.div.className="cactus";
this.div.main=this;
document.body.appendChild(this.div);
};
Cactus.prototype.delete =function(leave_div)
{
if (leave_div == false){
this.div.remove();}
delete this;
}
function CreateCactus(){
new Cactus();
}
function move_object(object){
object.main.x -= 1;
object.main.div.style.left = object.main.x+'px';
if (object.main.x<230)
{
object.main.delete(false);
}
};
population_dino.js:
class Dino_population{
constructor(nbPopulation,id,prevPop=[]){
this.population=[];
this.id=id;
document.getElementById("test").innerHTML=this.id;
this.brains=new Population(nbPopulation,[2,5,5,3],prevPop);
for (var i = 0; i < nbPopulation; i++) {
this.population.push(new Dino(this.brains.population[i],this));
}
this.number=nbPopulation;
this.still_alive=nbPopulation;
this.score=0;
this.speed=4.5;
var self= this;
this.move_interval=setInterval(function(){self.move_all(self)},self.speed);
this.last_cactus=1000;
this.records=[];
}
move_all(self){
if (getRndInteger(0,60)<10){
CreateDot();
}
self.last_cactus-=getRndInteger(1,10);
if (self.last_cactus<10){
self.last_cactus=getRndInteger(500,5000);
CreateCactus();
}
var cactuses=document.getElementsByClassName("cactus");
for (var i = cactuses.length - 1; i >= 0; i--) {
move_object(cactuses[i]);
};
var dots=document.getElementsByClassName("dot");
for (var v = dots.length - 1; v >= 0; v--) {
move_object(dots[v]);
}
self.score+=1;
document.getElementById("score").innerHTML = "Score: "+Math.floor(self.score/10).toString();
for (var i = self.population.length - 1; i >= 0; i--) {
let dino=self.population[i];
dino.cooldown-=1;
if (dino.cooldown<=0){
dino.cooldown=10;
dino.smart(dino);
}
dino.check_collision(dino);
}
if (self.still_alive==0){
clearInterval(self.move_interval);
var cactuses=document.getElementsByClassName("cactus");
while (cactuses.length>0){
delete cactuses[0].main;
cactuses[0].remove();
};
var dots=document.getElementsByClassName("dot");
while (dots.length>0){
delete dots[0].main;
dots[0].remove();
};
self.new_pop(self);
}
}
new_pop(old){
let old_bests= old.records.slice(Math.max(old.records.length - 10, 0));
let old_best_weighted=[]
for(let i=0;i<old_bests.length;i++){
console.log([old_bests[i].feedAll([0.05,0])])
old_best_weighted.push([10-i,old_bests[i]]);
}
let old_nb=old.number;
let old_id=old.id;
globalThis.pop= new Dino_population(old_nb,old_id+1,old_best_weighted);
}
}
var pop=new Dino_population(200,1);
dino.css:
.Dino{
background-image: url("Dinausaure.png");
background-repeat: no-repeat;
background-size: contain;
width: 60px;
height: 45px;
left: 240px;
position: absolute;
z-index: 3;
}
#ground{
width: 1000px;
height: 200px;
top:270px;
left: 240px;
position: absolute;
}
#line{
width: 670px;
height: 0px;
top:345px;
left:230px;
border-top: 2px solid black;
position: absolute;
z-index: 1;
}
.dot{
border-top: 2px solid black;
width: 2px;
position: absolute;
z-index: 1;
}
.cactus{
background-image: url("cactus.png");
background-repeat: no-repeat;
background-size: contain;
width: 60px;
height: 40px;
top:310px;
position: absolute;
z-index: 0;
}
#score{
top:180px;
left:230px;
position: absolute;
}
Here are the images:
Do no doubht in telling me any optimisation, mistake or bug. I am new at neural networks and do not have much experience with Js.
Any question ask me on comments.
Related
A function defined in setTimeOut only runs once in certain situations
I set up 3 inputs in ComboBox by which the user could set the grid size in the game. Selecting a value changes the rows and cols variables respectively, and then reboots the game by calling the init function.
The program starts normally, when I choose a different size the timer does not run the game more than once. When I change the size again it does work. If for example I change the sizes 6 times the game will only work in 3 of the times.
/* Game Of Life Application */
/* ------------------------ */
// initialize global variables
var rows = 55;
var cols = 140;
//initialize 2dim arrays
var arr;// current generation array
var nextArr; // next generation array
var mode = 0; //game current mode
var timeInMS = 40;
var timer;
//buttons selectors
var randomBtn = document.getElementById("randomBtnId");
var startBtn = document.getElementById("startBtnId");
var clearBtn = document.getElementById("clearBtnId");
var gridSize = document.getElementById("sizeId");
var container = document.getElementById("container");
function remove() {
let tb = document.querySelector("table");
tb.outerHTML = "";
}
gridSize.addEventListener("change",function(e) {
remove();
if (this.value === "Small") {
cols = 80;
rows = 20;
}
else if (this.value === "Medium") {
cols = 126;
rows = 34;
}
else {
cols = 140;
rows = 55;
}
timer = 0;
init();
});
//update the visual grid according to the states of the cell - live or dead.
function update() {
for (var i = 0; i < rows; i++) {
for (var j = 0; j < cols; j++) {
var cell = document.getElementById(i + "_" + j);
if (arr[i][j] === 0) {
cell.setAttribute("class", "dead");
} else {
cell.setAttribute("class", "live");
}
}
}
}
//copy generation 0 array to generation 1. current arr gets the values of next arr
function copyAndResetGrid() {
console.log("in the reset grid");
for (var i = 0; i < rows; i++) {
for (var j = 0; j < cols; j++) {
arr[i][j] = nextArr[i][j];
nextArr[i][j] = 0;
}
}
}
//count number of neighbors for every cell - inputs are r - rows , c - columns
function countNeighbors(r, c) {
let rstart = 0, cstart = 0, rend = rows - 1, cend = cols - 1;
let count = 0;
if (r - 1 > 0)
rstart = r - 1;
if (c - 1 > 0)
cstart = c - 1;
if (r + 1 <= rend)
rend = r + 1;
if (c + 1 <= cend)
cend = c + 1;
for (let i = rstart; i <= rend; i++) {
for (let j = cstart; j <= cend; j++) {
if (arr[i][j] === 1)
count++;
}
}
count -= arr[r][c];
if (count < 0)
count = 0;
// console.log("number of live neighbors at : " + r + "," + c + " is : " + count);
return count;
}
// calculate next 2dim array (generation 1) according to gameOfLife rules
function calculateNext() {
let numOfLivesArr = 0;
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
let currentMode = arr[i][j];
if (currentMode === 1)
numOfLivesArr++;
let count = countNeighbors(i, j);
if (currentMode === 0 && count === 3) {
nextArr[i][j] = 1;
}
else if (currentMode === 1 && (count < 2 || count > 3)) {
nextArr[i][j] = 0;
}
else {
nextArr[i][j] = currentMode;
}
}
}
// console.log("num of lives next: " + numOfLivesArr);
copyAndResetGrid();
//update();
}
//run game
function run() {
calculateNext();
update();
timer = setTimeout(run, 1000);
}
//populate the array with random values 0/1
function populateArr() {
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
arr[i][j] = Math.floor(Math.random() * 2);
if (arr[i][j] === 1) {
let cell = document.getElementById(i + "_" + j);
cell.setAttribute("class", "live");
}
else {
let cell = document.getElementById(i + "_" + j);
cell.setAttribute("class", "dead");
}
}
}
}
function deleteArr() {
}
//clear array - set 0 values for current and next generations arrays
function clear() {
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
arr[i][j] = 0;
nextArr[i][j] = 0;
}
}
//mode = 0;
}
function buttonsControl() {
randomBtn.addEventListener("click", function () {
clear();
populateArr();
});
startBtn.addEventListener("click", function () {
if (mode == 1) {
mode = 0;
startBtn.textContent = "Continue";
clearTimeout(timer);
}
else {
mode = 1;
startBtn.textContent = "Pause";
run();
}
});
clearBtn.addEventListener("click", function () {
startBtn.textContent = "Start";
clear();
update();
})
}
//draw table grid in the web page
function drawGrid() {
let grid = document.getElementById("container");
let table = document.createElement("table");
table.setAttribute("class", "center");
for (let i = 0; i < rows; i++) {
let tr = document.createElement("tr");
for (let j = 0; j < cols; j++) {
let cell = document.createElement("td");
cell.setAttribute("id", i + "_" + j);
cell.setAttribute("class", "dead");
tr.appendChild(cell);
cell.addEventListener("click", function () {
if (cell.classList.contains("live")) {
cell.setAttribute("class", "dead");
arr[i][j] = 0;
}
else
cell.setAttribute("class", "live");
arr[i][j] = 1;
});
}
table.appendChild(tr);
}
grid.appendChild(table);
}
//create 2 dim arrays - current and next generations.
function make2DArr() {
console.log("befire create arr !! ");
for (let i = 0; i < rows; i++) {
arr[i] = new Array(cols);
nextArr[i] = new Array(cols);
}
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
arr[i][j] = 0;
nextArr[i][j] = 0;
}
}
}
//initial game
function init() {
arr = new Array(rows);
nextArr = new Array(rows);
make2DArr();
drawGrid();
buttonsControl();
}
//load init function
window.onload = init();
body {
background-color: rgba(76, 77, 62, 0.514);
}
.center {
margin: auto;
width: 90%;
padding: 0.5rem;
position: relative;
}
#container {
margin: 0;
position: relative;
overflow: auto;
display: flex;
}
table {
border:1px rgb(241, 241, 241) solid;
border-spacing: 0;
position: absolute;
flex:1;
}
.live {
background-color:rgba(0, 0, 0, 0.685);
}
.dead {
background-color:rgba(228, 228, 241, 0.829);
}
td {
border:1px rgb(29, 182, 29) solid;
/* border-radius: 61px;*/
width: 10px;
height: 10px;
}
/* button {
margin-left: 0.5rem;
} */
button {
background-color: #4CAF50; /* Green */
border: none;
color: white;
padding: 1rem 2rem;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 0.5rem 0.5rem;
transition-duration: 0.4s;
cursor: pointer;
}
button:hover {
background-color: rgba(144, 180, 145, 0.596);
color: rgb(54, 59, 54)
}
<body>
<div class="center">
<div id="container">
</div>
<button id="startBtnId"><span>Start</span></button>
<button id="clearBtnId"><span>Clear</span></button>
<button id="randomBtnId"><span>Random</span></button>
<select id="sizeId">
<option value="Big">Big</option>
<option value="Medium">Medium</option>
<option value="Small">Small</option>
</select>
</div>
<script type="text/javascript" src="game.js"></script>
</body>
the timer is work only in even number of mode selection and does not work in odd number of mode selection.
for example , if i changed the mode 4 times : work -> not -> word -> not
Once an option has been selected from the list, init function was called. Within the function I called for 3 functions that build the arrays, initialize the board and create the button events listeners. The solution is to build the arrays and initialize the board without create the buttons event listeners again. so i just calld make2darray and drawgrid functions.
I'm writing simple Sudoku solver as an exercise and I've thought that I will show entire process by displaying it step by step on 9x9 grid.
I'm using HTML table with nested divs for displaying game board (probably not relevant) and recursive function for solving preseeded Sudoku. My solution is in "spaghetti" state right now, so below I give you pseudocode for what I have:
function fillBoard() {
for(let i = 0; i < 9; i++) {
for(let j = 0; j < 9; j++) {
const cell = document.querySelector(`div[data-row="${i}"][data-column="${j}"]`);
cell.innerHTML = gameState.solution[i][j];
}
}
}
function solve(row, column) {
/* simplified, it's working :) */
for(let guess = 1; guess < 10; guess++) {
this.solution[row][column] = guess; <--- SHOW THIS STEP TO USER
let conflicts = checkConflicts(row, column)
if(!conflicts) {
let emptyCell = this.findNextEmptyCell(row, column);
if(emptyCell) {
let result = this.solve(emptyCell.i, emptyCell.j);
if(!result) continue;
else return true;
}
return true;
}
else continue;
}
}
I've tried putting fillBoard() function call inside solve() but that obviously didn't worked as I'm getting only the final result in form of solved grid. I've also tried using setInterval(fillBoard, 100) but solve() function is executing too fast.
How can I achieve "incremental" displaying of entire solving process by updating HTML after each solve() call?
I'm trying to get something like this: https://www.youtube.com/watch?v=ChjQRIhH414 but I'm filling the board left-right, top-bottom
Current solution: Codepen
You'll want to slow down your html rendering process, which suggests animation to me. You can look into this approach, and maybe throttle it if you want. Without having a complete example I can't run it to be sure. I'll give you some pseudo code in response for the way I would test it to start with, and hopefully that'll point you in the right direction:
function fillBoard(i=0, j=0) {
const cell = document.querySelector(`div[data-row="${i}"][data-column="${j}"]`);
cell.innerHTML = gameState.solution[i][j];
j++;
if( j >= 9) { j = 0; i++; }
if(i < 9)
requestAnimationFrame(function() { fillBoard(i,j) });
}
If you want, you can replace requestAnimationFrame with a setTimeout on a given delay. You can set it to 1-2 seconds or something to start with to see if it gives you the results you're looking for.
Unoptimized, but working example, by following #loctrice advice from comments above. Still looking for other solutions to this problem.
console.clear();
let states = [];
let x = 0;
document.addEventListener("DOMContentLoaded", function() {
const start = document.getElementById("start");
const check = document.getElementById("check");
const sudoku = document.getElementById("sudoku");
function fillBoard(index) {
console.log(`Displaying ${index}/${states.length}`);
for (let i = 0; i < 9; i++) {
for (let j = 0; j < 9; j++) {
const cell = document.querySelector(
`div[data-row="${i}"][data-column="${j}"]`
);
cell.innerHTML =
states[index][i][j] == 0 ? "" : states[index][i][j];
}
}
}
class Sudoku {
checkRow(row) {
for (let i = 0; i < 9; i++) {
let number = this.solution[row][i];
if (!number) continue;
for (let j = 0; j < 9; j++) {
if (i == j) continue;
const challenge = this.solution[row][j];
if (number == challenge) return number;
}
}
return false;
}
checkColumn(column) {
for (let i = 0; i < 9; i++) {
let number = this.solution[i][column];
if (!number) continue;
for (let j = 0; j < 9; j++) {
if (i == j) continue;
const challenge = this.solution[j][column];
if (number == challenge) return number;
}
}
return false;
}
checkBox(box) {
const rowModifier = Math.floor(box / 3) * 3;
const colModifier = (box % 3) * 3;
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let number = this.solution[i + rowModifier][j + colModifier];
if (!number) continue;
for (let x = 0; x < 3; x++) {
for (let y = 0; y < 3; y++) {
if (x == i && y == j) continue;
const challenge = this.solution[x + rowModifier][y + colModifier];
if (number == challenge) return number;
}
}
}
}
return false;
}
solve(row, column, array) {
for (let guess = 1; guess < 11; guess++) {
if (guess == 10) {
this.solution[row][column] = 0;
return false;
}
this.solution[row][column] = guess; // <=== SHOW ENTIRE BOARD HERE
let state = this.solution.map(a => [...a]);
array.push(state);
const rowError = this.checkRow(row);
const columnError = this.checkColumn(column);
const boxError = this.checkBox(
3 * Math.floor(row / 3) + Math.floor(column / 3)
);
if (!rowError && !columnError && !boxError) {
// find next empty cell
let emptyCell = this.findNextEmptyCell(row, column);
if (emptyCell) {
let result = this.solve(emptyCell.i, emptyCell.j, array);
if (!result) continue;
else return true;
}
return true;
} else continue;
}
}
findNextEmptyCell(row, column) {
for (let i = row; i < 9; i++) {
if (column == 8) column = 0;
for (let j = column; j < 9; j++) {
if (this.solution[i][j]) continue;
else return { i: i, j: j };
}
column = 0;
}
return false;
}
generateBox(boxNumber) {
let numbers = [];
for (let i = 0; i < 9; i++) {
numbers.push(i);
}
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
const length = numbers.length;
const index = Math.floor(Math.random() * length);
const number = numbers.splice(index, 1);
const row = i + boxNumber * 3 / 4;
const col = j + boxNumber * 3 / 4;
this.solution[row][col] = parseInt(number) + 1;
}
}
}
initialize() {
this.solution = [];
for (let i = 0; i < 9; i++) {
this.solution.push([]);
for (let j = 0; j < 9; j++) {
this.solution[i][j] = 0;
}
}
for (let i = 0; i < 3; i++) {
this.generateBox(i * 4);
}
}
}
let gameState = new Sudoku();
gameState.initialize();
start.onclick = function() {
gameState.solve(0, 3, states);
window.setInterval(function() {if(x < states.length) fillBoard(x++);}, 15);
};
check.onclick = function() {
for (let i = 0; i < 9; i++) {
let error = gameState.checkRow(i);
if (error) {
for (let j = 0; j < 9; j++) {
const cell = document.querySelector(
`div[data-row="${i}"][data-column="${j}"]`
);
cell.classList.add("incorrect-area");
if (cell.innerHTML == error) cell.classList.add("incorrect");
}
return;
}
error = gameState.checkColumn(i);
if (error) {
const cells = document.querySelectorAll(`div[data-column="${i}"]`);
cells.forEach(c => {
c.classList.add("incorrect-area");
if (c.innerHTML == error) c.classList.add("incorrect");
});
return;
}
error = gameState.checkBox(i);
if (error) {
const cells = document.querySelectorAll(`div[data-box="${i}"]`);
cells.forEach(c => {
c.classList.add("incorrect-area");
if (c.innerHTML == error) c.classList.add("incorrect");
});
return;
}
}
};
for (let i = 0; i < 9; i++) {
const row = document.createElement("tr");
row.classList.add("row");
for (let j = 0; j < 9; j++) {
let td = document.createElement("td");
let cell = document.createElement("div");
cell.classList.add("cell");
cell.dataset.row = i;
cell.dataset.column = j;
let a = Math.floor(i / 3);
let b = Math.floor(j / 3);
cell.dataset.box = 3 * a + b;
cell.innerHTML =
gameState.solution[i][j] == "0" ? "" : gameState.solution[i][j];
if (!cell.innerHTML)
cell.onclick = function(e) {
const row = e.target.dataset.row;
const col = e.target.dataset.column;
gameState.solution[row][col] =
++gameState.solution[row][col] > 9
? 0
: gameState.solution[row][col];
cell.innerHTML =
gameState.solution[row][col] == "0"
? ""
: gameState.solution[row][col];
document
.querySelectorAll("div.cell")
.forEach(c =>
c.classList.remove("correct", "incorrect", "incorrect-area")
);
};
td.appendChild(cell);
row.appendChild(td);
}
sudoku.appendChild(row);
}
});
.incorrect-area {
background-color: #A55 !important;
border-color: #F00 !important;
}
.correct {
background-color: #1A1 !important;
border-color: #0F0 !important;
}
.incorrect {
background-color: #A11 !important;
border-color: #F00 !important;
}
div[data-box='1'],
div[data-box='3'],
div[data-box='5'],
div[data-box='7'] {
background-color: #444;
}
.button {
display: inline-block;
min-height: 30px;
width: 120px;
background-color: white;
font-size: 32px;
cursor: pointer;
}
#buttons {
text-align: center;
}
div {
padding: 0px;
}
body {
background-color: #000;
}
#game {
width: 500px;
margin-left: auto;
margin-right: auto;
margin-top: 0px;
}
#sudoku {
width: 500px;
height: 500px;
margin-left: auto;
margin-right: auto;
background-color: #111;
border: dashed 1px white;
color: white;
}
.row {
border: 1px solid yellow;
}
.cell {
cursor: default;
height: 40px;
width: 40px;
padding: 0;
margin: 0;
border: solid white 1px;
text-align: center;
font-weight: bold;
display: table-cell;
vertical-align: middle;
user-select: none;
}
.cell:hover {
background-color: #765;
transform: scale(1.3);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>SudoQ</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="screen" href="main.css" />
<script src="main.js"></script>
</head>
<body>
<div id="game">
<div id="buttons">
<div id="start" class="button">SOLVE</div>
<div id="check" class="button">CHECK</div>
</div>
<table id="sudoku">
</table>
</div>
</body>
</html>
I need a rainbow function in plain javascript.
Solution 1: Javascript + HSL
this should be working in any browser
window.addEventListener("load", function() {
var elements = document.getElementsByClassName("rainbowText");
for (let i = 0; i < elements.length; i++) {
generateRainbowText(elements[i]);
}
});
function generateRainbowText(element) {
var text = element.innerText;
element.innerHTML = "";
for (let i = 0; i < text.length; i++) {
let charElem = document.createElement("span");
charElem.style.color = "hsl(" + (360 * i / text.length) + ",80%,50%)";
charElem.innerHTML = text[i];
element.appendChild(charElem);
}
}
p {
font-size: 2em;
font-weight: 500;
}
<p class="rainbowText">This is an awesome text</p>
Solution 2: background-clip + linear-gradient
This is a webkit only answer (Chrome) but should be more efficient.
Update (01/2021): This is supported by modern browsers.
For compatibility list, check background-clip: text (including those with only -webkit- prefix support) here (MDN)
let nb_stops = 10; // 10 color stops should be enough
let dir = "left"; // left, right, top, bottom
function SetupRainbow() {
var rainbowStr = GetRainbowString(nb_stops, 80, 50);
var oppositeDir = (dir==="left"?"right":(dir==="right"?"left":(dir==="top"?"bottom":"top")));
var css = '.rainbowText {\
background-clip: text;\
color: transparent;\
-webkit-background-clip: text;\
-webkit-text-fill-color: transparent;\
background-image: -webkit-linear-gradient(' + dir + ',' + rainbowStr + '); \
background-image: linear-gradient(to ' + oppositeDir + ',' + rainbowStr + ') \
}'
var style = document.createElement("style");
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
document.head.appendChild(style);
}
// function that generate the rainbow string
function GetRainbowString(nbStops, saturation, luminosity) {
let gap = 360 / nbStops,
colors = [];
for (let i = 0; i < nbStops; i++) {
colors.push("hsl(" + (i * gap) + "," + saturation + "%," + luminosity + "%)");
}
return colors.join();
}
window.addEventListener("load", function() {
SetupRainbow();
});
span {
font-size: 2em;
font-weight: 500;
}
<span class="rainbowText">This is an awesome text</span>
It depends on what kind of rainbow text do you want. Some rainbow styles are really elegant.
Here are few :-
A pen from codepen.
Another pen here.
animated rainbow text at jsfiddle.
<div class="rainbow-text">Words and things</div>
#keyframes rainbow-text {
0% {
color: #e87d7d;
}
2% {
color: #e88a7d;
}
4% {
color: #e8977d;
}
6% {
color: #e8a47d;
}
8% {
color: #e8b07d;
}
10% {
color: #e8bd7d;
}
12% {
color: #e8ca7d;
}
14% {
color: #e8d77d;
}
16% {
color: #e8e47d;
}
18% {
color: #dfe87d;
}
20% {
color: #d3e87d;
}
22% {
color: #c6e87d;
}
24% {
color: #b9e87d;
}
26% {
color: #ace87d;
}
28% {
color: #9fe87d;
}
30% {
color: #92e87d;
}
32% {
color: #86e87d;
}
34% {
color: #7de881;
}
36% {
color: #7de88e;
}
38% {
color: #7de89b;
}
40% {
color: #7de8a8;
}
42% {
color: #7de8b5;
}
44% {
color: #7de8c1;
}
46% {
color: #7de8ce;
}
48% {
color: #7de8db;
}
50% {
color: #7de8e8;
}
52% {
color: #7ddbe8;
}
54% {
color: #7dcee8;
}
56% {
color: #7dc1e8;
}
58% {
color: #7db5e8;
}
60% {
color: #7da8e8;
}
62% {
color: #7d9be8;
}
64% {
color: #7d8ee8;
}
66% {
color: #7d81e8;
}
68% {
color: #867de8;
}
70% {
color: #927de8;
}
72% {
color: #9f7de8;
}
74% {
color: #ac7de8;
}
76% {
color: #b97de8;
}
78% {
color: #c67de8;
}
80% {
color: #d37de8;
}
82% {
color: #df7de8;
}
84% {
color: #e87de4;
}
86% {
color: #e87dd7;
}
88% {
color: #e87dca;
}
90% {
color: #e87dbd;
}
92% {
color: #e87db0;
}
94% {
color: #e87da4;
}
96% {
color: #e87d97;
}
98% {
color: #e87d8a;
}
100% {
color: #e87d7d;
}
}
.rainbow-text {
animation: rainbow-text 1s infinite;
}
I researched the same thing and came up with this:
var css = 'body {animation-name:test; animation-duration:4s; animation-iteration-count:infinite; } #keyframes test{ 0%{color:#ff0000} 20%{color:#00ff00} 40%{color:#ffff00} 60%{color:#0000ff} 80%{color:#00ffff} 100%{color:#ff0000}', head = document.head || document.getElementsByTagName('head')[0], style = document.createElement('style'); style.type = 'text/css'; if (style.styleSheet){ style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style);
<p>WOO!<p>
This also works as a bookmarklet, with great results!
const colors = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];
var temp=document.getElementsByTagName('span');
for(let i=0;i<colors.length;i++){
temp[i].style.color=colors[i];
}
<!DOCTYPE html>
<head>
<title>Rainbow</title>
<script src="node_modules/babel-polyfill/dist/polyfill.js" type="text/javascript"> </script>
<script src="https://unpkg.com/#babel/standalone/babel.min.js"></script>
</head>
<body>
<h1>
<span>R</span>
<span>A</span>
<span>I</span>
<span>N</span>
<span>B</span>
<span>O</span>
<span>W</span>
</h1>
</body>
</html>
function rainbow(str) {
var multiplier = 5;
var result = "";
for (var i = 0; i < str.length; i++) {
result += "<font style='color: hsl(" + i * multiplier % 360 + ", 100%, 70%)'>";
result += str.substr(i, 1);
result += "</font>";
}
return result;
}
And it does the same in less time.
Pretty old question, but if anyone's still looking for a plain javascript ONLY answer to animated rainbow text (of which you can control direction and speed if you look hard enough through my spaghetti), here's my version: https://github.com/FeedbackFox/RGB-CSS-script
Working JSfiddle: https://jsfiddle.net/FeedbackFox/68ekobav/1/
//Script made by FeedbackFox. Please refrain from distributing this outside of github, but feel free to use it in whatever you want, whether commercial or non-commercial.
//https://github.com/FeedbackFox/RGB-CSS-script
(function(){
let textspeed = 1;
let backgroundspeed = 0.1;
let hoverspeed = 10;
let hoverbackgroundspeed = -1;
let classestoberainbowed = document.getElementsByClassName('foxrainbow');
let backgroundtoberainbowed = document.getElementsByClassName('foxrainbowbg');
let spanstoberainbowed = spanArrayContents(classestoberainbowed);
textcolorchange(spanstoberainbowed, textspeed);
//Actually do the rainbow effect. Backgrounds only.
let backgroundcounter = 0;
setInterval(() => {
for(let i = 0; i < backgroundtoberainbowed.length; i++) {
backgroundtoberainbowed[i].style.backgroundColor = 'hsl(' + (backgroundcounter + Math.floor(i * 1)) + ', 100%, 70%';
}
backgroundcounter = backgroundcounter + backgroundspeed;
}, 15);
//Turn the rainbow effect on only when the mouse is over the element. Use foxrainbowhover to use.
let rainbowhover = document.getElementsByClassName('foxrainbowhover');
let invertedhover = document.getElementsByClassName('foxrainbowhoverinv');
let rainbowelements = [];
let rainbowinvelements = [];
let hoverinterval = [];
let hoverinvinterval = [];
let hovercounters = [];
let invcounters = [];
let originalcolors = [];
let originalinvcolors = [];
for(let i = 0; i < rainbowhover.length; i++) {
rainbowelements[i] = spanElementContents(rainbowhover[i]);
}
for(let i = 0; i < invertedhover.length; i++) {
rainbowinvelements[i] = spanElementContents(invertedhover[i]);
}
//Set up the wavey effect with counters.
for(let id = 0; id < rainbowelements.length; id++) {
hovercounters[id] = [];
for(let i = 0; i < rainbowelements[id].length; i++) {
hovercounters[id].push(i);
}
}
for(let id = 0; id < rainbowinvelements.length; id++) {
invcounters[id] = [];
for(let i = 0; i < rainbowinvelements[id].length; i++) {
invcounters[id].push(i);
}
}
//Save the original color to easily return to it later.
for(let i = 0; i < rainbowhover.length; i++) {
originalcolors[i] = rainbowhover[i].style.color;
}
// Add event listeners for every item classed foxrainbowhover. If it has a data tag called foxrainbowhover with an id inside it instead uses that to start the hover effect.
for(let id = 0; id < rainbowhover.length; id++) {
//Checks if the passed along id exists or not. If it doesn't, execute regularly. If it does, execute with hover on a different element.
if(rainbowhover[id].dataset.foxrainbowhover) {
let hoverelement = document.getElementById(rainbowhover[id].dataset.foxrainbowhover);
hoverelement.addEventListener("mouseenter", function startanimation() {
hoverinterval[id] = setInterval(() => {
for(let i = 0; i < rainbowelements[id].length; i++) {
rainbowelements[id][i].style.color = 'hsl(' + (hovercounters[id][i] + Math.floor(i * hoverspeed)) + ', 100%, 70%';
hovercounters[id][i]++;
}
}, 7);
}, false);
hoverelement.addEventListener("mouseleave", function stopanimation() {
console.log("gay1");
clearInterval(hoverinterval[id]);
for(let i = 0; i < rainbowelements[id].length; i++) {
rainbowelements[id][i].style.color = originalcolors[id];
}
}, false);
}
else {
rainbowhover[id].addEventListener("mouseenter", function startanimation() {
hoverinterval[id] = setInterval(() => {
for(let i = 0; i < rainbowelements[id].length; i++) {
rainbowelements[id][i].style.color = 'hsl(' + (hovercounters[id][i] + Math.floor(i * hoverspeed)) + ', 100%, 70%';
hovercounters[id][i]++;
}
}, 7);
}, false);
rainbowhover[id].addEventListener("mouseleave", function stopanimation() {
clearInterval(hoverinterval[id]);
for(let i = 0; i < rainbowelements[id].length; i++) {
console.log("gay1");
rainbowelements[id][i].style.color = originalcolors[id];
}
}, false);
}
}
//Same code as before. Will make it way DRY-er later, but for now, this'll have to do.
for(let i = 0; i < invertedhover.length; i++) {
originalinvcolors[i] = invertedhover[i].style.color;
}
let startinterval = [];
// Add event listeners for every item classed foxrainbowhoverinv.
for(let id = 0; id < invertedhover.length; id++) {
startinterval[id] = setInterval(() => {
for(let i = 0; i < rainbowinvelements[id].length; i++) {
rainbowinvelements[id][i].style.color = 'hsl(' + (invcounters[id][i] + Math.floor(i * hoverspeed)) + ', 100%, 70%';
invcounters[id][i]++;
}
}, 7);
//Checks if the passed along id exists or not. If it doesn't, execute regularly. If it does, execute with hover on a different element.
if(invertedhover[id].dataset.foxrainbowhover) {
let hoverelement = document.getElementById(invertedhover[id].dataset.foxrainbowhover);
hoverelement.addEventListener("mouseenter", function stopanimation() {
clearInterval(startinterval[id]);
clearInterval(hoverinvinterval[id]);
for(let i = 0; i < rainbowinvelements[id].length; i++) {
rainbowinvelements[id][i].style.color = originalinvcolors[id];
}
}, false);
hoverelement.addEventListener("mouseleave", function startanimation() {
hoverinvinterval[id] = setInterval(() => {
for(let i = 0; i < rainbowinvelements[id].length; i++) {
rainbowinvelements[id][i].style.color = 'hsl(' + (invcounters[id][i] + Math.floor(i * hoverspeed)) + ', 100%, 70%';
invcounters[id][i]++;
}
}, 7);
}, false);
}
else {
invertedhover[id].addEventListener("mouseenter", function stopanimation() {
clearInterval(startinterval[id]);
clearInterval(hoverinterval[id]);
for(let i = 0; i < rainbowinvelements[id].length; i++) {
rainbowinvelements[id][i].style.color = originalinvcolors[id];
}
}, false);
invertedhover[id].addEventListener("mouseleave", function startanimation() {
hoverinterval[id] = setInterval(() => {
for(let i = 0; i < rainbowinvelements[id].length; i++) {
rainbowinvelements[id][i].style.color = 'hsl(' + (invcounters[id][i] + Math.floor(i * hoverspeed)) + ', 100%, 70%';
invcounters[id][i]++;
}
}, 7);
}, false);
}
}
//Hover but for backgrounds.
let rainbowhoverbg = document.getElementsByClassName('foxrainbowhoverbg');
let hoverbginterval = [];
let hoverbgcounter = 0;
let originalbgcolors = [];
//Save the original color to easily return to it later, but for backgrounds.
for(let i = 0; i < rainbowhoverbg.length; i++) {
originalbgcolors[i] = rainbowhoverbg[i].style.backgroundColor;
}
for(let id = 0; id < rainbowhoverbg.length; id++) {
rainbowhoverbg[id].addEventListener("mouseenter", function startbganimation() {
hoverbginterval[id] = setInterval(() => {
rainbowhoverbg[id].style.backgroundColor = 'hsl(' + (hoverbgcounter + Math.floor(id * hoverbackgroundspeed)) + ', 100%, 70%';
hoverbgcounter++;
}, 15);
}, false);
rainbowhoverbg[id].addEventListener("mouseleave", function stopbganimation() {
clearInterval(hoverbginterval[id]);
rainbowhoverbg[id].style.backgroundColor = originalbgcolors[id];
}, false);
}
})()
//Actually do the rainbow effect. Text only.
function textcolorchange(rainbowarray, rainbowspeed) {
let counterarray = [];
for(let i = 0; i < rainbowarray.length; i++) {
counterarray[i] = 0 + i;
}
setInterval(() => {
for(let i = 0; i < rainbowarray.length; i++) {
rainbowarray[i].style.color = 'hsl(' + (counterarray[i] + Math.floor(i * rainbowspeed)) + ', 100%, 70%';
if(counterarray[i] == 360)
{
counterarray[i] = 0;
}
else {
counterarray[i]++;
}
}
}, 7);
}
//Prepare text for having its color changed by splicing it up into individual bits
//and taking it out of the HTMLcollection.
function spanArrayContents(classes) {
let spans = [];
let chars = [];
for(let i = 0; i < classes.length; i++) {
chars.push(classes[i].innerText.split(""));
classes[i].innerHTML = chars[i].map(function(char) {
return '<span>' + char + "</span>";
}).join('');
}
for(let i = 0; i < classes.length; i++) {
let temphtmlcollection = [].slice.call(classes[i].children)
for(let j = 0; j < temphtmlcollection.length; j++) {
spans.push(temphtmlcollection[j]);
}
}
return spans;
}
//Same as above except for single elements instead of an array of elements.
//Helps split them up and give them an ID before they're taken to the slaughterhouse.
function spanElementContents(element) {
let spans = [];
let chars = [];
chars.push(element.innerText.split(""));
for(let i = 0; i < chars.length; i++){
element.innerHTML = chars[i].map(function(char) {
return '<span>' + char + "</span>";
}).join('');
}
let temphtmlcollection = [].slice.call(element.children)
for(let j = 0; j < temphtmlcollection.length; j++) {
spans.push(temphtmlcollection[j]);
}
return spans;
}
I am trying to make a memory board game. I got the css part of the game done, but how it the JavaScript part suppose to work out. I tried using the codes below. When I click on the box, even if they are the same, the box won't disappear and when it's not the same number, the box doesn't turn back. Also, for my "gamebox", I want to add a picture to be the background. I couldn't get it to work. Can anyone help me. Thanks.
<html>
<style>
#gamebox
{
position: absolute;
top: 100px;
left: 100px;
background-image: url("https://www.google.com/url?sa=i&rct=j&q=&esrc=s&source=images&cd=&cad=rja&uact=8&ved=&url=http%3A%2F%2Fwww.pokemontimes.it%2Fhome%2F2014%2F10%2Fannunciato-il-pokemon-center-mega-tokyo-in-apertura-a-dicembre%2F%3F%3Drelated&psig=AFQjCNFGPAm9tU9MR4AZJKe1s6F90F8UFg&ust=1454720806721506");
}
div.box
{
position: absolute;
background-color: red;
top: -800px;
left: -800px;
width: 100px;
height: 100px;
text-align: center;
font-size: 30px;
}
div.box:hover
{
background-color: blue;
}
</style>
<div id=gamebox></div>
<div id=boxdiv class=box onclick="clickedBox(this)"></div>
<script>
var squaresize = 100;
var numsquares = 6;
var numClicked = 0;
var firstClicked;
var secondClicked;
var game = [];
for (var i = 0; i < numsquares; i++)
{
game[i] = [];
for (var j = 0; j < numsquares; j++)
{
game[i][j] = Math.floor(Math.random()*5);
makeBox(i, j);
}
}
function theSame(abox, bbox)
{
var boxParts = abox.id.split("-");
var i = boxParts[1];
var j = boxParts[2];
var boxaNum = game[i][j];
var boxParts = bbox.id.split("-");
i = boxParts[1];
j = boxParts[2];
var boxbNum = game[i][j];
return(boxaNum == boxbNum);
}
function nextTurn()
{
if (numClicked != 2)
return;
if (theSame(firstClicked, secondClicked))
{
deleteBox(firstClicked);
deleteBox(secondClicked);
}
else
{
hideBox(firstClicked);
hideBox(secondClicked);
}
numClicked = 0;
}
function hideBox(box)
{
box.innerHTML = "";
box.style.backgroundColor = "red";
}
function deleteBox(box)
{
//really delete the box
box.style.backgroundColor = "";
}
function showBox(box)
{
var boxParts = box.id.split("-");
var i = boxParts[1];
var j = boxParts[2];
box.innerHTML = game[i][j];
box.style.backgroundColor = "black";
box.style.color = "white";
}
function clickedBox(box)
{
showBox(box);
numClicked++;
if (numClicked == 1)
{
firstClicked = box;
return;
}
if (numClicked == 2)
{
secondClicked = box;
}
}
function makeBox(i, j)
{
var boxdiv = document.getElementById("boxdiv");
var newBox = boxdiv.cloneNode(true);
newBox.style.left = i * (squaresize + 5);
newBox.style.top = j * (squaresize + 5);
newBox.style.width = squaresize;
newBox.style.height = squaresize;
newBox.id = 'box-' + i + '-' + j;
var gamebox = document.getElementById("gamebox");
gamebox.appendChild(newBox);
}
</script>
</html>
I think you're not calling nextTurn() anywhere in your code, meaning theSame() is never called, so nothing gets compared to eachother.
Maybe try calling nextTurn() when the numClicked === 2 in the clickedBox() function.
This HTML and Javascript combined are supposed to form bars that are the height of the numbers entered in the prompt, relative to each other. The bars are not appearing when the numbers are entered. What do I need to fix in my code in order to make the bars appear?
"use strict";
window.onload=function()
{
var userValue;
var i;
var j;
var k;
var error;
var correct;
j = 0;
k = 0;
error = new Array(j);
correct = new Array(k);
userValue = window.prompt("Insert values separated by comma, whitespace, or both.");
userValue = packArray(trimElements(toArray(userValue, " ,")));
for(i = 0; i < userValue.length; i++)
{
if(isNumeric(userValue[i]) === false)
{
error[j] = userValue[i];
j = j + 1;
}
else
{
correct[k] = userValue[i];
k = k + 1;
}
}
if(error.length > 0)
{
window.alert("Error: " + error);
}
else
{
createGraph(userValue, document.getElementById("positiveQuadrant"));
}
};
function toArray(data, delimiters)
{
var locArray;
var result;
var i;
var dataArray;
var start;
locArray = findPositions(data, delimiters);
result = "";
i = 0;
if(data === null)
{
data = "";
}
else
{
result = result + data;
}
if(delimiters === null)
{
delimiters = "";
}
else
{
result = result + delimiters;
}
if(delimiters.length === 0)
{
delimiters = delimiters + " \t\r\n\f";
}
dataArray = new Array(locArray.length + 1);
start = 0;
while(i < dataArray.length)
{
dataArray[i] = data.substring(start, locArray[i]);
start = locArray[i] + 1;
i = i + 1;
}
return dataArray;
}
function findPositions(someString, lookForThis)
{
var i;
var result;
var count;
result = new Array(count);
i = 0;
count = 0;
while(i < someString.length)
{
if(lookForThis.indexOf(someString.charAt(i)) >= 0)
{
result[count] = someString.indexOf(lookForThis.charAt(i), (i + 1) - 1);
count = count + 1;
}
i = i + 1;
}
return result;
}
function trimElements(array)
{
var i;
var trimArray;
trimArray = new Array(array.length);
i = 0;
while(i < array.length)
{
trimArray[i] = trim(array[i]);
i = i + 1;
}
return trimArray;
}
function packArray(array)
{
var i;
var count;
var packedArray;
i = 0;
count = 0;
packedArray = new Array(count);
while(i < array.length)
{
if(array[i] !== null && array[i] !== "")
{
packedArray[count] = array[i];
count = count + 1;
}
i = i + 1;
}
return packedArray;
}
function convertToNumber(array)
{
var i;
var result;
i = 0;
result = "";
while(i < array.length)
{
if(isNumeric(array[i]) === true)
{
array[i] = Number(array[i]);
}
else
{
result = result + " " + array[i];
}
i = i + 1;
}
return trim(result);
}
function trim(data)
{
var start;
var whitespace;
var end;
var result;
if(typeof data==="string")
{
whitespace=" \n\r\t\f";
start=0;
}
else
{
result=data;
}
while((start<data.length)&&(whitespace.indexOf(data.charAt(start))))
{
start=start+1;
};
end=data.length-1;
while((end>=0)&&(whitespace.indexOf(data.charAt(end))))
{
end=end-1;
};
if(end<start)
{
result="";
}
else
{
result=data.substring(1+start,end);
}
return result;
};
function createHTMLElement(elementType, id, classInfo, content)
{
if(elementType===null)
{
elementType="";
};
trim(elementType);
if(id===null)
{
id="";
}
trim(id);
if(id.length>0)
{
id=" "+"id="+'"'+id+'"'+" ";
};
if(classInfo===null)
{
classInfo="";
}
trim(classInfo);
if(classInfo.length>0)
{
classInfo=" "+ "class="+'"'+classInfo+'"';
}
if(content===null)
{
content="";
};
trim(content);
return '<' +elementType +
id + classInfo +
'>' + content +
'</' + elementType + '>';
};
function isNumeric(data)
{
return isNaN(data);
};
function getRandomInteger(upperLimit)
{
return Math.floor(Math.random()*(upperLimit+1));
};
function getRandomRGB()
{
var blue;
var green;
var red;
red=getRandomInteger(255);
blue=getRandomInteger(255);
green=getRandomInteger(255);
return"rgb("+red+","+green+","+blue+")";
};
function createScaledArray(array, scaleFactor)
{
var i;
var scaledArray;
scaledArray = new Array(array.length);
for(i = 0; i < array.length; i++)
{
scaledArray[i] = (array[i] / scaleFactor);
}
return scaledArray;
}
function createGraph(array, quadReference)
{
var i;
var loc;
var scaleFactor;
var scaleArray;
var html;
var element;
var elementTop;
if(array.length > 0)
{
loc = 0;
for(i = 0; i < array.length; i++)
{
if(Number(array[i]) > Number(array[loc]))
{
loc = i;
}
}
scaleFactor = Math.abs(array[loc]);
scaleArray = createScaledArray(array, scaleFactor);
html = "";
for(i = 0; i < scaleArray.length; i++)
{
html = html + createHTMLElement("div", "columnContainer", "columnContainer", createHTMLElement("div", "coloredArea" + i, "coloredArea", createHTMLElement("div", "dataValue", "dataValue", array[i])));
}
quadReference.innerHTML = html;
for(i = 0; i < scaleArray.length; i++)
{
element = document.getElementById("coloredArea" + i);
elementTop = (100 - (scaleArray[i] * 100));
if(elementTop > 100)
{
elementTop = elementTop + (scaleArray[i] * 100);
}
element.style.top = elementTop + "%";
element.style.height = Math.abs(scaleArray[i] * 100) + "%";
element.style.backgroundColor = getRandomRGB();
}
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<title> Graphing </title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
<script src="Graphing.js" type="text/javascript"></script>
<style type="text/css">
{
border : 0;
margin : 0;
padding : 0;
}
body
{
font-family : "Times New Roman", serif;
font-size : 12pt;
}
.positiveQuadrant
{
height:12em;
width:2em;
border-right:solid black 3px;
}
.negativeQuadrant
{
position:relative;
height:2em;
width:22em;
border-top:solid black 3px;
bottom:2em;
}
.columnContainer
{
position: relative;
float: left;
height: 10em;
width: 1.5em;
margin: 1px;
}
.coloredArea
{
position: relative;
background-color: red;
}
.dataValue
{
font-size: 12pt;
text-align: center;
position: relative;
top: -16px;
}
</style>
</head>
<body>
<div class ="positiveQuadrant" id="positiveQuadrant"></div>
<div class = "negativeQuadrant" id ="negativeQuadrant"></div>
</body>
</html>