39

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

这是源路径:

在此处输入图像描述

这是改造后的路径:

在此处输入图像描述

4

2 回答 2

36

这是我的拖拽扭曲建议(分享你的知识,问答式)。

现场示例在http://jsfiddle.net/xjHUk/278/中,主要代码是这样的:(
仅输出窗口:http: //jsfiddle.net/xjHUk/279/embedded/result/

函数 transferPoint (xI, yI, source, destination)
{
    变量添加 = 0.001; // 避免被零除

    var xA = 源[0].x;
    var yA = 源[0].y;

    var xC = 源[2].x;
    var yC = 源[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 以避免被零除
    如果(xBu==xCu)xCu+=添加;
    如果(xAu==xDu)xDu+=添加;
    如果(xAu==xBu)xBu+=添加;
    如果(xDu==xCu)xCu+=添加;
    var kBC = (yBu-yCu)/(xBu-xCu);
    var kAD = (yAu-yDu)/(xAu-xDu);
    var kAB = (yAu-yBu)/(xAu-xBu);
    var kDC = (yDu-yCu)/(xDu-xCu);

    如果(kBC==kAD)kAD+=添加;
    var xE = (kBC*xBu - kAD*xAu + yAu - yBu) / (kBC-kAD);
    var yE = kBC*(xE - xBu) + yBu;

    如果(kAB==kDC)kDC+=添加;
    var xF = (kAB*xBu - kDC*xCu + yCu - yBu) / (kAB-kDC);
    变量 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);
    变量 yG = kEF*(xG - xDu) + yDu;

    如果(kEF==kBC)kBC+=添加;
    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);

    变量 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); //23
    var kKE = (yE-yK) / (xE-xK); //12

    变量 xKE;
    如果(kJF==kKE)kKE+=添加;
    var xIu = (kJF*xF - kKE*xE + yE - yF) / (kJF-kKE);
    var yIu = kJF * (xIu - xJ) + yJ;

    变量 b={x:xIu,y:yIu};
    bx=数学.round(bx);
    by=Math.round(by);
    返回 b;
}

结果被正确地扭曲为透视(两个消失点一)。两点透视计算的原理就到这里了。如果满足以下要求,该脚本可以处理 SVG 路径数据:

  • 所有坐标都是绝对的(这意味着大写字母)。看到这个
  • 不使用弧(“A”)
  • V 和 H 归一化为 L

弧线可以标准化,但我还没有找到任何跨浏览器的方式。V 和 H 到 L 很容易,您必须获取最后使用的 x 或 y 坐标,然后在 L 之后添加缺少的坐标。

相同的脚本也可以处理路径中的曲线(曲线来自时代)。以下是完全相同的代码,但路径属性(“d”)不同:

http://jsfiddle.net/xjHUk/277/ function dummy(a) {return a;} (此代码没有检查无效位置,如上所示)。

以上示例的路径来自 Arial 和 Times 的 SVG 版本。请注意字体使用笛卡尔坐标系,向上时y坐标增加。否则 SVG 使用极坐标系,用于位图图像和 css。这意味着当在上述代码中使用来自 SVG 字体的路径时,路径必须垂直翻转并缩放到所需的字体大小。TTF 字体(及其 SVG 对应字体)通常 em 大小为 2048,因此字形的边界框没有缩放 2048 px,这通常在 SVG 字形路径转换为 ​​SVG 路径时太大。

但是,如果您想扭曲其他 SVG 路径,则无需进行翻转和缩放。

这是相当长的代码(很大程度上是因为拖动功能),但我认为同样的效果也可以通过一些 css-3D-transform-way 来实现,但在这样的实现中还没有运气......

为了比较非透视扭曲的示例(SVG 的主要竞争对手 SWF):
http ://www.rubenswieringa.com/code/as3/flex/DistortImage/

为了进一步比较有效透视计算的示例:http:
//zehfernando.com/f/TriangleTest.swf

于 2012-10-16T16:36:12.973 回答
16

所选答案已过时。

尽管 SVG 不支持改变元素的透视,但可以通过使用 CSS3 变换来实现。

CSS3 是一种非常强大的动画对象方法。可以使用 Javascript 实时创建和应用 CSS3 转换。

对 CSS3 Transform 有很好的支持,所有最新版本的主要浏览器都支持它。(IE 8+、Chrome 31+、Safari 7.1+、Opera 26+、Firefox 34+、Android 浏览器 4.1+)。更多信息:http ://caniuse.com/#feat=transforms2d

对于某些浏览器版本,您需要使用特定于浏览器的前缀来创建转换。但是,有一个非常简洁的网站解释了处理该问题的好方法:http: //bl.ocks.org/mbostock/10571478

一些 CSS3 变换属性是:rotate(angle), scale(dimension). 我知道,它们看起来与 SVG 变换非常相似rotate(angle)scale(x y)但最好不要将它们视为相等,因为两者之间存在根本差异,CSS3 比 SVG 变换强大得多。此外,CSS3 Transforms 有一个perspective你绝对需要查看的属性。

没有比 W3 更好的地方可以找到有关 CSS3 转换的更多信息:http: //www.w3.org/TR/css3-transforms/

这是一个代码片段: CSS3 变换的一个例子

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>

快乐蜕变!

于 2015-02-08T17:56:33.073 回答