如果我要将图像创建为具有初始大小[w1,h1]的 Raphael.js 对象,然后使用该transform()
方法对其进行缩放,我将如何检索其新大小[w2,h2]?因为调用image.attr("width")
返回 w1,即初始宽度,而不是转换后的宽度。
我知道你可能会说我应该简单地将 w1 和 h1 与缩放因子相乘,但大多数时候,还会应用旋转变换,这会使事情变得更加麻烦。
简而言之,Raphael.js 中是否有一种方法可以检索对象的正确大小,而不管可能对其应用的任何转换?
如果我要将图像创建为具有初始大小[w1,h1]的 Raphael.js 对象,然后使用该transform()
方法对其进行缩放,我将如何检索其新大小[w2,h2]?因为调用image.attr("width")
返回 w1,即初始宽度,而不是转换后的宽度。
我知道你可能会说我应该简单地将 w1 和 h1 与缩放因子相乘,但大多数时候,还会应用旋转变换,这会使事情变得更加麻烦。
简而言之,Raphael.js 中是否有一种方法可以检索对象的正确大小,而不管可能对其应用的任何转换?
Matt Esch 的示例可能仅适用于一些(矩形)元素,但要获得所有可能元素的度量(以及在元素受父组的嵌套转换影响的情况下),我们必须使用其他方法。为了获得转换后的 SVG 元素的各种指标(宽度、高度、bbox 宽度、bbox 高度、角坐标、边长等),我创建了一个 get_metrics() 函数:
完整功能示例: http: //output.jsbin.com/zuvuborehe/
下图显示了 get_metrics() 的一种可能用例:
该函数get_metrics()
使用纯javascript,没有库。但它可以与像 Raphaël 这样的库一起使用 OC。它基于native element1.getTransformToElement(element2)
,可以获得两个元素之间的关系矩阵,在这种情况下是转换后的元素(例如<path>
)和SVG根元素(<svg>
)。当然你也可以使用其他元素,比如图像、多边形、矩形等。顺便说一句,getTransformToElement
它非常强大且用途广泛,例如可以使用。以这种方式展平由任何路径命令组成的路径变换(如果它们首先使用 Raphaël 的 path2curve 转换为 Cubics,则甚至是弧线):http: //jsbin.com/atidoh/9。
SVGElement.prototype.getTransformToElement =
SVGElement.prototype.getTransformToElement || function(elem)
{
return elem.getScreenCTM().inverse().multiply(this.getScreenCTM());
};
function get_metrics(el) {
function pointToLineDist(A, B, P) {
var nL = Math.sqrt((B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y));
return Math.abs((P.x - A.x) * (B.y - A.y) - (P.y - A.y) * (B.x - A.x)) / nL;
}
function dist(point1, point2) {
var xs = 0,
ys = 0;
xs = point2.x - point1.x;
xs = xs * xs;
ys = point2.y - point1.y;
ys = ys * ys;
return Math.sqrt(xs + ys);
}
var b = el.getBBox(),
objDOM = el,
svgDOM = objDOM.ownerSVGElement;
// Get the local to global matrix
var matrix = svgDOM.getTransformToElement(objDOM).inverse(),
oldp = [[b.x, b.y], [b.x + b.width, b.y], [b.x + b.width, b.y + b.height], [b.x, b.y + b.height]],
pt, newp = [],
obj = {},
i, pos = Number.POSITIVE_INFINITY,
neg = Number.NEGATIVE_INFINITY,
minX = pos,
minY = pos,
maxX = neg,
maxY = neg;
for (i = 0; i < 4; i++) {
pt = svgDOM.createSVGPoint();
pt.x = oldp[i][0];
pt.y = oldp[i][1];
newp[i] = pt.matrixTransform(matrix);
if (newp[i].x < minX) minX = newp[i].x;
if (newp[i].y < minY) minY = newp[i].y;
if (newp[i].x > maxX) maxX = newp[i].x;
if (newp[i].y > maxY) maxY = newp[i].y;
}
// The next refers to the transformed object itself, not bbox
// newp[0] - newp[3] are the transformed object's corner
// points in clockwise order starting from top left corner
obj.newp = newp; // array of corner points
obj.width = pointToLineDist(newp[1], newp[2], newp[0]) || 0;
obj.height = pointToLineDist(newp[2], newp[3], newp[0]) || 0;
obj.toplen = dist(newp[0], newp[1]);
obj.rightlen = dist(newp[1], newp[2]);
obj.bottomlen = dist(newp[2], newp[3]);
obj.leftlen = dist(newp[3], newp[0]);
// The next refers to the transformed object's bounding box
obj.BBx = minX;
obj.BBy = minY;
obj.BBx2 = maxX;
obj.BBy2 = maxY;
obj.BBwidth = maxX - minX;
obj.BBheight = maxY - minY;
return obj;
}
有一种方法可以检索带有和不带有变换的元素的边界框。
随着转型:
var bbox = image.getBBox(),
width = bbox.width,
height = bbox.height;
没有转换:
var bbox = image.getBBoxWOTransform(),
width = bbox.width,
height = bbox.height;
如果这对您有帮助,您可以使用帮助方法(如果您小心的话)直接提供宽度和高度来扩展 Raphael.el。您可以只使用边界框方法并返回您感兴趣的部分,但为了更高效,我只使用元素上的矩阵属性和属性的位置/宽度/高度计算了请求的属性。
(function (r) {
function getX() {
var posX = this.attr("x") || 0,
posY = this.attr("y") || 0;
return this.matrix.x(posX, posY);
}
function getY() {
var posX = this.attr("x") || 0,
posY = this.attr("y") || 0;
return this.matrix.y(posX, posY);
}
function getWidth() {
var posX = this.attr("x") || 0,
posY = this.attr("y") || 0,
maxX = posX + (this.attr("width") || 0),
maxY = posY + (this.attr("height") || 0),
m = this.matrix,
x = [
m.x(posX, posY),
m.x(maxX, posY),
m.x(maxX, maxY),
m.x(posX, maxY)
];
return Math.max.apply(Math, x) - Math.min.apply(Math, x);
}
function getHeight() {
var posX = this.attr("x") || 0,
posY = this.attr("y") || 0,
maxX = posX + (this.attr("width") || 0),
maxY = posY + (this.attr("height") || 0),
m = this.matrix,
y = [
m.y(posX, posY),
m.y(maxX, posY),
m.y(maxX, maxY),
m.y(posX, maxY)
];
return Math.max.apply(Math, y) - Math.min.apply(Math, y);
}
r.getX = getX;
r.getY = getY;
r.getWidth = getWidth;
r.getHeight = getHeight;
}(Raphael.el))
随着用法:
var x = image.getX();
var y = image.getY();
var width = image.getWidth();
var height = image.getHeight();
只需在包含 Raphael 后包含脚本即可。请注意,它仅适用于具有宽度、高度、x 和 y 属性的元素,适用于图像。Raphael 实际上是根据路径数据计算边界框,它会转换路径中的所有点,并在转换后获取最小/最大 x/y 值。