Ninjas: Given some coordinates, take css transform (skew, rotate) to paint an image

2

the API returns some random coordinates that will be the container of the image, and these coordinates will always be a rectangle but it may not have angles of 90 degrees so I have to deform the image to adapt it to this container.

I think the solution would be transoforming the coordinates to css-transform. Can anyone think of something?

Thank you.

var app = {
  init: function() {
    let coords = this.getDataFromApi(); // getting coords
    this.reDrawPolygon(coords);
    this.positionateImg(coords);
  },

  getDataFromApi: () => {
    /* http request with random points*/
    return {
      "p1": {
        "x": 28,
        "y": 51
      },
      "p2": {
        "x": 393,
        "y": 21
      },
      "p3": {
        "x": 401,
        "y": 170
      },
      "p4": {
        "x": 40,
        "y": 135
      }
    };
  },
  reDrawPolygon: (coords) => {
    let svg = document.querySelector('svg');
    let points = [];
    for (let i in coords) {
      points.push(coords[i].x + ' ' + coords[i].y)
    }
    if (!svg.querySelector('polygon').getAttribute('points')) {
      svg.querySelector('polygon').setAttribute('points', points.join())
    } else {
      svg.querySelector('polygon').setAttribute('points', svg.querySelector('animate').getAttribute('to'))
    }
    svg.querySelector('animate').setAttribute('to', points.join())
    let anim = document.getElementById('animation-to-click');
    anim['beginElement']()
  },
  positionateImg: (coords) => {
    let img = document.querySelector('img');
    img.style.top = coords.p1.y + 'px';
    img.style.left = coords.p1.x + 'px';
    img.style.width = (coords.p2.x - coords.p1.x) + 'px';
    img.style.height = (coords.p4.y - coords.p1.y) + 'px';
  }

}

app.init();
div {
  position: relative
  width:100vw;
  height:100vh;
}

svg {
  width: 100%;
  height: 100%;
  position: relative;
  z-index: 1;
}

img {
  position: absolute;
  transition: all 600ms;
}
<div>
  <img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTYOz3O64CoAaQUStkjHStEJZVADvfOlbVzjPok68XTeT-ytdGH" />
  <svg>
  <polygon style="stroke:#b5bf03;fill:transparent;stroke-width:3" points="0,0,0,0"> 
    <animate id="animation-to-click" fill="freeze" attributeName="points" dur="100ms" />
  </polygon>
</svg>
</div>
    
asked by David DP 22.03.2018 в 12:10
source

1 answer

0

This is not exactly an answer but a demonstration that is probably impossible to do what you want with transformations. I do not have a "slider" to skew the image but I do not think it would be helpful. If you think that transform: matrix3d() is the solution you can try to create something similar with 16 "sliders" and try to see if you can deform the image to your liking.

Please open the following demo to "Full page".

var s = document.createElement('style');
document.head.appendChild(s);

var div1 = document.getElementById("div1");

var theParent = document.getElementById("parent");

var to = document.getElementById("to");
var radiosX = document.querySelectorAll("input[name = 'X']");
var radiosY = document.querySelectorAll("input[name = 'Y']");

var cssObject = {
  perspective: 100,
  rotateX: 0,
  rotateY: 0,
  rotateZ: 0,
  translateZ: 0,
  transformOriginX: "center",
  transformOriginY: "center"
};

for (var i = 0; i < theParent.children.length; i++) {
  var childElement = theParent.children[i];
  var theId = theParent.children[i].id;
  var theIndex = i;
  cssObject[theId] = document.querySelector("#" + theId + " input").value;
  childElement.addEventListener('input', onInput, false);
}

function onInput(e) {
  var itemId = e.target.id;
  var thisValue = document.getElementById(itemId).value;
  document.querySelector("label[for = " + itemId + " ]" + " span").innerHTML = thisValue;
  cssObject[itemId.replace("Input", "")] = thisValue;
  manipulateCSS(cssObject);
}

for (var i = 0; i < radiosX.length; i++) {
  radiosX[i].addEventListener("change",
    onChecked, false);

}
for (var i = 0; i < radiosY.length; i++) {
  radiosY[i].addEventListener("change",
    onChecked, false);
}

function onChecked(e) {
  if (this.checked == true) {
    var itemId = e.target.id;
    var thisName = e.target.name;
    var thisValue = document.getElementById(itemId).value;
    cssObject["transformOrigin" + thisName] = thisValue;
    manipulateCSS(cssObject);
  }
}

