Perspective transformation only working on svg tag and not g or image

1.7k Views Asked by At

I am working on a project which involves a series of perspective transformations on figures where the user will eventually be able to navigate through them. I've been working on a prototype for the transformations which I've been developing with the help of this code

Basically, I have 4 points from which I calculate the matrix using the numberic.js function and then apply the matrix3D css3 transformation to the svg element.

You can see the transformation working here (hit the transform button) (simplified js code bellow). The problem is, if I apply the transformation to the g tag, inside the SVG, or the image for that matter, the transformation comes out wrong and I can't figure out why.

var margin = {top: 152.5, right: 200, bottom: 152.5, left: 200},
    width = 700 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;
var sourcePoints = [[0, 0], [width, 0], [width, height], [0, height]],
    targetPoints = [[225.201, 48.411], [1188.39, 185.159], [1869.12, 892.339], [217.525, 231.14]];

var svgTransform;

var transform = ["", "-webkit-", "-moz-", "-ms-", "-o-"].reduce(function(p, v) { 
        return v + "transform" in document.body.style ? v : p; 
    }) + "transform";

function transformed() {  
  for (var a = [], b = [], i = 0, n = sourcePoints.length; i < n; ++i) {
    var s = sourcePoints[i], t = targetPoints[i];
    a.push([s[0], s[1], 1, 0, 0, 0, -s[0] * t[0], -s[1] * t[0]]), b.push(t[0]);
    a.push([0, 0, 0, s[0], s[1], 1, -s[0] * t[1], -s[1] * t[1]]), b.push(t[1]);
  }

  var X = numeric.solve(a, b, true), matrix = [
    X[0], X[3], 0, X[6],
    X[1], X[4], 0, X[7],
       0,    0, 1,    0,
    X[2], X[5], 0,    1
  ].map(function(x) {
    return d3.round(x, 6);
  });

  svgTransform.style(transform, "matrix3d(" + matrix + ")");
}

function reset() {
    targetPoints = [[0, 0], [width, 0], [width, height], [0, height]];
    transformed();
    targetPoints = [[225.201, 48.411], [1188.39, 185.159], [1869.12, 892.339], [217.525, 231.14]];
}

function initialize() {
    svgTransform = d3.select("#vis").append("svg")
        .attr("width", $("#vis").width())
        .attr("height", $("#vis").height())
        .style(transform + "-origin", 0 + "px " + 0 + "px " + 0 + "px");

    svgTransform.append("g")
        .append("image")
        .attr("xlink:href", "http://i.imgur.com/RqtyZjC.png")
        .attr("width", width)
        .attr("height", height);

    $("button.transform").click(function(evt) {
        evt.stopPropagation();
        transformed();
    });
    $("button.reset").click(function(evt) {
        evt.stopPropagation();
        reset();
    });   
}

initialize();

On the final product I'll have several imagens transformed and, with this solution, I'll have to create a svg tag for each of them. This'll complicate things as I want padding and zooming options on the visualization.

I've also tried doing this with only divs and it also works fine (fiddle here) but the reason I wanted to use SVG was to facilitate the user interface creation and the use of zoom and panning.

Anyone more experienced than me can figure out why the transformations do not work inside the svg?

Bellow is a picture of the result if the transformation is applied to the g or image tag, inside the SVG.

Transformation applied inside the SVG tag

Thanks in advance for your help!

1

There are 1 best solutions below

1
On BEST ANSWER

It is safe to apply CSS 3D transforms to outermost <svg> elements, just as you can any HTML element. But browser support for 3D transforms of SVG child elements is still under development and is currently unreliable. The spec that describes it (http://www.w3.org/TR/css3-transforms/#svg-three-dimensional-functions) is still just a working draft. It might make sense to avoid it for now.