Если "тянуть" draggable элемент за край, то событие применятся сразу ко всем элементам

172
17 апреля 2022, 04:00

есть блок с draggable элементами, добавил js, все хорошо работает, но если постараться потянуть за край drag элемента - drag event применяется ко всем элементам

<html>
  <head>  
    <script src="https://code.jquery.com/jquery-3.5.0.js"></script> 
  </head>
  <body>
    <div class="sequence-scale"></div>
    <div class="promt"></div>
  </body>
</html> 

вот js, который строит шкалу, хотя я уверен проблема не в нем

let zones = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24];
const build = () =>
 {
   const elem =    // list of different elements
     {
       topLine: '<div class="scale__line top-line" draggable="false"><span></span></div>',
       topLineReverse: '<div class="scale__line top-line-reverse" draggable="false"><span style="left: 0;"></span></div>',
       middleLine: '<div class="scale__line middle-line" draggable="false"></div>',
       bottomLine: '<div class="scale__line bottom-line" draggable="false"><span></span></div>',
       halfroundDefault: '<div class="scale__halfround default-halfround"></div>',
       halfroundReverse: '<div class="scale__halfround reverse-halfround"></div>',
     },  
         inLine = 6,   // max amount of elements at one line
         $scale = $(".sequence-scale");
 // data for constructing the scale    
   let reverse = inverseBuild = false,
       amount = zones.length,
       lines = Math.ceil( amount / inLine ),
       halfrounds = lines - 1,
       total = Math.trunc(amount / lines),
       remainder = amount - total * lines;
   // console.log("total: "+ total + ", remainder: " + remainder + ", amount: " + amount)
 // constructing top line
   if(halfrounds % 2 == 0)
     {
       $scale.append(elem.topLineReverse);   // top line - reverse
       reverse = inverseBuild = true;
     }
     else 
       $scale.append(elem.topLine);    // top line - default
   
 // constructing middle lines and bottom line
   for(let i = 0; i < halfrounds; i++)  
     {
       if(inverseBuild && halfrounds !== 0)
         $scale.append(elem.halfroundReverse);
       else  
         $scale.append(elem.halfroundDefault);  
       if(i == halfrounds - 1)
         $scale.append(elem.bottomLine);
       else   
         $scale.append(elem.middleLine);
       inverseBuild = !inverseBuild;  
     }
   const append = function($list)
     {
       $list.append('<div draggable="true" data-order="' + amount +'" data-zone-id="' + amount +'" class="zone__list">' + amount + '</div>');
       amount--;
     };   
 // appending (adding) element at line
   for(let i = 0; i < lines; i++)
     { 
       let $line = $('.scale__line').eq(i);    // The line on which is appending (adding) elements on the current iteration of the loop
       if(!reverse)        
         $line.addClass('order-reverse');
       
       if(i + remainder >= lines)     // if there is remainder
         {
           for(let i = 0; i < (total + 1); i++)    // append (add) elements at a line with remainder
             {
               append($line);
             }
         }
         else 
           {
             for(let i = 0; i < total; i++)    // append (add) elements at a line 
               {
                 append($line);
               }
           }
           
       reverse = !reverse      
     }       
 };
build();

js, который меняет порядок и обрабатывает drag events

 
const items = () => 
  {
    const $list = $('.scale__line'),
          $items = $('.zone__list');
    
  // function that reads data- attribute and writes it to array        
    const readData = function()     
      {
        let data = [];    // array with objects for every item parameters
        $items.each( function(i)
          {
            let $this = $(this);
            data[( $items.length - 1 - i)] = //
              {
                id: $this.attr('data-zone-id'),
                order: $this.attr('data-order')
              };
              
          });    
          
        return data;  
      };
  // function that changes the item order on the scale    
    const changeOrder = function()     
      {
        let data = readData(),    // read data-
            by_order = [],    // data array by order
            quantity = [],    // amount of elements on the every line (row)
            addingNum = 0;    
      // write value to the quantity array      
        for(let i = 0; i < $list.length; i++)
          {
            quantity[i] = $list.eq(i).children('div').length;    
          }
      // filling array (by_order) and detach elements
        for(let i = 0; i < data.length; i++)
          {
            let result = data.find(elem => elem.order == i + 1);    // get needed element
            if(!result)
              return;
            let elem = $(".zone__list[data-zone-id='" + result.id +"']").detach();    // detach element by id
            // console.log("| elem = " + elem.text() + "|order = " + result.order + "|id = " + result.id  ); // for debugging
            by_order[i] =    // write values to array
              {
                order: result.order,
                id: result.id,
                element: elem
              };
          }
        
      // append elements back in new order 
        for(let i = 0; i < $list.length; i++)    // ratio:  i = 0  to i = max  AS top line to bottom line, how much lines - so many loops
          {
            let $this = $list.eq(i),
                len = quantity[i];
            for(let i = 0; i < len; i++)    // append elements at aline at the same amount, in order
              {
                by_order[by_order.length -( addingNum + i + 1)].element.appendTo($this);    // append elements back
              }
            addingNum += len;
          }
      };
     let $active, $over, contains, thisCenter,
        changeable = false,
        insert = ["insert After", "insert Before"], inserted;
        
    $items.prop("draggable", true);      
       
    const dragStart = function(e)  
      {
        e.stopPropagation();
        $(this).addClass('selected'); 
      }

    const dragEnter = function(e)  
      {
        e.preventDefault();
        e.stopPropagation();
        let $current = $(e.target);
        $active = $('.selected');
        changeable = false;
      if(!($active[0] !== $current[0]))
        return;
        
        $over = $current;
        $over.addClass('over');
        
        changeable = true;
        contains = ($over.parent().attr("class").split(' ')).includes('order-reverse');
        
        if(contains)
          [insert[0], insert[1]] = [insert[1], insert[0]];
        let thisCoord = $current[0].getBoundingClientRect(); 
        thisCenter = thisCoord.x + thisCoord.width / 2;
        $('.promt').css(
          {
            'top': (thisCoord.top - 35) + "px",
            'left': (thisCoord.left - 28) + "px",
            'opacity': "1"
          });    
      }
      
    const dragOver = function(e)  
      {
        e.stopPropagation();
        e.preventDefault();
        if(!changeable)
          return;
        
        if(window.event.clientX > thisCenter)
          {
            $('.promt').text(insert[1]);
            $over.css('background','linear-gradient(270deg, #4d774e 50%, transparent 50%)');
            inserted = insert[1] ;
          }
          else 
            {
              $('.promt').text(insert[0]);
              $over.css('background','linear-gradient(90deg, #4d774e 50%, transparent 50%)');
              inserted = insert[0];
            }
      }
    const dragLeave = function(e)  
      {
        setDefault();
      }  
    const dragEnd = function(e)  
      {
        e.preventDefault();
        e.stopPropagation();
        if(!changeable)
          {
            $('.selected').removeClass('selected');  
            return;
          }
        let newData = parseInt($over.attr('data-order')),
            oldData = parseInt($active.attr('data-order')),
            affectedNum;
        if(inserted === 'insert After')
          inserted = 1;
        else  
          inserted = 0;  
        if(newData > oldData)    
          {
            affectedNum = newData - oldData;
            if(!inserted)
              affectedNum--;
            for(let i = 0; i < affectedNum; i++ )
              {
                let currentElem = oldData + i + 1,
                    $this = $(".zone__list[data-order='" + currentElem +"']");
                
                $this.attr('data-order', currentElem - 1 );
              }
            $active.attr("data-order", affectedNum + oldData);
          }
        else
          {
            affectedNum = oldData - newData;
            if(inserted)
              affectedNum--;
            for(let i = 0; i < affectedNum; i++ )
              {
                let currentElem = oldData - i - 1,
                    $this = $(".zone__list[data-order='" + currentElem +"']");
                
                $this.attr('data-order', currentElem + 1 );
              }
            $active.attr("data-order", oldData - affectedNum);
          }   
     
        changeOrder();  
        setDefault();
        $('.selected').removeClass('selected');
      }  
    const setDefault = function()
      {
        if(!changeable)
          return;
        $over.css('background','rgb(77, 119, 78)').removeClass('over');
        $('.promt').css('opacity','0');
        if(contains)
          [insert[0], insert[1]] = [insert[1], insert[0]];
        contains = false;
      }  
    $items.on('dragstart', dragStart);
    $items.on('dragenter', dragEnter);
    $items.on('dragover', dragOver);
    $items.on('dragleave', dragLeave); 
    $items.on('dragend', dragEnd);    
  }
items();

и сss

 *, *::before, *::after
  {
    padding: 0%;
    margin: 0%;
    box-sizing: border-box;
    font-size: 8pt;
  }
body
  {
    font-family: sans-serif;
    font-weight: normal;
    background-color: rgb(157, 200, 141);
    padding: 10px;
  }
.sequence-scale
  {
    max-width: 500px;
    display: flex;
    flex-direction: column;
    margin-top: 40px;
    --line-height: 6px;
    --halfround-height: 9px;
    --background:rgb(22, 74, 65);
    pointer-events: none;
  }
.scale__line
  {
    position: relative;
    height: var(--line-height);  
    background-color: var(--background);
    width: calc(100% - 50px);
    z-index:2;
    display: flex;
    justify-content: space-between;
    pointer-events: none;
  }
.top-line
  {
    margin-bottom: calc( (var(--halfround-height) + var(--line-height)) / 2 * -1 );
    margin-left: auto;
    padding: 0 70px 0 20px;
  }  
.top-line-reverse
  {
    margin-bottom: calc( (var(--halfround-height) + var(--line-height)) / 2 * -1 );
    margin-right: auto;
    padding: 0 20px 0 70px;
  }  
.middle-line
  {
    margin-bottom: calc( (var(--halfround-height) + var(--line-height)) / 2 * -1 );
    margin-top: calc( (var(--halfround-height) + var(--line-height)) / 2 * -1 );
    width: calc(100% - 100px);
    margin-left: auto;
    margin-right: auto;
    padding: 0 20px;
  }   
  
.bottom-line
  {
    margin-top: calc( (var(--halfround-height) + var(--line-height)) / 2 * -1 );
    margin-left: auto;
    padding: 0 70px 0 20px;
  } 

.order-reverse
  {
    flex-direction: row-reverse;
  }
.scale__halfround
  {
    position: relative;
    height: 80px;
    width: 80px;
    border: var(--halfround-height) solid var(--background);
    z-index: 1;
  }
.default-halfround
  {
    border-radius: 50% 0 0 50%;
    border-right: transparent;
  }  
.reverse-halfround
  {
    margin-left: auto;
    border-radius: 0 50% 50% 0;
    border-left: transparent;
  } 
   
.zone__list
  {
    pointer-events: auto;
    list-style-type: none;
    margin-top: -10px;
    width: 30px;
    height: 30px;
    background-color: rgb(77, 119, 78);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: white;
    cursor: grab;
    transition: transform 0.2s;
  }  
   
.scale__line span
  {
    position: absolute;
    height: 15px;
    width: 6px;
    background-color: var(--background);
    top: calc( ( 15px - 6px ) / -2);
    right: 0;
  }
.selected
  {
    filter: brightness(0.6);
  }  
.over 
  {
    transform: scale(1.5);
    filter: brightness(1.45);
    content: '';
  }  
.promt
  {
    position: absolute;
    width:75px;
    height:10px;
    padding:4px 5px;
    background: rgba(22, 74, 65, .6);
    color:rgb(255, 255, 255);
    text-align: center;
    border-radius: 5px;
    display: flex;
    align-items: center;
    justify-content: center;
    box-sizing: content-box;
    font-family: Verdana, Geneva, Tahoma, sans-serif;
    opacity: 0;
    transition: opacity 0.4s;
  }
.promt::before 
  {
    content:'';
    position:absolute;
    bottom:-8px;
    left:calc(50% - 8px);
    border-left:8px solid transparent;
    border-right:8px solid transparent;
    border-top:8px solid rgba(22, 74, 65, .6);
  }
Answer 1

Проблема была: при попытке потянуть за край выделялся объект и полностью ломал всю логику javascript, все решилось при добавление в сss

body
 {
   user-select:none;
 }
READ ALSO
Как работать с cors

Как работать с cors

Делаю fetch-запрос на сервер, но получаю предупреждение о corsКак можно обработать POST-запрос на сервер

123
Как настроить метки в яндекс картах?

Как настроить метки в яндекс картах?

Как сделать чтобы при открытии балуна метка оставалась окрашенной? При закрытии балуна метки должны быть черными

106
Взаимодействие с элементами другой страницы

Взаимодействие с элементами другой страницы

Допустим есть две страницы, хранящиеся в одной папкеНа каждой странице есть по две кнопки

190
Решение задачи проходит 5/7 тестов [закрыт]

Решение задачи проходит 5/7 тестов [закрыт]

Хотите улучшить этот вопрос? Добавьте больше подробностей и уточните проблему, отредактировав это сообщение

101