2012-10-19 72 views
4

我試圖找到一種方法來實現跨瀏覽器路徑規範。有一種原生的方式,描述爲here,功能示例爲here,但它只適用於最新的Opera(但不適用於IE,FF,Safari,Chrome)。如何規範化SVG路徑數據(跨瀏覽器)?

本地方式使用pathElm.normalizedPathSegList它將所有相對座標轉換爲絕對座標,並將所有路徑段類型表示爲以下類型的子集:M,L,C,z。

我發現只有one javascript codejsfiddled functional example of it,但它只適用於IE和FF。 Chrome提供了「未捕獲的錯誤:INDEX_SIZE_ERR:DOM例外1」。如何在Opera,Safari和Chrome中修復這些問題,或者是否有其他任何方法來標準化SVG路徑?

+0

我不確定這個行爲是否與原生'normalizedPathSegList'完全相同,但它確實從相對絕對轉換:http://phrogz.net/convert-svg-path-to-all-absolute-commands – Duopixel

+0

@ Duopixel:謝謝你。我測試了它,並且它確實使REL-> ABS轉換如所假定的那樣,但是使Q,A,H,V,S和T不標準化。 http://jsfiddle.net/ybochatay/AtTND/3/很有前途(因爲它可以在IE和FF中使用),但是一些錯誤或類似的問題阻礙了它在其他瀏覽器中的工作。 –

+0

應該爲由問題組成的帖子創建'精神分裂'徽章,然後由OP編寫每一個答案。 – MrMisterMan

回答

1

編輯:我已經修復了Raphaëlbug,並且對動畫和非動畫複雜路徑進行了全面測試,所以我認爲使用Raphaël進行路徑規範化是明智的。錯誤的解釋和它的修復在這裏:https://stackoverflow.com/a/13079377/1691517。 Raphaël的path2曲線函數可以很容易地將所有路徑命令(也就是Arc)轉換爲標準化形式(即Cubic曲線)。很好,Cubics可以代表所有路徑命令!


另一種方法是使用新的拉斐爾,這裏是一個有趣的功能Raphael.path2curve(),其將所有路徑命令三次曲線,但它有一些bug。下面的圖像可視化的bug:

enter image description here

功能的例子是here,代碼如下:

<style>path {fill:none}</style> 
<script src="http://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script> 
<div id="res" style="width:800px"></div> 
<div id="raphael"></div> 

<script> 
window.onload = function() { 
var paper = Raphael("raphael", 400, 400); 
var original_path = "M30 30 S40 23 23 42 L23,42 C113.333,113.333 136.667,113.333 150,80 t40,50 T230,240 q20 20 54 20 s40 23 23 42 t20,30 a20,30 0,0,1 -50,-50"; 
var arr=Raphael.path2curve(original_path); 
var normalized_path = arr.toString(); 

var path1 = paper.path(normalized_path).attr({stroke: "red", "stroke-width":6}); 
var path2 = paper.path(original_path).attr({stroke: "black", "stroke-width":2}); 

document.getElementById("res").innerHTML="ORIGINAL PATH (black):<br>"+original_path+"<br><br>NORMALIZED PATH (red):<br>"+normalized_path; 
} 
</script>​ 

這將是非常好的,可以讓在拉斐爾路徑規範化,因爲它支持大量的瀏覽器,並使用數組而不是DOM路徑段(=速度和向後兼容性)。我做了a bug report。希望它在未來的某個版本中得到修復。

1

我想我在Opera,Safari和Chrome中找到DOM異常的原因。

The SVG docgetItem()從列表中返回指定的項目。退回的商品是商品本身,不是副本。對該項目所做的任何更改都會立即反映在列表中。

而且同樣appendItem()插入在列表的最後一個新的項目。如果newItem已經在列表中,那麼將被插入到此列表中,並從之前的列表中刪除。插入的項目是項目本身,不是副本。

所以這referes原來的項目:

seg = path1.pathSegList.getItem(i); 

而當這個項目被追加到使用

newpath.pathSegList.appendItem(seg); 

每個瀏覽器都有自己的見解其他路徑的段列表怎樣做才能原來賽格。 IE9和FF保留原始路徑1的段列表完好(或至少保留了索引(我在上面的例子中)),Safari,Chrome和Opera從seg1的段列表中刪除seg。 SVG文檔清楚地說明該項目(已從其先前列表中刪除),因此IE9和FF似乎具有錯誤的實現。因此,我還沒有(非常確定)該項目是從以前的列表中刪除,還是隻保留了索引(稍後我會檢查這一點)。

EDIT:檢查了這一點,並確認IE9和FF保持原始路徑的(path1)段列表完好無損,當它的段被附加到其他路徑的段列表中時,也保留了索引。 Safari,Chrome和Opera中的行爲是不同的:當附加到其他列表時,項目從原始列表中刪除,當然索引也會更新(舊索引在附加後不再有效)。製造jsfiddle這證實了差異。 IE9和FF返回段列表長度1,1,10,10。 Opera,Safari,Chrome返回1,0,10,8。

再次,我們必須考慮瀏覽器的差異,例如。在第一項之前添加虛擬段或查詢path1.numberOfItems()以確定原始路徑是否被修改。

3

編輯:不要使用這個!我對其進行了更多測試,並意識到A-> C轉換在所有情況下都不可靠,並且還有一些其他路徑命令組合失敗。請改用this

最後得到它在Safari,Opera或IE9,Firefox和鉻的工作: http://jsfiddle.net/timo2012/M6Bhh/41/

功能正常化SVG路徑的數據,使得所有路徑段被轉換爲M,C,L和Z(=絕對座標,這意味着所有相對座標都轉換爲絕對座標)。所有其他分段都很平常,100%準確,但弧(A)是一種特殊情況,您可以選擇將弧線轉換爲線(L),二次曲線(Q)還是三次曲線(C)。最準確的是線條,但是然後我們失去了獨立性。由於某些原因,Quadratics在某些弧段中失敗,但立方體更精確。

如果我們有以下路徑:

<svg width="400" height="400"> 
    <path stroke="red" stroke-width="3" d="M30 30 S40 23 23 42 L23,42 C113.333,113.333 136.667,113.333 150,80 t40,50 T230,240 q20 20 54 20 s40 23 23 42 t20,30 a20,30 0,0,1 -50,-50"/> 
</svg> 

,並使用規範它:

var path = document.querySelector('path'); 
path.normalizePath(3, 0.1); // 3 = C = cubic curves. Best alternative, rather good accuracy and path data remains reasonable sized 

標準化的版本是這樣的:

<svg width="400" height="400"> 
    <path stroke="red" stroke-width="3" d="M 30 30 C 30 30 40 23 23 42 L 23 42 C 113.333 113.333 136.667 113.333 150 80 C 150 80 163.333 96.6667 190 130 C 216.667 163.333 230 200 230 240 C 243.333 253.333 261.333 260 284 260 C 284 260 324 283 307 302 C 307 302 313.667 312 327 332 C 324.811 336.924 321.997 341.154 318.719 344.448 C 315.441 347.741 311.762 350.033 307.893 351.194 C 304.024 352.355 300.04 352.361 296.169 351.213 C 292.298 350.064 288.616 347.783 285.333 344.5 C 282.05 341.217 279.23 336.996 277.035 332.078 C 274.839 327.161 273.311 321.642 272.537 315.839 C 271.763 310.035 271.759 304.06 272.525 298.254 C 273.291 292.448 274.811 286.924 277 282"/> 
</svg> 

如果我們對頂面佈置兩個彼此的結果是這樣的(紅色標準化,黑色是原創):

Normalized path and original

其他可能性是這些:

path.normalizePath(1,0.5); // A->L, Many lines, high accuracy. Very good accuracy, but not so resolution independent, because when scaled, the corners become visible 

path.normalizePath(1,40); // A->L, Few lines, less accuracy 

path.normalizePath(2,0.5); // A->Q, quadratic curves. I tested this, but not good. Fails in some cases. 

而這有什麼好處呢?

規範化路徑數據的原生方式尚未在所有瀏覽器中實現,所以我們目前爲止都是獨立的。而當原生方式實施時,我們並不確定所有瀏覽器都採用相同的方式。 SVG文檔提到了將弧線轉換爲線條,但這不是一個好方法,因爲SVG的主要優勢 - 分辨率獨立性 - 將會丟失。我們應該完全控制弧的規範化是如何完成的,並且這個腳本提供了一個方法。

數據標準化後,可以完全改變位圖圖像中的座標。如果我們想要以Illustrator方式彎曲(Arc,Arch,Bulge,Shell,Flag,Wave,Fish,Rise,Fisheye,Inflate,Squeeze,Twist)路徑或扭曲路徑以獲得透視錯覺,則可以修改規範化路徑數據可靠。

該代碼基於YannickBochatay的script,我使它更加跨瀏覽器。