【问题标题】:Why HTML SVG hexagon onClick "hitbox" being rectangular?为什么 HTML SVG 六边形 onClick “hitbox” 是矩形的?
【发布时间】:2020-12-09 07:47:26
【问题描述】:

我正在尝试仅使用 HTML 和 CSS 绘制由六边形组成的板。 这是一个 React 应用程序。

我的问题是这些六边形的“hitbox”是矩形的。有没有办法让我的onClick hitbox 完全适合我的六边形?

React.JS 代码:

<div className={`land${getClassNames(landState)}`}>
<svg
  viewBox="0 0 100 100"
  version="1.1"
  xmlns="http://www.w3.org/2000/svg"    
>
  <polygon points="50 1 95 25 95 75 50 99 5 75 5 25"
  onClick={() => handleClick(index, selectLand, landState)} />
</svg>

CSS

.land {
  float: left;
  margin-left: -5px;
  margin-bottom: -32px;
  width: 140px;
}
.land svg {
  width: 100%;
}
.land.isVacant svg {
  fill : #e0e0e0;
}
.land.isOccupiedByPlayer1 svg {
  fill : #90caf9;
}
.land.isOccupiedByPlayer2 svg {
  fill : #ef9a9a;
}
.active svg:hover {
  cursor: pointer;
}

编辑:
polygone 上移动onClick 给了我一个更好的结果,但仍然不完美和奇怪。我在下图中突出显示了不可点击的区域。我不明白这个。

.board {
    float: left; width: 1200px;
}

.land-row {
    clear: left;
}
.land-row.three {
    margin-left: 135px;
}
.land-row.four {
    margin-left: 67px;
}
.land {
    float: left;
    margin-left: -5px;
    margin-bottom: -32px;
    width: 140px;
}

.land svg {
    width: 100%;
    height: 100%;
}

.land.isVacant svg {
    fill : #e0e0e0;
}

.land.isOccupiedByPlayer1 svg {
    fill : #90caf9;
}

.land.isOccupiedByPlayer2 svg {
    fill : #ef9a9a;
}

.active svg:hover {
    cursor: pointer;
}



**EDIT:**<br>
&lt;div id="root"&gt;&lt;div class="App"&gt;&lt;div class="board"&gt;&lt;div class="land-row three"&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="land-row four"&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div class="land isOccupiedByPlayer1"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="land-row"&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="land-row four"&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div class="land isOccupiedByPlayer1"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="land-row three"&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div class="land isActive isVacant"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;div class="land isOccupiedByPlayer2"&gt;&lt;svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"&gt;&lt;polygon points="50 1 95 25 95 75 50 99 5 75 5 25"&gt;&lt;/polygon&gt;&lt;/svg&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

【问题讨论】:

  • 与@ksav 相同,我无法重现您所描述的内容。您测试过哪个浏览器,哪个版本?是否有其他 CSS 规则应用于 &lt;svg&gt; 元素?删除 filter 属性后,点击行为是否会改变?
  • 感谢您的宝贵时间,我更新了我的问题。你有同样的结果吗?
  • 我刚测试过,只有当我点击的六边形下面有一个六边形时才会这样做...会不会是另一个元素妨碍了?
  • @Boubou,是的,可以有一些不可见的元素。请从开发者窗口的浏览器中复制您的代码(但不是您的 React.JS 代码)。
  • @Bharata 我添加了一个带有 html 和 css 的代码 sn-p。我还尝试删除 margin-bottom: -32px 规则,没有它它工作得很好(尽管元素没有按我想要的方式放置。所以我知道一个元素妨碍了我,但不知道如何避免它...

标签: javascript html reactjs svg


【解决方案1】:

所有 SVG 元素都不是矩形的。而且您的六边形polygon 也不是矩形。在我下面的演示中,您将看到它。在我的演示的以下屏幕截图中:

您可以看到一些黄色和红色点。如果您在我的演示中单击这些点(区域)(但不是在屏幕截图上!),那么您会看到这些元素不是矩形的。

互动演示

document.querySelector('svg').onclick = function(e)
{
    if(e.target.tagName == 'polygon')
        state.innerText = 'Congratulation! You clicked on polygon element.';
    else if(e.target.tagName == 'circle')
        state.innerText = 'You clicked on circle element.';
    else
        state.innerText = 'Bad result! You clicked on SVG, but NOT on polygon element.';
};
<svg width="150" height="150" viewBox="0 0 100 100" style="background:#048">
    <polygon points="50 1 95 25 95 75 50 99 5 75 5 25"/>
    <circle cx="50" cy="50" r="30" fill="green"/>
</svg>
<div id="state"></div>

更新

现在您已经添加了 HTML 代码,我们可以看到您的问题:对于每个 polygon 元素,您在 div 元素中都有一个 SVG。在开发者视图中,它看起来像这个屏幕截图:

您的polygon 元素不是矩形,但它位于land 类的div 元素内。要解决此问题,您可以使用.board .land{pointer-events: none} 停用来自div.land 的鼠标事件,因为现在来自完整div 元素(包括带有polygon 的SVG)的鼠标事件已停用,您必须使用polygon 激活鼠标事件.board polygon{pointer-events: all}。在添加这个 CSS 之后,它就可以工作了。

document.querySelector('.board').onclick = function(e)
{
    if(e.target.tagName == 'polygon')
    {
        var parentDivCL = e.target.closest('.land').classList;
        if(parentDivCL.contains('isVacant'))
        {
            parentDivCL.remove('isActive', 'isVacant');
            parentDivCL.add('isOccupiedByPlayer1');
        }
    }
};
.board .land{pointer-events: none}
.board polygon{pointer-events: all}

.board {
    float: left; width: 1200px;
}

.land-row {
    clear: left;
}
.land-row.three {
    margin-left: 135px;
}
.land-row.four {
    margin-left: 67px;
}
.land {
    float: left;
    margin-left: -5px;
    margin-bottom: -32px;
    width: 140px;
}

.land svg {
    width: 100%;
    height: 100%;
}

.land.isVacant svg {
    fill : #e0e0e0;
}

.land.isOccupiedByPlayer1 svg {
    fill : #90caf9;
}

.land.isOccupiedByPlayer2 svg {
    fill : #ef9a9a;
}

.active svg:hover {
    cursor: pointer;
}
<div id="root">
<div class="App">
<div class="board">

<div class="land-row three">
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
</div>
<div class="land-row four">
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
    <div class="land isOccupiedByPlayer1">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
</div>
<div class="land-row">
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
</div>
<div class="land-row four">
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
    <div class="land isOccupiedByPlayer1">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
</div>
<div class="land-row three">
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
    <div class="land isActive isVacant">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
    <div class="land isOccupiedByPlayer2">
        <svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg>
    </div>
</div>

【讨论】:

    【解决方案2】:

    您所描述的应该是附加到 SVG 形状的点击处理程序的默认值。

    <svg viewBox="0 0 100 100">
          <polygon points="50 1 95 25 95 75 50 99 5 75 5 25"
              onclick="console.log('You have clicked the polygon.')" />
    </svg>

    更新。这与您更新的代码相同,并且在 svg、多边形和 div 中添加了一些指针事件属性。

    document.querySelectorAll('polygon').forEach(polygon => {
      polygon.addEventListener('click', e => {
        e.target.closest('.land').classList.add('isOccupiedByPlayer1')
      })
    })
    .board {
      float: left;
      width: 1200px;
    }
    
    .land-row {
      clear: left;
    }
    
    .land-row.three {
      margin-left: 135px;
    }
    
    .land-row.four {
      margin-left: 67px;
    }
    
    .land {
      float: left;
      margin-left: -5px;
      margin-bottom: -32px;
      width: 140px;
    }
    
    .land svg {
      width: 100%;
      height: 100%;
    }
    
    .land.isVacant svg {
      fill: #e0e0e0;
    }
    
    .land.isOccupiedByPlayer1 svg {
      fill: #90caf9;
    }
    
    .land.isOccupiedByPlayer2 svg {
      fill: #ef9a9a;
    }
    
    .active svg:hover {
      cursor: pointer;
    }
    
    div,
    svg {
      pointer-events: none;
    }
    
    polygon {
      pointer-events: fill;
    }
    <div id="root">
      <div class="App">
        <div class="board">
          <div class="land-row three">
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
          </div>
          <div class="land-row four">
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
            <div class="land isOccupiedByPlayer1"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
          </div>
          <div class="land-row">
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
          </div>
          <div class="land-row four">
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
            <div class="land isOccupiedByPlayer1"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
          </div>
          <div class="land-row three">
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
            <div class="land isActive isVacant"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
            <div class="land isOccupiedByPlayer2"><svg viewBox="0 0 100 100" version="1.1" xmlns="http://www.w3.org/2000/svg"><polygon points="50 1 95 25 95 75 50 99 5 75 5 25"></polygon></svg></div>
          </div>
        </div>
      </div>
    </div>

    【讨论】:

    • 我编辑了我的问题,您也可以查看我的 cmets。谢谢!
    • @ksav,«+1»。但是,如果您想获得更多积分,您必须学习添加更多关于您所做的事情和原因的描述。而且我还会扩展代码 sn-p 因为不是所有人都知道如何看到它,有些人看不到这个链接。
    • @ksav,我不明白你为什么不赞成我的回答?您是否看到 OP 已经在线并且他从您的回答中收到了有关更新的系统消息?你认为他能理解你做了什么,为什么?你认为任何不理解它的人会赞成和/或接受你的回答吗?
    • 我首先虽然你在重复发布的内容.. 第二个片段就在现场。感谢您的帮助和时间,点赞
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-07-22
    • 1970-01-01
    • 1970-01-01
    • 2014-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多