SVG 路径的透视变换(四角扭曲) [英] Perspective transform of SVG paths (four corner distort)
问题描述
如何在浏览器中扭曲 SVG 中的路径,以便使用 javascript 或 css 将它们扭曲到某些角度?可以在 Photoshop、Illustrator 等中轻松制作透视扭曲,但浏览器如何?
这是源路径:
这是改造后的路径:
这是我的拖动扭曲方案 (以问答方式分享您的知识).
实时示例在 http://jsfiddle.net/xjHUk/278/ 和主要代码是这样的:
(仅输出窗口:http://jsfiddle.net/xjHUk/279/embedded/result/)
结果正确地扭曲到透视(两个消失点一个).两点透视计算的原理是这里.如果满足以下要求,该脚本可以处理 SVG 路径数据:
- 所有坐标都是绝对坐标(即大写字母).请参阅此.
- 不使用弧(A")
- V 和 H 归一化为 L
弧线可以标准化,但我还没有找到任何跨浏览器的方式.V 和 H 到 L 是一项简单的任务,您必须获得最后使用的 x 或 y 坐标,并在 L 之后添加缺少的坐标.
同样的脚本也可以处理路径中的曲线(曲线来自时代).以下是完全相同的代码,但路径属性(d")不同:
http://jsfiddle.net/xjHUk/277/ 函数假人(a) {return a;}
(此代码没有检查无效位置,就像上面一样).
以上示例的路径来自Arial 和Times 的SVG 版本.请注意,字体使用 笛卡尔坐标系,其中 y 坐标向上时增加.否则 SVG 使用极坐标系,用于位图图像和 css.这意味着当在上面的代码中使用来自 SVG 字体的路径时,路径必须垂直翻转并缩放到所需的字体大小.TTF 字体(以及它们的 SVG 对应字体)的 em 大小通常为 2048,因此字形的边界框没有缩放 2048 像素,这通常在 SVG 字形路径转换为 SVG 路径时太多了.
但如果您想扭曲其他 SVG 路径,则无需进行翻转和缩放.
这是相当长的代码(很大程度上是因为拖动功能),但我认为也可以通过一些 css-3D-transform-way 实现相同的效果,但在这种实现中还没有运气......
非透视扭曲示例(SVG 的主要竞争对手 SWF):
http://www.rubenswieringa.com/code/as3/flex/DistortImage/
另外一个 VALID 透视计算的例子:
http://zehfernando.com/f/TriangleTest.swf
How is it possible to distort paths in SVG in browser so that they are distorted to certain perspective using possibly javascript or css? The perspective distort can be made easily in Photoshop, Illustrator etc, but how about browsers?
This is source path:
And this is the path after transformation:
This is my drag distort proposal (share you knowledge, Q&A-style).
Live example is in http://jsfiddle.net/xjHUk/278/ and the main code is this:
(only output window: http://jsfiddle.net/xjHUk/279/embedded/result/)
function transferPoint (xI, yI, source, destination) { var ADDING = 0.001; // to avoid dividing by zero var xA = source[0].x; var yA = source[0].y; var xC = source[2].x; var yC = source[2].y; var xAu = destination[0].x; var yAu = destination[0].y; var xBu = destination[1].x; var yBu = destination[1].y; var xCu = destination[2].x; var yCu = destination[2].y; var xDu = destination[3].x; var yDu = destination[3].y; // Calcultations // if points are the same, have to add a ADDING to avoid dividing by zero if (xBu==xCu) xCu+=ADDING; if (xAu==xDu) xDu+=ADDING; if (xAu==xBu) xBu+=ADDING; if (xDu==xCu) xCu+=ADDING; var kBC = (yBu-yCu)/(xBu-xCu); var kAD = (yAu-yDu)/(xAu-xDu); var kAB = (yAu-yBu)/(xAu-xBu); var kDC = (yDu-yCu)/(xDu-xCu); if (kBC==kAD) kAD+=ADDING; var xE = (kBC*xBu - kAD*xAu + yAu - yBu) / (kBC-kAD); var yE = kBC*(xE - xBu) + yBu; if (kAB==kDC) kDC+=ADDING; var xF = (kAB*xBu - kDC*xCu + yCu - yBu) / (kAB-kDC); var yF = kAB*(xF - xBu) + yBu; if (xE==xF) xF+=ADDING; var kEF = (yE-yF) / (xE-xF); if (kEF==kAB) kAB+=ADDING; var xG = (kEF*xDu - kAB*xAu + yAu - yDu) / (kEF-kAB); var yG = kEF*(xG - xDu) + yDu; if (kEF==kBC) kBC+=ADDING; var xH = (kEF*xDu - kBC*xBu + yBu - yDu) / (kEF-kBC); var yH = kEF*(xH - xDu) + yDu; var rG = (yC-yI)/(yC-yA); var rH = (xI-xA)/(xC-xA); var xJ = (xG-xDu)*rG + xDu; var yJ = (yG-yDu)*rG + yDu; var xK = (xH-xDu)*rH + xDu; var yK = (yH-yDu)*rH + yDu; if (xF==xJ) xJ+=ADDING; if (xE==xK) xK+=ADDING; var kJF = (yF-yJ) / (xF-xJ); //23 var kKE = (yE-yK) / (xE-xK); //12 var xKE; if (kJF==kKE) kKE+=ADDING; var xIu = (kJF*xF - kKE*xE + yE - yF) / (kJF-kKE); var yIu = kJF * (xIu - xJ) + yJ; var b={x:xIu,y:yIu}; b.x=Math.round(b.x); b.y=Math.round(b.y); return b; }
The result is distorted correctly to perspective (two vanishing point one). The principle of two point perspective calculation is here. The script can handle SVG path data if it meets the following requirements:
- All coordinates are absolute (which means uppercase letters). See this.
- Arc ("A") is not used
- V and H are normalized to L
Arcs can be normalized, but I have not found any crossbrowser way yet. V and H to L is easy task, you have to get the last used x or y coordinate and add the missing one after L.
The same script can handle also curves in path (curves are from Times). The following is exactly same code but the path attribute ("d") is different:
http://jsfiddle.net/xjHUk/277/ function dummy(a) {return a;}
(This code has no check for invalid positions, like the above).
Paths of above examples are got from SVG versions of Arial and Times. Please note that fonts uses Cartesian coordinate system, in which y-coordinate increases when going upwards. Otherwise SVG uses Polar coordinate system, which is used in bitmap images and css. This means that when using paths from SVG fonts in above code, the path have to be flipped vertically and scaled to desired font-size. TTF fonts (and their SVG counterparts) have usually em size 2048, so the bounding box of glyph is without scaling 2048 px, which usually is too much when SVG glyph path is converted to SVG path.
But if you want to distort other SVG paths, then flipping and scaling in unnecessary.
This is fairly long code (much because of drag functionality), but I think that the same effect can be achieved also some css-3D-transform-way, but not luck in such implementation yet...
For comparison an example of non-perspective distort (SVG's main competitor SWF):
http://www.rubenswieringa.com/code/as3/flex/DistortImage/
And for additional comparison an example of VALID perspective calculation:
http://zehfernando.com/f/TriangleTest.swf
这篇关于SVG 路径的透视变换(四角扭曲)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!