How do I add class for time(clock) - javascript

I get date and clock.
var mydate = new Date();
var clock = tarih.getHours();
var minute = tarih.getMinutes();
And want this;
if (clock> 5) {
add this class, if have id "menu" = "menu_edit" (i dont know how can i do)
}
How can I do that?

If 'menu' is id of element:
document.querySelector('#menu').className += " menu_edit";
UPD:
According to your comment:
document.querySelector('.class1').className += ' class2';
Or if there are several elements:
var elems = document.querySelectorAll('.class1');
elems.forEach = [].forEach;
elems.forEach(function(el){
el.className += ' class2';
});
https://developer.mozilla.org/docs/Web/API/Document/querySelector - about function.
http://www.w3schools.com/cssref/css_selectors.asp - about selectors.

Maybe something like this. Please see the comments for an explanation.
checkout https://babeljs.io/ for info on compiling ES6 to ES5
const menu = document.querySelector('#menu')
const menuClasses = [
'menu--morning',
'menu--afternoon',
'menu--evening'
]
// helper function to toggle classes like a radio button
// this uses currying to lock in the classes and element, but
// allow us to change the active class dynamically
const toggleClasses = (classes, element) => clazz => {
element.classList.remove(...classes)
element.classList.add(clazz)
}
// create the toggle function and pass in the classes and the element
const toggleMenuClass = toggleClasses(menuClasses, menu)
// run a timer every n seconds
const timer = () => {
const date = new Date()
// I'm using seconds for the example as you will see the change
// but you should change this to hours
const second = date.getSeconds()
if (second < 20) {
toggleMenuClass('menu--morning')
}
else if (second < 40) {
toggleMenuClass('menu--afternoon')
}
else {
toggleMenuClass('menu--evening')
}
// just to show the current time for the example
menu.textContent = second
// call the timer function again after 500 milliseconds
setTimeout(timer, 500)
}
// init the timer on load
timer()
#menu {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
transition: 1s background;
font-size: 5em;
font-family: sans-serif;
color:#fff;
text-align: center;
line-height: 100vh;
}
#menu.menu--morning {
background: #AED6F1;
}
#menu.menu--afternoon {
background: #ABEBC6;
}
#menu.menu--evening {
background: #B95A75;
}
<div id="menu">clock</div>

Thanks everyone. I solved my problem with pHp.
Instead of adding class, i try take a different css page. Thanks for all things.
Have a nice day. :)
$clock = date('H');
if ($clock > 14) {
echo "<link rel='stylesheet' type='text/css' href='css/night.css'>";
}

Related

Unable to update CSS coloring using JavaScript

I've been trying to make this work for a while and for some reason the colors aren't updating. If I had to guess, it has to do with my returning an invalid string, but I'm not sure. The intended result is it converts the hours, minutes, and seconds into hexadecimal values respectively, but for some reason it is not working. If anyone can help it would be greatly appreciated. Thanks!
var div = document.getElementById("full");
function getclockColor() {
var h = toString(today.getHours());
var m = toString(today.getMinutes());
var s = toString(today.getSeconds());
color = '#' + h + m + s;
}
return color;
}
function changeColor() {
div.style.backgroundColor = getclockColor();
}
setInterval(changeColor, 1000);
body {
overflow: hidden;
margin: 0;
padding: 0;
}
#full {
position: absolute;
height: 100%;
width: 100%;
}
<link rel="stylesheet" type="text/css" href="/Users/zanolon/Desktop/Color Clock/Clock.css">
<div id="full"></div>
You have multiple errors:
You are invoking return outside your getclockColor function (and you have an extra }).
There is no today object. From your code I assume you want a Date object newly generated (with the current date). You can create a Date object like this: new Date().
This is not an error, but just so you know, you don't need to convert the numbers to string. It will automatically cast the values to string when concatenating to a string with the + operator.
Consider adding a zero when the number only contains one digit, because otherwise you will find many cases where the string generated will have less than 6 digits (plus the #).
The idea doesn't make that much sense, because you are combining three "random" numbers into a string. In many cases this won't result in a valid hex color string. You could try using the hsl format instead, which looks like this: hsl(120, 100%, 50%). You can achieve this easily with string templates: ` hsl(${h}, ${m}%, ${s}%) `
var div = document.getElementById("full");
function getclockColor() {
const today = new Date()
var h = today.getHours();
var m = today.getMinutes();
var s = today.getSeconds();
color = '#' + h + m + s;
return color;
}
function changeColor() {
div.style.backgroundColor = getclockColor();
}
setInterval(changeColor, 1000);
body {
overflow: hidden;
margin: 0;
padding: 0;
}
#full {
position: absolute;
height: 100%;
width: 100%;
}
<link rel="stylesheet" type="text/css" href="/Users/zanolon/Desktop/Color Clock/Clock.css">
<div id="full"></div>
Several issues:
You have an extra dangling } there (Which is why you're getting the illegal return statement). You cannot return when not in a function.
Also, today is not set anywhere.
There is no function called toString(). toString() is a method on number, so you can call it like so: today.getHours().toString()
You might want to consider 0 padding your h, m, and s if they're < 10, as you may be getting invalid hex codes (4 characters long), which may not be what you're looking for.
See this (Be aware, the color is changing, but because it's using the hex code :
var div = document.getElementById("full");
function getclockColor() {
var today = new Date();
var h = today.getHours().toString();
var m = today.getMinutes().toString();
var s = today.getSeconds().toString();
var color='#'+h+m+s;
return color;
}
function changeColor() {
console.log(getclockColor());
div.style.backgroundColor = getclockColor();
}
setInterval(changeColor, 1000);
body {
overflow: hidden;
margin: 0;
padding: 0;
}
#full {
position: absolute;
height: 100%;
width: 100%;
}
<div id="full"></div>
To fix the potential 0 padding issue, see below (Grabbed pad from this question):
var div = document.getElementById("full");
function pad(n, width, z) {
z = z || '0';
n = n + '';
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}
function getclockColor() {
var today = new Date();
var h = today.getHours().toString();
var m = today.getMinutes().toString();
var s = today.getSeconds().toString();
var color='#'+pad(h,2)+pad(m,2)+pad(s,2);
return color;
}
function changeColor() {
console.log(getclockColor());
div.style.backgroundColor = getclockColor();
}
setInterval(changeColor, 1000);
body {
overflow: hidden;
margin: 0;
padding: 0;
}
#full {
position: absolute;
height: 100%;
width: 100%;
}
<div id="full"></div>

requestAnimationFrame gives the wrong timestamp when showing a confirm dialog (Chromium?)

I have a simple animation, which is done using requestAnimationFrame (for demo purposes adapted from the example on MDN). If before the animation I show a confirm dialog, the timestamp received by the animation function is wrong. The difference between the first and second timestamps is equal to the time from the moment the confirm message was shown, until the "OK" button was clicked. This behaviour (bug?) is visible in Chrome and Opera (both running Chromium). Firefox and Internet Explorer 11 run as expected. Check the fiddle or the example below.
const cache = {
start: null,
target: null
};
function animate(timestamp) {
console.log(timestamp);
if (cache.start === null) {
cache.start = timestamp;
}
var progress = timestamp - cache.start;
cache.target.style.left = Math.min(progress / 10, 100) + 'px';
if (progress < 1000) {
requestAnimationFrame(animate);
} else {
cache.target.style.left = 0;
cache.start = null;
}
}
(function() {
const target = document.getElementsByTagName("div")[0];
cache.target = target;
const cb = document.getElementsByTagName("input")[0];
const btn = document.getElementsByTagName("button")[0];
btn.addEventListener("click", function() {
if (cb.checked) {
if (confirm("Just click 'OK' to start the animation, ok?")) {
requestAnimationFrame(animate);
}
} else {
requestAnimationFrame(animate);
}
})
})();
html,
body {
padding: 0;
margin: 0;
}
div {
width: 50px;
height: 50px;
border: 1px solid black;
background-color: yellowgreen;
position: absolute;
top: 50px;
}
button {
margin-top: 20px;
}
<button type="button">Start</button>
<label>
<input type="checkbox" />use "confirm"</label>
<div>
</div>
Open the console to see the received timestamps. The animation is set to run for 2 seconds. When showing the confirm dialog, if the "OK" button gets clicked faster than 2 seconds, the animation runs for the "remaining" time. If the time needed to click the "OK" button is longer than the time animation time, the element will not be animated and there will be 2 values (timestamps) sent to the console; the difference of these 2 values is the time needed to click the "OK" button.
I assume that this is a bug in Chromium. Is there a workaround for this (still animating with requestAnimationFrame, not trough CSS)? I couldn't find anything regarding this in their tracker. Does anybody have additional info on this?
I have to say, I found this very interesting.
After spending to much time on it I may have found a workaround for you. You can see that here. https://jsfiddle.net/qtj467n0/13/
The basic gist of it is, I replaced the DOMHighResTimeStamp that requestAnimationFrame provides with performance.now() which also returns a DOMHighResTimeStamp.
const cache = {
start: null,
target: null,
time: 2000
};
function animate(timestamp) {
console.log(timestamp);
if (cache.start === null) {
cache.start = timestamp;
}
var progress = timestamp - cache.start;
cache.target.style.left = Math.min(progress / 10, cache.time / 10) + 'px';
if (progress < cache.time) {
requestAnimationFrame(animate);
} else {
cache.target.style.left = 0;
cache.start = null;
}
}
const render = () => {
requestAnimationFrame((timestamp) => {
const performanceNow = performance.now();
animate(performanceNow)
});
}
(function() {
const target = document.getElementsByTagName("div")[0];
cache.target = target;
const cb = document.getElementsByTagName("input")[0];
const btn = document.getElementsByTagName("button")[0];
btn.addEventListener("click", function() {
if (cb.checked) {
const confirmed = confirm("Just click 'OK' to start the animation, ok?");
if (confirmed) {
render();
}
} else {
requestAnimationFrame(animate);
}
})
})();
html,
body {
padding: 0;
margin: 0;
}
div {
width: 50px;
height: 50px;
border: 1px solid black;
background-color: yellowgreen;
position: absolute;
top: 50px;
}
button {
margin-top: 20px;
}
<button type="button">Start</button>
<label>
<input type="checkbox" />use "confirm"</label>
<div>
</div>

Reverse background-position animation without resetting

I created an animation with CSS that changes the background-position of an element over time, to create a sort of scrolling effect with the background.
#keyframes stars-animate {
0% {
background-position: 0 -500px;
}
100% {
background-position: 2000px -500px;
}
}
This works perfectly. However, I also want to start to rewind the animation and create a reverse scrolling event. This is triggered by some irrelevant action.
function triggerReverse(element) {
element.style.animationDirection = 'reverse';
}
However, when I set the animation-direction to reverse, it does work, but not before it flips the entire background.
Am I doing it wrong, or is that the wrong way to do it, and if so, what is the right way?
Edit: I need to be able to reverse the animation while it is playing
UPDATE
The renewed sample code below provide the effect that enables a user to interrupt/pause the animation (during the first iteration) and immediately start to reverse the animation.
Here it is using time to control. Record the elapsed time from the beginning of animation, and calculate how to start the reverse animation. There are 2 iterations defined in css to make a whole loop. Without user intervention, the animation pauses/stops after the first iteration. But if there is, pause the iteration and immediately re-start it with a calculated animation-delay time. This will looks like an immediate reverse, however actually it is a new start.
There is also a trick on how to re-start the animation. Please refer to the code comment.
I searched around but found nobody has mentioned a similar scenario so far, nor a similar solution. Instead of to use time to control, I would like to see other better approaches.
My test also proves that different running environments render slightly different smoothness. Fortunately, here in SO is the best.
Try the solution to see if it can works well in your own scenario.
const span = document.querySelector('span'),
button = document.querySelector('button'),
duration = 10; // animation-during
let startTime;
span.addEventListener('animationstart', () => {
startTime = Date.now();
button.style.visibility = 'visible';
});
span.addEventListener('animationiteration', () => span.style.animationPlayState = 'paused');
span.addEventListener('animationend', () => {
button.style.visibility = 'hidden';
});
button.addEventListener('click', () => {
span.classList.remove('my_anim');
void span.offsetWidth; // safely apply changes
span.classList.add('my_anim');
const elapsed = Date.now() - startTime;
const delay = (elapsed < duration * 1000) ? (elapsed / 1000 - duration * 2) : -duration;
span.style.animationDelay = `${delay}s`;
span.style.animationPlayState = 'running';
});
span.my_anim {
animation: 10s 2 alternate my_move;
}
#keyframes my_move {
from {
margin-left: 0;
}
to {
margin-left: 50%;
}
}
button {
visibility: hidden;
}
<div>
<span class="my_anim">#</span>
</div>
<button>reverse</button>
This example does not use background-position for animation but a plain character.
const span = document.querySelector("span"),
button = document.querySelector("button");
span.addEventListener(
"animationiteration",
function() {
this.classList.add("paused");
button.style.visibility = "visible";
}
);
button.addEventListener(
"click",
function() {
this.style.visibility = "hidden";
span.classList.remove("paused");
}
);
span {
animation: 3s 2 alternate my_move;
}
span.paused {
animation-play-state: paused;
}
#keyframes my_move {
from {
margin-left: 0;
}
to {
margin-left: 50%;
}
}
button {
visibility: hidden;
}
<div>
<span>#</span>
</div>
<button>reverse</button>
NB: Use -webkit- prefix for css animation when necessary.
building off of #themefield's answer above - thanks, #themefield! - this way works the 'best', not perfect. (Sometimes the letter isn't in exactly the right spot when it reverses.)
The approach that worked was
a) reset animation to forward / reverse at the end
b) replace the animation with its opposite on toggling, setting a - start time to try to position it where it was.
Often it works pretty good, sometimes a lot off.
span = document.querySelector('span')
button = document.querySelector('button')
timerElement = document.querySelector('#timerId')
duration = 3; // animation-during
let startTime = Date.now();
toSec = (msec) => msec / 1000
elapsedTimeMsec = () => Date.now() - startTime
elapsedTimeSec = () => toSec(elapsedTimeMsec())
updateTimer = () => timerElement.innerHTML = `${elapsedTimeSec().toPrecision(2)}s`
let intervalHandle;
startTimer = () => {
intervalHandle = window.setInterval(() => {
updateTimer()
}, 500)
}
endTimer = () => {
window.clearInterval(intervalHandle)
intervalHandle = null
}
span.addEventListener('animationstart', () => {
startTime = Date.now();
startTimer()
});
span.addEventListener('animationiteration', () => span.style.animationPlayState = 'paused');
toggleAnimation = (shouldDelay) => {
span.classList.remove('my_anim');
void span.offsetWidth;
span.classList.add('my_anim');
if(span.style.animationDirection !== 'reverse')
span.style.animationDirection = 'reverse';
else
span.style.animationDirection = 'normal';
if(shouldDelay !== null && shouldDelay) {
span.style.animationDelay = `-${elapsedTimeSec()}s`;
} else {
span.style.animationDelay = `0s`;
}
span.style.animationPlayState = 'running';
}
span.addEventListener('animationend', () => {
endTimer()
updateTimer()
toggleAnimation();
});
button.addEventListener('click', () => {
endTimer()
updateTimer()
toggleAnimation(true) // todo pass in delay!
});
span.my_anim {
font-size: 54px;
animation: 3s 1 normal both my_move;
}
#keyframes my_move {
from {
margin-left: 0;
}
to {
margin-left: 50%;
}
}
button {
/*visibility: hidden;*/
}
#timerId {
font-size: 24px;
color: darkturquoise;
position: fixed;
bottom: 0;
left: 50%;
}
<div>
<span class="my_anim">#</span>
</div>
<button>reverse</button>
<span id="timerId"></span>

