SVG 路径的透视变换(四角扭曲) [英] Perspective transform of SVG paths (four corner distort)

查看:31
本文介绍了SVG 路径的透视变换(四角扭曲)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在浏览器中扭曲 SVG 中的路径,以便使用 javascript 或 css 将它们扭曲到某些角度?可以在 Photoshop、Illustrator 等中轻松制作透视扭曲,但浏览器如何?

这是源路径:

这是改造后的路径:

解决方案

这是我的拖动扭曲方案 (以问答方式分享您的知识).

实时示例在 http://jsfiddle.net/xjHUk/278/ 和主要代码是这样的:
(仅输出窗口:http://jsfiddle.net/xjHUk/279/embedded/result/)

<前>功能转移点(xI,yI,源,目的地){无功添加 = 0.001;//避免除以零var xA = source[0].x;var yA = source[0].y;var xC = source[2].x;var yC = source[2].y;var xAu = 目的地[0].x;var yAu = 目的地[0].y;var xBu = 目的地[1].x;var yBu = 目的地[1].y;var xCu = 目的地[2].x;var yCu = 目的地[2].y;var xDu = 目的地[3].x;var yDu = 目的地[3].y;//计算//如果点数相同,则必须添加 ADDING 以避免被零除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;如果 (xE==xF) xF+=添加;var kEF = (yE-yF)/(xE-xF);如果 (kEF==kAB) kAB+=添加;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;如果 (xF==xJ) xJ+=添加;如果 (xE==xK) xK+=添加;var kJF = (yF-yJ)/(xF-xJ);//23var kKE = (yE-yK)/(xE-xK);//12var 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);返回 b;}

结果正确地扭曲到透视(两个消失点一个).两点透视计算的原理是这里.如果满足以下要求,该脚本可以处理 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