2014-02-24 1 views
1

참고 : 정확한 질문에 대한 설명은 아래 CSS를 참조하십시오. 샘플 코드는 this 바이올린에서 볼 수 있습니다.JavaScript를 사용하여 마우스로 드래그하여 그래픽 목록 주문

<div class="categories_container"> 
    <div class="category one">One</div> 
    <div class="category two">Two</div> 
    <div class="category three">Three</div> 
    <div class="category four">Four</div> 
    <div class="category five">Five</div> 
    <div class="category six">Six</div> 
</div> 
: 컨테이너와 아이들이 말했다위한

List of children divs

HTML :

나는 다음과 같은 아이의이 그 안에 div를 목록 부모 DIV를 가지고

여기서, 클래스 .one, .two, .three 등등은 클래스의 상대 위치 i 목록.

어린이 요소는 부모 내에 절대 위치 지정을 통해 배치됩니다.

CSS 다음과 같이 (일부 속성은 단순을 위해 도시하지 않음) :

.categories_container { 
    height: 324px; 
    width: 100%; 
    position: relative; 
} 
.category { 
    height: 50px; 
    width: 98%; 
    position: absolute; 
    left: 0px; 
    z-index: 0; 
} 
.one { 
    top: 0px; 
} 
.two { 
    top: 54px; 
} 
.three { 
    top: 108px; 
} 
.four { 
    top: 162px; 
} 
.five { 
    top: 216px; 
} 
.six { 
    top: 270px; 
} 
바와 같이 this 바이올린에서 볼 수

, 당신은 아이의 어느 하나를 클릭 (길게) 수 요소를 만들고 부모 div 내에서 위아래로 이동합니다. 마우스를 놓으면 선택한 자식이 원래 위치로 다시 스냅됩니다.

질문 :

선택한 요소가 서로의 솟다 드래그 된 경우 어떻게 감지 할 수 있습니까? 나는 그들이 겹치는지를 알고 싶을뿐만 아니라 그것에 범위를두기를 원한다. 뭔가 같은 ...

if(center of current child is overtop a set range within another child){ 
    do stuff... 
} 

내가 (개념 증명으로) 지금 할 싶은 무엇이 아래 자녀의 배경 색상 변경 선택한 아이의 동안 수직 중심을 내 것입니다 하위 아동의 신장의 0.4-0.6 범위. 선택한 자식이 해당 영역 밖으로 드래그되면 배경이 다시 변경됩니다.

내가 좋아하는 뭔가를 시도했다 :

$('.category').mouseover(function(){ 
    if(dragging){ 
     ... execute code... 
    } 
}); 

을하지만 내가 다른 통해 하나 개의 요소를 드래그하고있는 경우, 하단 요소가 마우스를 볼 수 없습니다, 그래서 기능이 실행되지 않을 것 같다. 또한

: 나는 상관없이 드래그하는 동안 텍스트 커서로 전환 무엇을 드래그하는 동안 pointer로 커서를 유지하기 위해 몇 가지 방법을 시도,하지만 한

. 그래서 그것으로 어떤 도움을 주시면 감사하겠습니다.

포인터에 대해서는 mousedownmouse move 함수에 $(this).css('cursor', 'pointer');을 넣어 봤지만 아무 소용이 없었습니다.

미리 감사드립니다. 죄송합니다. 혼란스러운 점이 있다면.

+1

jQueryUI의 sortables 당신을 위해 이런 종류의 작업을 수행 ... – dandavis

+0