fadeIn and fadeOut in javascript

I'm trying to write my own animations using JavaScript.
I wrote a function for fadeIn() as below, it changes the display property followed by a change in value of opacity. But it doesn't seem to be working.
What am I doing wrong?
function fadeIn(obj, defDisp) {
obj.style.opacity = 0;
obj.style.display = defDisp;
var opVal = 0;
while (opVal < 1) {
obj.style.opacity = opVal;
opVal += 0.1;
}
}
defDisp = Default value for display property
Without a timing interval, this will likely execute too fast for you to see it. The while loop, without a timeout feature, will execute in far less than a second, and you won't see it happen. It's like asking a computer to count to 10, it will do it in less than a millisecond.
Try using a setTimeout
http://www.w3schools.com/jsref/met_win_settimeout.asp
while(opVal < 1) {
setTimeout(function(){
obj.style.opacity = opVal;
opVal += 0.1;
}, 3000);
}
Alter the timer (3000 in this case) to something that makes your fade work for you. Every 1000 is a one second and your loop runs 10 times, so in this case it would be 30 seconds, likely too slow.
I would probably stick with a CSS transition however, as they tend to render better on all browsers.
var el = document.getElementById('fadein');
fadeIn(el);
function fadeIn(ele, defDisp) {
ele.style.opacity = 0;
ele.style.display = defDisp;
var opVal = 0;
var t = setInterval(function(){
if(opVal >= 1){
clearInterval(t);
}
ele.style.opacity = opVal;
opVal += 0.1;
}, 100);
}
#fadein{ background: #ccc; border:1px solid #ddd; padding: 10px }
<div id="fadein">Hello</div>
Use a function that calls itself after a delay.
function fadeIn(obj, defDisp) {
obj.style.opacity = 0;
obj.style.display = defDisp;
var last = +new Date(); // Keep track of the time to calculate the opacity
var fadeStep = function () {
obj.style.opacity = +obj.style.opacity + (new Date() - last) / 800;
last = +new Date();
if (+obj.style.opacity < 1) {
setTimeout(fadeStep, 16);
}
};
fadeStep();
}
var el = document.getElementById('box');
fadeIn(el, 'block');
#box{ padding: 1em; background: #009afd; color: #ffffff; display: none; }
<div id="box">Hello</div>
If you want the fade to be faster, replace 800 by anything lower and vice-versa.
Because html render and for loop use the same thread, so when you doing the for-loop,you can't see any changes until the function complete. You have to use a setTimeout or setInterval (or requestAnimationFrame which is introduced from html5) so you browser can have the control to change the properties on the page:
You can see a example from the snippet, although the second that use a setTimeout is faster than the first one, which use for loop, the first one will not change its color as browser not able to change color during for-loop.
And if you choose to use requestAnimationFrame like I do in the snippets, you can have a smooth animation while the time can also be controlled precisely.
function fadeIn() {
this.style.opacity = 0;
this.style.display = 'block';
var opVal = 0;
console.time("count");
while(opVal < 1) {
this.style.opacity = opVal;
opVal += 0.000001;
}
console.timeEnd("count");
}
// Accept target as the target to apply anim, time is total anim time in ms.
function fadeInAlt(target, time) {
var opacity = 0;
var last = window.performance.now();
console.time("count2");
target.style.opacity = opacity;
target.style.display = 'block';
var fadeInFunc = function(timeStamp) {
if (opacity < 1) {
// Define the change by passed time.
var timePassed = timeStamp - last;
opacity += timePassed / time;
target.style.opacity = opacity;
last = timeStamp;
requestAnimationFrame(fadeInFunc);
} else {
console.timeEnd("count2");
return;
}
};
requestAnimationFrame(fadeInFunc);
}
var div = document.getElementById('test');
div.onclick = fadeIn;
var div2 = document.getElementById('test2');
div2.onclick = function() {
fadeInAlt(this, 3000);
};
#test {
background-color: red;
width: 30px;
height:30px;
}
#test2 {
background-color: blue;
width: 30px;
height:30px;
}
<div id="test"></div>
<div id="test2"></div>

