坐标转换变得简单 – GeometryUtils 的强大功能

之前的一篇文章中,我们介绍了GeometryUtils 接口和 getBoxQuads() API,用于检索 DOM 节点的 CSS 盒子几何形状。GeometryUtils 还解决了另一个重要问题:可靠地将坐标从一个 DOM 节点转换为另一个 DOM 节点。例如,您可能希望找到一个元素相对于另一个元素的边界框,或者您可能希望将事件坐标从视口转换为某个任意元素。

现有 API

到目前为止,简单的情况可以使用 getBoundingClientRect() 和一些数学运算来处理,但复杂的情况(例如涉及 CSS 变换的情况)几乎无法使用标准 API 来处理。非标准 API webkitConvertPointToPagewebkitConvertPageToPoint 是一个很大的改进,但除了没有标准化之外,它们的功能也没有达到所需的强大程度。特别是,提供一个直接将坐标从一个元素转换为另一个元素的 API 更加方便和健壮。[1]

新的 API

GeometryUtils 引入了三种新的坐标转换方法

  • to.convertPointFromNode(point, from) 将相对于“from”的第一个边框左上角的点转换为相对于“to”的第一个边框左上角的点。“point”是一个 DOMPointInit,这意味着您可以传递一个 DOMPoint 或一个 JS 对象,例如 {x:0, y:0}
  • to.convertRectFromNode(rect, from) 通过转换 DOMRect 的顶点,将相对于“from”的第一个边框左上角的 DOMRect 转换为相对于“to”的第一个边框左上角的 DOMQuad。它转换为 DOMQuad 以确保结果即使需要通过 CSS 变换旋转或倾斜也是准确的。
  • to.convertQuadFromNode(quad, from) 将“from”中的 DOMQuad 转换为“to”中的 DOMQuad。它与 convertRectFromNode 类似,只是接收一个 DOMQuad

getBoxQuads 一样,节点可以是 ElementTextNodeDocument;当使用 Document 时,坐标相对于文档的视口。

示例

var p1 = document.convertPointFromNode({
    x:0, y:0
  }, document.getElementById("e")
);
// p1.x == 100, p1.y == 100

var p2 = document.convertPointFromNode({
    x:0, y:0
  }, document.getElementById("d")
);
// p2.x == 150, p2.y == 150 - 50*sqrt(2) (approx)

p2 = document.getElementById("e").convertPointFromNode({
    x:0, y:0
  }, document.getElementById("d")
);
// p2.x == 50, p2.y == 50 - 50*sqrt(2) (approx)

var q1 = document.convertRectFromNode(
  new DOMRect(0, 0, 50, 50),
  document.getElementById("e")
);
// q1.p1.x == 100, q1.p1.y == 100
// q1.p2.x == 150, q1.p2.y == 100
// q1.p3.x == 150, q1.p3.y == 150
// q1.p4.x == 100, q1.p4.y == 150

var q2 = document.convertQuadFromNode(
  new DOMQuad({
    x:60, y:50
  }, {
    x:90, y:50
  }, {
    x:100, y:100
  }, {
    x:50, y:100
  }),
  document.getElementById("e")
);
// q2.p1.x == 100, q2.p1.y == 100
// q2.p2.x == 150, q2.p2.y == 100
// q2.p3.x == 140, q2.p3.y == 150
// q2.p4.x == 110, q2.p4.y == 150
p1
p2

有时将坐标转换为或从元素的 CSS 内容框、填充框或边距框很有用。这可以通过一个可选的 ConvertCoordinateOptions 字典来支持,该字典具有以下选项

  • fromBox"content""padding""border""margin" 之一,选择输入点相对于 from 节点的第一个片段的哪个 CSS 盒子。
  • toBox:选择返回的点相对于 to 节点的第一个片段的哪个 CSS 盒子。

作为特例,这使得在同一元素的不同
CSS 盒子类型之间转换点变得容易。例如,要将点从
元素的边框框转换为相对于其内容框,请使用
element.convertPointFromNode(point, element, {toBox:"content"}).

示例

var p1 = document.convertPointFromNode({
    x:0, y:0
  }, document.getElementById("e"),
  {fromBox:"content"}
);
// p1.x == 120, p1.y == 120

p1 = document.getElementById("e").convertPointFromNode({
    x:120, y:120
  }, document,
  {toBox:"content"}
);
// p1.x == 0, p1.y == 0

p1 = document.getElementById("e").convertPointFromNode({
    x:0, y:0
  }, document.getElementById("e"),
  {fromBox:"content"}
);
// p1.x == 20, p1.y == 20

p1 = document.getElementById("e").convertPointFromNode({
    x:20, y:20
  }, document.getElementById("e"),
  {toBox:"content"}
);
// p1.x == 0, p1.y == 0
p1
e 内容框
e 边框框

这些 API 在Firefox nightly 版本中可用,并将在 Firefox 31 中发布。Firefox 是第一个实现这些 API 的浏览器。

脚注

[1] 考虑以下示例

...<>
...<>

在这种情况下,通过首先转换为页面坐标,然后转换回 b 来将相对于 a 的点转换为相对于 b 的点不起作用,因为 scale(0)a 中的每个点映射到页面中的一个点。

关于 roc

Robert O'Callahan 是 Mozilla 公司的杰出工程师。在加入 MoCo 之前,他曾是 Mozilla 的志愿者贡献者多年(自 2000 年起)。

roc 的更多文章…

关于 Robert Nyman [荣誉编辑]

技术布道者和 Mozilla Hacks 编辑。发表关于 HTML5、JavaScript 和开放网络的演讲和博客。Robert 坚定地相信 HTML5 和开放网络,并且自 1999 年以来一直在从事 Web 前端开发工作 - 在瑞典和纽约市。他还在 http://robertnyman.com 上定期发表博客,并且喜欢旅行和结识新朋友。

Robert Nyman [荣誉编辑] 的更多文章…