簡體   English   中英

檢測HTML畫布中某些點的鼠標懸停?

[英]Detect mouseover of certain points within an HTML canvas?

我已經為Canvas構建了一個分析數據可視化引擎,並且已經被要求在數據元素上添加類似工具提示的懸停,以顯示光標下數據點的詳細度量。

對於簡單的條形圖和Gaant圖表,具有簡單方形區域或特定興趣點的樹形圖和節點圖,我能夠通過將絕對定位的DIV與:懸停屬性重疊來實現這一點,但是還有一些更復雜的可視化,例如餅圖以及由bezeir曲線定義的數百個獨立區域的交通流渲染。

是否有可能以某種方式附加疊加層,或在用戶將鼠標懸停在特定的封閉路徑上時觸發事件?

需要指定懸停的每個區域定義如下:

context.beginPath();
context.moveTo(segmentRight, prevTop);
context.bezierCurveTo(segmentRight, prevTop, segmentLeft, thisTop, segmentLeft, thisTop);
context.lineTo(segmentLeft, thisBottom);
context.bezierCurveTo(segmentLeft, thisBottom, segmentRight, prevBottom, segmentRight, prevBottom);
/*
 * ...define additional segments...
 */
// <dream> Ideally I would like to attach to events on each path:
context.setMouseover(function(){/*Show hover content*/});
// </dream>
context.closePath();

綁定到這樣的對象在Flash或Silverlight中實現幾乎是微不足道的,因為當前的Canvas實現具有直接使用我們現有的Javascript API並與其他Ajax元素集成的優勢,我們希望避免將Flash置於混合中。

有任何想法嗎?

您可以處理mousemove事件並從事件中獲取x,y坐標。 然后,您可能必須遍歷所有路徑以測試該點是否在路徑上。 我有一個類似的問題 ,可能有一些你可以使用的代碼。

以這種方式循環事物可能會很慢,尤其是在IE上。 一種方法可以加速它 - 這是一個黑客,但它會非常有效 - 將改變每個路徑繪制的顏色,以便人類不會注意到,但每個路徑都是繪制的不同的顏色。 有一個表來查找路徑的顏色,只需查看鼠標下的像素顏色。

陰影畫布

我在其他地方看到的用於鼠標懸停檢測的最佳方法是將要檢測的繪圖部分重復到隱藏的清除畫布上。 然后存儲ImageData對象。 然后,您可以檢查ImageData數組中的感興趣像素,如果alpha值大於0,則返回true。

// slow part
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.fillRect(100,100,canvas.width-100,canvas.height-100);
var pixels = ctx.getImageData(0,0,canvas.width,canvas.height).data;

// fast part
var idx = 4 * (mouse_x + mouse_y * canvas.width) + 3;
if (pixels[idx]) { // alpha > 0
  ...
}

好處

  • 您可以檢測任何您想要的內容,因為您只是重復上下文方法。 這適用於PNG alpha,瘋狂復合形狀,文本等。
  • 如果您的圖像是相當靜態的,那么您只需要每個感興趣的區域執行一次此操作。
  • “面具”很慢,但查找像素很便宜。 因此,“快速部分”非常適合鼠標懸停檢測。

缺點

  • 這是一個記憶豬。 每個掩模是W * H * 4值。 如果你有一個小的帆布區域或幾個區域來掩蓋,它並沒有那么糟糕。 使用chrome的任務管理器來監控內存使用情況。
  • 目前Chrome和Firefox中存在getImageData的已知問題。 如果你使變量無效,結果不會立即收集垃圾,所以如果你經常這樣做,你會看到內存迅速上升。 它最終會收集垃圾並且不會使瀏覽器崩潰,但它可能會在具有少量RAM的計算機上產生負擔。

拯救記憶的黑客

我們可以只記住哪些像素具有alpha值,而不是存儲整個ImageData數組。 它節省了大量內存,但為掩碼進程添加了一個循環。

var mask = {};
var len = pixels.length;
for (var i=3;i<len;i+=4) if ( pixels[i] ) mask[i] = 1;

// this works the same way as the other method
var idx = 4 * (mouse_x + mouse_y * canvas.width) + 3;
if (mask[idx]) {
  ...
}

這可以使用方法ctx.isPointInPath完成,但它不是在ExCanvas for IE中實現的。 但另一個解決方案是使用HTML地圖,就像我為這個小庫所做的那樣: http//phenxdesign.net/projects/phenx-web/graphics/example.htm你可以從中獲得靈感,但它仍然是一點點越野車。

我建議覆蓋一個圖像地圖,並在區域上設置適當的坐標,以匹配畫布繪制的項目。 這樣,您可以免費獲得工具提示和許多其他DOM /瀏覽器功能。

我需要檢測鼠標點擊方塊的網格(如excel電子表格的單元格)。 為了加快速度,我將網格划分為遞歸減半的區域,直到剩余少量單元格,例如100x100網格,前4個區域可以是包含四個象限的50x50網格。 然后可以將它們分成另外4個(因此給出16個區域,每個區域25x25)。 這需要進行少量比較,最后可以針對每個單元測試25x25網格(在該示例中為625個比較)。

Eric Rowell有一本名為“HTML5 CANVAS COOKBOOK”的書。 在那本書中有一章名為“與畫布交互:將事件監聽器附加到形狀和區域”。 可以實現mousedown,mouseup,mouseover,mouseout,mousemove,touchstart,touchend和touchmove事件。 我強烈建議你閱讀。

這是不可能的(好吧,至少不那么容易),因為你在畫布上繪制的對象(路徑)不會在畫布中表示為相同的對象。 我的意思是它只是一個簡單的2D上下文,一旦你在它上面畫了一些東西,它就會完全忘記它的繪制方式。 它只是一組像素。

為了觀看鼠標懸停和它的喜歡,你需要某種矢量圖形畫布,即SVG或在現有的基礎上實現你自己的(這是Sam Hasler建議的)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM