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

visgl / loaders.gl / 25070233425

28 Apr 2026 06:20PM UTC coverage: 59.434% (+0.01%) from 59.423%
25070233425

push

github

web-flow
website: Add tabs for navigating between format docs (#3407)

11310 of 20887 branches covered (54.15%)

Branch coverage included in aggregate %.

89 of 136 new or added lines in 13 files covered. (65.44%)

1742 existing lines in 132 files now uncovered.

23500 of 37682 relevant lines covered (62.36%)

16296.63 hits per line

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

70.93
/modules/deck-layers/src/vector-source-layer.ts
1
// loaders.gl
2
// SPDX-License-Identifier: MIT
3
// Copyright (c) vis.gl contributors
4

5
import {
6
  CompositeLayer,
7
  type CompositeLayerProps,
8
  type DefaultProps,
9
  type Layer,
10
  type UpdateParameters,
11
  _deepEqual as deepEqual
12
} from '@deck.gl/core';
13
import type {GeoJsonLayerProps} from '@deck.gl/layers';
14
import {GeoJsonLayer} from '@deck.gl/layers';
15
import type {GeoJSONTable} from '@loaders.gl/schema';
16
import type {VectorSource, VectorSourceData} from '@loaders.gl/loader-utils';
17
import {VectorSet} from './vector-source-layer/vector-set';
18

19
/** Props for {@link VectorSourceLayer}. */
20
export type VectorSourceLayerProps = CompositeLayerProps & {
21
  /** Fully constructed loaders.gl vector source. */
22
  data: VectorSource;
23
  /** Named source layers forwarded to `VectorSource#getFeatures`. */
24
  layers: string | string[];
25
  /** Output CRS forwarded to `VectorSource#getFeatures`. */
26
  crs?: string;
27
  /** Output format forwarded to `VectorSource#getFeatures`. */
28
  format?: 'geojson' | 'binary' | 'arrow';
29
  /** Debounce interval applied before viewport requests are issued. */
30
  debounceTime?: number;
31
  /** Called when the current viewport request resolves successfully. */
32
  onDataLoad?: (table: VectorSourceData) => void;
33
  /** Called when metadata or viewport requests fail. */
34
  onError?: (error: Error) => void;
35
  /** Called when metadata/viewport loading starts or stops. */
36
  onLoadingStateChange?: (isLoading: boolean) => void;
37
  /** Optional props forwarded into the default `GeoJsonLayer`. */
38
  geoJsonLayerProps?: Partial<GeoJsonLayerProps>;
39
};
40

41
type VectorSourceLayerState = {
42
  vectorSet: VectorSet | null;
43
  unsubscribeVectorSetEvents: (() => void) | null;
44
};
45

UNCOV
46
const defaultProps: DefaultProps<VectorSourceLayerProps> = {
6✔
47
  id: 'vector-source-layer',
48
  crs: 'EPSG:4326',
49
  format: 'geojson',
50
  debounceTime: 200,
51
  geoJsonLayerProps: {type: 'object', compare: false, value: {}},
52
  onDataLoad: {type: 'function', value: () => {}},
53
  onError: {
54
    type: 'function',
55
    compare: false,
56
    value: (error: Error) => {
57
      // eslint-disable-next-line no-console
58
      console.error(error);
×
59
    }
60
  },
61
  onLoadingStateChange: {type: 'function', value: () => {}}
62
};
63

64
/**
65
 * Internal deck.gl layer that renders a source-backed vector table for the active viewport.
66
 *
67
 * This class is exported for internal repository use and examples, and is not documented
68
 * beyond these TSDoc comments.
69
 */
70
export class VectorSourceLayer extends CompositeLayer<VectorSourceLayerProps> {
71
  /** deck.gl layer name used in debugging output. */
UNCOV
72
  static layerName = 'VectorSourceLayer';
6✔
73

74
  /** Default props shared across source-backed vector layers. */
UNCOV
75
  static defaultProps: DefaultProps = defaultProps;
6✔
76

77
  /** Typed deck.gl state for the owned vector runtime. */
UNCOV
78
  state = null as unknown as VectorSourceLayerState;
4✔
79

80
  /** Returns true when the current vector runtime has accepted data. */
81
  get isLoaded(): boolean {
82
    return Boolean(this.state?.vectorSet?.isLoaded) && super.isLoaded;
×
83
  }
84

85
  /** Lets deck.gl know that viewport changes should trigger updates. */
86
  shouldUpdateState(): boolean {
87
    return true;
×
88
  }
89

90
  /** Initializes state on first render. */
91
  initializeState(): void {
UNCOV
92
    this.state = {
3✔
93
      vectorSet: null,
94
      unsubscribeVectorSetEvents: null
95
    };
96
  }
97

98
  /** Finalizes subscriptions and owned vector state. */
99
  finalizeState(): void {
100
    this._releaseVectorSet();
×
101
  }
102

103
  /** Keeps the owned vector runtime in sync with the current source props and viewport. */
104
  updateState({changeFlags, props, oldProps}: UpdateParameters<this>): void {
UNCOV
105
    const dataChanged = changeFlags.dataChanged;
4✔
106

UNCOV
107
    if (dataChanged) {
4✔
UNCOV
108
      const vectorSet = this._getOrCreateVectorSet(props.data, true);
3✔
UNCOV
109
      vectorSet.setOptions(this._getVectorSetOptions(props));
3✔
UNCOV
110
      void vectorSet.loadMetadata().catch(() => {});
3✔
UNCOV
111
      void this._updateViewport();
3✔
UNCOV
112
      return;
3✔
113
    }
114

UNCOV
115
    if (!this.state.vectorSet) {
1!
116
      return;
×
117
    }
118

UNCOV
119
    if (
1!
120
      !deepEqual(props.layers, oldProps.layers, 1) ||
3✔
121
      props.crs !== oldProps.crs ||
122
      props.format !== oldProps.format
123
    ) {
124
      this.state.vectorSet.setOptions(this._getVectorSetOptions(props));
×
125
      void this._updateViewport();
×
126
      return;
×
127
    }
128

UNCOV
129
    if (props.debounceTime !== oldProps.debounceTime) {
1!
130
      this.state.vectorSet.setOptions(this._getVectorSetOptions(props));
×
131
      void this._updateViewport();
×
132
      return;
×
133
    }
134

UNCOV
135
    if (changeFlags.viewportChanged) {
1!
UNCOV
136
      void this._updateViewport();
1✔
137
    }
138
  }
139

140
  /** Renders the current accepted vector table through `GeoJsonLayer`. */
141
  renderLayers(): Layer | null {
UNCOV
142
    const table = this.state.vectorSet?.data;
2✔
UNCOV
143
    if (!table) {
2!
144
      return null;
×
145
    }
146

UNCOV
147
    if (isArrowTable(table)) {
2✔
UNCOV
148
      throw new Error(
1✔
149
        'VectorSourceLayer does not render Arrow tables directly. Request geojson/binary output or convert Arrow results before rendering.'
150
      );
151
    }
152

UNCOV
153
    const geoJsonData = isGeoJSONTable(table)
1!
154
      ? {
155
          type: table.type,
156
          features: table.features
157
        }
158
      : table;
159

UNCOV
160
    return new GeoJsonLayer({
2✔
161
      ...this.getSubLayerProps({id: 'geojson'}),
162
      ...this.props.geoJsonLayerProps,
163
      data: geoJsonData
164
    }) as unknown as Layer;
165
  }
166

167
  /** Creates or reuses the shared vector runtime for the current source. */
168
  private _getOrCreateVectorSet(vectorSource: VectorSource, sourceChanged: boolean): VectorSet {
UNCOV
169
    if (!this.state.vectorSet || sourceChanged) {
3!
UNCOV
170
      this._releaseVectorSet();
3✔
171

UNCOV
172
      const vectorSet = VectorSet.fromVectorSource(vectorSource, {
3✔
173
        layers: this.props.layers,
174
        crs: this.props.crs,
175
        format: this.props.format,
176
        debounceTime: this.props.debounceTime
177
      });
UNCOV
178
      const unsubscribeVectorSetEvents = vectorSet.subscribe({
3✔
UNCOV
179
        onLoadingStateChange: isLoading => this.props.onLoadingStateChange?.(isLoading),
8✔
UNCOV
180
        onUpdate: () => this.setNeedsUpdate(),
19✔
UNCOV
181
        onDataLoad: table => this.props.onDataLoad?.(table),
3✔
UNCOV
182
        onError: error => this.props.onError?.(error)
1✔
183
      });
184

UNCOV
185
      this.setState({vectorSet, unsubscribeVectorSetEvents});
3✔
UNCOV
186
      return vectorSet;
3✔
187
    }
188

189
    return this.state.vectorSet;
×
190
  }
191

192
  /** Tears down subscriptions and owned vector runtime state. */
193
  private _releaseVectorSet(): void {
UNCOV
194
    this.state?.unsubscribeVectorSetEvents?.();
3✔
UNCOV
195
    this.state?.vectorSet?.finalize();
3✔
UNCOV
196
    this.setState?.({
3✔
197
      vectorSet: null,
198
      unsubscribeVectorSetEvents: null
199
    });
200
  }
201

202
  /** Builds runtime options from the current layer props. */
203
  private _getVectorSetOptions(props: VectorSourceLayerProps) {
UNCOV
204
    return {
3✔
205
      vectorSource: props.data,
206
      layers: props.layers,
207
      crs: props.crs,
208
      format: props.format,
209
      debounceTime: props.debounceTime
210
    };
211
  }
212

213
  /** Requests the current viewport table when a viewport is available. */
214
  private async _updateViewport(): Promise<void> {
UNCOV
215
    const viewport = this.context.viewport;
4✔
UNCOV
216
    const vectorSet = this.state.vectorSet;
4✔
UNCOV
217
    if (!viewport || !vectorSet) {
4!
218
      return;
×
219
    }
220

UNCOV
221
    await vectorSet.updateViewport(viewport);
4✔
222
  }
223
}
224

225
function isGeoJSONTable(data: VectorSourceData): data is GeoJSONTable {
UNCOV
226
  return (data as GeoJSONTable).shape === 'geojson-table';
1✔
227
}
228

229
function isArrowTable(data: VectorSourceData): boolean {
UNCOV
230
  return (data as {shape?: string}).shape === 'arrow-table';
2✔
231
}
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