Unable to update image position in css using javascript - javascript

There are some runner(animation-image) in my program which move from position x to y when clicked on start button, i want to add a (reverse)button on completion that when clicked on that the image moves from y to x.
Here is the link of my js-fiddle: https://jsfiddle.net/o6egL4qr/
I have added the reverse button but when clicked on that the image doesn't move at all.
class raceManager {
raceCount = 0;
races = [];
addRace() {
var mainContainer = document.getElementById('mainContainer');
mainContainer.appendChild(document.createElement('br'));
var race = new raceClass(this.raceCount);
this.races.push(race);
this.raceCount++;
}
}
class raceClass {
runners = [];
count;
runnerCount = 0;
raceDiv = document.createElement('div');
raceNum = document.createElement('div');
startRaceButton = document.createElement('input');
addRunnerButton = document.createElement('input');
revRaceButton = document.createElement('input');
tableDiv = document.createElement('div');
tableNum = document.createElement('div');
startInterval;
startTime;
revStartTime;
reverseInterval;
constructor(number) {
// store the race no.
this.count = number;
// delcare the race div id
this.raceNum.id = 'raceNum' + this.count;
// delcare the table div id
this.tableNum.id = 'tableNum' + this.count;
// Add raceDiv to the race
document.getElementById('races').appendChild(this.raceDiv);
// Add tableDiv to the race
document.getElementById('tables').appendChild(this.tableDiv);
this.applyDivProperty();
this.initializeButtons();
}
applyDivProperty() {
// apply properties to the tableNum
this.tableNum.style.display = "inline-block";
// apply properties to the raceDiv
this.raceDiv.id = "Race" + this.count;
document.getElementById(this.raceDiv.id).classList.add("raceDivClass");
this.raceDiv.appendChild(this.raceNum);
document.getElementById(this.raceNum.id).innerHTML = '<p>Race: ' + this.count + '</p>';
// append the add race button
this.raceDiv.appendChild(this.addRunnerButton);
// apply properties to the tableDiv
this.tableDiv.id = "Table" + this.count;
document.getElementById(this.tableDiv.id).classList.add("tableClass");
this.tableDiv.appendChild(this.tableNum);
document.getElementById(this.tableNum.id).innerHTML = '<p>Table: ' + this.count + '</p>';
}
initializeButtons() {
// initialize add runner button
this.addRunnerButton.type = 'Button';
this.addRunnerButton.value = 'Add Runner';
this.addRunnerButton.id = 'AddRunner' + this.count;
this.addRunnerButton.onclick = this.addRunner.bind(this);
// initialize start race buttton
this.startRaceButton.type = 'Button';
this.startRaceButton.value = 'Start Race';
this.startRaceButton.id = "startRaceButton" + this.count;
this.startRaceButton.onclick = this.startRace.bind(this);
// initialize reverse race buttton
this.revRaceButton.type = 'Button';
this.revRaceButton.value = 'Reverse Race';
this.revRaceButton.id = "revRaceButton" + this.count;
this.revRaceButton.onclick = this.revRace.bind(this);
}
addRunner() {
var track = new Runner(this); //Initialize the runner object
this.runners.push(track); //Store the runner object in runners array of Race class
if (this.runnerCount > 0) {
// append the start race button
this.raceDiv.appendChild(this.startRaceButton);
}
this.runnerCount++;
}
startRace() {
this.startTime = Date.now();
this.startInterval = setInterval(() => {
this.runners.forEach(function(element) {
element.animate();
});
document.getElementById(this.startRaceButton.id).disabled = "true";
document.getElementById(this.addRunnerButton.id).disabled = "true";
}, 50);
}
stop() {
clearInterval(this.startInterval);
// append the start race button
this.raceDiv.appendChild(this.revRaceButton);
}
revRace() {
this.revStartTime = Date.now();
this.reverseInterval = setInterval(() => {
this.runners.forEach(function(element) {
element.animateReverse();
});
document.getElementById(this.revRaceButton.id).disabled = "true";
}, 50);
}
stopRev() {
clearInterval(this.reverseInterval);
}
}
class Runner {
count = 0;
parent;
track;
sprite;
timeTaken;
trackWidth;
element;
speed;
table;
printCount = 1;
stepCount = 1;
trackNum;
tbl;
lastStep;
constructor(race) {
// initialize the divs
this.parent = race;
this.track = document.createElement('div');
this.sprite = document.createElement('div');
this.table = document.createElement('table');
// assigns #id to table and track corresponding with parent div.
this.table.id = race.tableNum.id + '_Table_' + this.parent.runnerCount;
this.track.id = race.raceNum.id + '_Track_' + this.parent.runnerCount;
this.createUI();
this.timeTaken = ((Math.random() * 5) + 3);
this.speed = this.trackWidth / (this.timeTaken * 1000);
console.log(this.trackWidth, this.timeTaken);
console.log(this.timeTaken * 100);
}
createUI() {
this.count = this.parent.runnerCount;
this.createTable();
this.createTrack();
this.createSprite();
}
createTable() {
var parentDiv1 = document.getElementById(this.parent.tableNum.id);
parentDiv1.appendChild(this.table);
this.table.setAttribute = "border"
this.table.border = "1";
document.getElementById(this.table.id).classList.add("tableClass");
this.tbl = document.getElementById(this.table.id);
this.addRow("Track " + (this.count + 1), "");
this.addRow("Time", "Distance");
}
addCell(tr, val) {
var td = document.createElement('td');
td.innerHTML = val;
tr.appendChild(td)
}
addRow(val_1, val_2) {
var tr = document.createElement('tr');
this.addCell(tr, val_1);
this.addCell(tr, val_2);
this.tbl.appendChild(tr)
}
createTrack() {
var parentDiv = document.getElementById(this.parent.raceNum.id);
parentDiv.appendChild(this.track);
this.track.appendChild(this.sprite);
document.getElementById(this.track.id).classList.add("trackClass");
this.trackWidth = this.track.getBoundingClientRect().width;
}
createSprite() {
this.sprite.id = this.track.id + "_Runner";
document.getElementById(this.sprite.id).classList.add("spriteClass");
this.element = document.getElementById(this.sprite.id);
}
animate() {
// declare time variables
var timeNow = Date.now();
var timespent = timeNow - this.parent.startTime;
var diff = Math.floor(this.timeTaken * 100);
// step is position of sprite.
var step = timespent * this.speed;
// Print table for all tracks with 10 laps.
if ((Math.round(timespent / 50) * 50) == (Math.round(((diff - 25) * this.printCount) / 50) * 50)) {
this.addRow(this.printCount + ": " + timespent, (Math.floor(step)));
this.printCount++;
}
// check condition to stop
if (step > this.trackWidth - 23) {
document.getElementById(this.parent.raceNum.id).innerHTML += 'Winner: Runner' + (this.count + 1);
this.parent.stop();
}
this.element.style.left = step + 'px';
// ------------sprite animation----------------
// start position for the image slicer
var position = (3 - (Math.floor(step / 6.5) % 4)) * 25;
// we use the ES6 template literal to insert the variable "position"
this.element.style.backgroundPosition = `${position}px 0px`;
}
animateReverse() {
// declare time variables
var timeNow = Date.now();
var timespent = timeNow - this.parent.revStartTime;
var diff = Math.floor(this.timeTaken * 100);
console.log(this.count + " position of step " + this.element.style.left);
while (this.stepCount < 2) {
this.lastStep = parseFloat(this.element.style.left);
this.stepCount++;
}
console.log(this.count + " this is lastStep " + this.lastStep);
// step is position of sprite.
var step = this.lastStep - (this.speed * timespent);
// Print table for all tracks with 10 laps.
if ((Math.round(timespent / 50) * 50) == (Math.round(((diff - 25) * this.printCount) / 50) * 50)) {
this.addRow(this.printCount + ": " + timespent, (Math.floor(step)));
this.printCount++;
}
// check condition to stop
if (step < 25) {
document.getElementById(this.parent.raceNum.id).innerHTML += 'Winner: Runner' + (this.count + 1);
this.parent.stopRev();
}
this.element.style.left = step + 'px';
// ------------sprite animation----------------
// start position for the image slicer
//var position = (3 - (Math.floor(step / 6.5) % 4)) * 25;
//this.element.style.backgroundPosition = position + 'px 0px';
}
}
manager = new raceManager();
#tableContainer {
float: left;
}
#addRaces {
text-align: center;
}
.raceDivClass {
margin: 1% auto;
width: 60%;
text-align: center;
border: 1px solid;
}
.tableClass {
text-align: center;
border: 1px solid;
margin: 5px;
float: left;
}
.trackClass {
background-color: black;
height: 30px;
width: 98%;
margin: 1%;
position: relative;
}
.spriteClass {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGgAAAAeCAYAAADAZ1t9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAASwSURBVGhD7Zq/axRBFMfv9u4MxATUSgsVm3QWigYbexuxUkiaKIqNoIUiwRSJoJLCxpSCaJoEYimo/4AgQVRIZxdBEIREYwzc5X74vndvlrm5mdnZ3dm9oPnAsDubu52Z93373pvNFQsJOXO9NUKHsU4vZPH90+IXPt/FA2kEmqbDTKcX8pza7K5I/vAtEJghge7zeSrwlDYbtYlmfWuILxWC8uBmUNoz/784wY4WaPRq9SGJcY+7Mt7GEOzUkB0pkGHi4Ci1K53TEK8h7tTE+pPywL6b3JXJQqBcQ7arQwR87AE34ElPUsPE1ZapODsErFHnnD7AfVWb9oylFYjVFcKoQuQC5kD55hB3Qxrbf17RYbHT+/fpCXGSOEmEaYcevofwhkRxXM0/VCi8azXr3+q1Xw8+LRxZ4cte4PneoHaQ2iVck0gVThVbyOhSRM9YOoFMyR9eW6KmLkAGYW6Vmjx47AViUfSkPC5V9p7nS23q1Z9zH+b33+KuF9iAOocUa0lcKFjubQJ2h51D5zbmIAVM9gc1mzgAE0kdFlFaq+JkQYQBV+FYOYoDGy9Tw3dgQ7QxnUBQUHxAtJfUhqllDhbWam4f525mJDCgMynufZFa13d6BILHsOeEjS6PUjMNtsRHFXgExI2V0PN6egiEkTzFMdlJgM/3zMd1H2Tzhjlqa53TLhLFbsvep9Cob70uFsuffbxJoHWZcq1A5CCZyDUZ7gtxotKDCsafdRHIZSFe9j9wBl1xoIJSuxhUVpIK5eB0JiILHo29EouDtVmLBF4IKjIbWOQkfzYVruENn+ESXFe+upBJeDMQVfWiyXQ5fFQV57oQLyLJL0VlsAfi06yJyhMuIOci7Efdqy0ENzxxonVFI22IY0NDHN1mykaX+nHAmKbw1qhtLLVaze8U1o6Jv9OmdaEYlI1lsLQGGVGwmMKbKZ8KXHIQxnUJn062CgVSFmQTRjySpr8n2nlb3lxTztl8W6+u3x0YOlylrpij1Vi0Hl3uxNx/U9MWIYSPtwZxclukSG2B4qreOTV+3skzBBgbuafVrJ0sVYbO8eUe4r5FMAgEbEnbSSC2l/p0grgRB1jHDGKqjt019kkwvoid4okS4D7O+Qji4MmxiQMonI2cGP/qYwMbt6LSAXFEzpCbyYaJcxuKBAwWJQ5EwATCTScLBeUhVGKRTIWBCgQsVYavcdcF8UZEnVveYPwXfIwNBMJCdF/GNeEZCFnahMzX1A0dgEi6MJALigP1SyiMCdu9wZH7sZBzkGpM5zcBljAZGdNPX964UAhKt0vlwbN8SQs2p/Xq2lTSfzU4hvK0OUily4b0PV1etI4Z+SbBFYMBrIPjO1QuT1N+GedLbVC1FYM9Hyk31fgScHYYE5JhD1Dz/r+fKPoqEJAMILAa1VRaU+HwaPnZwBR3vWJwJCDCUSonsKERKHJMrwLFAYbSbUwRyujanawMZfBikPXTEzvCgKhXPZmhe+/W2ZCuTWXpxQbgyWGFmhGILLb8p6V/AmnKa+Qd3783cCDz0JaGvgmEX4jyaRu8W6N8NM/dPGlvvvk8T5ye2r7mIIQ5PEl5/pyXc4FzIeOLZOMWCn8Bh1eBvOSZzIIAAAAASUVORK5CYII=');
position: absolute;
height: 30px;
width: 25px;
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="mainContainer">
<div id="addRaces">
<input type="Button" value="Add Race" onclick="manager.addRace()">
</div>
<div id="races">
</div>
<br>
</div>
<div id="tableContainer">
<div id="tables"></div>
</div>
</body>
</html>
I expect it to move from y to x after clicking the reverse button, but it is not moving.

When you run the reverse function the elements are no longer referencing the dom elements.
I am actually not sure why that is, maybe someone else can chime in.
Anyway, this will fix your problem:
Replace this.element.style.left = step + 'px';
With: document.getElementById(this.element.id).style.left = step + 'px';

Related

Using nested setTimeout to create an animated selection sort

I am working on a basic sorting visualizer with using only HTML, CSS, and JS, and I've run into a problem with the animation aspect. To initialize the array, I generate random numbers within some specified range and push them on to the array. Then based on the webpage dimensions, I create divs for each element and give each one height and width dimensions accordingly, and append each to my "bar-container" div currently in the dom.
function renderVisualizer() {
var barContainer = document.getElementById("bar-container");
//Empties bar-container div
while (barContainer.hasChildNodes()) {
barContainer.removeChild(barContainer.lastChild);
}
var heightMult = barContainer.offsetHeight / max_element;
var temp = barContainer.offsetWidth / array.length;
var barWidth = temp * 0.9;
var margin = temp * 0.05;
//Creating array element bars
for (var i = 0; i < array.length; i++) {
var arrayBar = document.createElement("div");
arrayBar.className = "array-bar"
if (barWidth > 30)
arrayBar.textContent = array[i];
//Style
arrayBar.style.textAlign = "center";
arrayBar.style.height = array[i] * heightMult + "px";
arrayBar.style.width = barWidth;
arrayBar.style.margin = margin;
barContainer.appendChild(arrayBar);
}
}
I wrote the following animated selection sort and it works well, but the only "animated" portion is in the outer for-loop, and I am not highlighting bars as I traverse through them.
function selectionSortAnimated() {
var barContainer = document.getElementById("bar-container");
var barArr = barContainer.childNodes;
for (let i = 0; i < barArr.length - 1; i++) {
let min_idx = i;
let minNum = parseInt(barArr[i].textContent);
for (let j = i + 1; j < barArr.length; j++) {
let jNum = parseInt(barArr[j].textContent, 10);
if (jNum < minNum) {
min_idx = j;
minNum = jNum;
}
}
//setTimeout(() => {
barContainer.insertBefore(barArr[i], barArr[min_idx])
barContainer.insertBefore(barArr[min_idx], barArr[i]);
//}, i * 500);
}
}
I am trying to use nested setTimeout calls to highlight each bar as I traverse through it, then swap the bars, but I'm running into an issue. I'm using idxContainer object to store my minimum index, but after each run of innerLoopHelper, it ends up being equal to i and thus there is no swap. I have been stuck here for a few hours and am utterly confused.
function selectionSortTest() {
var barContainer = document.getElementById("bar-container");
var barArr = barContainer.childNodes;
outerLoopHelper(0, barArr, barContainer);
console.log(array);
}
function outerLoopHelper(i, barArr, barContainer) {
if (i < array.length - 1) {
setTimeout(() => {
var idxContainer = {
idx: i
};
innerLoopHelper(i + 1, idxContainer, barArr);
console.log(idxContainer);
let minIdx = idxContainer.idx;
let temp = array[minIdx];
array[minIdx] = array[i];
array[i] = temp;
barContainer.insertBefore(barArr[i], barArr[minIdx])
barContainer.insertBefore(barArr[minIdx], barArr[i]);
//console.log("Swapping indices: " + i + " and " + minIdx);
outerLoopHelper(++i, barArr, barContainer);
}, 100);
}
}
function innerLoopHelper(j, idxContainer, barArr) {
if (j < array.length) {
setTimeout(() => {
if (j - 1 >= 0)
barArr[j - 1].style.backgroundColor = "gray";
barArr[j].style.backgroundColor = "red";
if (array[j] < array[idxContainer.idx])
idxContainer.idx = j;
innerLoopHelper(++j, idxContainer, barArr);
}, 100);
}
}
I know this is a long post, but I just wanted to be as specific as possible. Thank you so much for reading, and any guidance will be appreciated!
Convert your sorting function to a generator function*, this way, you can yield it the time you update your rendering:
const sorter = selectionSortAnimated();
const array = Array.from( { length: 100 }, ()=> Math.round(Math.random()*50));
const max_element = 50;
renderVisualizer();
anim();
// The animation loop
// simply calls itself until our generator function is done
function anim() {
if( !sorter.next().done ) {
// schedules callback to before the next screen refresh
// usually 60FPS, it may vary from one monitor to an other
requestAnimationFrame( anim );
// you could also very well use setTimeout( anim, t );
}
}
// Converted to a generator function
function* selectionSortAnimated() {
const barContainer = document.getElementById("bar-container");
const barArr = barContainer.children;
for (let i = 0; i < barArr.length - 1; i++) {
let min_idx = i;
let minNum = parseInt(barArr[i].textContent);
for (let j = i + 1; j < barArr.length; j++) {
let jNum = parseInt(barArr[j].textContent, 10);
if (jNum < minNum) {
barArr[min_idx].classList.remove( 'selected' );
min_idx = j;
minNum = jNum;
barArr[min_idx].classList.add( 'selected' );
}
// highlight
barArr[j].classList.add( 'checking' );
yield; // tell the outer world we are paused
// once we start again
barArr[j].classList.remove( 'checking' );
}
barArr[min_idx].classList.remove( 'selected' );
barContainer.insertBefore(barArr[i], barArr[min_idx])
barContainer.insertBefore(barArr[min_idx], barArr[i]);
// pause here too?
yield;
}
}
// same as OP
function renderVisualizer() {
const barContainer = document.getElementById("bar-container");
//Empties bar-container div
while (barContainer.hasChildNodes()) {
barContainer.removeChild(barContainer.lastChild);
}
var heightMult = barContainer.offsetHeight / max_element;
var temp = barContainer.offsetWidth / array.length;
var barWidth = temp * 0.9;
var margin = temp * 0.05;
//Creating array element bars
for (var i = 0; i < array.length; i++) {
var arrayBar = document.createElement("div");
arrayBar.className = "array-bar"
if (barWidth > 30)
arrayBar.textContent = array[i];
//Style
arrayBar.style.textAlign = "center";
arrayBar.style.height = array[i] * heightMult + "px";
arrayBar.style.width = barWidth;
arrayBar.style.margin = margin;
barContainer.appendChild(arrayBar);
}
}
#bar-container {
height: 250px;
white-space: nowrap;
width: 3500px;
}
.array-bar {
border: 1px solid;
width: 30px;
display: inline-block;
background-color: #00000022;
}
.checking {
background-color: green;
}
.selected, .checking.selected {
background-color: red;
}
<div id="bar-container"></div>
So I thought about this, and it's a little tricky, what I would do is just store the indexes of each swap as you do the sort, and then do all of the animation seperately, something like this:
// how many elements we want to sort
const SIZE = 24;
// helper function to get a random number
function getRandomInt() {
return Math.floor(Math.random() * Math.floor(100));
}
// this will hold all of the swaps of the sort.
let steps = [];
// the data we are going to sort
let data = new Array(SIZE).fill(null).map(getRandomInt);
// and a copy that we'll use for animating, this will simplify
// things since we can just run the sort to get the steps and
// not have to worry about timing yet.
let copy = [...data];
let selectionSort = (arr) => {
let len = arr.length;
for (let i = 0; i < len; i++) {
let min = i;
for (let j = i + 1; j < len; j++) {
if (arr[min] > arr[j]) {
min = j;
}
}
if (min !== i) {
let tmp = arr[i];
// save the indexes to swap
steps.push({i1: i, i2: min});
arr[i] = arr[min];
arr[min] = tmp;
}
}
return arr;
}
// sort the data
selectionSort(data);
const container = document.getElementById('container');
let render = (data) => {
// initial render...
data.forEach((el, index) => {
const div = document.createElement('div');
div.classList.add('item');
div.id=`i${index}`;
div.style.left = `${2 + (index * 4)}%`;
div.style.top = `${(98 - (el * .8))}%`
div.style.height = `${el * .8}%`
container.appendChild(div);
});
}
render(copy);
let el1, el2;
const interval = setInterval(() => {
// get the next step
const {i1, i2} = steps.shift();
if (el1) el1.classList.remove('active');
if (el2) el2.classList.remove('active');
el1 = document.getElementById(`i${i1}`);
el2 = document.getElementById(`i${i2}`);
el1.classList.add('active');
el2.classList.add('active');
[el1.id, el2.id] = [el2.id, el1.id];
[el1.style.left, el2.style.left] = [el2.style.left, el1.style.left]
if (!steps.length) {
clearInterval(interval);
document.querySelectorAll('.item').forEach((el) => el.classList.add('active'));
}
}, 1000);
#container {
border: solid 1px black;
box-sizing: border-box;
padding: 20px;
height: 200px;
width: 100%;
background: #EEE;
position: relative;
}
#container .item {
position: absolute;
display: inline-block;
padding: 0;
margin: 0;
width: 3%;
height: 80%;
background: #cafdac;
border: solid 1px black;
transition: 1s;
}
#container .item.active {
background: green;
}
<div id="container"></div>

increase score by mouse over event javascript

function createFlake(){
var el= document.createElement('i');
el.classList.add("fab");
el.classList.add("fa-bitcoin")
el.classList.add("fa-7x")
el.style.left=Math.random()* window.innerWidth+'px';
el.style.animationDuration= Math.random()*3+ 3 +'s';
el.style.opacity=Math.random();
let score=5;
el.addEventListener('mouseover',()=>{
score=score+1;
console.log(score)
el.classList.add('fa-bitcoin-hover');
var s=document.getElementById('scor');
s.innerText="Score: "+score;
})
document.body.appendChild(el)
}
with above code, I am creating icons thats falling from top to bottom, and as I do that, every time that I mouse over the icon I want it to increase the score. everything works fine except i keep getting a same score or score+1. cant increase the score.
Move let score outside the function unless you need each flake to have its own score
let score = 5;
const s = document.getElementById('scor');
function createFlake() {
var el = document.createElement('i');
el.classList.add("fab");
el.classList.add("fa-bitcoin")
el.classList.add("fa-7x")
el.style.left = Math.random() * window.innerWidth + 'px';
el.style.animationDuration = Math.random() * 3 + 3 + 's';
el.style.opacity = (Math.random()+0.009).toFixed(2); // or you get invisible flakes
el.addEventListener('mouseover', () => {
score++
el.classList.add('fa-bitcoin-hover');
s.innerText = "Score: " + score;
})
document.body.appendChild(el)
}
createFlake()
createFlake()
createFlake()
createFlake()
.fa-bitcoin-hover { border: 1px solid black; }
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css" />
<span id="scor">Score: 5</span>
<hr/>
If you get points each time you hit a flake, even when hitting the same flake more than once, you need something like this:
const s = document.getElementById('scor');
const showScore = () => {
let total = 0;
[...document.querySelectorAll(".fab")].forEach(el => total += +el.title)
s.innerHTML = total;
}
function createFlake() {
var el = document.createElement('i');
el.classList.add("fab");
el.classList.add("fa-bitcoin")
el.classList.add("fa-7x")
el.style.left = Math.random() * window.innerWidth + 'px';
el.style.animationDuration = Math.random() * 3 + 3 + 's';
el.style.opacity = (Math.random()+0.009).toFixed(2); // or you get invisible flakes
let score = 5;
el.addEventListener('mouseover', () => {
score++
el.classList.add('fa-bitcoin-hover');
el.title = score;
showScore();
})
document.body.appendChild(el)
}
createFlake()
createFlake()
createFlake()
createFlake()
.fa-bitcoin-hover { border: 1px solid black; }
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css" />
<div>Score: <span id="scor">5</span>
<hr/>
Instead of taking a variable score, You can add score as property of the element. Simply el.score, see the code below:
el.score = 5;
el.addEventListener('mouseover', ()=> {
el.score++;
console.log(el.score);
el.classList.add('fa-bitcoin-hover');
let s = document.getElementById('score');
s.innerText = "Score: " + el.score;
});

im having problems to edit css using javascript

for some reason when i use JavaScript to edit the css of batata[y] nothing happens. The objective of the code is to create multiple blocks and move then from the top to the button of the page.
var p1
var p2 = [];
var y = 0;
var x = 0;
var telaJogo, telaJogo2, telaInicio;
var balao = [];
var a = 0;
var batata;
function ola() {
var bola = setInterval(addBalao, 1000);
}
function addBalao() {
telaJogo2 = document.getElementById('telaJogo2');
p2.push(0);
balao.push(0);
p1 = Math.floor(Math.random() * 445);
batata = "balao" + y;
balao[y] = document.createElement('div'); //create the block
balao[y].setAttribute("id", batata);
telaJogo2.appendChild(balao[y]);
balao[y].style = "top:" + p2[y] + "px;";
balao[y].style = "left:" + 30 + "px;";
balao[y].style = "background-color: red;";
balao[y].style = "height: 50px;";
balao[y].style = "width: 50px;";
balao[y].style = "position: absolute";
console.log("p2[y]" + p2[2]);
setInterval(ola2, 100);
y++;
}
function ola2() {
// move block
for (x = 0; x < y; x++) {
p2[x]++;
atualiza();
}
a = 0;
//console.log(p2);
}
function atualiza() {
// update the frame
balao[x].setAttribute("style", "top:" + p2[x] + "px;");
}
#telaJogo2 {
height: 800px;
width: 445px;
background-color: #90ee90;
}
<body onLoad="ola()">
<script type="text/javascript">
</script>
<div id="telaJogo2">
<div id="barra1"></div>
</div>

Is there a way to combine multiple divs into one

I have a dynamic group of n by m divs to form a grid. The items in this grid can be selected. The end result which I am hoping to achieve is to be able to combine and split the selected divs.
I have managed to get the divs to show correctly and select them, storing their id's in a list. Is there a way I could combine the selected divs, keeping the ones around it in their place?
#(Html.Kendo().Window()
.Name("window") //The name of the window is mandatory. It specifies the "id" attribute of the widget.
.Title("Dashboard Setup") //set the title of the window
.Content(#<text>
<div id="divSetup">
<div class="dvheader">
<b>Dashboard Setup</b>
</div>
<div>
<p>Enter the number of columns and rows of dashboard elements. This will create an empty dashboard with a set number of items which can be filled with KPI charts.</p>
<br />
<div class="dvform">
<table>
<tr style="margin-bottom: 15px;">
<td>
#Html.Label("Number of Columns: ")
</td>
<td>
<input type="number" name="NumColumns" id="NoColumns" min="1" max="20" />
</td>
</tr>
<tr style="margin-bottom: 15px;">
<td>
#Html.Label("Number of Rows: ")
</td>
<td>
<input type="number" name="NumRows" id="NoRows" min="1" max="20" />
</td>
</tr>
</table>
</div>
</div>
<div style="float: right">
<button id="btnSave" class="k-primary">Save</button>
<button id="btnClose">Close</button>
</div>
</div>
</text>)
.Draggable() //Enable dragging of the window
.Resizable() //Enable resizing of the window
.Width(600) //Set width of the window
.Modal(true)
.Visible(false)
)
<div id="dashboard">
</div>
<button id="combine" title="Combine">Combine</button>
<script>
$(document).ready(function () {
debugger;
$("#window").data("kendoWindow").open();
$("#btnClose").kendoButton({
click: close
});
$("#btnSave").kendoButton({
click: Save
});
$("#combine").kendoButton();
});
var array = [];
function clicked(e)
{
debugger;
var selectedDiv = "";
var x = document.getElementsByClassName('column')
for (var i = 0; i < x.length; i++)
{
if (x[i].id == e.id)
{
x[i].classList.add("selected");
array.push(x[i]);
}
}
for (var x = 0; x < array.length - 1; x++) {
array[x].classList.add("selected");
}
}
function close() {
$("#window").hide();
}
function Save()
{
debugger;
var col = document.getElementById("NoColumns").value;
var row = document.getElementById("NoRows").value;
for (var x = 1; x <= row; x++)
{
debugger;
document.getElementById("dashboard").innerHTML += '<div class="row">';
debugger;
for (var i = 1; i <= col; i++)
{
document.getElementById("dashboard").innerHTML += '<div onclick="clicked(this)" id="Row ' + x + ' Col ' + i + '" class="column">' + i + '</div>';
}
document.getElementById("dashboard").innerHTML += '</div>';
}
}
<style>
.selected {
background-color: #226fa3;
transition: background-color 0.4s ease-in, border-color 0.4s ease-in;
color: #ffffff;
}
#dashboard {
width: 80%;
margin: auto;
background-color: grey;
padding: 20px;
}
* {
box-sizing: border-box;
}
/* Create three equal columns that floats next to each other */
.column {
float: left;
padding: 20px;
border: 1px black solid;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
Below is an image of the selected blocks I would like to combine into one, while keeping it's place
If you were using a table it would be much easier, for div's, I can think of a solution if the style position is absolute, maybe it would help you start at least.
<div id="container"></div>
<button id="combine" title="Combine" disabled="disabled">Combine</button>
<div id="output"></div>
the script:
<script>
var cc;
function group() {
var xx = $(".selected").map(function () { return $(this).attr("data-x"); }).get();
var yy = $(".selected").map(function () { return $(this).attr("data-y"); }).get();
this.minX = Math.min.apply(Math, xx);
this.minY = Math.min.apply(Math, yy);
this.maxX = Math.max.apply(Math, xx);
this.maxY = Math.max.apply(Math, yy);
this.selectedCount = $(".selected").length;
this.CorrectGroup = function () {
var s = this.selectedCount;
return s == this.cellsCount() && s > 1;
}
this.width = function () {
return this.maxX - this.minX + 1;
}
this.height = function () {
return this.maxY - this.minY + 1;
}
this.cellsCount = function () {
return this.width() * this.height();
}
}
function cell(x, y, g) {
this.x = x;
this.y = y;
this.g = g;
this.spanX = 1;
this.spanY = 1;
this.visible = true;
var cellWidth = 80;
var cellHeight = 50;
this.div = function () {
var output = jQuery('<div/>');
output.attr('id', 'y' + y + 'x' + x);
output.attr('data-x', x);
output.attr('data-y', y);
output.attr('style', this.left() + this.top() + this.width() + this.height());
output.addClass('clickable');
output.html('(y=' + y + ' x=' + x + ')')
return output;
}
this.left = function () {
return 'left:' + (x * cellWidth) + 'px;';
}
this.top = function () {
return 'top:' + (100 + y * cellHeight) + 'px;';
}
this.width = function () {
return 'width:' + (this.spanX * cellWidth) + 'px;';
}
this.height = function () {
return 'height:' + (this.spanY * cellHeight) + 'px;';
}
}
function cells(xx, yy) {
this.CellWidth = xx;
this.CellHeight = yy;
this.CellList = [];
for (var y = 0; y < yy; y++)
for (var x = 0; x < xx; x++) {
this.CellList.push(new cell(x, y, 1));
}
this.findCell = function (xx, yy) {
return this.CellList.find(function (element) {
return (element.x == xx && element.y == yy);
});
}
this.displayCells = function (container) {
container.html('');
for (var y = 0; y < yy; y++)
for (var x = 0; x < xx; x++) {
var cell = this.findCell(x, y);
if (cell.visible)
cell.div().appendTo(container);
}
}
}
$(document).ready(function () {
$('#combine').click(function () {
$(".selected").each(function () {
var x = $(this).data('x');
var y = $(this).data('y');
var cell = cc.findCell(x, y);
cell.visible = false;
cell.g = 'y';
});
var first = $(".selected").first();
var xx = $(first).data('x');
var yy = $(first).data('y');
var cell = cc.findCell(xx, yy);
var g = new group();
cell.visible = true;
cell.g = xx + '_' + yy;
cell.spanX = g.width();
cell.spanY = g.height();
cc.displayCells($('#container'));
});
//make divs clickable
$('#container').on('click', 'div', function () {
$(this).toggleClass('selected');
if (CheckIfSelectedAreGroupable())
$('#combine').removeAttr("disabled");
else
$('#combine').attr("disabled", "disabled");
});
cc = new cells(12, 10);
cc.displayCells($('#container'));
});
function CheckIfSelectedAreGroupable() {
var g = new group();
return g.CorrectGroup();
}
</script>
Style:
<style>
.selected {
background-color: #226fa3 !important;
transition: background-color 0.4s ease-in, border-color 0.4s ease-in;
color: #ffffff;
}
.clickable {
border: 1px solid lightgray;
margin: 0px;
padding: 0px;
background-color: lightyellow;
position: absolute;
}
</style>
Im starting the divs by the following line, you can hock your form to trigger something similar.
cc = new cells(12, 10);
the combine button will not activate if you dont select a correct group, a rectangle shape selection.
the split will not be hard too but I did not have time to put it together, if this solution help, I can update it for the split.
Note: I wrote this quickly so its not optimized.
to try the solution use :
jsfiddle

setInterval wont work if timing is too short

I have a setInterval function that wont execute if the increment is less than 101ms. The timing will go any number above 100ms. I want to be able to increment the function by 10ms. offY and strtPos also become undefined when the timing goes below 101ms. How do I make it work the same as it is, but instead, have it incremented by 10ms?
var strtPos;
var offY;
var offX;
var hold = true;
var obj = document.getElementById('obj');
var st = function() {
offY = obj.offsetTop;
}
var init = setInterval(function() {
other()
}, 101); //<-- When I change that value to below 101, it prevents the code from working
var other = function() {
if (hold) {
strt();
hold = false
};
console.log(offY)
console.log(strtPos)
if (strtPos - 100 <= offY) {
obj.style.top = (offY - 11) + "px";
} else {
clearInterval(init);
hold = true;
}
}
var strt = function() {
strtPos = offY
}
setInterval(st, 100)
body {
margin: 0;
}
#obj {
width: 50px;
height: 100px;
background-color: red;
position: fixed;
}
<div id="obj"></div>
The short answer is you need to give offY a value that is not undefined initially, so I've rearranged the variables at the top of your code.
Originally, offY only gets a value after ~100ms (setInterval(st, 100)), and without a value that is not undefined the otherfunction's calculations won't work. So you needed the st function to execute first, hence requiring a value > 100.
var strtPos;
var offX;
var hold = true;
var obj = document.getElementById('obj');
var offY = obj.offsetTop;
var st = function() {
offY = obj.offsetTop;
}
var init = setInterval(function() {
other()
}, 10);
var other = function() {
if (hold) {
strt();
hold = false
};
console.log(offY)
console.log(strtPos)
if (strtPos - 100 <= offY) {
obj.style.top = (offY - 11) + "px";
} else {
clearInterval(init);
hold = true;
}
}
var strt = function() {
strtPos = offY
}
setInterval(st, 100)
body {
margin: 0;
}
#obj {
width: 50px;
height: 100px;
background-color: red;
position: fixed;
}
<div id="obj"></div>

Categories

Resources