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

visgl / deck.gl / 23689953389

28 Mar 2026 05:00PM UTC coverage: 79.878% (-11.0%) from 90.907%
23689953389

push

github

web-flow
chore(test): vitest migration (#9969)

3050 of 3709 branches covered (82.23%)

Branch coverage included in aggregate %.

131 of 169 new or added lines in 11 files covered. (77.51%)

171 existing lines in 60 files now uncovered.

13988 of 17621 relevant lines covered (79.38%)

26917.67 hits per line

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

0.0
/modules/core/src/scripting/map-wrapper.ts
1
// deck.gl
2
// SPDX-License-Identifier: MIT
3
// Copyright (c) vis.gl contributors
4

5
import type {MapViewState} from '../views/map-view';
6

7
export type MapProps = {
8
  /** mapboxgl, maplibregl, or compatible library */
9
  mapLib: {
10
    Map: any;
11
    accessToken?: string;
12
  };
13
  container: HTMLElement;
14
  mapStyle?: string;
15
  mapboxApiAccessToken?: string;
16
  /** Directly passed to Map class constructor */
17
  mapOptions?: any;
18
  width: number;
19
  height: number;
20
  viewState: MapViewState;
21
};
22

23
/** A small wrapper that turns mapbox-gl or maplibre-gl Map into a stateless component
24
 */
25
export class MapWrapper {
26
  constructor(props: MapProps) {
27
    this.props = {...props};
×
28
    this._initialize(this.props);
×
29
  }
30

31
  private props: MapProps;
UNCOV
32
  private map: any = null;
×
UNCOV
33
  private width: number = 0;
×
UNCOV
34
  private height: number = 0;
×
35

36
  finalize() {
37
    this.map?.remove();
×
38
    this.map = null;
×
39
  }
40

41
  setProps(props: Partial<MapProps>) {
42
    const oldProps = this.props;
×
43
    const newProps = {...this.props, ...props};
×
44
    this.props = newProps;
×
45

46
    if (!this.map) {
×
47
      return;
×
48
    }
49

50
    const needsRedraw = this._update(oldProps, newProps);
×
51

52
    if (needsRedraw) {
×
53
      this.redraw();
×
54
    }
55
  }
56

57
  // Force redraw the map now. Typically resize() and jumpTo() is reflected in the next
58
  // render cycle, which is managed by Mapbox's animation loop.
59
  // This removes the synchronization issue caused by requestAnimationFrame.
60
  redraw() {
61
    const map = this.map;
×
62
    // map._render will throw error if style does not exist
63
    // https://github.com/mapbox/mapbox-gl-js/blob/fb9fc316da14e99ff4368f3e4faa3888fb43c513
64
    //   /src/ui/map.js#L1834
65
    if (map.style) {
×
66
      // cancel the scheduled update
67
      if (map._frame) {
×
68
        map._frame.cancel();
×
69
        map._frame = null;
×
70
      }
71
      // the order is important - render() may schedule another update
72
      map._render();
×
73
    }
74
  }
75

76
  // External apps can access map this way
77
  getMap() {
78
    return this.map;
×
79
  }
80

81
  private _initialize(props: MapProps) {
82
    const {mapLib, container} = props;
×
83

84
    // Creation only props
85
    mapLib.accessToken = props.mapboxApiAccessToken || '';
×
86

87
    this.map = new props.mapLib.Map({
×
88
      container,
89
      maxZoom: 24,
90
      ...props.mapOptions,
91
      ...viewStateToMapboxProps(props.viewState),
92
      style: props.mapStyle,
93
      interactive: false,
94
      trackResize: false
95
    });
96

97
    // Hijack dimension properties
98
    // This eliminates the timing issue between calling resize() and DOM update
99
    /* eslint-disable accessor-pairs */
100
    Object.defineProperty(container, 'offsetWidth', {get: () => this.width});
×
101
    Object.defineProperty(container, 'clientWidth', {get: () => this.width});
×
102
    Object.defineProperty(container, 'offsetHeight', {
×
103
      get: () => this.height
×
104
    });
105
    Object.defineProperty(container, 'clientHeight', {
×
106
      get: () => this.height
×
107
    });
108
    this.map.resize();
×
109
  }
110

111
  private _update(oldProps: MapProps, newProps: MapProps) {
112
    const styleChanged = oldProps.mapStyle !== newProps.mapStyle;
×
113
    if (styleChanged) {
×
114
      this.map.setStyle(newProps.mapStyle);
×
115
    }
116

117
    const sizeChanged = oldProps.width !== newProps.width || oldProps.height !== newProps.height;
×
118
    if (sizeChanged) {
×
119
      this.width = newProps.width;
×
120
      this.height = newProps.height;
×
121
      this.map.resize();
×
122
    }
123

124
    const oldViewState = oldProps.viewState;
×
125
    const newViewState = newProps.viewState;
×
126
    const viewportChanged =
127
      newViewState.latitude !== oldViewState.latitude ||
×
128
      newViewState.longitude !== oldViewState.longitude ||
129
      newViewState.zoom !== oldViewState.zoom ||
130
      newViewState.pitch !== oldViewState.pitch ||
131
      newViewState.bearing !== oldViewState.bearing;
132
    if (viewportChanged) {
×
133
      this.map.jumpTo(viewStateToMapboxProps(newViewState));
×
134
    }
135
    return sizeChanged || viewportChanged;
×
136
  }
137
}
138

139
function viewStateToMapboxProps(viewState: MapViewState) {
140
  return {
×
141
    center: [viewState.longitude, viewState.latitude],
142
    zoom: viewState.zoom,
143
    bearing: viewState.bearing ?? 0,
144
    pitch: viewState.pitch ?? 0
145
  };
146
}
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