Skip to content

[Bug] Misalignment/drift in MapboxOverlay at fractional zoom levels #10173

@kahole

Description

@kahole

Description

Since upgrading from 9.1 to 9.2.11, MapboxOverlay layers exhibit misalignment relative to the base map when the browser is set to a fractional zoom (e.g., 67% or 66.666%).

The issue is more easily triggered when the body has margin: 0. This appears to be a regression in how the new luma.gl v9 engine calculates the CanvasContext size compared to Mapbox GL JS v3's internal rounding/snapping logic.

Flavors

  • Script tag
  • React
  • Python/Jupyter notebook
  • MapboxOverlay
  • GoogleMapsOverlay
  • CARTO
  • ArcGIS

Expected Behavior

Deck.gl layers should remain perfectly aligned with Mapbox markers and tiles regardless of browser zoom level or body margins.

Steps to Reproduce

  1. Use MapboxOverlay in "overlaid" mode with deck.gl@9.2.11 and mapbox-gl@3.x.

  2. Set CSS body { margin: 0; padding: 0; }.

  3. Set browser zoom to 67% (I guess changing the devicePixelRatio to a fractional value).

  4. Pan the map or observe layers; a shift is visible between the Deck.gl canvas and the Mapbox canvas.

Reverting to body { margin: 8px; } makes the problem harder to reproduce. Downgrading to deck.gl@9.1 eliminates it.

Minimal reproduction code

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Map Zoom Shift Issue</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
  </body>
</html>

index.css

body {
  width: 100%;
  max-width: 100%;
  height: 100vh;
  margin: 0;
}

#root {
  width: 100%;
  height: 100%;
}

main.jsx

import "./index.css";
import "mapbox-gl/dist/mapbox-gl.css";
import ReactDOM from "react-dom";
import { ScatterplotLayer } from "@deck.gl/layers";
import { MapboxOverlay } from "@deck.gl/mapbox";
import { Map, useControl } from "react-map-gl/mapbox";

const data = [
  { pos: [-80.0133149, 40.4554421] },
  { pos: [-8.0133149, 40.4554421] },
  { pos: [-84.0133149, 40.4554421] },
  { pos: [-86.0133149, 40.4554421] },
  { pos: [-88.0133149, 40.4554421] },
  { pos: [-80.0133149, 42.4554421] },
  { pos: [-80.0133149, 44.4554421] },
  { pos: [-80.0133149, 46.4554421] },
  { pos: [-80.0133149, 48.4554421] },
];

const layers = [
  new ScatterplotLayer({
    id: "test",
    data,
    getPosition: (d) => d.pos,
    pickable: true,
    opacity: 1.0,
    stroked: true,
    filled: true,
    radiusScale: 6,
    radiusMinPixels: 1,
    radiusMaxPixels: 1000,
    lineWidthMinPixels: 1,
    getRadius: (d) => 10000,
    getFillColor: (d) => [255, 140, 0],
    getLineColor: (d) => [0, 0, 0],
  }),
];

function DeckGLOverlay(props) {
  const overlay = useControl(() => new MapboxOverlay(props));
  overlay.setProps(props);
  return null;
}

function Main() {
  return (
    <Map
      initialViewState={{
        longitude: -80,
        latitude: 40,
        zoom: 3,
      }}
      mapStyle="mapbox://styles/mapbox/streets-v9"
      mapboxAccessToken={process.env.MAPBOX_ACCESS_TOKEN}
      reuseMaps
      dragRotate={false}
      touchPitch={false}
    >
      <DeckGLOverlay layers={layers} />
    </Map>
  );
}

const App = () => {
  return <Main />;
};

ReactDOM.createRoot(document.getElementById('root')).render(<App />);

Environment

Framework version: deck.gl 9.2.11, react-map-gl 7.x/8.x
Browser: Chrome (latest)
OS: macOS

Logs

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions