js实现框选(依赖jquery)
这个例子的关键之处有两点选择框和盒子与选择框相交的算法
1、选择框相关算法
选择框有如图所示的四种拖动情况。最简单的情况是第一种情况从起点向右下角拖动这种情况只需要设置选择框的宽高就行。另外三种情况的话不仅要设置宽带高度还需要设置选择框的坐标位置。
- 四种情况都需要设置宽高则在最开始为其设置宽高
- x方向上,当向右不管,向左的话将起点的x坐标向左移动宽度的距离
- y方向上,当向下不管,向上的话则将起点的y坐标想上移动高度的距离
核心代码:
//选择框核心代码
//x,y为当前鼠标的位置
function resizeToPoint(x,y){
var width = Math.abs(x-startX);
var height = Math.abs(y-startY);
rector.width(width);
rector.height(height);
//当鼠标x方向上为向左拖动 设置left位置
if(x<startX){
rector.css({
left:(startX-width)+'px',
});
}
//当鼠标y方向上为向上拖动 设置top位置
if(y<startY){
rector.css({
top:(startY-height)+'px',
});
}
}
2、矩形相交算法
由下图可看出只要确定一个点在另外一个点的内部即可证明相交,这个点的关系:x:x1< x< x2,y:y1< y< y2
对于点(x1’,y1’)的判断是:(x1< x1’< x2)&&(y1< y1’< y2)
这样一个点一个点的判断似乎太麻烦了。其实我们只需要判断两个矩形不想交取反就行。只要y1’>y2 就表示红色框在蓝色框下方相反y1>y2’证明蓝色框在红色框下面。在x方向上同样的道理。只要满足x方向上不重合并且y方向上不重合就表示矩形不想交。所以不相交的公式如下:- (x1>x2’ || x1’>x2) || (y1>y2’ || y1’>y2)
/**
*核心相交算法
* @param rect1{x1,y1,x2,y2}
* @param rect2 {x1,y1,x2,y2}
*/
function isCross(rect1,rect2){
var xNotCross=true;//x方向上不重合
var yNotCross = true;//y方向上不重合
xNotCross =((rect1.x1>rect2.x2) || (rect2.x1>rect1.x2));
yNotCross = ((rect1.y1>rect2.y2) || (rect2.y1>rect1.y2));
return !(xNotCross || yNotCross);
}
3、源码
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script src="http://127.0.0.1/bower_components/jquery/dist/jquery.js"></script>
<style>
.dragbox {
float: left;
list-style: none;
width: 100px;
height: 100px;
border: 1px solid;
margin: 20px;
}
.dragbox, img {
-webkit-user-select: none;
-webkit-user-drag: none;
}
.draging {
background-color: aquamarine;;
}
.selected{
background-color: #FF0;
}
* {
cursor: default;
}
</style>
</head>
<body>
<ul style="display: inline-block">
<li class="dragbox" id="box1">1</li>
<li class="dragbox" id="box2">2</li>
<li class="dragbox" id="box3">3</li>
<li class="dragbox" id="box4">4</li>
<li class="dragbox" id="box5">5</li>
<li class="dragbox" id="box6">6</li>
<li class="dragbox" id="box7">7</li>
<li class="dragbox" id="box8">8</li>
<li class="dragbox" id="box9">9</li>
<li class="dragbox" id="box10">10</li>
<li class="dragbox" id="box11">11</li>
<li class="dragbox" id="box12">12</li>
<li class="dragbox" id="box13">13</li>
<li class="dragbox" id="box14">14</li>
<li class="dragbox" id="box15">15</li>
<li class="dragbox" id="box16">16</li>
<li class="dragbox" id="box17">17</li>
<li class="dragbox" id="box18">18</li>
<li class="dragbox" id="box19">19</li>
<li class="dragbox" id="box20">20</li>
</ul>
<div id="selectionRect" style="position: absolute;background-color: rgba(137,189,189,0.5);border:1px solid rgb(137,189,189);;"></div>
</body>
</html>
<script>
var rector = $('#selectionRect');
//拖选起点
var startX = 0;
var startY = 0;
//选择框核心代码
function resizeToPoint(x,y){
var width = Math.abs(x-startX);
var height = Math.abs(y-startY);
rector.width(width);
rector.height(height);
//当鼠标x方向上为向左拖动 设置left位置
if(x<startX){
rector.css({
left:(startX-width)+'px',
});
}
//当鼠标y方向上为向上拖动 设置top位置
if(y<startY){
rector.css({
top:(startY-height)+'px',
});
}
}
/**
*核心相交算法
* @param rect1{x1,y1,x2,y2}
* @param rect2 {x1,y1,x2,y2}
*/
function isCross(rect1,rect2){
var xNotCross=true;//x方向上不重合
var yNotCross = true;//y方向上不重合
xNotCross =((rect1.x1>rect2.x2) || (rect2.x1>rect1.x2));
yNotCross = ((rect1.y1>rect2.y2) || (rect2.y1>rect1.y2));
return !(xNotCross || yNotCross);
}
/**
*获取元素的矩形的起始点坐标与其对角点坐标
* @param $el
* @return {x1,y1,x2,y2}
*/
function getRect($el){
var x1 = $el.offset().left;
var y1 = $el.offset().top;
var x2 = x1 +$el.outerWidth();
var y2 = y1+$el.outerHeight();
return {x1,x2,y1,y2};
}
//框选处理 如果元素与选择框相交则设置样式
function handleRectSelection(){
var selectionReact = getRect(rector);
$('.dragbox').each(function(){
var rect = getRect($(this));
if(isCross(selectionReact,rect)){
$(this).addClass('selected');
}else{
$(this).removeClass('selected');
}
});
}
$(window).on({
mousemove:function(e){
if(e.which===1){
rector.show();
resizeToPoint(e.pageX, e.pageY);
handleRectSelection();
}
},
mouseup:function(){
rector.hide();
},
mousedown:function(e){
startX = e.pageX;
startY = e.pageY;
rector.css({
top: startY+'px',
left: startX+'px'
});
}
});
</script>