我有这样的代码:
$(function() {
var $selection = $('.selection');
$('li').filter(function() {
var self = $(this);
return /* ????? */;
}).addClass('selected');
});
.widget {
width: 320px;
height: 200px;
border: 1px solid gray;
position: absolute;
overflow: scroll;
}
.selection {
position: absolute;
top: 90px;
left: 90px;
border: 1px dotted black;
height: 120px;
width: 120px;
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
float: left;
background: blue;
width: 40px;
height: 40px;
margin: 10px;
}
li.selected {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="widget">
<div class="selection"></div>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
如何只选择与.selection矩形相交的li元素?
答案 0 :(得分:5)
使用标准DOM技术,您可以迭代每个LI元素并获得一个边界矩形,该矩形给出了LI矩形的坐标。
也可以选择矩形,然后只需检查坐标是否在选择范围内。
的 Element.getBoundingClientRect() 强>
Element.getBoundingClientRect()方法返回元素的大小及其相对于视口的位置。
返回的值是一个DOMRect对象,它是getClientRects()为元素返回的矩形的并集,即与元素关联的CSS边框。
返回的值是一个DOMRect对象,它包含描述边框的只读左,上,右,下,x,y,宽度,高度属性,以像素为单位。宽度和高度以外的属性相对于视口的左上角。
请参阅下面的编辑代码,该代码选择完全包含或部分与选择相交的LI元素。
var selection = document.querySelector(".selection");
var rectSelection = selection.getBoundingClientRect();
// Iterate over all LI elements.
[].forEach.call(document.querySelectorAll("li"), function(li) {
var rect = li.getBoundingClientRect();
if(rect.top + rect.height > rectSelection.top
&& rect.left + rect.width > rectSelection.left
&& rect.bottom - rect.height < rectSelection.bottom
&& rect.right - rect.width < rectSelection.right) {
li.classList.add("selected");
}
});
&#13;
.widget {
width: 320px;
height: 200px;
border: 1px solid gray;
position: absolute;
overflow: scroll;
}
.selection {
position: absolute;
top: 90px;
left: 90px;
border: 1px dotted black;
height: 120px;
width: 120px;
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
float: left;
background: blue;
width: 40px;
height: 40px;
margin: 10px;
}
li.selected {
background: red;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="widget">
<div class="selection"></div>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
&#13;
答案 1 :(得分:1)
理解盒子碰撞的概念 Origin answer
如果必须通过旋转检查2个视图,则必须在另一个矩形的轴上投影矩形角。 如果rect1的所有投影都击中了rect2,并且rect2投影击中了rect1,那么两个rect会碰撞。
有些投影不会在这里碰撞,2个投影不会发生碰撞。
4个投影击中另一个矩形,2个投影相撞。
我已就此CodePen做了一个演示,以便更加理解。
在这里克隆代码(它已经老了,并且不要粗鲁,只是为了显示..不要看代码:p)
function merge_object(obj1, obj2){
var obj3 = {};
for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
return obj3;
};
/**
* Transforme degrees to radians
*/
Math.radians = function(degrees) {
return degrees * Math.PI / 180;
};
Math.degrees = function(radians) {
return radians * 180 / Math.PI;
};
/**
* Square Javascript File
*
* -- Changelog
* Version 1.0.0 (11/05/2013) AGE
* - Début du versionnement
*
* @package js
* @author AGE
* @version 1.0.0
*/
// App Object
var collide = {
// Define
PROJECT_ID : 'collide',
PROJECT_SPEED : 50, // FPS : 1000/PROJECT_SPEED
FIXED_SQUARE_SIZE : 100,
FIXED_SQUARE_X : 250,
FIXED_SQUARE_Y : 250,
CURSOR_SQUARE_SIZE : 50,
// Attribute
$el : null,
$ctx : null,
project_pos_top : null,
project_pos_left : null,
width : null,
height : null,
cursor_x : 0,
cursor_y : 0,
fixed_angle : 0,
fixed_rotaton_speed : null,
cursor_angle : 0,
cursor_rotaton_speed : null,
draw_approx : true,
fixed_projections : {},
cursor_projections : {},
/**
* Init Square Game
*/
__init : function( options ){
// Get element and informations
collide.$el = $('#' + collide.PROJECT_ID);
collide.$ctx = collide.$el[0].getContext('2d');
var offset = collide.$el.offset();
collide.project_pos_top = offset.top;
collide.project_pos_left = offset.left;
collide.width = collide.$el.width();
collide.height = collide.$el.height();
// Events on Move
collide.$el.mousemove(function(e){
// Calculate new position
collide.cursor_x = e.pageX - collide.project_pos_left;
collide.cursor_y = e.pageY - collide.project_pos_top;
});
$('#cursor_set_angle').change(function(){
collide.cursor_angle = parseInt($(this).val());
});
$('#fixed_set_angle').change(function(){
collide.fixed_angle = parseInt($(this).val());
});
// Run the project
collide.run();
},
/**
* Run the project
*/
run : function(){
// Reset HTML
$('.corners, .functions, .projections').remove();
// Get 2 angles rotation speed
collide.fixed_rotaton_speed = parseInt($('#fixed_rotation_speed').val());
collide.cursor_rotaton_speed = parseInt($('#cursor_rotation_speed').val());
// Upadte rotation
collide.fixed_angle = collide.fixed_angle+collide.fixed_rotaton_speed;
if(collide.fixed_angle > 360) {collide.fixed_angle -= 360};
if(collide.fixed_angle < 0) {collide.fixed_angle += 360};
$('#fixed_angle').val(collide.fixed_angle);
collide.cursor_angle = collide.cursor_angle+collide.cursor_rotaton_speed;
if(collide.cursor_angle > 360) {collide.cursor_angle -= 360};
if(collide.cursor_angle < 0) {collide.cursor_angle += 360};
$('#cursor_angle').val(collide.cursor_angle);
// Approx Collide
if(collide.is_approx_collide()){
collide.draw_approx = false;
// Get corners
var fixer_corner = collide.get_corners(
collide.FIXED_SQUARE_X, collide.FIXED_SQUARE_Y,
collide.FIXED_SQUARE_SIZE, collide.fixed_angle);
var cursor_corner = collide.get_corners(
collide.cursor_x, collide.cursor_y,
collide.CURSOR_SQUARE_SIZE, collide.cursor_angle);
// Get projections
// CURSOR on FIXED.X && FIXED.Y
collide.cursor_projections = collide.get_projections(
collide.FIXED_SQUARE_X, collide.FIXED_SQUARE_Y,
collide.fixed_angle,cursor_corner);
// FIXED on CURSOR.X && CURSOR.Y
collide.fixed_projections = collide.get_projections(
collide.cursor_x, collide.cursor_y,
collide.cursor_angle, fixer_corner);
}else{
collide.draw_approx = true;
}
collide.draw();
// Re-lauch Run
setTimeout(function(){
collide.run();
}, collide.PROJECT_SPEED);
},
draw : function(){
// Clear
collide.$ctx.clearRect(0, 0, collide.width, collide.height);
collide.$ctx.setTransform(1, 0, 0, 1, 0, 0);
collide.$ctx.save();
// Draw squares
collide.draw_square(collide.FIXED_SQUARE_X, collide.FIXED_SQUARE_Y,
collide.FIXED_SQUARE_SIZE, collide.fixed_angle, '0,0,255');
collide.draw_square(collide.cursor_x, collide.cursor_y,
collide.CURSOR_SQUARE_SIZE, collide.cursor_angle, '255,128,0');
if(collide.draw_approx){
// Approx
collide.draw_approx_square(collide.FIXED_SQUARE_X, collide.FIXED_SQUARE_Y,
collide.FIXED_SQUARE_SIZE, '0,0,255');
collide.draw_approx_square(collide.cursor_x, collide.cursor_y,
collide.CURSOR_SQUARE_SIZE, '255,128,0');
}
else{
// Axes
collide.draw_axe(collide.FIXED_SQUARE_X, collide.FIXED_SQUARE_Y,
collide.fixed_angle, '0,0,255');
collide.draw_axe(collide.cursor_x, collide.cursor_y,
collide.cursor_angle, '255,128,0');
// Projections
collide.draw_projections( collide.fixed_projections, '0,0,255');
collide.draw_projections( collide.cursor_projections, '255,128,0');
}
},
draw_square : function(center_x, center_y, size, angle, rgb){
// Is collide ?
if(collide.is_approx_collide() && collide.is_collide()){ rgb = "255,0,0"; }
collide.$ctx.save();
// Draw Fixed square
collide.$ctx.translate(center_x, center_y);
collide.$ctx.rotate( Math.radians( angle ) );
collide.$ctx.fillStyle = 'rgba('+rgb+',.2)';
collide.$ctx.fillRect(size / -2, size / -2, size, size);
// Draw Corner
collide.$ctx.translate(size/2, size/2);
collide.$ctx.beginPath();
collide.$ctx.fillStyle = 'rgba('+rgb+',1)';
collide.$ctx.arc(0, 0, 2, 0, Math.PI*2, true);
collide.$ctx.closePath();
collide.$ctx.fill();
collide.$ctx.translate(-size, 0);
collide.$ctx.beginPath();
collide.$ctx.fillStyle = 'rgba('+rgb+',1)';
collide.$ctx.arc(0, 0, 2, 0, Math.PI*2, true);
collide.$ctx.closePath();
collide.$ctx.fill();
collide.$ctx.translate(0, -size);
collide.$ctx.beginPath();
collide.$ctx.fillStyle = 'rgba('+rgb+',1)';
collide.$ctx.arc(0, 0, 2, 0, Math.PI*2, true);
collide.$ctx.closePath();
collide.$ctx.fill();
collide.$ctx.translate(size,0);
collide.$ctx.beginPath();
collide.$ctx.fillStyle = 'rgba('+rgb+',1)';
collide.$ctx.arc(0, 0, 2, 0, Math.PI*2, true);
collide.$ctx.closePath();
collide.$ctx.fill();
collide.$ctx.restore();
},
draw_approx_square : function(center_x, center_y, size, rgb){
collide.$ctx.save();
// Draw Fixed square
collide.$ctx.translate(center_x, center_y);
collide.$ctx.strokeStyle = 'rgba('+rgb+',1)';
collide.$ctx.lineWidth = 1;
collide.$ctx.strokeRect(-size, -size, 2*size, 2*size);
collide.$ctx.restore();
},
draw_axe : function (center_x, center_y, angle, rgb){
collide.$ctx.save();
collide.$ctx.translate(center_x, center_y);
collide.$ctx.rotate( Math.radians( angle ) );
collide.$ctx.beginPath();
collide.$ctx.strokeStyle = 'rgba('+rgb+',1)';
collide.$ctx.moveTo(-500, 0);
collide.$ctx.lineTo(500,0);
collide.$ctx.stroke();
collide.$ctx.restore();
collide.$ctx.save();
collide.$ctx.translate(center_x, center_y);
collide.$ctx.rotate( Math.radians( angle+90 ) );
collide.$ctx.beginPath();
collide.$ctx.strokeStyle = 'rgba('+rgb+',1)';
collide.$ctx.moveTo(-500,0);
collide.$ctx.lineTo(500,0);
collide.$ctx.stroke();
collide.$ctx.restore();
},
draw_projections : function(projections, rgb){
for(axe in projections){
for(key in ['min', 'max']){
var projection = projections[axe][key==0?"min":"max"];
collide.$ctx.save();
collide.$ctx.translate(projection.x, projection.y);
collide.$ctx.beginPath();
collide.$ctx.fillStyle = 'rgba('+rgb+',1)';
collide.$ctx.arc(0, 0, 2, 0, Math.PI*2, true);
collide.$ctx.closePath();
collide.$ctx.fill();
collide.$ctx.beginPath();
collide.$ctx.strokeStyle = 'rgba('+rgb+',.2)';
collide.$ctx.moveTo(00,0);
collide.$ctx.lineTo(projection.corner.x - projection.x,
projection.corner.y - projection.y);
collide.$ctx.stroke();
collide.$ctx.restore();
}
collide.$ctx.save();
collide.$ctx.beginPath();
collide.$ctx.strokeStyle = (projections[axe].is_collide)? 'rgba(255,0,0,1)' : 'rgba('+rgb+',1)';
collide.$ctx.lineWidth = 2;
collide.$ctx.moveTo(projections[axe].min.x, projections[axe].min.y);
collide.$ctx.lineTo(projections[axe].max.x,projections[axe].max.y);
collide.$ctx.stroke();
collide.$ctx.restore();
}
},
/**
* Calculate corners position and draw it
*/
get_corners : function(x, y, size, angle){
var corners = [];
var radius = parseInt(Math.sqrt(2*size*size)/2);
for(var i_angle=0; i_angle<=270; i_angle+=90){
var corner = {
x : parseInt(x + radius * Math.cos(Math.radians(angle + 45 + i_angle) )),
y : parseInt(y + radius * Math.sin(Math.radians(angle + 45 + i_angle) ))
};
corners.push(corner);
}
return corners;
},
/**
* Calculate square functions and draw it
*/
get_functions : function(x, y, size, angle){
var functions = {
x : Math.tan(Math.radians( - angle%90)),
y : Math.tan(Math.radians(90 - angle%90))
};
return functions;
},
get_projections : function(center_x, center_y,angle, corners){
// Genere start Min-Max projection on center of Square
var projections = {
"x": {
'min' : null,
'max' : null,
'distance' : null
},
"y": {
'min' : null,
'max' : null,
'distance' : null
}
};
for(i in corners){
var corner = corners[i];
var projection_x = {}, projection_y = {};
/**
* Global calcul for projection X and Y
*/
// Angle 0:horizontale (center > left) 90:verticatale (center > top)
var angle90 = -(angle%90);
//Distance :
var distance_corner_center = Math.floor(Math.sqrt((center_x-corner.x)*(center_x-corner.x) + (center_y-corner.y)*(center_y-corner.y)));
// Angle between segment [center-corner] and real axe X (not square axe), must be negative (radius are negative clockwise)
var angle_with_axeX = -Math.floor(Math.degrees(Math.atan((corner.y-center_y) / (corner.x-center_x)))); // Tan(alpha) = opposé (ecart sur Y) / adjacent (ecart sur X)
// If angle is ]0;90[, he is on the 2em et 4th quart of rotation
if(angle_with_axeX > 0) {angle_with_axeX -= 180;}
// If corner as upper (so with less pixel on y) thant center, he is on 3th or 4th quart of rotation
if(corner.y < center_y || (corner.y == center_y && corner.x < center_x) ){angle_with_axeX -= 180;}
// Calculate difference between 2 angles to know the angle between [center-corner] and Square axe X
var delta_angle = angle_with_axeX - angle90;
// If angle is on ]-180;-360], corner are upper than Square axe X, so set a positive angle on [0;180]
if(delta_angle < -180){delta_angle += 360;}
/**
* Projection on X
*/
// Calculate distance between center and projection on axe X
var distance_center_projection_x = Math.floor(distance_corner_center * Math.cos(Math.radians( delta_angle )));
// Create projection
projection_x.x = Math.floor(center_x + distance_center_projection_x * Math.cos(Math.radians( -angle90 )));
projection_x.y = Math.floor(center_y + distance_center_projection_x * Math.sin(Math.radians( -angle90 )));
// If is the min ?
if(projections.x.min == null
|| distance_center_projection_x < projections.x.min.distance){
projections.x.min = projection_x;
projections.x.min.distance = distance_center_projection_x;
projections.x.min.corner = corner;
}
// Is the max ?
if(projections.x.max == null
|| distance_center_projection_x > projections.x.max.distance){
projections.x.max = projection_x;
projections.x.max.distance = distance_center_projection_x;
projections.x.max.corner = corner;
}
/**
* Projection on Y
*/
// Calculate distance between center and projection on axe Y
var distance_center_projection_y = Math.floor(distance_corner_center * Math.cos(Math.radians( delta_angle-90 )));
// Create projection
projection_y.x = Math.floor(center_x + distance_center_projection_y * Math.cos(Math.radians( -angle90 -90 )));
projection_y.y = Math.floor(center_y + distance_center_projection_y * Math.sin(Math.radians( -angle90 -90)));
// If is the min ?
if(projections.y.min == null
|| distance_center_projection_y < projections.y.min.distance){
projections.y.min = projection_y;
projections.y.min.distance = distance_center_projection_y;
projections.y.min.corner = corner;
}
// Is the max ?
if(projections.y.max == null
|| distance_center_projection_y > projections.y.max.distance){
projections.y.max = projection_y;
projections.y.max.distance = distance_center_projection_y;
projections.y.max.corner = corner;
}
}
// Return object
return projections;
},
is_approx_collide : function(){
return (collide.FIXED_SQUARE_X + collide.FIXED_SQUARE_SIZE + collide.CURSOR_SQUARE_SIZE >= collide.cursor_x
&& collide.FIXED_SQUARE_Y + collide.FIXED_SQUARE_SIZE + collide.CURSOR_SQUARE_SIZE >= collide.cursor_y
&& collide.FIXED_SQUARE_X <= collide.cursor_x + collide.FIXED_SQUARE_SIZE + collide.CURSOR_SQUARE_SIZE
&& collide.FIXED_SQUARE_Y <= collide.cursor_y + collide.FIXED_SQUARE_SIZE + collide.CURSOR_SQUARE_SIZE) ? true : false;
},
is_collide : function(){
collide.fixed_projections.x.is_collide =
( (collide.fixed_projections.x.min.distance <= -collide.CURSOR_SQUARE_SIZE/2 && collide.fixed_projections.x.max.distance >= -collide.CURSOR_SQUARE_SIZE/2 )
|| (collide.fixed_projections.x.min.distance <= collide.CURSOR_SQUARE_SIZE/2 && collide.fixed_projections.x.max.distance >= collide.CURSOR_SQUARE_SIZE/2 )
|| (collide.fixed_projections.x.min.distance >= -collide.CURSOR_SQUARE_SIZE/2 && collide.fixed_projections.x.max.distance <= collide.CURSOR_SQUARE_SIZE/2 )) ? true : false;
collide.fixed_projections.y.is_collide =
( (collide.fixed_projections.y.min.distance <= -collide.CURSOR_SQUARE_SIZE/2 && collide.fixed_projections.y.max.distance >= -collide.CURSOR_SQUARE_SIZE/2 )
|| (collide.fixed_projections.y.min.distance <= collide.CURSOR_SQUARE_SIZE/2 && collide.fixed_projections.y.max.distance >= collide.CURSOR_SQUARE_SIZE/2 )
|| (collide.fixed_projections.y.min.distance >= -collide.CURSOR_SQUARE_SIZE/2 && collide.fixed_projections.y.max.distance <= collide.CURSOR_SQUARE_SIZE/2 )) ? true : false;
collide.cursor_projections.x.is_collide =
( (collide.cursor_projections.x.min.distance <= -collide.FIXED_SQUARE_SIZE/2 && collide.cursor_projections.x.max.distance >= -collide.FIXED_SQUARE_SIZE/2 )
|| (collide.cursor_projections.x.min.distance <= collide.FIXED_SQUARE_SIZE/2 && collide.cursor_projections.x.max.distance >= collide.FIXED_SQUARE_SIZE/2 )
|| (collide.cursor_projections.x.min.distance >= -collide.FIXED_SQUARE_SIZE/2 && collide.cursor_projections.x.max.distance <= collide.FIXED_SQUARE_SIZE/2 )) ? true : false;
collide.cursor_projections.y.is_collide =
( (collide.cursor_projections.y.min.distance <= -collide.FIXED_SQUARE_SIZE/2 && collide.cursor_projections.y.max.distance >= -collide.FIXED_SQUARE_SIZE/2 )
|| (collide.cursor_projections.y.min.distance <= collide.FIXED_SQUARE_SIZE/2 && collide.cursor_projections.y.max.distance >= collide.FIXED_SQUARE_SIZE/2 )
|| (collide.cursor_projections.y.min.distance >= -collide.FIXED_SQUARE_SIZE/2 && collide.cursor_projections.y.max.distance <= collide.FIXED_SQUARE_SIZE/2 )) ? true : false;
return (collide.fixed_projections.x.is_collide
&& collide.fixed_projections.y.is_collide
&& collide.cursor_projections.x.is_collide
&& collide.cursor_projections.y.is_collide) ? true : false;
}
};
$(document).ready(function(){
collide.__init();
});
var debug = function(attr){
if($('.debugjs').length == 0){
$('<span class="debugjs"></span>').appendTo('body');
}
$('.debugjs').text(attr);
}
&#13;
#collide {
margin: 25px;
border: 1px solid black;
float: left;
}
#form {
margin-left: 550px;
padding-top: 2px;
}
#fixed_form h2 {
color: #0033FF;
}
#cursor_form h2 {
color: #FF8800;
}
#fixed_form input, #cursor_form input {
margin-left: 25px;
width: 50px;
}
#fixed_rotation_speed, #cursor_rotation_speed {
margin-right: 150px;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="collide" width="500" height="500"></canvas>
<div id="form">
<h3>Understand how to detect if 2 rotates squares collide.</h3>
<p>The 2 rotates squares collide only when all the projection of a square hit the second one.</p>
<div id="fixed_form">
<h2>Fixed square :</h2>
Rotation speed : <input type="number" id="fixed_rotation_speed" value="0"/>
Angle : <input type="number" id="fixed_angle" value="0"/>
(Set : <input type="number" id="fixed_set_angle" value="0"/>)
</div>
<div id="cursor_form">
<h2>Cursor square :</h2>
Rotation speed : <input type="number" id="cursor_rotation_speed" value="-1"/>
Angle : <input type="number" id="cursor_angle" value="0"/>
(Set : <input type="number" id="cursor_set_angle" value="0"/>)
</div>
</div>
&#13;
使用no-rotate rect执行相同的工作(这将更容易)并且它将适用于每个案例