Skip to content

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

@alaws-USGS

Description

@alaws-USGS

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.

Screen.Recording.2026-02-27.095756.mp4

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions