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

时光毁灭记忆、已成空白 提交于 2021-02-10 14:14:55

问题


In my application, I need to detect the mouse events on the edge / border / stroked part of a shape - but not on the filled part. I have not found a way to do this.

I do not know how to get started with this but here is pseudo code of what I am trying to do.

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


回答1:


To detect mouse hits on the edge of a shape only, use the fillEnabled:false property. What this does is tell Konva to disregard fill - meaning that any event-listening on the fill-part of the shape will be switched off. However, with great power great responsibility comes and the fillEnabled property also stops any visual fill you might want to appear.

Putting that together, if you want to hit-test the stroke part of a shape only you will need another transparent shape drawn on top of the visual shape to detect mouse events.

As a bonus, you can use the hitStrokeWidth property to make the hit-detecting region of the stroke wider - as if you set the stroke 'thicker' for purposes of mouse detection.

Snippet below shows this approach on a rect and random polygon.

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

It is easy to clone a shape to make an edge-event detecting version and place the clone over the original shape so that you can detect the edge-events specifically. See the following working snippet - enable the console to view the events sequence.

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


It's not a precise approach ,just a approximate way which detect if the cursor just near the out edge of the object.

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

      });


来源:https://stackoverflow.com/questions/65230257/how-to-do-mouse-hit-testing-on-the-edge-border-stroked-part-of-a-shape

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!