Checking function for sliding puzzle javascript

I created a sliding puzzle with different formats like: 3x3, 3x4, 4x3 and 4x4. When you run my code you can see on the right side a selection box where you can choose the 4 formats. The slidingpuzzle is almost done. But I need a function which checks after every move if the puzzle is solved and if that is the case it should give out a line like "Congrantulations you solved it!" or "You won!". Any idea how to make that work?
In the javascript code you can see the first function loadFunc() is to replace every piece with the blank one and the functions after that are to select a format and change the format into it. The function Shiftpuzzlepieces makes it so that you can move each piece into the blank space. Function shuffle randomizes every pieces position. If you have any more question or understanding issues just feel free to ask in the comments. Many thanks in advance.
Since I don't have enough reputation I will post a link to the images here: http://imgur.com/a/2nMlt . These images are just placeholders right now.
Here is the jsfiddle:
http://jsfiddle.net/Cuttingtheaces/vkyxgwo6/19/
As always, there is a "hacky", easy way to do this, and then there is more elegant but one that requires significant changes to your code.
Hacky way
To accomplish this as fast and dirty as possible, I would go with parsing id-s of pieces to check if they are in correct order, because they have this handy pattern "position" + it's expected index or "blank":
function isFinished() {
var puzzleEl = document.getElementById('slidingpuzzleContainer').children[0];
// convert a live list of child elements into regular array
var pieces = [].slice.call(puzzleEl.children);
return pieces
.map(function (piece) {
return piece.id.substr(8); // strip "position" prefix
})
.every(function (id, index, arr) {
if (arr.length - 1 == index) {
// last peace, check if it's blank
return id == "blank";
}
// check that every piece has an index that matches its expected position
return index == parseInt(id);
});
}
Now we need to check it somewhere, and naturally the best place would be after each move, so shiftPuzzlepieces() should be updated to call isFinished() function, and show the finishing message if it returns true:
function shiftPuzzlepieces(el) {
// ...
if (isFinished()) {
alert("You won!");
}
}
And voilĂ : live version.
How would I implement this game
For me, the proper way of implementing this would be to track current positions of pieces in some data structure and check it in similar way, but without traversing DOM or checking node's id-s. Also, it would allow to implement something like React.js application: onclick handler would mutate current game's state and then just render it into the DOM.
Here how I would implement the game:
/**
* Provides an initial state of the game
* with default size 4x4
*/
function initialState() {
return {
x: 4,
y: 4,
started: false,
finished: false
};
}
/**
* Inits a game
*/
function initGame() {
var gameContainer = document.querySelector("#slidingpuzzleContainer");
var gameState = initialState();
initFormatControl(gameContainer, gameState);
initGameControls(gameContainer, gameState);
// kick-off rendering
render(gameContainer, gameState);
}
/**
* Handles clicks on the container element
*/
function initGameControls(gameContainer, gameState) {
gameContainer.addEventListener("click", function hanldeClick(event) {
if (!gameState.started || gameState.finished) {
// game didn't started yet or already finished, ignore clicks
return;
}
if (event.target.className.indexOf("piece") == -1) {
// click somewhere not on the piece (like, margins between them)
return;
}
// try to move piece somewhere
movePiece(gameState, parseInt(event.target.dataset.index));
// check if we're done here
checkFinish(gameState);
// render the state of game
render(gameContainer, gameState);
event.stopPropagation();
return false;
});
}
/**
* Checks whether game is finished
*/
function checkFinish(gameState) {
gameState.finished = gameState.pieces.every(function(id, index, arr) {
if (arr.length - 1 == index) {
// last peace, check if it's blank
return id == "blank";
}
// check that every piece has an index that matches its expected position
return index == id;
});
}
/**
* Moves target piece around if there's blank somewhere near it
*/
function movePiece(gameState, targetIndex) {
if (isBlank(targetIndex)) {
// ignore clicks on the "blank" piece
return;
}
var blankPiece = findBlankAround();
if (blankPiece == null) {
// nowhere to go :(
return;
}
swap(targetIndex, blankPiece);
function findBlankAround() {
var up = targetIndex - gameState.x;
if (targetIndex >= gameState.x && isBlank(up)) {
return up;
}
var down = targetIndex + gameState.x;
if (targetIndex < ((gameState.y - 1) * gameState.x) && isBlank(down)) {
return down;
}
var left = targetIndex - 1;
if ((targetIndex % gameState.x) > 0 && isBlank(left)) {
return left;
}
var right = targetIndex + 1;
if ((targetIndex % gameState.x) < (gameState.x - 1) && isBlank(right)) {
return right;
}
}
function isBlank(index) {
return gameState.pieces[index] == "blank";
}
function swap(i1, i2) {
var t = gameState.pieces[i1];
gameState.pieces[i1] = gameState.pieces[i2];
gameState.pieces[i2] = t;
}
}
/**
* Handles form for selecting and starting the game
*/
function initFormatControl(gameContainer, state) {
var formatContainer = document.querySelector("#formatContainer");
var formatSelect = formatContainer.querySelector("select");
var formatApply = formatContainer.querySelector("button");
formatSelect.addEventListener("change", function(event) {
formatApply.disabled = false;
});
formatContainer.addEventListener("submit", function(event) {
var rawValue = event.target.format.value;
var value = rawValue.split("x");
// update state
state.x = parseInt(value[0], 10);
state.y = parseInt(value[1], 10);
state.started = true;
state.pieces = generatePuzzle(state.x * state.y);
// render game
render(gameContainer, state);
event.preventDefault();
return false;
});
}
/**
* Renders game's state into container element
*/
function render(container, state) {
var numberOfPieces = state.x * state.y;
updateClass(container, state.x, state.y);
clear(container);
var containerHTML = "";
if (!state.started) {
for (var i = 0; i < numberOfPieces; i++) {
containerHTML += renderPiece("", i) + "\n";
}
} else if (state.finished) {
containerHTML = "<div class='congratulation'><h2 >You won!</h2><p>Press 'Play!' to start again.</p></div>";
} else {
containerHTML = state.pieces.map(renderPiece).join("\n");
}
container.innerHTML = containerHTML;
function renderPiece(id, index) {
return "<div class='piece' data-index='" + index + "'>" + id + "</div>";
}
function updateClass(container, x, y) {
container.className = "slidingpuzzleContainer" + x + "x" + y;
}
function clear(container) {
container.innerHTML = "";
}
}
/**
* Generates a shuffled array of id-s ready to be rendered
*/
function generatePuzzle(n) {
var pieces = ["blank"];
for (var i = 0; i < n - 1; i++) {
pieces.push(i);
}
return shuffleArray(pieces);
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
}
body {
font-family: "Lucida Grande", "Lucida Sans Unicode", Verdana, Helvetica, Arial, sans-serif;
font-size: 12px;
color: #000;
}
#formatContainer {
position: absolute;
top: 50px;
left: 500px;
}
#formatContainer label {
display: inline-block;
max-width: 100%;
margin-bottom: 5px;
}
#formatContainer select {
display: block;
width: 100%;
margin-top: 10px;
margin-bottom: 10px;
}
#formatContainer button {
display: inline-block;
width: 100%;
}
.piece {
width: 96px;
height: 96px;
margin: 1px;
float: left;
border: 1px solid black;
}
.slidingpuzzleContainer3x3,
.slidingpuzzleContainer3x4,
.slidingpuzzleContainer4x3,
.slidingpuzzleContainer4x4 {
position: absolute;
top: 50px;
left: 50px;
border: 10px solid black;
}
.slidingpuzzleContainer3x3 {
width: 300px;
height: 300px;
}
.slidingpuzzleContainer3x4 {
width: 300px;
height: 400px;
}
.slidingpuzzleContainer4x3 {
width: 400px;
height: 300px;
}
.slidingpuzzleContainer4x4 {
width: 400px;
height: 400px;
}
.congratulation {
margin: 10px;
}
}
<body onload="initGame();">
<div id="slidingpuzzleContainer"></div>
<form id="formatContainer">
<label for="format">select format:</label>
<select name="format" id="format" size="1">
<option value="" selected="true" disabled="true"></option>
<option value="3x3">Format 3 x 3</option>
<option value="3x4">Format 3 x 4</option>
<option value="4x3">Format 4 x 3</option>
<option value="4x4">Format 4 x 4</option>
</select>
<button type="submit" disabled="true">Play!</button>
</form>
</body>
Here we have the initGame() function that starts everything. When called it will create an initial state of the game (we have default size and state properties to care about there), add listeners on the controls and call render() function with the current state.
initGameControls() sets up a listener for clicks on the field that will 1) call movePiece() which will try to move clicked piece on the blank spot if the former is somewhere around, 2) check if after move game is finished with checkFinish(), 3) call render() with updated state.
Now render() is a pretty simple function: it just gets the state and updates the DOM on the page accordingly.
Utility function initFormatControl() handles clicks and updates on the form for field size selection, and when the 'Play!' button is pressed will generate initial order of the pieces on the field and call render() with new state.
The main benefit of this approach is that almost all functions are decoupled from one another: you can tweak logic for finding blank space around target piece, to allow, for example, to swap pieces with adjacent ids, and even then functions for rendering, initialization and click handling will stay the same.
$(document).on('click','.puzzlepiece', function(){
var count = 0;
var imgarray = [];
var test =[0,1,2,3,4,5,6,7,8,'blank']
$('#slidingpuzzleContainer img').each(function(i){
var imgalt = $(this).attr('alt');
imgarray[i] = imgalt;
count++;
});
var is_same = (imgarray.length == test.length) && imgarray.every(function(element, index) {
return element === array2[index];
});
console.log(is_same); ///it will true if two array is same
});
try this... this is for only 3*3.. you pass the parameter and makethe array value as dynamically..

Categories