如何确定Javascript中项目网格中的选择范围之间的重叠
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何确定Javascript中项目网格中的选择范围之间的重叠相关的知识,希望对你有一定的参考价值。
想象一下像物品网格。用户可以在网格中选择多个项目范围。当存在多个范围(选择)时,我想确定最后创建的范围是否与现有范围重叠。可以将网格系统与文本区域中的字符进行比较,其中可以突出显示多个文本范围。
- 每个单一范围始终存在相邻项目,彼此相邻或网格中下一行中的第一项。 (也与在文本文档中选择文本完全相似。)
- 当用户创建范围时,它可以与现有范围重叠,甚至完全适合现有范围。
范围存储在内存中:
{
'rangeStartLineIndex': 2,
'rangeStartColIndex': 9,
'rangeEndLineIndex': 4,
'rangeEndColIndex': 7
}
上面的范围可以像图像一样可视化。但请注意,网格的行数和列数不是恒定的。
目标是遍历现有范围,并查看刚刚创建的范围是否与现有范围重叠(或完全适合)。如果是,则获取该现有范围,并对其进行扩展,以使创建的范围与其重叠的范围合并。所以,这是一种规范化数据。
代码中的另一个例子:
var ranges = []; // stores the range objects that are created earlier.
var createdRange = {...}; // range object just created.
for(var i = 0; i < ranges; i++) {
var overlap = doesThisOverlap(createdRange, ranges[i]);
if(overlap) {
// overlaps, which means we extend the existing range.
range[i].rangeStartLineIndex = Math.min(range[i].rangeStartLineIndex, createdRange.rangeStartLineIndex);
range[i].rangeStartColIndex = Math.min(range[i].rangeStartColIndex, createdRange.rangeStartColIndex);
range[i].rangeEndLineIndex = Math.max(range[i].rangeEndLineIndex, createdRange.rangeEndLineIndex);
range[i].rangeEndColIndex = Math.max(range[i].rangeEndColIndex, createdRange.rangeEndColIndex);
} else {
// means the new range does not extend an existing range, so add it.
ranges.push(createdRange);
}
}
function doesThisOverlap(rangeA, rangeB) {
// ???
}
当试图实现doesThisOverlap
函数时,我最终得到了过多的if-blocks。我感到困惑,也因为我觉得有一种算法可以找到。
我还尝试了添加一个范围起点的线和col索引来给它一个'得分',(并对它的端点的行和列索引做同样的事情)。然后比较范围之间的起点/终点分数。
这个问题实际上不是2D,如果你将范围表示为,则会变得容易得多
{
rangeStart: 29,
rangeEnd:48
}
您可以通过计算转换为此表示形式
lineIndex * COLUMN_NUMBER + columnIndex.
你应该基本上迭代所有范围并找到min rangeStart和rangeEnd。然后,您可以使用以下结果将结果转换为列/行:
columnIndex = x % COLUMN_NUMBER;
lineIndex = parseInt(x / COLUMN_NUMBER).
确定createdRange
是否与其中一个ranges
重叠的方法之一是给每个range
起始指数和结束指数,然后检查createdRange
的指数是否与任何其他范围的指数重叠。
首先,让我们从更好的可读性改变range
对象的形状:
{
start: { row: 2, col: 9 },
end: { row: 4, col: 7 }
}
将range
对象与您定义的对象映射很简单:
rangeStartLineIndex => start.row
rangeStartColIndex => start.col
rangeEndLineIndex => end.row
rangeEndColIndex => end.col
有了这个,我首先会指出逻辑中的一个小错误。
在for
循环中,您正在检查createdRange
是否与当前的range
重叠。如果没有,则将createdRange
添加到范围数组中。
但是,你只需要在createdRange
中添加ranges
如果没有一个范围与createdRange
重叠
因此,正确的for
循环看起来像:
var hasOverlap = false; // this will tell if any of the ranges overlap
for(var i = 0; i < ranges; i++) {
var overlap = doesThisOverlap(createdRange, ranges[i]);
if(overlap) {
// overlaps, which means we extend the existing range.
// some logic to update the overlapped ranges
hasOverlap = true; // a range has overlapped, set the flag to true
break;
}
}
// Did we see any overlap?
if(!hasOverlap) {
// no we did not, let us add this range to ranges array
// means the new range does not extend an existing range, so add it.
ranges.push(createdRange);
}
好的,现在让我们看看如何计算给定范围的指数。
如果我们开始在网格中从左到右分配索引(从0开始),简单的数学表示行r
和c
列中的框的索引将是:
index = r * (COL + 1) + c [COL is the total number of columns in the grid]
以下是辅助函数,它们有助于计算给定范围的索引:
function getIndex(row, col, COL) {
return row * (COL + 1) + col;
}
function getIndices(range) {
var start = range.start;
var end = range.end;
var startIndex = getIndex(start.row, start.col, COLS);
var endIndex = getIndex(end.row, end.col, COLS);
return { start: startIndex, end: endIndex };
}
请注意,getIndices
采用range
并输出一个start
和end
指数的对象。我们现在可以计算createdRange
和当前range
的指数。并且基于指数,我们将知道范围是否重叠。
问题现在归结为: 我们有一条AB线,给定一条新线PQ,找出新线PQ是否与AB重叠。 (其中A,B,P,Q是数字线上的点,A <B和P <Q)。 拿笔和纸画几行。你会发现线条不会重叠时只有两种情况:
Q <A或B <P
将这些观察结果映射到我们的range
对象,我们可以说:
P => createdRange.startIndex
Q => createdRange.endIndex
A => currentRange.startIndex
B => currentRange.endIndex
这就是它在代码中的样子:
var createdRangeIndices = getIndices(createdRange);
var hasOverlap = false;
for (var i = 0; i < ranges.length; i++) {
var currentRangeIndices = getIndices(ranges[i]);
var overlap = (createdRangeIndices.end < currentRangeIndices.start)
|| (currentRangeIndices.end < createdRangeIndices.start);
if (!overlap) {
// overlaps, which means we extend the existing range.
// some logic to update the overlapped ranges
hasOverlap = true;
break;
}
}
if (!hasOverlap) {
// means the new range does not extend an existing range, so add it.
ranges.push(createdRange);
}
请注意,我们摆脱了doesThisOverlap
功能。一个简单的旗帜就可以了。
如果存在重叠,现在剩下的就是更新range
的逻辑。您已经在问题中找到的部分内容。我们采用起始索引的最小值和结束索引的最大值。这是代码:
for (var i = 0; i < ranges.length; i++) {
var currentRangeIndices = getIndices(ranges[i]);
var overlap = (createdRangeIndices.end < currentRangeIndices.start)
|| (currentRangeIndices.end < createdRangeIndices.start);
if (!overlap) {
// overlaps, which means we extend the existing range.
// some logic to update the overlapped ranges
var start, end;
if (currentRangeIndices.start < createdRangeIndices.start) {
start = ranges[i].start;
} else {
start = createdRange.start;
}
if (currentRangeIndices.end > createdRangeIndices.end) {
end = ranges[i].end;
} else {
end = createdRange.end;
}
ranges[i] = { start: start, end: end };
hasOverlap = true;
break;
}
}
并做了!
以下是将所有部分组合在一起的完整代码:
var ROWS = 7;
var COLS = 3;
function getIndex(row, col, COL) {
return row * (COL + 1) + col;
}
function getIndices(range) {
var start = range.start;
var end = range.end;
var startIndex = getIndex(start.row, start.col, COLS);
var endIndex = getIndex(end.row, end.col, COLS);
return { start: startIndex, end: endIndex };
}
function addRange(ranges, createdRange) {
var createdRangeIndices = getIndices(createdRange);
var hasOverlap = false;
for (var i = 0; i < ranges.length; i++) {
var currentRangeIndices = getIndices(ranges[i]);
var overlap =
createdRangeIndices.end < currentRangeIndices.start ||
currentRangeIndices.end < createdRangeIndices.start;
if (!overlap) {
var start, end;
if (currentRangeIndices.start < createdRangeIndices.start) {
start = ranges[i].start;
} else {
start = createdRange.start;
}
if (currentRangeIndices.end > createdRangeIndices.end) {
end = ranges[i].end;
} else {
end = createdRange.end;
}
ranges[i] = { start: start, end: end };
hasOverlap = true;
break;
}
}
if (!hasOverlap) {
// means the new range does not extend an existing range, so add it.
ranges.push(createdRange);
}
}
var ranges = []; // stores the range objects that are created earlier.
var rangesToAdd = [
{
start: { row: 2, col: 1 },
end: { row: 6, col: 0 }
},
{
start: { row: 6, col: 2 },
end: { row: 7, col: 2 }
},
{
start: { row: 3, col: 1 },
end: { row: 6, col: 1 }
},
{
start: { row: 6, col: 1 },
end: { row: 6, col: 2 }
}
];
rangesToAdd.forEach(aRange => addRange(ranges, aRange));
console.log(ranges);
以上是关于如何确定Javascript中项目网格中的选择范围之间的重叠的主要内容,如果未能解决你的问题,请参考以下文章