SVGDOM鼠标事件目标对象研究

来源:互联网 发布:心情无人知 编辑:程序博客网 时间:2024/06/18 03:44

SVGDOM鼠标事件目标对象研究

2007-05-08 创建

  在DOM事件对象中target和currentTarget指明了用户操作的目标对象, 二者的区别在于, target是事件的最终接受者,而currentTarget是当前事件侦听器所在的节点.
例如
 <g id="canvas" onclick="showTarget(evt)">
  <rect id="green" fill="green" x="0" y="0" width="100" height="100"/>
  <rect id="red" fill="red" x="20" y="20" width="100" height="100"/>
 </g>

在showTarget中, evt.currentTarget指向id为canvas的group, 因为事件侦听器设置在group上; 而evt.target则根据具体点击的位置,指向rect, 因为是矩形实际接收了该点击事件.对于currentTarget的理解比较简单,而target可能因引用的复杂变得比较难以理解.例如在使用符号引用的时候,target指向哪个对象呢?

 <defs>
 <symbol id="Circle_s1" viewBox="0 0 100 100" preserveAspectRatio="none">
  <circle id="real_circle" fill="blue" cx="50" cy="50" r="25" />
 </symbol>
 </defs>
 
 <g id="canvas" onclick="showTarget(evt)">
  <rect id="green" fill="green" x="0" y="0" width="100" height="100"/>
  <rect id="red" fill="red" x="20" y="20" width="100" height="100"/>
  <use id="useSymbol" x="30" y="30" height="100" width="100" xlink:href="#Circle_s1"/>
 </g>

根据SVG标准, 如果点击在id为useSymbol的区域内,evt.currentTarget仍指向id为canvas的group, 而evt.target则应指向id="real_circle"的圆.经过测试在BATIK中的确如此,但在ASV和FireFox中,得到的结果却是evt.target为useSymbol.难道ASV和FF都错了?
 情况可能确实如此, SVG标准中允许SVG文档引用其它文档中定义的资源,例如符号或图案等.但目前只用BATIK做到了这一点,而ASV和FF中只能引用本文档中定义的资源,因此在处理USE节点时, ASV和FF可以简单的在渲染过程中解析该资源,而不需要对DOM树进行改动. 而BATIK中则使用了一个处理技巧,具体方法是先根据资源创建一个XML文档片断,然后将SYMBOL改为SVG引入文档片断中. 最后将文档片断插入USE节点下, 处理结束后的USE节点为:

 <use>
 <documentFragment> 
 <svg id="Circle_s1" viewBox="0 0 100 100" preserveAspectRatio="none">
  <circle id="real_circle" fill="blue" cx="50" cy="50" r="25" />
 </svg>
 </documentFragment>
 </use> 

 因此在上面的例子中,BATIK的鼠标点击目标自然为real_circle.

 在这个问题上, BATIK的处理无疑更加符合标准,但在实际的应用中,大多数情况下我们希望得到的却是ASV或FF中的目标对象. 因为使用符号等资源时,我们往往不希望处理符号内部的图形,而是将资源作为一个整体的图形进行处理. 如果要使用currentTarget, 就需要为每个USE节点创建一个侦听器, 比较麻烦. 因此存在通过target对象得到当前USE节点的需要.由于BATIK使用的是文档片断,因此无法简单的使用getParentNode从目标对象回溯到USE节点, 幸好BATIK提供了进行回溯的手段. 在BATIK1.6中, 我们可以根据SVGOMCSSImportedElementRoot根节点得到USE节点对象

 Element e = (Element)((SVGOMCSSImportedElementRoot)target).getCSSParentElement();
 String symbolStr = e.getAttributeNS(xlinkNS, "href");

在BATIK1.7中, 可以通过SVGOMUseShadowRoot得到相同的效果.