Подтвердить что ты не робот

Перспективное преобразование путей SVG (четыре искажения угла)

Как можно искажать пути в SVG в браузере, чтобы они искажались в определенной перспективе, используя, возможно, javascript или css? Прогноз перспективы можно легко сделать в Photoshop, Illustrator и т.д., Но как насчет браузеров?

Это исходный путь:

enter image description here

И это путь после преобразования:

enter image description here

4b9b3361

Ответ 1

Это мое предложение искажения перетаскивания (поделиться знаниями, Q & A-style).

Живой пример находится в http://jsfiddle.net/xjHUk/209/, а основной код: (только окно вывода: http://jsfiddle.net/xjHUk/210/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;
}

Результат искажен правильно для перспективы (две точки сбрасывания одна). Принцип расчета двухточечной перспективы здесь. script может обрабатывать данные пути SVG, если он удовлетворяет следующим требованиям:

  • Все координаты являются абсолютными (что означает заглавные буквы). См. .
  • Дуга ( "A" ) не используется
  • V и H нормированы на L

Арки могут быть нормализованы, но я еще не нашел пути для кроссбраузеров. V и H в L - это легкая задача, вы должны получить последнюю использованную координату x или y и добавить отсутствующую после L.

Тот же script может обрабатывать также кривые в пути (кривые от Times). Ниже приведен точно такой же код, но атрибут path ( "d" ) отличается:

http://jsfiddle.net/xjHUk/45/ function dummy(a) {return a;} (Этот код не проверяет недопустимые позиции, как указано выше).

Пути приведенных выше примеров получены из версий SVG Arial и Times. Обратите внимание, что шрифты используют декартова система координат, в которой y-координата увеличивается при движении вверх. В противном случае SVG использует полярную систему координат, которая используется в растровых изображениях и css. Это означает, что при использовании путей из SVG-шрифтов в вышеприведенном коде путь должен быть перевернут по вертикали и масштабирован до нужного размера шрифта. Шрифты TTF (и их SVG-копии) обычно имеют размер 2048, поэтому ограничивающая рамка глифа не имеет масштабирования 2048 px, что обычно слишком велико, когда путь SVG-глифов преобразуется в путь SVG.

Но если вы хотите исказить другие пути SVG, а затем перевернуть и масштабировать ненужные.

Это довольно длинный код (много из-за функции перетаскивания), но я думаю, что тот же эффект может быть достигнут и в каком-то css-3D-преобразовании, но не удача в такой реализации еще...

Для сравнения пример неаспектного искажения (главный конкурент SVG SWF):
http://www.rubenswieringa.com/code/as3/flex/DistortImage/

И для дополнительного сравнения пример расчета VALID перспективы:
http://zehfernando.com/f/TriangleTest.swf

Ответ 2

Выбранный ответ устарел.

Несмотря на то, что SVG не поддерживает изменение перспективы элементов, это можно достичь с помощью CSS3 Transforms.

CSS3 - чрезвычайно мощный способ анимации объектов. CSS3 Transform можно создавать и применять в реальном времени с помощью Javascript.

Существует хорошая поддержка CSS3 Transform, при этом поддерживается последняя версия основных браузеров. (IE 8+, Chrome 31+, Safari 7.1+, Opera 26+, Firefox 34+, Android Browser 4.1+). Дополнительная информация: http://caniuse.com/#feat=transforms2d

Для некоторых версий браузера вам нужно будет использовать префиксы, специфичные для браузера, для создания преобразований. Тем не менее, есть очень аккуратный сайт, который объясняет хороший способ обработки: http://bl.ocks.org/mbostock/10571478

Некоторые свойства CSS3 Transform: rotate(angle), scale(dimension). Я знаю, они выглядят так же, как SVG Transforms rotate(angle), scale(x y), но лучше не воспринимать их как равные, поскольку между ними существуют фундаментальные различия, причем CSS3 намного мощнее SVG Transforms. Кроме того, CSS3 Transforms имеет свойство perspective, которое вам обязательно нужно посмотреть.

Нет лучшего места для поиска дополнительной информации о CSS3 Transforms, чем W3: http://www.w3.org/TR/css3-transforms/

Вот фрагмент кода: an example of CSS3 Transforms

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>