WMTS Overzoom (Google Maps JS API)

HTML

<script
  async
  src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&v=weekly&callback=initMap"
></script>

<div id="map"></div>

CSS

html,
body,
#map {
  height: 100%;
  margin: 0;
  padding: 0;
}
.credit {
  position: absolute;
  z-index: 5;
  left: 8px;
  bottom: 8px;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  padding: 6px 8px;
  border-radius: 6px;
  font:
    12px/1.2 system-ui,
    -apple-system,
    Segoe UI,
    Roboto,
    sans-serif;
}
.credit a {
  color: #9bd;
  text-decoration: none;
}

JavaScript

const MAX_NATIVE_ZOOM = 19; // change if your layer supports more

// Build a WMTS URL for a given z/x/y (XYZ in Google Maps tile space)
function wmtsUrl(zoom, x, y) {
  return `https://data.geopf.fr/wmts?layer=HR.ORTHOIMAGERY.ORTHOPHOTOS&style=normal&tilematrixset=PM&Service=WMTS&Request=GetTile&Version=1.0.0&Format=image%2Fjpeg&TileMatrix=${zoom}&TileCol=${x}&TileRow=${y}`;
}

// Normalize tile coords to the world at a given zoom:
// - wrap X horizontally (world repeats)
// - clamp Y vertically (outside world becomes null)
function normalizeCoord(coord, zoom) {
  const tileRange = 1 << zoom; // 2^zoom
  const x = ((coord.x % tileRange) + tileRange) % tileRange;
  const y = coord.y;
  if (y < 0 || y >= tileRange) return null;
  return { x, y };
}

class OverzoomWMTSMapType {
  constructor() {
    this.tileSize = new google.maps.Size(256, 256);
    this.maxZoom = 22; // allow users to zoom further than native (even made it possible to zoom past 22)
    this.minZoom = 0;
    this.name = "Orthophotos";
    this.alt = "WMTS Orthophotos with overzoom";
  }

  getTile(coord, zoom, ownerDocument) {
    const n = normalizeCoord(coord, zoom);
    if (!n) return null;

    const div = ownerDocument.createElement("div");
    div.style.width = "256px";
    div.style.height = "256px";
    div.style.backgroundRepeat = "no-repeat";
    // Optional: keep pixels crisp when scaling up tiles
    div.style.imageRendering = "pixelated";

    if (zoom <= MAX_NATIVE_ZOOM) {
      // Normal fetch at this zoom
      const url = wmtsUrl(zoom, n.x, n.y);
      div.style.backgroundImage = `url("${url}")`;
      return div;
    }

    // Overzoom: use parent tile(s) at MAX_NATIVE_ZOOM, crop & scale
    const dz = zoom - MAX_NATIVE_ZOOM;
    const scale = 1 << dz; // 2^dz
    const parentX = Math.floor(n.x / scale);
    const parentY = Math.floor(n.y / scale);
    const subX = n.x % scale; // child offset within parent
    const subY = n.y %...