【问题标题】:Change cursor depending on section of canvas根据画布部分更改光标
【发布时间】:2015-10-08 07:51:02
【问题描述】:

我有一个画布,我想更改用户光标(如样式光标指针十字准线移动等)。

是否可以在用户光标位于画布的某个区域时更改用户光标,而无需在这些命中框上引入带有光标样式的“命中框”?

【问题讨论】:

  • canvas 元素只接收与其整体相关的鼠标事件。要更改画布子部分上的光标,您确实必须使用鼠标相对于画布的位置进行命中测试。
  • 感谢@markE,所以做命中测试的唯一方法是在画布上覆盖其他 DOM 元素?
  • 是的,命中测试是检查鼠标是否悬停在画布上绘制的形状上的唯一方法。但是没有必要添加 DOM 元素作为悬停目标。我已经发布了一个答案,解释了如何使用 context.isPointInPath 方法来悬停测试单个形状。
  • 非常感谢 agian 的评论,如果不是这样的话,我会通过引入多个新的 dom 元素来超载和降低性能!

标签: html5-canvas mouse-cursor


【解决方案1】:

在画布上绘制的形状不会单独接收鼠标事件,因此单个形状无法接收悬停事件。

在画布上绘制的形状可以表示为一组路径命令

A Shape == A set of path commands.

// Example: A set of path commands drawing a triangle
context.beginPath();
context.moveTo(50,50);
context.lineTo(75,100);
context.lineTo(25,100);
context.closePath();

要在悬停在单个形状上时更改光标,您必须对每个形状(相对于每个路径)进行鼠标点击测试。

您可以使用isPointInPath 方法对形状(路径)进行命中测试。

要使用isPointInPath,您必须重新发出形状的路径命令(但无需描边或填充),然后使用当前鼠标坐标调用isPointInPath:

// first re-issue the path commands for the shape being tested
// and then test if the mouse is inside the shape using isPointInPath
if( context.isPointInPath(mouseX,mouseY) ){
    alert('The mouse is inside this shape');
}

这是示例代码和演示:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
  var BB=canvas.getBoundingClientRect();
  offsetX=BB.left;
  offsetY=BB.top;        
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }

var isDown=false;
var startX,startY;

var cursors=['default','w-resize','n-resize'];
var currentCursor=0;

var shapes=[];
shapes.push({
  points:[{x:20,y:50},{x:100,y:10},{x:180,y:50},{x:100,y:90}],
  cursor:1,
});
shapes.push({
  points:[{x:200,y:50},{x:250,y:150},{x:200,y:250},{x:150,y:150}],
  cursor:2,
});

for(var i=0;i<shapes.length;i++){
  var s=shapes[i];
  definePath(s.points);
  ctx.stroke();
}


$("#canvas").mousemove(function(e){handleMouseMove(e);});


function definePath(p){
  ctx.beginPath();
  ctx.moveTo(p[0].x,p[0].y);
  for(var i=1;i<p.length;i++){
    ctx.lineTo(p[i].x,p[i].y);
  }
  ctx.closePath();
}

function handleMouseMove(e){
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  // Put your mousemove stuff here
  var newCursor;
  for(var i=0;i<shapes.length;i++){
    var s=shapes[i];
    definePath(s.points);
    if(ctx.isPointInPath(mouseX,mouseY)){
      newCursor=s.cursor;
      break;
    }
  }
  if(!newCursor){
    if(currentCursor>0){
      currentCursor=0;
      canvas.style.cursor=cursors[currentCursor];              
    }
  }else if(!newCursor==currentCursor){
    currentCursor=newCursor;
    canvas.style.cursor=cursors[currentCursor];              
  }
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Move the mouse over the shapes and the cursor will change.</h4>
<canvas id="canvas" width=300 height=300></canvas>

【讨论】:

  • 感谢您的精彩回复!我正在做的是创建一个 firefox 插件,它截取所有监视器的屏幕截图,然后将它们绘制到每个监视器的画布上,现在我正在构建一个编辑器:youtube.com/watch?v=tzS3YgXhtLU
  • 哦,这太棒了!使用 mousemove 进行的点测试使光标变化如此绝对准确!并且没有覆盖 DOM 元素!!这是一个极好的答案,非常感谢你!!!它对我有很大帮助!
  • 这整件事对我又派上了用场!我添加了一个功能来绘制只是笔画的线条。所以相当于isPointInPath,但它是isPointInStroke,非常棒,再次感谢@markE!
  • 如果您的画布可以根据浏览器更改大小,这似乎不起作用。当画布变得太小时,指针不再变化。有什么想法吗?
  • 很好的答案。可以通过将路径分配给形状对象来改进,这样您就不必在每次 mousemove 时都绘制它,即在 s.path 中使用 new Path2D() 和 ctx.isPointInPath(s.path, mouseX, mouseY )
【解决方案2】:

您也可以在 JQUERY 中实现这一点,例如:

$( ".chrt" ).mouseover(function() {
  alert('you are over and put your code in this');
});

您的 html 代码在哪里:

<div class="col-lg-4 chrt">
     <div class="panel panel-default">
       <canvas id="myChart2" width="200" height="100"></canvas>
     </div>
</div>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-24
    • 1970-01-01
    • 2017-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-29
    • 2014-09-14
    相关资源
    最近更新 更多