Javascript 在HTML表格上拖动所选内容(带colspan/rowspan的方形/矩形部分)

Javascript 在HTML表格上拖动所选内容(带colspan/rowspan的方形/矩形部分),javascript,jquery,css,angularjs,html-table,Javascript,Jquery,Css,Angularjs,Html Table,我正在研究如何在表中选择单元格,但在我的例子中,单元格可以有一个colspan或rowspan,这样选择就不会局限于正方形/矩形选择(尝试选择“1-3”和“2-3”,这两个选项也会自动选择“1-4”)。这和问题类似,但我一直没能找到任何有效的方法。你知道这将如何实施吗 链接: HTML 我使用了起始单元格和结束单元格的x和y坐标,然后计算对应矩形内的每个单元格(甚至部分)。然后获取这些单元格的边框,并重复此过程,直到选择不再扩展 编辑:功能rectangleSelect是(几乎完全)来自: 编辑

我正在研究如何在表中选择单元格,但在我的例子中,单元格可以有一个colspan或rowspan,这样选择就不会局限于正方形/矩形选择(尝试选择“1-3”和“2-3”,这两个选项也会自动选择“1-4”)。这和问题类似,但我一直没能找到任何有效的方法。你知道这将如何实施吗

链接:

HTML


我使用了起始单元格和结束单元格的x和y坐标,然后计算对应矩形内的每个单元格(甚至部分)。然后获取这些单元格的边框,并重复此过程,直到选择不再扩展

编辑:功能
rectangleSelect
是(几乎完全)来自:

编辑2:现在支持rowspan和其他边缘,如选择[3-2,2-3]:

HTML:


安古拉斯普朗克
文件。写(“”);
1-1
1-2
1-3
1-4
2-1
2-32-2
3-1
3-2
3-4
4-1
4-2
4-3
4-4
所选ID:{IDs | json}

CSS:未更改

JS:

