2015-07-18 48 views
5

我有一個畫布,我想更改用戶光標(如樣式光標指針十字線移動等)。是否可以更改用戶光標,而不是在畫布的某個區域上進行更改,而無需在這些點擊框中引入帶有光標樣式的「點擊框」?更改光標取決於畫布的部分

+2

的C anvas元素只接收相對於其整體的鼠標事件。要在畫布的子部分上更改遊標,您必須使用相對於畫布的鼠標位置進行命中測試。 – markE

+0

感謝@markE所以做命中測試的唯一方法是在畫布頂部覆蓋其他DOM元素? – Noitidart

+2

是的,命中測試是檢查鼠標是否懸停在畫布上繪製的形狀上的唯一方法。但是不需要添加充當懸停目標的DOM元素。我發佈了一個解釋如何使用'context.isPointInPath'方法懸停測試各個形狀的答案。 – markE

回答

10

在畫布上繪製的形狀不會單獨接收鼠標事件,因此單個形狀無法接收懸停事件。

在畫布上繪製的形狀可作爲一組路徑的命令

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>

+0

謝謝你的真棒回覆!我正在做的是創建一個Firefox插件,它將所有顯示器的屏幕截圖繪製到每個顯示器的畫布上,現在我正在編輯一個編輯器:https://www.youtube.com/watch?v=tzS3YgXhtLU – Noitidart

+1

哦,這是輝煌!!用mousemove測試點事物使光標變化如此絕對準確!並沒有DOM元素覆蓋!這是一個非常棒的答案,非常感謝你!它幫助我一噸! – Noitidart

+2

這整件事再一次派上用場了!我添加了一個功能來繪製只是中風的線條。所以有相當於'isPointInPath',但它是'isPointInStroke',絕對真棒,再次感謝@markE! – Noitidart