Monday 16 July 2018

CSS scaling from a specific point when that point may change along the way?

I am trying to build an application where you can zoom a bit with the mouse wheel into one point, and then later zoom further in at another point.

In other words, the point of "origin" for the zooming can change along the way.

Take a look at this example: https://codesandbox.io/s/4w4m1k5zlx

var phase = 1;

var box1 = document.getElementById("box1");
var box2 = document.getElementById("box2");

box1.style.transformOrigin = "0 0";
box2.style.transformOrigin = "0 0";

var width = 100;
var height = 100;

function transform(originX, originY, translateX, translateY, scale) {
  transformElement(1, box1, originX, originY, translateX, translateY, scale);
  transformElement(2, box2, originX, originY, translateX, translateY, scale);
}

function transformElement(
  method,
  element,
  originX,
  originY,
  translateX,
  translateY,
  scale
) {
  element.style.transition = "transform 1s linear";

  if (method === 1) {
    element.style.transform = `translate(${originX}px, ${originY}px) translate(${translateX}px, ${translateY}px) scale(${scale}) translate(-${originX}px, -${originY}px)`;
  } else if (method === 2) {
    element.style.transformOrigin = `${originX}px ${originY}px`;
    element.style.transform = `translate(${translateX}px, ${translateY}px) scale(${scale})`;
  }

  var pointElement = document.createElement("div");
  pointElement.classList.add("point");
  pointElement.style.transform = `translate(${originX}px, ${originY -
    2 * scale}px)`;

  element.appendChild(pointElement);
}

function reset() {
  resetElement(box1);
  resetElement(box2);
}

function resetElement(element) {
  while (element.children.length > 0) {
    element.removeChild(element.children[0]);
  }

  element.style.transform = "";
  element.style.transition = "";

  void element.clientWidth;
}

function phase1() {
  transform(width * 0.75, height / 2, 0, 0, 1.5);
}

function phase2() {
  transform(width * 0.25, height / 2, 0, 0, 2);
}

function phase3() {
  transform(width / 2, height, 0, 0, 2.5);
}

function phase4() {
  transform(width / 2, 0, 0, 0, 3);
}

const phases = [reset, phase1, phase2, phase3, phase4];

setInterval(() => phases[phase++ % phases.length](), 1500);
* {
  box-sizing: border-box;
}

body {
  background-color: black;
}

.container {
  position: relative;
  margin: 60px;
  background-color: lightgray;
  width: 200px;
  height: 200px;
}

.point {
  width: 2px;
  height: 2px;
  background-color: white;
}

.box {
  position: absolute;
  top: 25%;
  left: 25%;
  transform-origin: 0 0;
  background-color: teal;
  opacity: 0.8;
  width: 100px;
  height: 100px;
}

.outline {
  background-color: transparent;
  border: 1px solid black;
}
<div class="container">
  <div class="box outline">
  </div>
  <div id="box1" class="box"></div>
</div>
<div class="container">
  <div class="box outline">
  </div>
  <div id="box2" class="box"></div>
</div>

Top box in the example: Here I tried simulating transform-origin with transform in order to be able to transition one property. However, the animation is not "even" - especially during the first scale (where it will zoom a bit in and out again - hard to explain but I hope you can see it).

Bottom box in the example: Changing both the transform-origin and transform at the same time, it becomes quite jumpy, because transform has a transition and transform-origin doesn't.

The top example is most ideal, but it still doesn't look good because of the unsmooth zooming. How can I zoom on points at different phases without making the translation either jump or zoom in and out again?



from CSS scaling from a specific point when that point may change along the way?

No comments:

Post a Comment