在之前的一篇文章中,我们介绍了GeometryUtils 接口和 getBoxQuads()
API,用于检索 DOM 节点的 CSS 盒子几何形状。GeometryUtils 还解决了另一个重要问题:可靠地将坐标从一个 DOM 节点转换为另一个 DOM 节点。例如,您可能希望找到一个元素相对于另一个元素的边界框,或者您可能希望将事件坐标从视口转换为某个任意元素。
现有 API
到目前为止,简单的情况可以使用 getBoundingClientRect()
和一些数学运算来处理,但复杂的情况(例如涉及 CSS 变换的情况)几乎无法使用标准 API 来处理。非标准 API webkitConvertPointToPage
和 webkitConvertPageToPoint
是一个很大的改进,但除了没有标准化之外,它们的功能也没有达到所需的强大程度。特别是,提供一个直接将坐标从一个元素转换为另一个元素的 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
一样,节点可以是 Element
、TextNode
或 Document
;当使用 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
有时将坐标转换为或从元素的 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
这些 API 在Firefox nightly 版本中可用,并将在 Firefox 31 中发布。Firefox 是第一个实现这些 API 的浏览器。
脚注
[1] 考虑以下示例
...<>
...<>
在这种情况下,通过首先转换为页面坐标,然后转换回 b
来将相对于 a
的点转换为相对于 b
的点不起作用,因为 scale(0)
将 a
中的每个点映射到页面中的一个点。
关于 roc
Robert O'Callahan 是 Mozilla 公司的杰出工程师。在加入 MoCo 之前,他曾是 Mozilla 的志愿者贡献者多年(自 2000 年起)。
关于 Robert Nyman [荣誉编辑]
技术布道者和 Mozilla Hacks 编辑。发表关于 HTML5、JavaScript 和开放网络的演讲和博客。Robert 坚定地相信 HTML5 和开放网络,并且自 1999 年以来一直在从事 Web 前端开发工作 - 在瑞典和纽约市。他还在 http://robertnyman.com 上定期发表博客,并且喜欢旅行和结识新朋友。