Как я могу установить «ограничивающую» область для моего перетаскиваемого объекта в JavaScript? - PullRequest
18 голосов
/ 27 февраля 2011

Я создаю движок Drag and Drop JavaScript. Я узнал, как установить ограничивающий прямоугольник в качестве родительского элемента. Однако теперь я хочу установить ограничивающий прямоугольник для любого родителя любого родителя или для всей страницы (без ограничений).

Прямо сейчас мой Javascript Engine выглядит так:

// JavaScript Document

var dragObj;

document.addEventListener("mousedown", down, false);

function down(event) {
    if(~event.target.className.search(/drag/)) {
        dragObj = makeObj(event.target);
        dragObj.element.style.zIndex="100";
        document.addEventListener("mousemove", freeMovement, false);
    }
}

function freeMovement(event) {

    if (typeof(dragObj.element.mouseup) == "undefined")
        document.addEventListener("mouseup", drop, false);
    //Prevents redundantly adding the same event handler repeatedly

    dragObj.element.style.left = Math.max(0, Math.min(event.clientX - dragObj.posX, dragObj.boundX)) + "px";
    dragObj.element.style.top = Math.max(0, Math.min(event.clientY - dragObj.posY, dragObj.boundY)) + "px";
}

function drop() {
    dragObj.element.style.zIndex="1";

    document.removeEventListener("mousemove", freeMovement, false);
    document.removeEventListener("mouseup", drop, false);
    //alert("DEBUG_DROP");
}

function makeBoundlessObj(e) {
    var obj = new Object();
    obj.element = e;

    obj.boundX = e.parentNode.offsetWidth - e.offsetWidth;
    obj.boundY = e.parentNode.offsetHeight - e.offsetHeight;

    obj.posX = event.clientX - e.offsetLeft;
    obj.posY = event.clientY - e.offsetTop;

    return obj;
}

function makeObj(e) {
    obj = new Object();
    obj.element = e;

    obj.boundX = e.parentNode.offsetWidth - e.offsetWidth;
    obj.boundY = e.parentNode.offsetHeight - e.offsetHeight;

    obj.posX = event.clientX - e.offsetLeft;
    obj.posY = event.clientY - e.offsetTop;

    var curleft = curtop = 0;
    if (e.offsetParent) {
        do {
            curleft += e.offsetLeft;
            curtop += e.offsetTop;
            //alert(e.id + ":" + e.innerHTML);
            if(~e.className.search(/bound/)) {
                obj.boundX = curleft - obj.element.offsetLeft;
                obj.boundY = curtop - obj.element.offsetTop;
                return obj;
            }

        } while (e = e.offsetParent);
    }

    return obj;
}

function findPos(obj) { // Donated by `lwburk` on StackOverflow
    var curleft = curtop = 0;
    if (obj.offsetParent) {
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
        return { x: curleft, y: curtop };
    }
}

Мой CSS выглядит следующим образом:

@charset "utf-8";
/* CSS Document */


* {
    padding: 0px;
    margin: 0px;
}

.drag {
    position: absolute;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
}

.bound {
    position: relative;
}

.square {
    width: 100px;
    height: 100px;
    background: red;
    cursor:move;
}

#center {
    width: 500px;
    height: 300px;
    margin: auto;
    margin-top: 50px;
    background-color:#ccc;
    text-align: center;
    border-radius: 25px;
    -moz-border-radius: 25px;
}

#box {
    background-color: #FF3;
    height: 278px;
    border-radius: 0 0 25px 25px;
    -moz-border-radius: 0 0 25px 25px;
    opacity: 0.5;
}

И мой HTML довольно чистый:

<div id="center">
    <h1>Hello World! <hr /></h1>
    <div id="box" class="bound">
        <p class="drag square"> One </p>
        <p class="drag square"> Two </p>
    </div>
</div>

Я пытался выполнять нужные функции несколько раз. Я дам один, который я сделал, который не работает, и я перечислю почему:

  1. Если у него нет границ, я устанавливаю границы по умолчанию в качестве родительского элемента (потому что я не знаю, как установить границы для всей страницы)

  2. Если один из родительских элементов IS связан, то я неправильно устанавливаю связанные координаты (опять же, я не знаю, как)

О, и я устанавливаю границы при создании объекта drag_object.

Функция создания JavaScript:

