You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

点击单元格边框区分区域功能存在封闭区域识别异常问题

问题修复:边框封闭区域识别异常

问题根源

原代码判断单元格连通性时,仅检查当前单元格的边框状态,未验证相邻单元格的对应边框是否同步存在。当边框状态不同步(如重复点击导致单边边框被取消)或遍历顺序导致先处理的区域未被完全隔离时,会出现B区域无法被识别为独立区域的情况。

修复方案

修改floodFill函数,在判断是否能连通到相邻单元格时,同时检查当前单元格的出边框和相邻单元格的入边框是否都不存在,确保两个单元格之间确实没有阻挡边框。

修复后的完整代码

JavaScript

const COLOR_PALETTE = ['#FDD', '#DFD', '#DDF', '#FFD', '#DBF', '#BFD', '#FDB', '#BDF'];
const CLICK_DISTANCE_THRESHOLD = 5;
const DATA = [
  ['A', 'A', 'A', 'B'],
  ['C', 'C', 'A', 'B'],
  ['C', 'D', 'B', 'B'],
  ['C', 'D', 'D', 'D']
];

const $grid = $('#grid');

$grid.append($('<tbody>')
  .append(DATA.map((row, rowIndex) => $('<tr>')
    .append(row.map((val, colIndex) => $('<td>')
      .text(val).data('coords', [rowIndex, colIndex]))))));

$grid.on('click', 'td', onBorderClick);

function onBorderClick(event) {
  const $target = $(this);
  const rect = this.getBoundingClientRect();
  const x = event.clientX - rect.left;
  const y = event.clientY - rect.top;

  // 判断点击的边框并切换状态
  if (x < CLICK_DISTANCE_THRESHOLD) {
    $target.toggleClass('selected-left');
    $target.prev().toggleClass('selected-right');
  } else if (x > rect.width - CLICK_DISTANCE_THRESHOLD) {
    $target.toggleClass('selected-right');
    $target.next().toggleClass('selected-left');
  } else if (y < CLICK_DISTANCE_THRESHOLD) {
    $target.toggleClass('selected-top');
    $target.parent().prev().children().eq($target.index()).toggleClass('selected-bottom');
  } else if (y > rect.height - CLICK_DISTANCE_THRESHOLD) {
    $target.toggleClass('selected-bottom');
    $target.parent().next().children().eq($target.index()).toggleClass('selected-top');
  }

  distinguishRegions();
}

function distinguishRegions() {
  // 清除之前的区域标记
  $grid.find('td').css('background-color', '').removeData('region').removeAttr('data-region');
  let regionId = 0;
  $grid.find('td').each(function() {
    const $cell = $(this);
    if (!$cell.data('region')) {
      regionId++;
      floodFill($cell, regionId);
    }
  });
}

function floodFill($cell, regionId) {
  const queue = [$cell];
  while (queue.length > 0) {
    const $current = queue.shift();
    if ($current.length === 0 || $current.data('region')) continue;

    $current.data('region', regionId)
      .attr('data-region', regionId)
      .css('background-color', getRandomColor(regionId));

    const [r, c] = $current.data('coords');
    const neighbors = [];
    
    // 检查上方邻居:当前无顶部边框,且上方邻居无底部边框
    const $top = getCell(r - 1, c);
    if ($top.length && !$current.hasClass('selected-top') && !$top.hasClass('selected-bottom')) {
      neighbors.push($top);
    }
    // 检查下方邻居:当前无底部边框,且下方邻居无顶部边框
    const $bottom = getCell(r + 1, c);
    if ($bottom.length && !$current.hasClass('selected-bottom') && !$bottom.hasClass('selected-top')) {
      neighbors.push($bottom);
    }
    // 检查左方邻居:当前无左侧边框,且左方邻居无右侧边框
    const $left = getCell(r, c - 1);
    if ($left.length && !$current.hasClass('selected-left') && !$left.hasClass('selected-right')) {
      neighbors.push($left);
    }
    // 检查右方邻居:当前无右侧边框,且右方邻居无左侧边框
    const $right = getCell(r, c + 1);
    if ($right.length && !$current.hasClass('selected-right') && !$right.hasClass('selected-left')) {
      neighbors.push($right);
    }

    queue.push(...neighbors.filter($n => !$n.data('region')));
  }
}

function getCell(rowIndex, colIndex) {
  return $grid.find(`tr:eq(${rowIndex})`).find(`td:eq(${colIndex})`);
}

function getRandomColor(index) {
  return COLOR_PALETTE[index % COLOR_PALETTE.length];
}

CSS

table {
  border: 2px solid grey;
  border-collapse: collapse;
  cursor: pointer;
}

td {
  width: 2rem;
  height: 2rem;
  border: 2px dotted grey;
  text-align: center;
}

.selected-left { border-left: 2px solid red; }
.selected-right { border-right: 2px solid red; }
.selected-top { border-top: 2px solid red; }
.selected-bottom { border-bottom: 2px solid red; }

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<table id="grid"></table>

修改说明

  • 在floodFill函数中,针对每个方向的邻居增加了双向边框检查,确保两个单元格之间的边框状态完全同步,避免因单边边框异常导致的错误连通。
  • 优化邻居判断逻辑,先验证邻居是否存在再检查边框状态,减少无效的空对象处理。

内容的提问来源于stack exchange,提问作者Mr. Polywhirl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 01:50:54