react-three-map icon indicating copy to clipboard operation
react-three-map copied to clipboard

Large screen canvas overflow

Open essejmclean opened this issue 1 year ago • 5 comments

Problem description:

On large screens/browser windows, the canvas and map while in NOT overlay mode "disconnect" causing models to appear to float while the map is consistently restricted to of approximately 2045x1364.

This is visible at the story here: https://rodrigohamuy.github.io/react-three-map/?story=canvas--maplibre

CleanShot 2024-09-06 at 17 21 42@2x

This is something we can recreate in our own project; however, has never an issue in when overlay mode is activated.

Can confirm the issue occurs in:

  • Chrome - Version 128.0.6613.120
  • Arc - Version 1.58.1 (53264)
  • Safari - Version 17.5 (19618.2.12.11.6)

I have not been able to recreate this issue by zooming out, only by viewing in larger browser windows.

essejmclean avatar Sep 06 '24 23:09 essejmclean

I tried on 2056x1329 and I can't reproduce the issue. Anyway to reproduce this without having to buy a new monitor 😄 ?

Tested on Chrome, Safari and Firefox (Mac).

RodrigoHamuy avatar Sep 09 '24 10:09 RodrigoHamuy

Are you able to overscale your browser? As in increase it larger than your browser by dragging it outside of the bounds of the screen then scaling up again?

I've narrowed this down further last night, and again this morning. MapLibre has an options value called maxCanvasSize. By default it maxes out at 4096x4096, which seems to explain the issues here.

I have it working on initial load by setting an "effective DPR" in use-root.ts. I also had to adjust the camera scale in onCreated for the root configuration:

const MAX_CANVAS_SIZE = 4096;
const effectiveDpr = Math.min(
  window.devicePixelRatio,
  MAX_CANVAS_SIZE / Math.max(canvas.width, canvas.height)
);

// Calculate the scale factor
const scaleFactor = canvas.width / canvas.clientWidth;

const root = createRoot(canvas);
root.configure({
  events,
  ...props,
  frameloop: "never",
  gl: {
    context: gl,
    autoClear: false,
    antialias: true,
    ...props?.gl,
  },
  onCreated: (state) => {
    state.gl.forceContextLoss = () => {};
    // Apply the scale factor to the camera
    state.camera.scale.setScalar(scaleFactor);
  },
  camera: {
    matrixAutoUpdate: false,
    near: 0,
  },
  size: {
    width: canvas.clientWidth,
    height: canvas.clientHeight,
    top: canvas.offsetTop,
    left: canvas.offsetLeft,
    updateStyle: false,
    ...props?.size,
  },
  dpr: effectiveDpr,
});

The issues occur now only on resize - albeit I'm sure there is likely a better approach to the initialization as well. I've made attempts at implementing the same approach with the effectiveDpr and other scaling; however, no luck..

One optimization I'd like to include in my app is adaptive DPR which seems tied to this same set of configuration, but isn't working at this time. It would be extremely valuable to be able to regress the DPR of the Three.js scene when framerates drop or for particular devices.

essejmclean avatar Sep 09 '24 10:09 essejmclean

Quick follow up: you can actually test this very easily by adding maxCanvasSize={[2056, 2056]} (or any other set of values) to a react-map-gl <Map />. I can also solve the problem by adjusting that same value to say... 10_000, though per my comment above, it would be nice to be able to properly update the DPR of the Three.js scene for performance and other considerations (and for this issue to not be a default).

essejmclean avatar Sep 09 '24 10:09 essejmclean

Thanks. Yes, I managed to replicate by using Chrome Debug Tools > Responsive > and set a very high screen resolution as suggested.

image

RodrigoHamuy avatar Sep 09 '24 12:09 RodrigoHamuy

If you have a solution already for this, PRs are welcomed, @essejmclean 😄. Thanks!

RodrigoHamuy avatar Sep 09 '24 12:09 RodrigoHamuy