• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

keplergl / kepler.gl / 23965535588

03 Apr 2026 11:07PM UTC coverage: 59.873% (-1.8%) from 61.699%
23965535588

push

github

web-flow
chore: deck.gl 9.2 upgrade & loaders.gl, luma.gl upgrades (#3271)

* chore: upgrade to deckgl 9.2.11

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* fixes

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* fix lint follow up

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* fix blending

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* fix geojson layer

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* more fixes for aggregation layers

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* fix h3 layer

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* potential fix for issues with geoarrow in point and line layers

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* fix postprocessing effects

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* fixes for light and shadow effect

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* shadow and light effect - restore uniform shadow during the nighttime

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* don't hide line and arc layers when layer type changed

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* restore filters for aggregation layers

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* fix aggregation layers - hightlight outlines

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* fixes for raster tile layer - raster pmtiles related

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* fixes for raster tiles shader modules updates

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* fix lint

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* more lint

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* try to fix CI lint

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* try to fix CI tests

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* install webgpu

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* try to fix Ci test env setup

Signed-off-by: Ihor Dykhta <dikhta.igor@gmail.com>

* cont fix setup browser env

Signed-o... (continued)

6517 of 12977 branches covered (50.22%)

Branch coverage included in aggregate %.

324 of 1031 new or added lines in 58 files covered. (31.43%)

123 existing lines in 18 files now uncovered.

13313 of 20143 relevant lines covered (66.09%)

78.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

2.04
/src/deckgl-layers/src/raster/raster-layer/raster-layer.ts
1
// SPDX-License-Identifier: MIT
2
// Copyright contributors to the kepler.gl project
3

4
import {UpdateParameters} from '@deck.gl/core';
5
import {BitmapLayer} from '@deck.gl/layers';
6

7
import {
8
  buildRasterFragmentShader,
9
  buildRasterVertexShader,
10
  rasterUniforms,
11
  ensureRasterHooksRegistered,
12
  prepareLumaModules
13
} from './raster-layer-shaders';
14
import {loadImages} from '../images';
15
import type {RasterLayerAddedProps, ImageState} from '../types';
16
import {modulesEqual} from '../util';
17
import {patchPipelineValidation} from '../pipeline-validation-patch';
18

19
const defaultProps = {
13✔
20
  ...BitmapLayer.defaultProps,
21
  modules: {type: 'array', value: [], compare: true},
22
  images: {type: 'object', value: {}, compare: true},
23
  moduleProps: {type: 'object', value: {}, compare: true},
24
  onRedrawNeeded: {type: 'function', value: null, compare: false}
25
};
26

27
export default class RasterLayer extends BitmapLayer<RasterLayerAddedProps> {
28
  declare state: BitmapLayer<RasterLayerAddedProps>['state'] & {
29
    images: ImageState;
30
  };
31

NEW
32
  _redrawScheduled = false;
×
33

34
  initializeState(): void {
NEW
35
    patchPipelineValidation();
×
NEW
36
    ensureRasterHooksRegistered();
×
UNCOV
37
    this.setState({images: {}});
×
UNCOV
38
    super.initializeState();
×
39
  }
40

41
  draw(_opts: {shaderModuleProps: Record<string, unknown>}): void {
42
    const {model, images, coordinateConversion, bounds} = this.state;
×
43
    const {desaturate, transparentColor, tintColor, moduleProps} = this.props;
×
44

UNCOV
45
    if (
×
46
      !model ||
×
47
      !images ||
48
      Object.keys(images).length === 0 ||
49
      !Object.values(images).every(item => item)
×
50
    ) {
51
      return;
×
52
    }
53

54
    // Set UBO uniforms for the raster module
NEW
55
    model.shaderInputs.setProps({
×
56
      raster: {
57
        desaturate: desaturate || 0,
×
NEW
58
        transparentColor: (transparentColor || [0, 0, 0, 0]).map(x => (x ? x / 255 : 0)),
×
NEW
59
        tintColor: (tintColor || [255, 255, 255]).slice(0, 3).map(x => x / 255),
×
60
        coordinateConversion: coordinateConversion || 0,
×
61
        bounds: bounds || [0, 0, 0, 0],
×
62
        opacity: this.props.opacity ?? 1
×
63
      }
64
    });
65

66
    // Set props for each custom module through shaderInputs.
67
    // We call getUniforms ourselves to skip modules that return null (inactive).
68
    // Passing allModuleProps directly to setProps would cause the null-fallback
69
    // in ShaderInputs to treat the entire props bag as uniforms/bindings,
70
    // triggering expensive texture rebinding every frame.
NEW
71
    const allModuleProps = {...moduleProps, ...images};
×
NEW
72
    const modules = this.props.modules || [];
×
NEW
73
    for (const mod of modules) {
×
NEW
74
      if (mod.getUniforms) {
×
NEW
75
        const result = mod.getUniforms(allModuleProps);
×
NEW
76
        if (result) {
×
NEW
77
          model.shaderInputs.setProps({[mod.name]: result});
×
78
        }
79
      }
80
    }
81

NEW
82
    const drawSuccess = model.draw(this.context.renderPass);
×
NEW
83
    if (!drawSuccess) {
×
NEW
84
      this._scheduleRedraw();
×
85
    }
86
  }
87

88
  _scheduleRedraw(): void {
NEW
89
    if (this._redrawScheduled) return;
×
NEW
90
    this._redrawScheduled = true;
×
NEW
91
    requestAnimationFrame(() => {
×
NEW
92
      this._redrawScheduled = false;
×
NEW
93
      if (this.context.deck) {
×
94
        // @ts-expect-error accessing private deck.gl property
NEW
95
        this.context.deck._needsRedraw = 'RasterLayer pipeline pending';
×
96
      }
NEW
97
      this.context.layerManager?.setNeedsRedraw('RasterLayer pipeline pending');
×
NEW
98
      if (typeof this.props.onRedrawNeeded === 'function') {
×
NEW
99
        this.props.onRedrawNeeded();
×
100
      }
101
    });
102
  }
103

104
  getShaders(): any {
105
    const {modules = []} = this.props;
×
106

NEW
107
    const lumaModules = prepareLumaModules(modules);
×
NEW
108
    const parentShaders = super.getShaders();
×
109

110
    return {
×
111
      ...parentShaders,
112
      vs: buildRasterVertexShader(),
113
      fs: buildRasterFragmentShader(),
114
      modules: [...(parentShaders.modules || []), rasterUniforms, ...lumaModules]
×
115
    };
116
  }
117

118
  // eslint-disable-next-line complexity
119
  updateState(params: UpdateParameters<BitmapLayer<RasterLayerAddedProps>>): void {
120
    const {props, oldProps, changeFlags} = params;
×
121
    const modules = props && props.modules;
×
122
    const oldModules = oldProps && oldProps.modules;
×
123

UNCOV
124
    if (changeFlags.extensionsChanged || !modulesEqual(modules, oldModules)) {
×
NEW
125
      this.state.model?.destroy?.();
×
126
      // @ts-expect-error _getModel is internal to BitmapLayer
NEW
127
      this.state.model = this._getModel(this.context.device || this.context.gl);
×
UNCOV
128
      this.getAttributeManager()?.invalidateAll();
×
129
    }
130

131
    if (props && props.images) {
×
132
      this.updateImages({props, oldProps});
×
133
    }
134

135
    const attributeManager = this.getAttributeManager();
×
136

137
    if (props.bounds !== oldProps.bounds) {
×
138
      const oldMesh = this.state.mesh;
×
139
      const mesh = this._createMesh();
×
140
      this.state.model?.setVertexCount(mesh.vertexCount);
×
141
      for (const key in mesh) {
×
142
        if (oldMesh && oldMesh[key] !== mesh[key]) {
×
143
          attributeManager?.invalidate(key);
×
144
        }
145
      }
146
      this.setState({mesh, ...this._getCoordinateUniforms()});
×
147
    } else if (props._imageCoordinateSystem !== oldProps._imageCoordinateSystem) {
×
148
      this.setState(this._getCoordinateUniforms());
×
149
    }
150
  }
151

152
  updateImages({
153
    props,
154
    oldProps
155
  }: {
156
    props: RasterLayerAddedProps;
157
    oldProps: RasterLayerAddedProps;
158
  }): void {
159
    const {images} = this.state;
×
NEW
160
    const device = this.context.device;
×
NEW
161
    const gl = device?.gl || this.context.gl;
×
162

163
    const newImages = loadImages({
×
164
      gl,
165
      device,
166
      images,
167
      imagesData: props.images,
168
      oldImagesData: oldProps.images
169
    });
170
    if (newImages) {
×
171
      this.setState({images: newImages});
×
172
    }
173
  }
174

175
  finalizeState(): void {
176
    super.finalizeState(this.context);
×
177

178
    if (this.state.images) {
×
179
      for (const image of Object.values(this.state.images)) {
×
180
        if (Array.isArray(image)) {
×
NEW
181
          image.map(x => x && (x.destroy ? x.destroy() : x.delete?.()));
×
182
        } else if (image) {
×
NEW
183
          image.destroy ? image.destroy() : image.delete?.();
×
184
        }
185
      }
186
    }
187
  }
188
}
189

190
RasterLayer.defaultProps = defaultProps;
13✔
191
RasterLayer.layerName = 'RasterLayer';
13✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc