如何在形状的边缘/边框/描边部分进行鼠标点击测试

How to do mouse hit testing on the edge / border / stroked part of a shape

在我的应用程序中,我需要检测形状的边缘/边框/描边部分上的鼠标事件 - 但不是填充部分上的鼠标事件。我还没有找到执行此操作的方法。

我不知道如何开始,但这是我正在尝试做的伪代码。

shape.on('mousemove', function () {
          if (mouse on the edge of the shape) {
             // change the cursor to a star
          } else {
            // do nothing
          }
        });

要仅检测鼠标点击形状的边缘,请使用 fillEnabled:false 属性。这样做是告诉 Konva 忽略填充——这意味着形状填充部分的任何事件监听都将被关闭。然而,能力越大,责任越大,fillEnabled 属性 也会停止任何您可能希望出现的视觉填充。

综上所述,如果您只想对形状的笔划部分进行命中测试,则需要在可视形状之上绘制另一个透明形状来检测鼠标事件。

作为奖励,您可以使用 hitStrokeWidth 属性 使笔画的命中检测区域更宽 - 就好像您将笔画 'thicker' 设置为鼠标的目的一样检测.

下面的代码片段显示了在矩形和随机多边形上的这种方法。

// Set up a stage
stage = new Konva.Stage({
    container: 'container',
    width: window.innerWidth,
    height: window.innerHeight
  }),

  // add a layer to draw on
  layer = new Konva.Layer(),

  rect = new Konva.Rect({
    name: 'r1',
    x: 220,
    y: 20,
    width: 100,
    height: 40,
    stroke: 'cyan',
    fill: 'transparent',
    fillEnabled: false
  }),
  poly = new Konva.Line({
    points: [23, 20, 23, 160, 70, 93, 150, 109, 290, 139, 270, 93],
    fill: '#00D2FF',
    stroke: 'black',
    strokeWidth: 5,
    closed: true,
    fillEnabled: false,
    hitStrokeWidth: 10
  });


// Add the layer to the stage
stage.add(layer);
layer.add(rect, poly)

stage.draw();

rect.on('mouseover', function() {
  $('#info').html('Rect MouseEnter')
})

rect.on('mouseout', function() {
  $('#info').html('Rect mouseOut')
})

poly.on('mouseover', function() {
  $('#info').html('Poly MouseEnter')
})

poly.on('mouseout', function() {
  $('#info').html('Poly mouseOut')
})
body {
  margin: 10;
  padding: 10;
  overflow: hidden;
  background-color: #f0f0f0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://unpkg.com/konva@^3/konva.min.js"></script>
<p>Move mouse over the shapes </p>
<p id='info'>Events show here</p>
<div id="container"></div>

很容易克隆一个形状来制作边缘事件检测版本,并​​将克隆体放在原始形状上,这样您就可以专门检测边缘事件。请参阅以下工作片段 - 启用控制台以查看事件序列。

// Set up a stage
stage = new Konva.Stage({
    container: 'container',
    width: window.innerWidth,
    height: window.innerHeight
  }),

  // add a layer to draw on
  layer = new Konva.Layer(),

  rect = new Konva.Rect({
    name: 'r1',
    x: 220,
    y: 20,
    width: 100,
    height: 40,
    stroke: 'cyan',
    fill: 'magenta'
  }),
  poly = new Konva.Line({
    points: [23, 20, 23, 160, 70, 93, 150, 109, 290, 139, 270, 93],
    fill: '#00D2FF',
    stroke: 'black',
    strokeWidth: 5,
    closed: true,
    hitStrokeWidth: 10
  }),

  // this is a clone of rect with fillEnabled set to false, placed 'above' rect in the z-order. 
  rect2 = rect.clone({
    fillEnabled: false
  }),
  poly2 = poly.clone({
    fillEnabled: false
  }),



  // Add the layer to the stage
  stage.add(layer);
layer.add(rect, rect2, poly, poly2)

stage.draw();

rect.on('mouseover', function() {
  showMsg('Rect MouseEnter');
})

rect2.on('mouseover', function() {
  showMsg('Rect2 Edge MouseEnter');
})

rect2.on('mouseout', function() {
  showMsg('Rect2 Edge mouseOut');
})

poly.on('mouseover', function() {
  showMsg('Poly MouseEnter');
})

poly.on('mouseout', function() {
  showMsg('Poly MouseOut');
})

poly2.on('mouseover', function() {
  showMsg('Poly2 Edge MouseEnter');
})

poly2.on('mouseout', function() {
  showMsg('Poly2 Edge MouseOut');
})

function showMsg(msg) {
  console.log(msg)
  $('#info').html(msg)
}
body {
  margin: 10;
  padding: 10;
  overflow: hidden;
  background-color: #f0f0f0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://unpkg.com/konva@^3/konva.min.js"></script>
<p>Move mouse over the shapes </p>
<p id='info'>Events show here</p>
<div id="container"></div>

这不是一种精确的方法,只是一种检测光标是否刚好接近对象外边缘的近似方法。

stage.on('mousemove', function (e) {

        var deta = 3;

        var node8 = stage.getIntersection({x: e.evt.clientX, y: e.evt.clientY});
        if(node8){
            console.log(node8.getClassName()+"====mouse on object=====");
            return;
        }

        var node = stage.getIntersection({x: e.evt.clientX+deta, y: e.evt.clientY});
        if(node){
            console.log(node.getClassName()+"====mouse on edge=====");
            return;
        }
        var  node1 = stage.getIntersection({x: e.evt.clientX, y: e.evt.clientY+deta});
        if(node1){
            console.log(node1.getClassName()+"====mouse on edge=====");
            return;
        }
        var  node2 = stage.getIntersection({x: e.evt.clientX+deta, y: e.evt.clientY+deta});
        if(node2){
            console.log(node2.getClassName()+"====mouse on edge=====");
            return;
        }
        var node3 = stage.getIntersection({x: e.evt.clientX-deta, y: e.evt.clientY});
        if(node3){
            console.log(node3.getClassName()+"====mouse on edge=====");
            return;
        }
        var node4 = stage.getIntersection({x: e.evt.clientX, y: e.evt.clientY-deta});
        if(node4){
            console.log(node4.getClassName()+"====mouse on edge=====");
            return;
        }
        var node5 = stage.getIntersection({x: e.evt.clientX-deta, y: e.evt.clientY-deta});
        if(node5){
            console.log(node5.getClassName()+"====mouse on edge=====");
            return;
        }

        var node6 = stage.getIntersection({x: e.evt.clientX-deta, y: e.evt.clientY+deta});
        if(node6){
            console.log(node6.getClassName()+"====mouse on edge=====");
            return;
        }

        var node7 = stage.getIntersection({x: e.evt.clientX+deta, y: e.evt.clientY-deta});
        if(node7){
            console.log(node7.getClassName()+"====mouse on edge=====");
            return;
        }

      });