function makeObj(e) {
    var obj = new Object();
    obj.element = e;

    obj.boundX = e.parentNode.offsetWidth - e.offsetWidth;
    obj.boundY = e.parentNode.offsetHeight - e.offsetHeight;

    obj.posX = event.clientX - e.offsetLeft;
    obj.posY = event.clientY - e.offsetTop;

    var curleft = curtop = 0;
    if (e.offsetParent) {
        do {
            curleft += e.offsetLeft;
            curtop += e.offsetTop;
            //alert(e.id + ":" + e.innerHTML);
            if(~e.className.search(/bound/)) {
                obj.boundX = curleft - obj.element.offsetLeft;
                obj.boundY = curtop - obj.element.offsetTop;
                return obj;
            }

        } while (e = e.offsetParent);
    }

    return obj;
}

Какая математика правильна для установки ограничительной рамки и почему? Можно ли избавиться от position: relative в классе .bound? Могу ли я сделать .drag класс не position: absolute? Я знаю, что все эти вещи, вероятно, сильно повлияют на то, как написана ограничительная функция. Если бы у меня было , чтобы выбрать между классом .drag или классу .bound, для которого не требуется определенный тип position, я бы выбрал для класса .bound любое позиционирование. .

Спасибо всем за чтение и помощь! Это очень много значит для меня; Я учусь в школе (интернат) с очень небольшим количеством свободного времени = /

EDIT:

Я должен отметить, что у меня десятый день изучения Javascript или пятнадцатый час в зависимости от того, как вы на него смотрите, и я хотел бы выучить язык, прежде чем начать использовать библиотеки, такие как jQuery. Этот двигатель - академическое упражнение, которое я сделал для себя ради знаний и изучения языка =]

Ответы [ 2 ]

19 голосов
/ 04 марта 2011

Первое, что я заметил, это то, что у вас не было минимальной границы.Это понадобится вам для обеспечения верхней и нижней границы.

Какова правильная математика для установки ограничительной рамки и почему?

Во-первых, dragObj необходимо учитывать обе границы (относится к position: absolute):

// parentNode is our bounding box
// the minimum boundary is based on the top left corner of our container
obj.minBoundX = e.parentNode.offsetLeft;
obj.minBoundY = e.parentNode.offsetTop;

// the maximum is the bottom right corner of the container
// or.. the top left (x,y) + the height and width (h,y) - the size of the square
obj.maxBoundX = obj.minBoundX + e.parentNode.offsetWidth - e.offsetWidth;
obj.maxBoundY = obj.minBoundY + e.parentNode.offsetHeight - e.offsetHeight;

Обеспечение соблюдения границ - это простое обновление для freeMovement:

dragObj.element.style.left = Math.max(dragObj.minBoundX, Math.min(event.clientX - dragObj.posX, dragObj.maxBoundX)) + "px";
dragObj.element.style.top = Math.max(dragObj.minBoundY, Math.min(event.clientY - dragObj.posY, dragObj.maxBoundY)) + "px";

Могу ли я избавиться от позиции: относительной в классе .bound? Да.

Могу ли я сделать класс .drag не позиционным: абсолютным? Да.Вы просто хотите изменить свои позиции, чтобы быть относительными и ваши расчеты для учета этого.Например, ваша минимальная граница теперь будет 0.

// parentNode is our bounding box
// the minimum boundary is based on the top left corner of our container
obj.minBoundX = 0;
obj.minBoundY = 0;

Вот JSFiddle для position:absolute версии: http://jsfiddle.net/feWcQ/ (работает с Firefox 4).Я также добавил две крошечные коробки, которые показывают ваши границы.Надеюсь, мой ответ поможет вам!

2 голосов
/ 01 марта 2011

Итак, перед тем, как нанести удар, я настоятельно рекомендую книгу OReilly "Полное руководство по JavaScript".Я изучил тонну там (и впоследствии забыл это, когда я не должен был использовать это каждый день).

Таким образом, существует множество способов снять шкуру с этой кошки, но мне сложнее всего определить положения соответствующих вещей в кросс-браузерном режиме без использования библиотеки.На самом деле я не помню точный синтаксис (поэтому я не буду пытаться), но в основном вам нужно найти позицию ограничивающего прямоугольника и положение перетаскиваемого элемента по следующей формуле: http://blog.firetree.net/2005/07/04/javascript-find-position/, а затемдля ширины элементов и т. д. чтобы оставаться внутри ящиков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...