Drag, drop and local storage

DragAndDrop

Една от многото интересни задачи в курса по JavaScript е свързана с упражняването на Drag and Drop техниката , а също така и използването на Local storage за съхраняване на информация.
За целта създавам игра, в която играчът събира разхвърлени торби с боклук и ги изхвърля в приготвена за целта кофа. При поднасяне на торба над кофата, капака на кофата се отваря. Също така се отчита времето за събиране на всички торби и се прави класиране. След края на всяка игра резултата на играча се записва Local storage. Веднага след това всички резултати се изчитат от Local storage, сортират се и имената на петте най-добри играчи се показват на екрана.

1.Drag and drop.

За да изпълня Drag and drop техниката съм подходил по следния начин:

  1. При създаването на кофата за боклук съм прикачил към нея два event-а. Първият слуша дали има изпуснат боклук в кофата (ondrop) и извиква функцията drop(ev), която измества торбата с боклук в кофата. Вторият слуша дали има провлачване на боклук върху кофата (ondragover) и съответно извиква функцията allowDrop(ev), която да отвори капака на кофата.
    function createTrashCan() {
    var trashCan = document.createElement("div");
    trashCan.id = "trashCan";
    trashCan.addEventListener("drop", drop, false);
    trashCan.addEventListener("dragover", allowDrop, false);
    document.body.appendChild(trashCan);
    }
    
  2. При създаването на площа, върху която е разпилян боклука прикачам към нея event, който слуша дали има провлачване на боклук върху тази площ (ondragover) и съответно извиква функцията closeTrashCan(), която да затвори капака на кофата.
    function createTrashArea() {
    var trashArea = document.createElement("div");
    trashArea.id = "trashArea";
    trashArea.addEventListener("dragover", closeTrashCan, false);
    document.body.appendChild(trashArea);
    createRandomBags();
    }
    
  3. При създаването на всяка от торбите с боклук (функциите createBags() -> createDivElements()) поставям атрибута на „div“ контейнера й draggable = „true“. Също така прикачам към него event, който слуша дали провлачване е започнало (ondragstart) и съответно извиква функцията drag(ev), която записва ID-to  на съответната торба с боклук в специален dataTransfer обект. Така, когато пуснем дадената торба и извикаме функцията drop(ev) може да вземем информацията за ID-то на торбата обратно от същия обект. Използват се двете функции dataTransfer.setData и dataTransfer.getData, съответно за записване и прочитане на информация от обекта.

2.Local storage.

Резултата от всяка игра се записва в Local storage-a -> localStorage.setItem(playerName, seconds). Веднага след записа всички резултати се прочитат обратно от Local storage, сортират се и първите пет се изкарват на екран – loadLocalStorageOnScoreBoard().

function savePlayerScore() {
 localStorage.setItem(playerName, seconds);
 loadLocalStorageOnScoreBoard();
 }

function loadLocalStorageOnScoreBoard() {
if (!localStorage.length || localStorage.length == 0) {
return;
}

var sorterItems = sortLocalStorage();
var resultHTML = "<ul>";

if (localStorage.length > 5) {
var numberOfItemsInScoreBoard = 5;
}
else {
numberOfItemsInScoreBoard = localStorage.length;
}

for (var i = 0; i < numberOfItemsInScoreBoard; i++) {
var playerName = sorterItems[i].key;
var playerValue = sorterItems[i].value;
resultHTML +=
'<li>' +
(i + 1) + ". " + playerName + " : " + playerValue + 's'
'</li>';
}
resultHTML += "</ul>";
document.getElementById("scoreBoard").innerHTML = resultHTML;
}

function sortLocalStorage() {
if (localStorage.length > 0) {
var localStorageArray = new Array();
for (i = 0; i < localStorage.length; i++) {
localStorageArray[i] = new LocalStorageItem(
localStorage.key(i),
localStorage.getItem(localStorage.key(i))
);
}
}
var sortedArray = localStorageArray.sort(comparator);
return sortedArray;
}

Използвал съм отделна функция comparator() за сортиране на информацията в Local storage. Така направена функцията comparator(a,b) и подадена на array.sort() ще сортира масива от обекти (LocalStorageItem(key, value)) в низходящ ред според резултата на играча.

function comparator(a, b) {
 return parseInt(a.value) - parseInt(b.value);
 }

//Class that represents Local storage item
 function LocalStorageItem(key, value)
 {
 this.key = key;
 this.value = value;
 }

Пълният javascript код следва, а тук може да изпробвате демото на играта -> DEMO.

function renderPlaygroud() {
 playerName = document.getElementById("playerName").value;

removeInitialInfo();
 createTrashCan();
 createTrashArea();
 createScoreBoard()
 createTimer();
 }

function removeInitialInfo() {
 var initialInfo = document.getElementById("initialInfo");
 document.body.removeChild(initialInfo);
 }

function createTrashCan() {
 var trashCan = document.createElement("div");
 trashCan.id = "trashCan";
 trashCan.addEventListener("drop", drop, false);
 trashCan.addEventListener("dragover", allowDrop, false);
 document.body.appendChild(trashCan);
 }