function manipulateCSS(cssObject) {
  var stylesStr1 = "perspective(" + cssObject.perspective + "px) rotateY(" + cssObject.rotateY + "deg)  rotateX(" + cssObject.rotateX + "deg) rotateZ(" + cssObject.rotateZ + "deg) translateZ(" + cssObject.translateZ + "px);";
  var stylesStr2 = cssObject.transformOriginX + " " + cssObject.transformOriginY;
  to.innerHTML = stylesStr2;
  s.textContent = "#div1{";
  s.textContent += "-webkit-transform:" + stylesStr1;
  s.textContent += "transform:" + stylesStr1;
  s.textContent += "-webkit-transform-origin:" + stylesStr2 + ";";
  s.textContent += "transform-origin:" + stylesStr2 + ";";
  s.textContent += "}";
}
* {
  margin: 0;
  padding: 0;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  font-family: Courier, monospace;
  font-size: 13px;
  font-weight: 300;
}
body {
  width: 100%;
}
#contenido {
  width: 400px;
  height: 400px;
  margin: 30px auto;
  border: 1px solid #d9d9d9;
  padding: 50px;
  overflow: hidden;
  position:relative;
}
#demo {
  padding: 70px 0;
  margin: 0 auto;
  -webkit-transform-style: preserve-3d;
  transform-style: preserve-3d;
}
h4 {
  display: block;
  width: 500px;
  margin: 30px 0 0;
  font-size: 140;
}

p {
  margin: 1em 0;
  line-height: 150%;
}
p label {
  width: 38%;
  display: inline-block;
}
p input {
  width: 60%;
  display: inline-block;
}
p input[type = "radio"] {
  width: 50%;
}
.div {
  background-image:url("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTYOz3O64CoAaQUStkjHStEJZVADvfOlbVzjPok68XTeT-ytdGH");
  width:313px;
  height:161px;
  
}
.row {
  width: 400px;
  margin: 0px auto;
}
._2 {
  width: 200px;
  display: inline-block;
}



svg{position:absolute;margin:auto; left:0;right:0;bottom:0;top:0;width:296;height:118.24; z-index:2 }
<div id="contenido">
<svg viewBox = "28 21 373 149" style="border:1px solid">
<polygon style="stroke:#b5bf03;fill:transparent;stroke-width:3" points="28 51 393 21 401 170 40 135"> 
</polygon>  
  </svg>
<div id="demo">
 <div class="div" id="div1"></div>
</div>

</div>
<div class="row" id="parent">
<p id="perspective"><label for="perspectiveInput">perspective: <span>100</span>px</label>
<input type="range" value="100" min="0" max="400" id="perspectiveInput" autocomplete="off"></p>

<p id="rotateX"><label for="rotateXInput">rotateX: <span>0</span>deg</label>
<input type="range" value="0" min="-180" max="180" id="rotateXInput" autocomplete="off"></p>

<p id="rotateY"><label for="rotateYInput">rotateY: <span>0</span>deg</label>
<input type="range" value="0" min="-180" max="180" id="rotateYInput" autocomplete="off"></p>

<p id="rotateZ"><label for="rotateZInput">rotateZ: <span>0</span>deg</label>
<input type="range" value="0" min="-360" max="360" id="rotateZInput" autocomplete="off"></p>

<p id="translateZ"><label for="translateZInput">translateZ: <span>0</span>px</label>
<input type="range" value="0" min="-200" max="200" id="translateZInput" autocomplete="off"></p>
</div>

<div class="row">
<h4>transform-origin: <span id="to">center center</span></h4>
<div class="_2" id="radiosX">
<p>
<label for="r1">left: </label><input type="radio" name="X" id="r1" value="left" />
<label for="r2">center: </label><input type="radio" name="X" id="r2" value="center"  checked />
<label for="r3">right: </label><input type="radio" name="X" id="r3" value="right" />
</p>
</div><div class="_2" id="radiosY">
<p>
<label for="r4">top: </label><input type="radio" name="Y" id="r4" value="top"/>
<label for="r5">center: </label><input type="radio" name="Y" id="r5" value="center"  checked />
<label for="r6">bottom: </label><input type="radio" name="Y" id="r6" value="bottom" />
</p>
</div>
</div>
    
answered by 02.10.2018 в 16:03