javascript SVG 路径的透视变换(四角扭曲)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12919398/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Perspective transform of SVG paths (four corner distort)
提问by Timo K?hk?nen
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?
如何在浏览器中扭曲 SVG 中的路径,以便使用可能的 javascript 或 css 将它们扭曲到某些角度?可以在 Photoshop、Illustrator 等中轻松制作透视扭曲,但是浏览器呢?
This is source path:
这是源路径:
And this is the path after transformation:
这是改造后的路径:
回答by Timo K?hk?nen
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/)
实时示例在http://jsfiddle.net/xjHUk/278/ 中,主要代码是这样的:(
仅输出窗口: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:
结果正确地扭曲到透视(两个消失点一个)。两点透视计算的原理就在这里。如果满足以下要求,该脚本可以处理 SVG 路径数据:
- All coordinates are absolute (which means uppercase letters). See this.
- Arc ("A") is not used
- V and H are normalized to L
- 所有坐标都是绝对坐标(即大写字母)。看到这个。
- 不使用弧(“A”)
- V 和 H 归一化为 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.
弧可以标准化,但我还没有找到任何跨浏览器的方式。V 和 H 到 L 是一项简单的任务,您必须获得最后使用的 x 或 y 坐标,并在 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:
相同的脚本也可以处理路径中的曲线(曲线来自 Times)。以下是完全相同的代码,但路径属性(“d”)不同:
http://jsfiddle.net/xjHUk/277/function dummy(a) {return a;}
(This code has no check for invalid positions, like the above).
http://jsfiddle.net/xjHUk/277/function dummy(a) {return a;}
(此代码没有检查无效位置,如上所述)。
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.
以上示例的路径来自Arial 和Times 的SVG 版本。请注意,字体使用笛卡尔坐标系,其中 y 坐标向上时增加。否则 SVG 使用极坐标系,用于位图图像和 css。这意味着当在上面的代码中使用来自 SVG 字体的路径时,路径必须垂直翻转并缩放到所需的字体大小。TTF 字体(以及它们的 SVG 对应字体)的 em 大小通常为 2048,因此字形的边界框没有缩放 2048 像素,这在 SVG 字形路径转换为 SVG 路径时通常太多了。
But if you want to distort other SVG paths, then flipping and scaling in unnecessary.
但是,如果您想扭曲其他 SVG 路径,则不需要进行翻转和缩放。
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...
这是相当长的代码(很大程度上是因为拖动功能),但我认为也可以通过一些 css-3D-transform-way 实现相同的效果,但在这种实现中还没有运气......
For comparison an example of non-perspective distort (SVG's main competitor SWF):
http://www.rubenswieringa.com/code/as3/flex/DistortImage/
为了比较非透视扭曲的示例(SVG 的主要竞争对手 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
对于其他比较,一个 VALID 透视计算的例子:http:
//zehfernando.com/f/TriangleTest.swf
回答by oabarca
The selected answer is outdated.
所选答案已过时。
Even though SVG does not support changing the perspective of elements, it is possible to achieve this by using CSS3 Transforms.
即使 SVG 不支持改变元素的视角,也可以通过使用 CSS3 Transforms 来实现这一点。
CSS3 is an extremely powerful way of animating objects. CSS3 Transform can be created and applied in real time using Javascript.
CSS3 是一种非常强大的动画对象方式。可以使用 Javascript 实时创建和应用 CSS3 变换。
There is good support for CSS3 Transform, with all recent version of major browsers supporting it. (IE 8+, Chrome 31+, Safari 7.1+, Opera 26+, Firefox 34+, Android Browser 4.1+). More info: http://caniuse.com/#feat=transforms2d
对 CSS3 Transform 有很好的支持,所有最新版本的主要浏览器都支持它。(IE 8+、Chrome 31+、Safari 7.1+、Opera 26+、Firefox 34+、Android 浏览器 4.1+)。更多信息:http: //caniuse.com/#feat=transforms2d
For some browser versions you would need to use browser-specific prefixes to create the transformations. However, there is very neat site that explains the good way of handling that: http://bl.ocks.org/mbostock/10571478
对于某些浏览器版本,您需要使用特定于浏览器的前缀来创建转换。但是,有一个非常简洁的网站解释了处理该问题的好方法:http: //bl.ocks.org/mbostock/10571478
Some CSS3 Transform properties are: rotate(angle)
, scale(dimension)
. I know, they look soooo similar to SVG Transforms rotate(angle)
, scale(x y)
, but it is best not to take them as equal since there are fundamental differences between the two, with CSS3 being far more powerful than SVG Transforms. In addition, CSS3 Transforms has a property perspective
that you definitely need to look at.
一些 CSS3 Transform 属性是:rotate(angle)
, scale(dimension)
. 我知道,他们看起来SOOOO类似SVG变换rotate(angle)
,scale(x y)
但最好不要把他们作为平等的,因为有两个本质上的区别,与CSS3比SVG变换更为强大。此外,CSS3 Transforms 有一个perspective
您绝对需要查看的属性。
There is no better place to find more information about CSS3 Transforms than the W3: http://www.w3.org/TR/css3-transforms/
没有比 W3 更好的地方可以找到有关 CSS3 转换的更多信息:http: //www.w3.org/TR/css3-transforms/
Here is a code snippet:
这是一个代码片段:
div {
height: 150px;
width: 150px;
}
.container {
perspective: 500px;
border: 1px solid black;
background: gray;
}
.transformed {
transform: rotateY(50deg);
background: blue;
}
<!doctype html>
<html>
<body>
<div class="container">
<div class="transformed"> Hola! He sido transformado!</div>
</div>
</body>
</html>
Happy transforming!
快乐蜕变!