我想使用瀏覽器svg + JavaScript從用戶準備的svg模板(例如,在Inkscape中創建的)中生成動態圖像,其中有矩形佔位符,用於標記應該放置動態圖形。獲取svg元素的全局變換矩陣
理想情況下,應允許用戶(模板創建者)以任何他們想要的方式移動,縮放,旋轉,傾斜矩形(傾斜後沒有太多矩形)。他們唯一要做的就是爲這些佔位符矩形設置正確的id值。
我正在尋找一種方法來獲取/計算這些佔位符的變換矩陣。由於它們可以嵌套在一起,所以讀取元素的屬性是不夠的。
我想使用瀏覽器svg + JavaScript從用戶準備的svg模板(例如,在Inkscape中創建的)中生成動態圖像,其中有矩形佔位符,用於標記應該放置動態圖形。獲取svg元素的全局變換矩陣
理想情況下,應允許用戶(模板創建者)以任何他們想要的方式移動,縮放,旋轉,傾斜矩形(傾斜後沒有太多矩形)。他們唯一要做的就是爲這些佔位符矩形設置正確的id值。
我正在尋找一種方法來獲取/計算這些佔位符的變換矩陣。由於它們可以嵌套在一起,所以讀取元素的屬性是不夠的。
SVG命令getCTM
和/或getScreenCTM
可能是您要查找的內容。 (我相信CTM代表'Current Transform Matrix',我相信)。例如,您可以使用它們,方法是使用jQuery檢索元素,去除封閉的jQuery對象並調用該命令。 $("#mySvgCircleId")[0].getScreenCTM()
。它們都返回SVG矩陣對象。兩者都會爲您提供矩陣信息,這些信息會考慮到它們自己的直接轉換以及已應用於嵌套形狀的任何父級svg元素的任何轉換。這聽起來像你在找什麼。
但請注意,這兩個命令之間存在重要差異。我在下面的代碼片段中演示了一些差異。在那裏,我展示了兩個svg
元素,其中一個帶有兩個紅色矩形,另一個帶有兩個藍色矩形。所有矩形具有相同的寬度和高度,但每種顏色中的一種未經轉換,而另一種則嵌套在三個不同轉換的組中。輸出顯示矩陣結果,每個矩形使用getCTM
和getScreenCTM
。注意以下幾點:
getCTM
和getScreenCTM
考慮到任何封閉祖先元素的帳戶變換,例如任何g
組元素,直到包含svg
元素。例如兩個命令的「untransformedRect1」和「transformedRect1」返回的矩陣是不同的。getCTM
結果不受其父代元素中封閉的svg
元素的位置影響,而getScreenCTM
結果爲。例如當使用getCTM
時,'untransformedRect1'和'untransformedRect2'的結果相同,但在使用getScreenCTM
時不同。可能會有進一步的併發症,如果,例如,你在處理內部框架,其他SVG元素等等,這些我在這裏不是解決之內嵌套的SVG元素。
var infoType = "CTM";
show("Matrix Results from getCTM()");
show(getInfo(infoType, "untransformedRect1"));
show(getInfo(infoType, "transformedRect1"));
show(getInfo(infoType, "untransformedRect2"));
show(getInfo(infoType, "transformedRect2"));
show("<br />");
var infoType = "ScreenCTM";
show("Matrix Results from getScreenCTM()");
show(getInfo(infoType, "untransformedRect1"));
show(getInfo(infoType, "transformedRect1"));
show(getInfo(infoType, "untransformedRect2"));
show(getInfo(infoType, "transformedRect2"));
function getInfo(mtrx, id) {
var mtrx;
if (infoType === "CTM") {
var mtrx = $("#" + id)[0].getCTM();
} else if (infoType === "ScreenCTM") {
var mtrx = $("#" + id)[0].getScreenCTM();
}
var str =
r(mtrx.a) + ", " +
r(mtrx.b) + ", " +
r(mtrx.c) + ", " +
r(mtrx.d) + ", " +
r(mtrx.e) + ", " +
r(mtrx.f);
return id + ": matrix: " + str;
}
function r(num) {
return Math.round(num * 1000)/1000;
}
function show(msg) {
document.write(msg + "<br />");
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Depending on how you are viewing this, you may need to scroll down to see the matrix values.</p>
<div id="containerForSvgs">
<svg id="svg1" width="150" height="100">
<rect id="background1" width="300" height="200" fill="#eee" transform="translate(0,0)"></rect>
<rect id="untransformedRect1" width="20" height="10" fill="red"></rect>
<g id="group1A" transform="scale(2)">
<g id="group1B" transform="translate(40,20)">
<g id="group1C" transform="rotate(-15)">
<rect id="transformedRect1" width="20" height="10" fill="red"></rect>
</g>
</g>
</g>
</svg>
<br />
shift ===>
<svg id="svg2" width="150" height="100">
<rect id="background2" width="300" height="200" fill="#eee" transform="translate(0,0)"></rect>
<rect id="untransformedRect2" width="20" height="10" fill="blue"></rect>
<g id="group2A" transform="scale(2)">
<g id="group2B" transform="translate(40,20)">
<g id="group2C" transform="rotate(-15)">
<rect id="transformedRect2" width="20" height="10" fill="blue"></rect>
</g>
</g>
</g>
</svg>
</div>
<br />
UPDATE事實上,在調查這我挖得更深一些,到SVG規範,發現了一個非常酷的其他功能,可能是如虎添翼你想要的東西:getTransformToElement
。基本上,您可以通過一個命令(target.getTransformToElement(enclosing)
)從任何元素(我將其稱爲target
)中檢索累積變換矩陣至其任何封閉元素(我將稱其爲enclosing
)。
我已經在下面提供了另一個代碼片段,它演示了它的行爲,用id命名,希望能夠清楚地說明它如何與您的情況相關。片段顯示target.getCTM()
實質上提供了與target.getTransformToElement(enclosingSvgElement)
相同的輸出。另外,它還表明,它能夠顯示從子子嵌套元素到其任何祖先封閉元素的轉換,以及任意任意距離的更大靈活性。此外,你可以看任何一個方向,例如都是target.getTransformToElement(enclosing)
和enclosing.getTransformToElement(target)
,其中一個將是另一個的矩陣逆(如果我在這裏得到我的數學術語正確)。
var svg = $("svg" )[0];
var grp1 = $("#grp1_formatting_of_entire_app" )[0];
var grp2 = $("#grp2_menus_and_buttons_and_stuff" )[0];
var grp3 = $("#grp3_main_drawing_canvas" )[0];
var grp4 = $("#grp4_some_intervening_group" )[0];
var shp1 = $("#shp1_the_shape_I_currently_care_about" )[0];
var grp5 = $("#grp5_a_lower_group_I_dont_currently_care_about")[0];
var shp1_CTM = shp1.getCTM();
var shp1_to_svg = shp1.getTransformToElement(svg);
var shp1_to_grp3 = shp1.getTransformToElement(grp3);
var grp3_to_shp1 = grp3.getTransformToElement(shp1);
document.write("<table>");
show("getCTM for shp1" , shp1_CTM );
show("getTransformToElement from shp1 to enclosing svg", shp1_to_svg);
show("getTransformToElement from shp1 to grp3" , shp1_to_grp3);
show("getTransformToElement from grp3 to shp1" , grp3_to_shp1);
document.write("</table>");
function show(msg, mtrx) {
document.write("<tr><td>" + msg + "</td><td>" + mtrxStr(mtrx) + "</td></tr>");
}
function mtrxStr(mtrx) {
return "(" +
rnd(mtrx.a) + ", " +
rnd(mtrx.b) + ", " +
rnd(mtrx.c) + ", " +
rnd(mtrx.d) + ", " +
rnd(mtrx.e) + ", " +
rnd(mtrx.f) + ")";
}
function rnd(n) {
return Math.round(n*10)/10;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg width="200" height="60">
<g id="grp1_formatting_of_entire_app" transform="translate(30.0, 0)">
<g id="grp2_menus_and_buttons_and_stuff" transform="translate(10.0, 0)">
<g id="grp3_main_drawing_canvas" transform="translate(3.0, 0)">
<g id="grp4_some_intervening_group" transform="translate(1.0, 0)">
<rect id="shp1_the_shape_I_currently_care_about" transform="translate(0.3, 0)"
x="0" y="0" width="100" height="40" fill="red"></rect>
<g id="grp5_a_lower_group_I_dont_currently_care_about" transform="translate(0.1, 0)">
</g>
</g>
</g>
</g>
</g>
</svg>
<p>Results</p>
不幸的是,瀏覽器不支持此功能涼了:https://www.chromestatus.com/feature/5736166087196672 – Passiday
這是嚴重的太糟糕了,因爲我是要找到很興奮這個。這將使操作在一個嚴重分組的svg圖像更容易。好吧。非常感謝這些信息。 –
您可以對不支持該功能的瀏覽器使用polyfill(stupid chrome ...)SVGElement.prototype.getTransformToElement = SVGElement.prototype.getTransformToElement ||函數(toElement){0}返回到Element.getScreenCTM()。inverse()。multiply(this.getScreenCTM()); }; –