【问题标题】:How to do mouse hit testing on the edge / border / stroked part of a shape如何在形状的边缘/边框/描边部分进行鼠标点击测试
【发布时间】:2020-12-11 23:02:44
【问题描述】:

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

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

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

【问题讨论】:

  • 你能描述一下你想要达到的目标吗?

标签: javascript konvajs


【解决方案1】:

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

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

作为奖励,您可以使用hitStrokeWidth 属性使笔划的命中检测区域更宽 - 就好像您将笔划设置为“更粗”以检测鼠标一样。

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

// 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>

很容易克隆形状以制作边缘事件检测版本并将克隆放置在原始形状上,以便您可以专门检测边缘事件。请参阅以下工作 sn-p - 启用控制台以查看事件序列。

// 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>

【讨论】:

  • 感谢您的回答,正如您所说,这将丢失填充部分的任何事件监听,最后,我找到了一个近似的方法,不优雅但对我有用。我把它贴在下面
  • 如果您使用堆叠的两个对象,使无填充的边缘检测位于已填充的可视对象上方,则可视对象仍可以在其填充部分监听鼠标悬停。跨度>
  • 我修改了下面的答案以展示如何克隆任何形状并将克隆堆叠在原始形状上,等等。
【解决方案2】:

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

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;
        }

      });

【讨论】:

  • 这种近似可行,但也很容易克隆形状并将克隆堆叠在原始形状上,从而提供一种非常准确的方法来处理不需要近似的边缘命中检测。
猜你喜欢
  • 1970-01-01
  • 2018-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多