SVG路径的透视变换(四角变形)

Tim*_*nen 29 javascript css svg transformation perspective

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

这是源路径:

在此输入图像描述

这是转型后的道路:

在此输入图像描述

Tim*_*nen 30

这是我的拖曳扭曲建议(分享你的知识,Q&A风格).

实例是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;
}

结果正确地扭曲到透视(两个消失点1).两点角度计算的原则是在这里.如果SVG路径数据满足以下要求,则该脚本可以处理:

  • 所有坐标都是绝对的(表示大写字母).看到这个.
  • 不使用圆弧("A")
  • V和H归一化为L.

弧可以标准化,但我还没有找到任何crossbrowser方式.V和H到L是很容易的任务,你必须得到最后使用的x或y坐标并在L之后添加缺失的坐标.

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

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

以上示例的路径来自Arial和Times的SVG版本.请注意,字体使用笛卡尔坐标系,其中y坐标在向上时会增加.否则SVG使用极坐标系,用于位图图像和css.这意味着在上面的代码中使用SVG字体的路径时,必须垂直翻转路径并缩放到所需的字体大小.TTF字体(及其SVG对应物)通常具有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

  • 很抱歉回答晚了,但现在才找到一个库,尽管它从 2013 年就已经存在了。该技术使用转换属性。这项技术的好处是它可以转换任何 DOM 元素,而不仅仅是我建议的 svg 路径。不好的事情是质量不是那么好,它在矢量形状中有些像素化,但在使用位图图像时还可以。我举了一个例子:http://jsbin.com/xuxataqahe。该库来自http://edankwan.github.io/PerspectiveTransform.js/。该库可能也适合与 SVG 图像一起使用,但尚未进行测试。 (2认同)

oab*_*rca 12

所选答案已过时.

即使SVG不支持更改元素的视角,也可以通过使用CSS3 Transforms来实现.

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 Transform属性是:rotate(angle), scale(dimension). 我知道,他们看起来SOOOO类似SVG变换rotate(angle),scale(x y)但最好不要把他们作为平等的,因为有两个本质上的区别,与CSS3比SVG变换更为强大.此外,CSS3 Transforms有一个perspective你肯定需要看的属性.

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

这是一段代码: CSS3 Transforms的一个例子

div {
  height: 150px;
  width: 150px;
}
.container {
  perspective: 500px;
  border: 1px solid black;
  background: gray;
}
.transformed {
  transform: rotateY(50deg);
  background: blue;
}
Run Code Online (Sandbox Code Playgroud)
<!doctype html>
<html>
<body>
<div class="container">
  <div class="transformed"> Hola! He sido transformado!</div>
</div>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

快乐转型!

  • 如何在您的方法中进行四个角拖动?这是我的质量检查的重点。 (2认同)
  • @user2070775 虽然 SVG 支持大多数 CSS3,但 SVG 渲染器总是忽略透视/3d 转换——就像你在示例中展示的那样。 (2认同)