function createTrashArea() {
 var trashArea = document.createElement("div");
 trashArea.id = "trashArea";
 trashArea.addEventListener("dragover", closeTrashCan, false);
 document.body.appendChild(trashArea);
 createBags();
 }

function createScoreBoard() {
 var scoreBoard = document.createElement("div");
 scoreBoard.id = "scoreBoard";
 document.body.appendChild(scoreBoard);
 loadLocalStorageOnScoreBoard();
 }

function createBags() {
 var numberBags = 10;
 var docFragment = document.createDocumentFragment();
 for (var i = 0; i < numberBags; i++) {
 var divElement = createDivElement(i);
 docFragment.appendChild(divElement);
 }
 var trashArea = document.getElementById("trashArea");
 trashArea.appendChild(docFragment);
 }

function createDivElement(number) {
 var divElement = document.createElement("div");

//Add inline styles
 divElement.id = "div" + number;
 divElement.style.width = "76px";
 divElement.style.height = "118px";
 divElement.style.backgroundImage = "url('pictures/trash.png')";
 divElement.style.position = "absolute";
 divElement.style.top = generateRandomNumberFromInterval(0, 480) + "px";
 divElement.style.left = generateRandomNumberFromInterval(0, 800) + "px";
 divElement.draggable = "true";
 divElement.addEventListener("dragstart", drag, false);

return divElement;
 }

function generateRandomNumberFromInterval(from, to) {
 return Math.floor(Math.random() * (to - from + 1) + from);
 }

function createTimer() {
 timer = document.createElement("div");
 timer.id = "timer";
 document.body.appendChild(timer);

seconds = 0;
 updateTimer();
 window.setTimeout("tick()", 1000);
 }

function tick() {
 seconds += 1;
 updateTimer();
 window.setTimeout("tick()", 1000);
 }

function updateTimer() {
 var timeString = playerName + " : " + seconds + "s";
 timer.innerHTML = timeString;
 }

function allowDrop(ev) {
 openTrashCan();
 ev.preventDefault();
 }

function drag(ev) {
 ev.dataTransfer.setData("dragged-id", ev.target.id);
 }

function drop(ev) {
 ev.preventDefault();
 var data = ev.dataTransfer.getData("dragged-id");
 var element = document.getElementById(data);
 element.parentNode.removeChild(element);
 closeTrashCan();

var numberOfBags = document.getElementById("trashArea").childNodes.length;
 if (numberOfBags == 0) {
 savePlayerScore(playerName, seconds);
 hidePlayGround();
 var message = document.createElement('p');
 message.innerHTML =
 "Congratulations! You have managed to clean the trash for " + seconds + 's';
 document.body.appendChild(message);
 createResetButton();
 }
 }

function hidePlayGround() {
 var trashCan = document.getElementById("trashCan");
 trashCan.parentNode.removeChild(trashCan);
 var trashArea = document.getElementById("trashArea");
 trashArea.parentNode.removeChild(trashArea);
 var timer = document.getElementById("timer");
 timer.style.display = "none";
 }

function createResetButton() {
 var button = document.createElement("input");
 button.type = "button";
 button.value = "Restart Game";
 button.addEventListener("click", function () { document.location.reload(true) }, false);
 document.body.appendChild(button);
 }

function openTrashCan() {
 var trashCan = document.getElementById("trashCan");
 trashCan.style.backgroundImage = "url('pictures/opened.png')"
 }

function closeTrashCan() {
 var trashCan = document.getElementById("trashCan");
 trashCan.style.backgroundImage = "url('pictures/closed.png')"
 }

function loadLocalStorageOnScoreBoard() {
if (!localStorage.length || localStorage.length == 0) {
return;
}

var sorterItems = sortLocalStorage();
var resultHTML = "<ul>";

if (localStorage.length > 5) {
var numberOfItemsInScoreBoard = 5;
}
else {
numberOfItemsInScoreBoard = localStorage.length;
}

for (var i = 0; i < numberOfItemsInScoreBoard; i++) {
var playerName = sorterItems[i].key;
var playerValue = sorterItems[i].value;
resultHTML +=
'<li>' +
(i + 1) + ". " + playerName + " : " + playerValue + 's'
'</li>';
}
resultHTML += "</ul>";
document.getElementById("scoreBoard").innerHTML = resultHTML;
}

function sortLocalStorage() {
if (localStorage.length > 0) {
var localStorageArray = new Array();
for (i = 0; i < localStorage.length; i++) {
localStorageArray[i] = new LocalStorageItem(
localStorage.key(i),
localStorage.getItem(localStorage.key(i))
);
}
}
var sortedArray = localStorageArray.sort(comparator);
return sortedArray;
}

function comparator(a, b) {
 return parseInt(a.value) - parseInt(b.value);
 }

//Class that represents Local storage item
 function LocalStorageItem(key, value)
 {
 this.key = key;
 this.value = value;
 }

function savePlayerScore() {
 localStorage.setItem(playerName, seconds);
 loadLocalStorageOnScoreBoard();
 }

Оставете коментар

Вашият имейл адрес няма да бъде публикуван. Задължителните полета са отбелязани с *