2

初期サイズ[w1、h1]のRaphael.jsオブジェクトとして画像を作成し、メソッドを使用して画像を拡大縮小した場合、後で新しいサイズ[w2、h2]transform()を取得するにはどうすればよいですか?呼び出しはw1を返すため、変換後の幅ではなく、初期の幅です。image.attr("width")

w1とh1にスケーリング係数を掛けるだけでいいと言うかもしれませんが、ほとんどの場合、回転変換も適用されるため、少し面倒です。

つまり、Raphael.jsには、適用された可能性のある変換に関係なく、オブジェクトの正しいサイズを取得するメソッドがありますか?

4

2 に答える 2

12

Matt Esch の例は一部の (四角形の) 要素でのみ機能する可能性がありますが、考えられるすべての要素のメトリックを取得するには (要素が親グループのネストされた変換の影響を受ける場合にも)、別のアプローチを使用する必要があります。変換された SVG 要素のさまざまなメトリック (幅、高さ、bbox の幅、bbox の高さ、角の座標、辺の長さなど) を取得するために、get_metrics() 関数を作成しました。

完全な機能の例: http://output.jsbin.com/zuvuborehe/

次の図は、get_metrics() の使用例の 1 つを示しています。

指標の例

関数get_metrics()は純粋な JavaScript を使用し、ライブラリは使用しません。ただし、Raphaël などのライブラリでは OC を使用できます。element1.getTransformToElement(element2)これは、変換された要素 (例: <path>) と SVG ルート要素 ( ) の 2 つの要素間の関係マトリックスを取得できるネイティブに基づいてい<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;
}
于 2012-10-28T18:14:36.470 に答える
5

要素のバウンディング ボックスを変換ありとなしで取得する方法があります。

変換あり:

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 の最小値/最大値が取得されます。

于 2012-10-24T10:13:20.257 に答える