visgl / visgl/deck.gl

[Bug] MVTLayer has flickering artifacts when zooming in and out

Open
#10,052 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
14.6k
Forks
2.3k
Avg merge
2d 9h
Merged PRs (30d)
42

Description

Description

When I zoom in and out, I get flickering and incomplete rendering of the polygons. It looks like a triangle opens up on the polygons where the fill color is not applied. It appears to happen at lesser zooms more often but still occurs at all zooms.

I tried setting different values for refinementStrategy and depthTest based on two previous issues, #5220 and #7252 and these did not solve the issue.

https://github.com/user-attachments/assets/3d9b4b74-8733-4c04-b25a-ab639bc8d286

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

When scrolling, flickering triangles would not appear in data visualization.

Steps to Reproduce

Unfortunately my data is not publicly available so I can only share the code that I am using to construct my layer.

// imports
import { MVTLayer } from '@deck.gl/geo-layers';
import chroma from 'chroma-js';
import { Feature } from 'maplibre-gl';

// local imports
import { generateDeckGlGetFillColor } from './AWDVizHelpers';
import { AWDVizConfigTransformed } from '../../services/awdVizConfigApi';

/**
 * Determines the border width for AWD polygons based on the current zoom level.
 *
 * @param {number} zoom - The current zoom level.
 * @returns {number} The border width in pixels.
 */
function calculateBorderWidth(zoom: number): number {
  if (zoom < 7.5) {
    return 0.5;
  } else if (zoom >= 7.5 && zoom < 9) {
    return 1;
  } else if (zoom >= 9 && zoom < 11) {
    return 1.5;
  } else {
    return 2;
  }
}

/**
 * Determines if the AWD layer should be pickable based on the zoom level.
 *
 * @param {number} zoom - The current zoom level.
 * @returns {boolean} True if the layer is pickable, false otherwise.
 */
export function awdLayerPickable(zoom: number): boolean {
  return zoom >= 7.5;
}

/**
 * Props for creating an AWD (Available Water Data) MVTLayer.
 */
type createAwdLayerProps = {
  /** The sector identifier (e.g., "agriculture", "municipal"). */
  sector: string;

  /** The model name used to generate the dataset (e.g., "gfdl", "cesm"). */
  model: string;

  /** The variable name in the dataset (e.g., "water_use", "depletion"). */
  variable: string;

  /** The month for which data is being visualized. */
  month: string;

  /** The year for which data is being visualized. */
  year: string;

  /** The current zoom level of the map view. */
  zoom: number;

  /** Transformed AWD visualization configuration object. */
  config: AWDVizConfigTransformed;

  /** Updates state in parent component */
  onFeatureClick: (feature: any) => void;

  /** The opacity of the layer */
  opacity: number;
};

/**
 * Creates a Deck.gl `MVTLayer` for rendering AWD (Aquifer Water Depletion) data.
 *
 * The layer is dynamically built based on the provided sector, model, variable,
 * zoom level, and visualization configuration. It includes custom fill and
 * line color styling.
 *
 * @param {createAwdLayerProps} props - Layer creation options.
 * @param {string} props.sector - The sector identifier (e.g., "agriculture").
 * @param {string} props.model - The dataset model name (e.g., "gfdl").
 * @param {string} props.variable - The dataset variable (e.g., "water_use").
 * @param {string} props.month - The month for which data is being visualized.
 * @param {string} props.year - The year for which data is being visualized.
 * @param {number} props.zoom - The current map zoom level.
 * @param {AWDVizConfigTransformed} props.config - Transformed AWD visualization configuration.
 * @param {number} props.opacity - The opacity of the layer.
 *
 * @returns {MVTLayer} A configured Deck.gl `MVTLayer` instance.
 */
function createAWDLayer({
  sector,
  model,
  variable,
  month,
  year,
  zoom,
  config,
  opacity,
}: createAwdLayerProps) {
  // construct URL for data layer
  const dataUrl = `https:path/to/data/${sector}/${model}/${variable}/tiles/${year}%2F${month}/{z}/{x}/{y}.pbf`;

  // construct color scale
    const getFeatureFillColor = generateDeckGlGetFillColor({
    bins: config.bins,
    colors: config.colors,
    valueAccessor: (f: Feature) => f.properties['value'],
  });

  // create MVTLayer
  return new MVTLayer({
    id: 'AWDLayer',
    data: dataUrl,
    pickable: awdLayerPickable(zoom),
    filled: true,
    opacity: opacity / 100, // convert to 0-1 range
    getFillColor: getFeatureFillColor,
    stroked: awdLayerPickable(zoom), // no borders at low zooms
    getLineColor: chroma('white').rgb(),
    getLineWidth: calculateBorderWidth(zoom),
    lineWidthUnits: 'pixels',
    maxZoom: 7, // max zoom that tiles were created for this layer
  });
}

export default createAWDLayer;

Environment
  • Framework version: 9.2.9
  • Browser: Edge, Chrome, Firefox
  • OS: Ubuntu/Windows
Logs

There are no console errors or warnings.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start from the supplied createAWDLayer entry point and its MVTLayer configuration, then reproduce the zooming behavior with a public or minimal tile dataset because the reporter's data is unavailable. Compare rendering with the reported React and MapboxOverlay setup; done means polygon fills remain complete and stable while zooming, without flickering triangles.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
data-visualization, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.