簡體   English   中英

document.elementFromPoint 為相同的輸入返回不同的元素

[英]document.elementFromPoint returning different elements for same input

我正在使用document.elementFromPoint來確定某個點的 svg 形狀是什么。 當我注意到我為相同的輸入獲得不同的輸出時,我正在此圖像上嘗試elementFromPoint chrome devtools 控制台的圖像,其中 document.elementFromPoint 在 2 個不同的地方使用參數 0.25 和 50 調用,返回不同的 svg 元素

這正是我為重現性所做的。

  1. 我從鏈接的 svg 中剪切並粘貼了 svg 標簽,並將其插入 html 文件的正文中。 html 文件是使用單文件設置的。 vscode 中的 emmet 快捷方式。 身體里沒有別的東西。 唯一的 css 是body{margin:0;}
  2. 在 chrome 中,我四處調用elementFromPoint 大多在.25,50,但有時只是稍微向右或向左一點。 有時用同一個 arguments 一遍又一遍地調用,看看它是否會改變。
  3. 在此期間沒有進行滾動。 甚至沒有選項,因為沒有滾動條。

我的問題是為什么會發生這種情況? 它有規律嗎? 有沒有辦法防止它? 謝謝。

雖然我不能告訴你為什么會發生這種情況,或者如何防止這種情況發生,但“模式”,或者讓我們更好地說,可以縮小不一致行為的原因。

讓我們看看調用elementFromPoint返回的路徑。 其中有兩個,如果省略 id 和類,即使考慮到它們的父元素,它們看起來也一樣:

<g transform="translate(-1.775,-1.575)">
    <path d="M 1.9,551.3 V 1.7 H 1102 V 551.3 H 2.3" />
</g>

如果您重寫路徑以解決transform ,您將在(瀏覽器)視口坐標中獲得路徑 - 為清楚起見,我已將VH命令重寫為L

<path d="M 0.125,549.725 L 0.125,0.125 L 1100.125,0.125 L 1100.125,549.725 L 0.525,549.725" />

SVG 包含描述這些元素的填充和描邊的樣式表。 這是相關的摘錄:

.seabase {
  fill: #C6ECFF;
  stroke: none;
}
.mapborder {
  fill: none;
  stroke: #0978AB;
}
path, circle {
  stroke-width: 0.25;
}

那么應該從document.elementFromPoint(0.25,50)返回什么? 在給定坐標處找到的最頂層元素,前提是pointer-events屬性允許該元素成為命中測試的目標。

沒有為元素顯式設置pointer-events ,因此應用了visiblePainted的默認值。 這意味着(至少部分)不透明的填充或描邊都可以被擊中。

兩個候選的底部元素<path class="seabase"/>有一個可見的填充,但沒有邊框。 (0.25,50)在該填充內。

兩個候選元素的最頂部元素<path class="mapborder"/>沒有填充,但有一個寬度為 0.25 的可見邊框,一半向內延伸,另一半向路徑輪廓外側延伸。 在左側,有一個垂直子路徑M 0.125,549.725 L 0.125,0.125 不涉及角落的細節,筆畫可以等效地繪制為具有定義的填充路徑

M 0,549.725 L 0,0.125 L 0.25,0.125 L 0.25,549.725 Z

換句話說,點(0.25,50)正好在筆畫的輪廓上。 規范對后果非常清楚:

形狀的零寬度幾何輪廓包含在要繪制的區域中。

該點應該擊中mapborder元素,因為該點是其可見的繪制描邊的一部分。 如果,如您所描述的,瀏覽器有時會返回seabase元素,那是錯誤的。

我可以打開 go 並推測這種行為的原因,但我認為這沒有實際意義。

你能阻止它嗎? 僅當您能夠始終避免所有路徑的確切輪廓,或者如果它們具有筆划,則該筆划的輪廓。 這幾乎不切實際,因為您必須找出瀏覽器是否錯過了它應該點擊的東西,而您不知道錯過了什么

最后,還有第二個界面可以使用。 它是 SVG 規范的一部分,而elementFromPoint是 CSSOM 規范的一部分。 這是否會對瀏覽器的實現產生影響,我不能說。

document.querySelector('.seabase').isPointInFill(new DOMPoint(2.025,48.425));
document.querySelector('.mapborder').isPointInStroke(new DOMPoint(2.025,48.425));

請注意,您需要提供一個要測試的元素,您無法獲得哪個元素位於頂部的信息,並且坐標在本地用戶空間中表示(在應用transform之前)。

暫無
暫無

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

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