ResizeObserver demo

ResizeObserver for chromestatus

by atotic

HTML

<div id="unavailable">
  <h1>ResizeObserver API not available.</h1>
  <p>
  In Chrome, you can enable it by running chrome with --enable-blink-features=ResizeObserver flag.
  </p>
</div>
<section>
  <button id="animate">start/stop animation</button>
  <button id="grow">grow</button>
  <button id="shrink">shrink</button>
</section>
<p>
  This is a div, whose content is generated inside a ResizeObserver callback. The callback creates tiles that fill div's content rect.
</p>
<div id="map" class="resize"></div>

CSS

.resize {
      border: 20px solid rgba(0,255,0, 0.5);
      background-color: #DDD;
      width: 300.49px;
      height: 200.5px;
      overflow: hidden;
      position: relative;
      display: inline-block;
    }
    .mapTile {
      box-sizing: border-box;
      position: absolute;
      border-color: yellow;
      border-width: 1px;
      border-style: solid;
      font-size: 24px;
    }
    #unavailable {
      display:none;
      color: red;
    }
    
    @keyframes resizeAnimationKeyframes {
      0%   {}
      50%  {width: 600px;height:300px;}
      100% {}
    }
    .resizeAnimation {
      animation-name: resizeAnimationKeyframes;
      animation-duration: 4s;
      animation-iteration-count: infinite;
    }
}

JavaScript

function mapTiles(entry) {
  let target = entry.target;
  let TileWidth = 100;
  let TileHeight = TileWidth * 2 / 3;

  let cols = Math.ceil(entry.contentRect.width / TileWidth);
  let rows = Math.ceil(entry.contentRect.height / TileHeight);

  // Ensure correct number of tiles
  let tileCount = cols * rows;
  while (target.childNodes.length > tileCount)
    target.removeChild(target.firstChild);
  while (target.childNodes.length < tileCount)
    target.appendChild(document.createElement('div'));

  // Position all tiles.
  let colWidth = entry.contentRect.width / cols;
  let rowHeight = entry.contentRect.height / rows;
  for (let r=0; r<rows; r++)
    for (let c=0; c<cols; c++) {
      let tile = target.childNodes.item(r * cols + c);
      tile.innerText = r + "." + c + String.fromCodePoint(0x1F600 + r );
      tile.style.left = `${c * colWidth}px`;
      tile.style.width = `${colWidth}px`;
      tile.style.top = `${r * rowHeight}px`;
      tile.style.height = `${rowHeight}px`;
      tile.classList.add('mapTile');
    }
}

function initUI() {
  function resizeBy(delta) {
    for (let el of document.querySelectorAll('.resize')) {
      let s = window.getComputedStyle(el);
      el.style.width = Math.max((parseFloat(s.width) + delta), 10) + 'px';
      el.style.height = Math.max((parseFloat(s.height) + delta * 2 / 3), 7) + 'px';
    }
  }
  function animate() {
  	for (let el of document.querySelectorAll('.resize'))
    	el.classList.toggle('resizeAnimation');
  }
  document.querySelector('#grow').addEventListener('click', function() { resizeBy(5) });
  document.querySelector('#shrink').addEventListener('click', function() { resizeBy(-5) });
  document.querySelector('#animate').addEventListener('click', animate);
  // set up resize handler for all maps
  document.querySelector('#map').onresize = mapTiles;
}

function initObserver() {
  if (!window.ResizeObserver) {
    document.querySelector('#unavailable').style.display = "block";
  } else {
    let ro = new...