Kinetic.SortableList = function(config){ Kinetic.Group.call(this, config); this.data = config.data; this.initExercise(); this.createExercise(); this.eventHandlers(); } Kinetic.SortableList.prototype = { createExercise: function(){ // list group this.itemGroup = new Kinetic.Group({}); this.add(this.itemGroup); // list items var itemData = shuffleArray(this.data.items); var yPos = 0; var labelHeight = 0; var labelWidth = 0; this.maxWidth = 0; this.items = new Array(); for (var i = 0; i < itemData.length; i++){ this.items[i] = new Kinetic.DragItem({ 'data': itemData[i], 'y': yPos, 'draggable': true }); this.itemGroup.add(this.items[i]); labelHeight = this.items[i].label.getHeight(); labelWidth = this.items[i].label.getWidth(); if (labelWidth > this.maxWidth){ this.maxWidth = labelWidth; } yPos += labelHeight + 5; } this.totalHeight = yPos - 5; }, addedToStage: function(){ // same width for all items + drag bounds var startY = this.getParent().getY() - 10; var endY = startY + this.totalHeight; for (var i = 0; i < this.items.length; i++){ this.items[i].label.setWidth(this.maxWidth); this.items[i].setDragBoundFunc(function(pos){ var newY = pos.y; if (newY < startY){ newY = startY; } else if (newY > endY){ newY = endY; } return { 'x': this.getAbsolutePosition().x, 'y': newY } }); } this.draw(); }, eventHandlers: function(){ var thisObject = this; for (var i = 0; i < this.items.length; i++){ this.items[i].on('dragstart', function(evt){ thisObject.dragStart(this, evt); }); this.items[i].on('dragmove', function(evt){ thisObject.dragMove(this, evt); }); this.items[i].on('dragend', function(evt){ thisObject.dragEnd(this, evt); }); } }, dragStart: function(thisObject, evt){ thisObject.moveToTop(); }, dragMove: function(thisObject, evt){ var myY = thisObject.getY(); var myOriY = thisObject.oriY; var myHeight = thisObject.label.getHeight(); var otherY = 0; var otherOriY = 0; var newY = 0; var myCenterY = myY + (myHeight / 2); var otherOriCenterY = 0; for (var i = 0; i < this.items.length; i++){ // only move other items if (thisObject != this.items[i]){ otherY = this.items[i].getY(); otherOriY = this.items[i].oriY; otherOriCenterY = otherOriY + (this.items[i].label.getHeight() / 2); // original positions: item below dragged item if (otherOriY > myOriY){ if (myCenterY > otherOriCenterY){ // go up this.items[i].setY(otherOriY - myHeight - 5); } else { // reset this.items[i].setY(otherOriY); } } // original positions: item above dragged item if (otherOriY < myOriY){ if (myCenterY < otherOriCenterY){ // go down this.items[i].setY(otherOriY + myHeight + 5); } else { // reset this.items[i].setY(otherOriY); } } } } }, dragEnd: function(thisObject, evt){ // sort items by position this.items.sort(function(a, b){ return a.getY()-b.getY(); }); // set new oriY on all items + move dragged item to the right spot var y = 0; var thisY = 0; for (var i = 0; i < this.items.length; i++){ this.items[i].oriY = y; if (thisObject == this.items[i]){ thisY = y; } y += this.items[i].label.getHeight() + 5; } var tween = new Kinetic.Tween({ 'node':thisObject, 'y': thisY, 'duration': 0.2, 'easing': Kinetic.Easings.EaseInOut }); tween.play(); }, checkAnswer: function(){ this.attempts -= 1; if (this.attempts == 0){ this.blockExercise(); } this.correct = true; var orderedItems = new Array(); for (var i = 0; i < this.items.length; i++){ if (i == this.items[i].data.position){ this.items[i].setCorrect(); } else { this.items[i].setWrong(); this.correct = false; } orderedItems[this.items[i].data.position] = this.items[i]; } // move to correct position if (!this.correct){ var y = 0; for (var i = 0; i < orderedItems.length; i++){ var tween = new Kinetic.Tween({ 'node':orderedItems[i], 'y': y, 'duration': 1, 'easing': Kinetic.Easings.EaseInOut }); tween.play(); y += orderedItems[i].label.getHeight() + 5; } } this.getLayer().draw(); this.showFeedback(this.correct, this.attempts); } } Kinetic.Util.extend(Kinetic.SortableList, Kinetic.ExerciseType);