는 그래서 않습니다. 전에는 들어 보지 못했습니다. [this] (https://jqueryui.com/sortable/) 링크를 보면, 엘리먼트에 수평 자유도가 없도록 작성할 수 있는지 여부를 머리 부분에서 빨리 알 수 있습니까? 제 예제처럼 수직으로 만 움직이는 것을 선호합니다. – Birrel

+0

yes : http://api.jqueryui.com/sortable/#option-axis – dandavis

답변

3

Here은 외부 라이브러리가 필요없고 JQueryUI Sortables를 사용하지 않고 JS와 JQuery를 사용하여 작성한 솔루션입니다.

HTML : list_container 개별 list_item 요소를 보유하고

<div class="list_container"> 
    <div class="list_item">One</div> 
    <div class="list_item">Two</div> 
    <div class="list_item">Three</div> 
    <div class="list_item">Four</div> 
    <div class="list_item">Five</div> 
    <div class="list_item">Six</div> 
</div> 

. 두 사람의 후자가 정렬 된 목록을 만들기 위해 이동할 수 있습니다. list_item 안에 원하는 것을 넣을 수 있으며 여전히 잘 작동합니다.

CSS :

.list_container { 
    position: relative; 
} 
.list_item { 
    position: absolute; 
    z-index: 0; 
    left: 0px; 
} 
.list_item.selected { 
    z-index: 1000; 
} 

은 CSS 규칙의 전체 목록 (만 필요한 사람은 위의 도시)에 대한 this 바이올린을 방문하시기 바랍니다.

자바 스크립트 :

나는이 비트 단위를 통과 한 후 하단에 전체 코드를 보여 드리겠습니다.

첫째로, 나는이 (페이지로드시) 동적으로 클래스를 만드는 데 사용되는 자신의 기록 대응

var classes = new Array("one", "two", "three", ...); 

과 인덱스 번호를 일치하는 배열을 정의했다. 이러한 클래스는 목록을 정렬하는 데 사용됩니다. 목록에있는 수만큼 항목을 채우기 만하면됩니다. 이것은 제가 작성한 코드의 하나의 몰락이며,이 문제를 극복하는 방법을 확신하지 못합니다 (수백 가지 항목 이상을 나열하기 위해 요소를 입력하는 것이 매우 지루합니다!)

다음으로 다른 변수 :

var margin = 2;  // Space desired between each list item 
var $el;    // Used to hold the ID of the element that has been selected 
var oldPos = 0;  // The position of the selected element BEFORE animation 
var newPos = 0;  // The position of the selected element AFTER animation (also current position) 
var dragging = false; // Whether or not an item is being moved 

var numElements = $('.list_container > div').length; 

// selectionHeight is the height of each list element (assuming all the same height) 
// It includes the div height, the height of top and bottom borders, and the desired margin 

var selectionHeight = $('.list_container .list_item').height() + parseInt($('.list_container .list_item').css("border-bottom-width")) + parseInt($('.list_container .list_item').css("border-top-width")) + margin; 

var classInfo = ''; // classInfo will be populated with the information that is used to dynamically create classes upon page load 

페이지를로드 할 때, 각 list_item 통과하고 목록에서 초기 위치에 따라 그것을 클래스를 지정합니다. 또한 classInfo에 목록 항목의 TOP 위치를 추가하십시오.

$('.list_container .list_item').each(function (index) { 
    $(this).addClass(classes[index]); 
    classInfo += '.' + classes[index] + ' {top: ' + index * selectionHeight + 'px;}\n'; 
}); 

이제 위에서 작성한 classInfo을 사용하여 페이지에 클래스를 동적으로 작성하십시오.

var style = document.createElement('style'); 
style.type = 'text/css'; 
style.innerHTML = classInfo; 
document.getElementsByTagName('head')[0].appendChild(style); 

위의 코드 비트는 필요한 클래스를 페이지의 HTML에 기록합니다. 페이지의 소스를 보면 페이지의 머리 부분에 클래스가 표시됩니다.

이제 주문 부탁드립니다.다음과 같이 첫째, mousedown

$('.list_item').mousedown(function (ev) { 
    $el = $(this); 
    oldPos = $el.index() + 1; 
    newPos = oldPos; 
    dragging = true; 
    startY = ev.clientY;    // Gets the current mouse position 
    startT = parseInt($el.css('top')); // Gets the current position of the TOP of the item 
    $el.addClass('selected');   // Adding class brings it to top (z-index) and changes color of list item 
}); 

다음으로, mousemovemouseup 기능을 함께 마지막

$(window).mousemove(function (ev) { // Use $(window) so mouse can leave parent div and still work 
    if (dragging) { 
     $el.attr('class', 'list_item') // Remove the numbered class (.one, .two, etc) 
     $el.addClass('selected');  // Add this class back for aesthetics 

     // ----- calculate new top 
     var newTop = startT + (ev.clientY - startY); 
     $el.css('cursor', 'pointer'); 
     // ------ 

     //------ stay in parent 
     var maxTop = $el.parent().height() - $el.height(); 
     newTop = newTop < 0 ? 0 : newTop > maxTop ? maxTop : newTop; 
     $el.css('top', newTop); 
     //------ 

     newPos = getPos(newTop, selectionHeight); // Determine what the current position of the selected list item is 

     // If the position of the list item has changed, move the position's current element out of the way and reassign oldPos to newPos 
     if (oldPos != newPos) { 
      moveThings(oldPos, newPos, selectionHeight); 
      oldPos = newPos; 
     } 
    } 
}).mouseup(function() { 
    dragging = false;   // User is no longer dragging 
    $el.removeClass('selected'); // Element is no longer selected 
    setNewClass($el, newPos); // Set the new class of the moved list item 
    $el.css('top', (newPos - 1) * selectionHeight); // Position the moved element where it belongs. Otherwise it'll come to rest where you release it, not in its correct position. 
}); 

연결되어, 세 가지 기능 getPos, moveThingssetNewClass은 다음과 같습니다

function getPos(a, b) { // a == newTop, b == selectionHeight 
return Math.round((a/b) + 1); 
} 

getPos 작품 선택된 엘멘 (elemen) t가 현재 입력되어 있습니다. newTop이 0.5b보다 작 으면 영역 1에 있습니다. 0.5b와 1.5b 사이에 있으면 영역 2입니다. 1.5b와 2.5b 사이에 있으면 영역 3에 있습니다. . 종이에 몇 가지 사례를 작성하면 무슨 일이 일어나는지 이해할 수 있습니다.

위의 함수는 실제 애니메이션 부분을 무엇입니까 및 선택한 목록 항목을 수용하기 위해 주위에 목록 항목을 이동합니다. 모든 자바 스크립트 함께

function setNewClass(e, a) { // e == selected element, a == newPos 
    // Remove 'selected' class, then add back the 'list_item' class and the new numbered class 
    e.attr('class', 'list_item').addClass(classes[a-1]); 
} 

** : **

var classes = new Array("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeem", "eighteen", "nineteen", "twenty", "twentyone", "twentytwo", "twentythree", "twentyfour"); 

$(document).ready(function() { 
    var margin = 2; 
    var $el; 
    var oldPos = 0; 
    var newPos = 0; 
    var dragging = false; 

    var selectionHeight = $('.list_container .list_item').height() + parseInt($('.list_container .list_item').css("border-bottom-width")) + parseInt($('.list_container .list_item').css("border-top-width")) + margin; 

    var classInfo = ''; 

    $('.list_container .list_item').each(function (index) { 
     $(this).addClass(classes[index]); 
     classInfo += '.' + classes[index] + ' {top: ' + index * selectionHeight + 'px;}\n'; 
    }); 

    var style = document.createElement('style'); 
    style.type = 'text/css'; 
    style.innerHTML = classInfo; 
    document.getElementsByTagName('head')[0].appendChild(style); 

    $('.list_item').mousedown(function (ev) { 
     $el = $(this); 
     oldPos = $el.index() + 1; 
     newPos = oldPos; 
     dragging = true; 
     startY = ev.clientY; 
     startT = parseInt($el.css('top')); 
     $el.addClass('selected'); 
    }); 

    $(window).mousemove(function (ev) { 
     if (dragging) { 
      $el.attr('class', 'list_item') 
      $el.addClass('selected'); 

      // ----- calculate new top 
      var newTop = startT + (ev.clientY - startY); 
      $el.css('cursor', 'pointer'); 
      // ------ 

      //------ stay in parent 
      var maxTop = $el.parent().height() - $el.height(); 
      newTop = newTop < 0 ? 0 : newTop > maxTop ? maxTop : newTop; 
      $el.css('top', newTop); 
      //------ 

      newPos = getPos(newTop, selectionHeight); 

      if (oldPos != newPos) { 
       moveThings(oldPos, newPos, selectionHeight); 
       oldPos = newPos; 
      } 
     } 
    }).mouseup(function() { 
     dragging = false; 
     $el.removeClass('selected'); 
     setNewClass($el, newPos); 
     $el.css('top', (newPos - 1) * selectionHeight); 
    }); 
}); 

function getPos(a, b) { // a == topPos, b == selectionHeight 
    return Math.round((a/b) + 1); 
} 

function moveThings(a, b, c) { // a == oldPos, b == newPos, c == selectedHeight 
    var first = classes[b - 1]; 
    var $newEl = $('.list_container .' + first); 

    if (a < b) { // oldPos less than newPos 
     var second = classes[b - 2]; 
     var newTop = parseInt($newEl.css('top')) - c; 
    } else { // oldPos more than newPos 
     var second = classes[b]; 
     var newTop = parseInt($newEl.css('top')) + c; 
    } 

    $newEl.css('top', parseInt($newEl.css('top'))); 
    $newEl.removeClass(first); 
    $newEl.animate({ 
     top: newTop 
    }, 300, function() { 
     $newEl.removeAttr('style'); 
    }); 
    $newEl.addClass(second); 

    return false; // Cleans up animations 
} 

function setNewClass(e, a) { // e == selected element, a == newPos 
    e.attr('class', 'list_item').addClass(classes[a - 1]); 
} 
+0

** 편집 ** [이] (http://jsfiddle.net/gGB4x/9/) fiddle에는 클래스 배열이없고 어떤 길이의 목록에서도 작동하는 솔루션이 있습니다. 필자가 작성한'toNumber()'함수를 사용했다. 실제로 숫자를 쓰지는 않습니다 (즉, 22는 2입니다). 그러나 각 클래스는 고유하며 필요한 것은 모두입니다. – Birrel

+0

** EDIT # 2 ** ...이 답변에 마지막으로 추가 ... ** [이쪽 (http://jsfiddle.net/gGB4x/14/) ** 해결 방법은 애니메이션 문제를 해결하고 작동합니다. * 완벽하게 * (내가 아는 한)! 몇 가지 변경 사항 : 1) CSS에서 마진이 변경되었습니다. 2) 부모 div 높이가 자동으로 설정되었습니다. 3) 애니메이션에'.stop() '이 추가되어 이제는 더 잘 작동합니다. 4) toNumer() 클래스의 이름이 변경되었습니다. 혼란을 피하기 위해 이전 주석에서'numToClass()'까지. – Birrel

+1

좋은 솔루션과 쓰기! – dandavis