var-app=angular.module('plunker',[]);
应用程序控制器('MainCtrl',函数($scope){
$scope.ids=[];
});
应用程序指令('dragSelect',函数($window,$document){
返回{
范围:{
DragSelectId:“=”
},
控制器:函数($scope$element){
var cls=‘工程选定项目’;
var startCell=null;
var=false;
功能鼠标(el){
拖动=假;
}
功能鼠标向下(el){
拖动=真;
电池(el);
setEndCell(el);
}
功能鼠标器(el){
如果(!拖动)返回;
setEndCell(el);
}
函数setStartCell(el){
startCell=el;
}
函数setEndCell(el){
$scope.dragSelectIds=[];
$element.find('td').removeClass(cls);
$(cellsBetween(startCell,el))。每个(函数(){
var el=角度元素(本);
el.addClass(cls);
$scope.dragSelectIds.push(el.attr('id'));
});
}
函数isPointBetween(点,x1,x2){

返回(点>=x1&&point应该选择1-1作为左上角,2-3作为右下角,也应该选择1-4?然后如何选择1-1,1-2,1-3,2-1,2-2,2-3?可能类似的东西更适合您所寻找的功能:是的。它应该基本上模仿excel的功能。因此选择应该始终是正方形的/矩形。谢谢!但是如果有行跨度(尝试从3-2拖动到3-4),有人可以添加对多个选择的支持吗?每次我做一个新的选择时,旧的选择都会显示出来?当一行的所有单元格合并,并尝试选择垂直的一列,横穿整行时会出现错误。(如十字架)
<table drag-select drag-select-ids="ids">
      <tr>
        <td id="td-1-1">1-1</td>
        <td id="td-1-2">1-2</td>
        <td id="td-1-3">1-3</td>
        <td id="td-1-4">1-4</td>
      </tr>
      <tr>
        <td id="td-2-1">2-1</td>
        <td id="td-2-2">2-2</td>
        <td id="td-2-3" colspan="2">2-3</td>
      </tr>
      <tr>
        <td id="td-3-1">3-1</td>
        <td id="td-3-2">3-2</td>
        <td id="td-3-3">3-3</td>
        <td id="td-3-4">3-4</td>
      </tr>
      <tr>
        <td id="td-4-1">4-1</td>
        <td id="td-4-2">4-2</td>
        <td id="td-4-3">4-3</td>
        <td id="td-4-4">4-4</td>
      </tr>
    </table>
var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.ids = [];
});

app.directive('dragSelect', function($window, $document) {
  return {
    scope: {
      dragSelectIds: '='
    },
    controller: function($scope, $element) {
      var cls = 'eng-selected-item';
      var startCell = null;
      var dragging = false;

      function mouseUp(el) {
        dragging = false;
      }

      function mouseDown(el) {
        dragging = true;
        setStartCell(el);
        setEndCell(el);
      }

      function mouseEnter(el) {
        if (!dragging) return;
        setEndCell(el);
      }

      function setStartCell(el) {
        startCell = el;
      }

      function setEndCell(el) {
        $scope.dragSelectIds = [];
        $element.find('td').removeClass(cls);
        cellsBetween(startCell, el).each(function() {
          var el = angular.element(this);
          el.addClass(cls);
          $scope.dragSelectIds.push(el.attr('id'));
        });
      }

      function cellsBetween(start, end) {
        var coordsStart = getCoords(start);
        var coordsEnd = getCoords(end);
        var topLeft = {
          column: $window.Math.min(coordsStart.column, coordsEnd.column),
          row: $window.Math.min(coordsStart.row, coordsEnd.row),
        };
        var bottomRight = {
          column: $window.Math.max(coordsStart.column, coordsEnd.column),
          row: $window.Math.max(coordsStart.row, coordsEnd.row),
        };
        return $element.find('td').filter(function() {
          var el = angular.element(this);
          var coords = getCoords(el);
          return coords.column >= topLeft.column
              && coords.column <= bottomRight.column
              && coords.row >= topLeft.row
              && coords.row <= bottomRight.row;
        });
      }

      function getCoords(cell) {
        var row = cell.parents('row');
        return {
          column: cell[0].cellIndex, 
          row: cell.parent()[0].rowIndex
        };
      }

      function wrap(fn) {
        return function() {
          var el = angular.element(this);
          $scope.$apply(function() {
            fn(el);
          });
        }
      }

      $element.delegate('td', 'mousedown', wrap(mouseDown));
      $element.delegate('td', 'mouseenter', wrap(mouseEnter));
      $document.delegate('body', 'mouseup', wrap(mouseUp));
    }
  }
});
[drag-select] {
  cursor: pointer;
 -webkit-touch-callout: none;
 -webkit-user-select: none;
 -khtml-user-select: none;
 -moz-user-select: none;
 -ms-user-select: none;
 user-select: none;
}

[drag-select] .eng-selected-item {
  background: blue;
  color: white;
}

td {
  padding: 10px;
  border: 1px solid gray;
}
<!DOCTYPE html>
<html ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="jquery" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
    <script data-require="angular.js@1.2.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.min.js" data-semver="1.2.16"></script>
    <script src="app.js"></script>
  </head>

  <body ng-controller="MainCtrl">
    <table drag-select drag-select-ids="ids">
      <tr>
        <td id="td-1-1">1-1</td>
        <td id="td-1-2">1-2</td>
        <td id="td-1-3">1-3</td>
        <td id="td-1-4">1-4</td>
      </tr>
      <tr>
        <td id="td-2-1" colspan=2>2-1</td>
        <td id="td-2-3" rowspan="2">2-3</td
        ><td id="td-2-4">2-2</td>
      </tr>
      <tr>
        <td id="td-3-1">3-1</td>
        <td id="td-3-2">3-2</td>
        <td id="td-3-4">3-4</td>
      </tr>
      <tr>
        <td id="td-4-1">4-1</td>
        <td id="td-4-2">4-2</td>
        <td id="td-4-3">4-3</td>
        <td id="td-4-4">4-4</td>
      </tr>
    </table>
    <p>Selected IDs: {{ids | json}}</p>
  </body>

</html>
var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.ids = [];
});

app.directive('dragSelect', function($window, $document) {
  return {
    scope: {
      dragSelectIds: '='
    },
    controller: function($scope, $element) {
      var cls = 'eng-selected-item';
      var startCell = null;
      var dragging = false;

      function mouseUp(el) {
        dragging = false;
      }

      function mouseDown(el) {
        dragging = true;
        setStartCell(el);
        setEndCell(el);
      }

      function mouseEnter(el) {
        if (!dragging) return;
        setEndCell(el);
      }

      function setStartCell(el) {
        startCell = el;
      }

      function setEndCell(el) {
        $scope.dragSelectIds = [];
        $element.find('td').removeClass(cls);
        $(cellsBetween(startCell, el)).each(function() {
          var el = angular.element(this);
          el.addClass(cls);
          $scope.dragSelectIds.push(el.attr('id'));
        });
      }

      function isPointBetween(point,x1,x2){
        return (point >=x1 && point <=x2) ||(point <=x1 && point>=x2);
      }
      function rectangleSelect(selector, bounds) {
    var elements = [];
    jQuery(selector).each(function() {
        var $this = jQuery(this);
        var offset = $this.offset();
        var x = offset.left;
        var y = offset.top;
        var w = $this.outerWidth();
        var h = $this.outerHeight();
        if ((isPointBetween(x,bounds.minX,bounds.maxX) && isPointBetween(y,bounds.minY,bounds.maxY))||
            (isPointBetween(x+w,bounds.minX,bounds.maxX) && isPointBetween(y+h,bounds.minY,bounds.maxY))
            ) {
            elements.push($this.get(0));
        }
    });
    return elements;
}
      function getBoundsForElements(elements){
        var x1= elements.reduce(function(currMinX,element){
          var elementLeft = $(element).offset().left;
          return currMinX && currMinX<elementLeft ? currMinX : elementLeft;
        },undefined);
        var x2= elements.reduce(function(currMaxX,element){
          var elementRight = $(element).offset().left+$(element).outerWidth();
          return currMaxX && currMaxX>elementRight ? currMaxX : elementRight;
        },undefined);
        var y1= elements.reduce(function(currMinY,element){
          var elementTop = $(element).offset().top;
          return currMinY && currMinY<elementTop ? currMinY : elementTop;
        },undefined);
        var y2= elements.reduce(function(currMaxY,element){
          var elementBottom = $(element).offset().top+$(element).outerHeight();
          return currMaxY && currMaxY>elementBottom ? currMaxY : elementBottom;
        },undefined);
        return {
          minX: x1,
          maxX: x2,
          minY: y1,
          maxY: y2
        };

      }


      function cellsBetween(start, end) {
        var bounds,elementsInside;
        elementsInside = [start,end];
        do{
          bounds = getBoundsForElements(elementsInside);
          var elementsInsideAfterExpansion = rectangleSelect("td",bounds);
          if(elementsInside.length==elementsInsideAfterExpansion.length)
            return elementsInside;
          else
            elementsInside=elementsInsideAfterExpansion;
        }while(true)

      }


      function wrap(fn) {
        return function() {
          var el = angular.element(this);
          $scope.$apply(function() {
            fn(el);
          });
        }
      }

      $element.delegate('td', 'mousedown', wrap(mouseDown));
      $element.delegate('td', 'mouseenter', wrap(mouseEnter));
      $document.delegate('body', 'mouseup', wrap(mouseUp));
    }
  }
});