|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<style> |
|
body > div { |
|
position: absolute; |
|
top: 0; |
|
bottom: 0; |
|
} |
|
|
|
#puzzle { |
|
display: flex; |
|
flex-wrap: wrap; |
|
} |
|
|
|
.tile { |
|
cursor: -webkit-grab; |
|
cursor: -moz-grab; |
|
cursor: grab; |
|
outline: 1px solid #fff; |
|
} |
|
|
|
.tile.hovered { |
|
outline: 2px dotted #999; |
|
} |
|
|
|
.tile:active, |
|
.tile.dragging { |
|
cursor: -webkit-grabbing; |
|
cursor: -moz-grabbing; |
|
cursor: grabbing; |
|
} |
|
|
|
.overlay { |
|
text-align: center; |
|
width: inherit; |
|
height: 260px; |
|
padding-top: 240px; |
|
background: #000; |
|
color: #fff; |
|
position: absolute; |
|
opacity: 0.5; |
|
} |
|
|
|
</style> |
|
</head> |
|
<body> |
|
<div id="puzzle"><!-- Hey, no cheating now --></div> |
|
<div id="peek" style="display:none;"></div> |
|
<script type="text/javascript"> |
|
"use strict"; |
|
|
|
var draggingElement, droppingElement; |
|
var stats = { moves: 0, peeks: 0 }; |
|
var container = document.getElementById('puzzle'); |
|
|
|
window.onload = init; |
|
|
|
function detectDragAndDrop() { |
|
if (navigator.appName == 'Microsoft Internet Explorer') { |
|
var ua = navigator.userAgent; |
|
var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})"); |
|
if (re.exec(ua) != null) { |
|
var rv = parseFloat( RegExp.$1 ); |
|
if(rv >= 6.0) return true; |
|
} |
|
return false; |
|
} |
|
if ('draggable' in document.createElement('span')) return true; |
|
return false; |
|
} |
|
|
|
function init() { |
|
if (!detectDragAndDrop()) { |
|
alert("Your browser doesn't support drag and drop"); |
|
return; |
|
} |
|
|
|
var difficulty = 5; |
|
var img_width = 960; |
|
var img_height = 500; |
|
var img_src = 'https://source.unsplash.com/collection/1521669/' + img_width + 'x' + img_height; |
|
var block = { |
|
width: img_width / difficulty, |
|
height: img_height / difficulty |
|
}; |
|
|
|
container.style.width = img_width + 'px'; |
|
container.style.height = img_height + 'px'; |
|
|
|
assemblePuzzle(block, img_width, img_height, img_src, container); |
|
initializePeek(img_width, img_height, img_src); |
|
|
|
} |
|
|
|
function initializePeek(width, height, img) { |
|
var peek = document.getElementById('peek'); |
|
var peekKey = 'alt'; |
|
|
|
peek.style.backgroundImage = 'url(' + img + ')'; |
|
peek.style.width = width + 'px'; |
|
peek.style.height = height + 'px'; |
|
|
|
window.addEventListener('mousedown', function(ev) { |
|
if (ev.button == 2 && peek.style.display === 'none') { |
|
peek.style.display = 'block'; |
|
stats.peeks++; |
|
} |
|
}); |
|
|
|
window.addEventListener('mouseup', function(ev) { |
|
if (ev.button === 2 && peek.style.display === 'block') { |
|
peek.style.display = 'none'; |
|
} |
|
}); |
|
|
|
window.addEventListener('contextmenu', function(ev) { |
|
ev.preventDefault(); |
|
return false; |
|
}); |
|
} |
|
|
|
function assemblePuzzle(b, img_w, img_h, src, parent) { |
|
|
|
var blocks = []; |
|
var tile; |
|
|
|
for (var h = 0, i = 0; h < img_h; h += b.height) { |
|
for (var w = 0; w < img_w; w += b.width, i++) { |
|
tile = document.createElement('DIV'); |
|
tile.style.backgroundImage = 'url(' + src + ')'; |
|
tile.style.backgroundPositionX = (-1 * w) + 'px'; |
|
tile.style.backgroundPositionY = (-1 * h) + 'px'; |
|
tile.id = i; |
|
tile.className = 'tile'; |
|
tile.style.height = b.height + 'px'; |
|
tile.style.width = b.width + 'px'; |
|
tile.draggable = true; |
|
tile.addEventListener('dragstart', handleDragStart, false); |
|
tile.addEventListener('dragend', handleDragEnd, false); |
|
tile.addEventListener('dragover', handleDragOver, false); |
|
tile.addEventListener('dragenter', handleDragEnter, false); |
|
tile.addEventListener('dragleave', handleDragLeave, false); |
|
tile.addEventListener('drop', handleDrop, false); |
|
|
|
blocks.push(tile); |
|
} |
|
} |
|
|
|
shuffle(blocks).forEach(function(node) { |
|
parent.append(node); |
|
}); |
|
} |
|
|
|
function handleDragStart(event) { |
|
draggingElement = this; |
|
draggingElement.className += ' dragging'; |
|
event.dataTransfer.setData('text/plain', this.id); |
|
} |
|
|
|
function handleDragEnd() { |
|
draggingElement.className = 'tile'; |
|
draggingElement.blur(); |
|
draggingElement = undefined; |
|
} |
|
|
|
function handleDragEnter() { |
|
if (this === draggingElement) return; |
|
this.className += ' hovered'; |
|
} |
|
|
|
function handleDragLeave() { |
|
if (this === draggingElement) return; |
|
this.className = 'tile'; |
|
} |
|
|
|
function handleDrop(event) { |
|
if (event.stopPropagation) event.stopPropagation(); // Stops some browsers from redirecting. |
|
if (event.preventDefault) event.preventDefault(); |
|
|
|
if (this !== draggingElement) { |
|
swap(draggingElement, this); |
|
this.className = 'tile'; |
|
stats.moves++; |
|
isWinner(); |
|
} |
|
} |
|
|
|
function handleDragOver(event) { |
|
if (event.preventDefault()) event.preventDefault(); |
|
|
|
return false; // some browsers may need this to prevent default |
|
} |
|
|
|
function swap(a, b) { |
|
var tmpX = b.style.backgroundPositionX; |
|
var tmpY = b.style.backgroundPositionY; |
|
var tmpid = b.id; |
|
|
|
b.style.backgroundPositionX = a.style.backgroundPositionX; |
|
b.style.backgroundPositionY = a.style.backgroundPositionY; |
|
b.id = a.id; |
|
|
|
a.style.backgroundPositionX = tmpX; |
|
a.style.backgroundPositionY = tmpY; |
|
a.id = tmpid; |
|
} |
|
|
|
function isWinner() { |
|
var img; |
|
var delay = 100; |
|
|
|
for (var i = 0; i < container.children.length; i++) { |
|
img = container.children[i]; |
|
if (+img.id !== i) return; |
|
} |
|
|
|
var overlay = document.createElement('DIV'); |
|
overlay.className = 'overlay'; |
|
overlay.innerHTML = '<h1>You solved the puzzle in ' + stats.moves + ' moves and peeked ' + stats.peeks +' times</h1>'; |
|
container.appendChild(overlay); |
|
} |
|
|
|
function randomInt(max) { |
|
return Math.floor(Math.random() * Math.floor(max)); |
|
} |
|
|
|
function shuffle(arr) { |
|
for (var j, n = arr.length - 1; n > 0; n--) { |
|
j = randomInt(n); |
|
exchange(n,j); |
|
} |
|
|
|
return arr; |
|
|
|
function exchange(a,b) { |
|
var tmp = arr[a]; |
|
arr[a] = arr[b]; |
|
arr[b] = tmp; |
|
} |
|
} |
|
|
|
</script> |
|
</body> |
|
</html> |