Javascript css3 mousewheel zoom origin problem

I’ve now changed for transform-origin. Before the next scroll it reset the origin and set top, left style properties.
The first scroll works fine but the second is shifted. :confused:

class Container {
  constructor(container) {
    this.container = container;
    this.viewport = container.parentNode;
    let rect = container.getBoundingClientRect();
    this.width = rect.width;
    this.height = rect.height;
    this.x = 0, this.y = 0;
    this.origin = {x: 0, y: 0};
    this.scale = 1; // default scale
    this.zoom = 1.125; // zoom factor
    this.dragging = false;

    this.init();
  }
  init() {
    this.updateStyles();
    let container = this.container;
    let viewport = this.viewport;
    let viewRect = viewport.getBoundingClientRect();

    let startPos = {x: 0, y: 0};
    viewport.addEventListener('mousedown', (e) => {
      if (e.button == 1 || e.shiftKey) {
        e.preventDefault();
        this.dragging = true;
        this.updateStyles();
        let rect = container.getBoundingClientRect();
        startPos = {
          x: e.pageX - this.x,
          y: e.pageY - this.y
        };
      } else if (e.ctrlKey) {
        // ctrl + click to recenter the origin
        this.recenter();
        this.updateStyles();
      }
    });
    window.addEventListener('mousemove', (e) => {
      if (this.dragging) {
        this.x = e.pageX - startPos.x;
        this.y = e.pageY - startPos.y;
        this.updateStyles();
      }
    });
    window.addEventListener('mouseup', () => {
      if (this.dragging) {
        this.dragging = false;
        this.updateStyles();
      }
    });

    let onscroll = (e) => {
      e.preventDefault();
      let scale = 0;
      let wheel = e.detail || e.deltaY;
      scale = wheel > 0 ? this.scale / this.zoom : this.scale * this.zoom;
      let mouseX = (e.pageX - viewRect.left);
      let mouseY = (e.pageY - viewRect.top);
      this.setScale(scale, mouseX, mouseY);
    };
    viewport.addEventListener('DOMMouseScroll', onscroll); // Firefox
    viewport.addEventListener('mousewheel', onscroll); // Chrome, etc.
  }
  recenter() {
    // Calculate left and top property from origin and reset the origin
    this.x -= (this.origin.x * this.scale) - this.origin.x;
    this.y -= (this.origin.y * this.scale) - this.origin.y;
    this.origin = {x:0, y:0};
  }
  setScale(scale, x = this.width / 2, y = this.height / 2) {
    console.log("x, y", x, y);
    this.recenter();
    // Get relative pos from container
    x = x - this.x;
    y = y - this.y;
    this.scale = scale;
    this.scale = this.scale < .25 ? .25 : this.scale; // min zoom
    this.scale = this.scale > 4 ? 4 : this.scale; // max zoom
    this.origin = {
      x: x,
      y: y
    };
    this.updateStyles();
  }
  updateStyles() {
    this.container.style.left = this.x + 'px';
    this.container.style.top = this.y + 'px';
    this.container.style.transform = `scale(${this.scale})`;
    this.container.style.transformOrigin = `${this.origin.x}px ${this.origin.y}px`;
    this.viewport.style.cursor = this.dragging ? 'move' : '';
  }
}

df