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

iTowns / itowns / 7166285413

11 Dec 2023 10:44AM UTC coverage: 76.943% (-0.1%) from 77.075%
7166285413

Pull #2128

github

web-flow
Merge 06b44bf2c into ac9cea429
Pull Request #2128: Mapbox style multiple source

4020 of 5962 branches covered (0.0%)

Branch coverage included in aggregate %.

17 of 44 new or added lines in 2 files covered. (38.64%)

14 existing lines in 2 files now uncovered.

7990 of 9647 relevant lines covered (82.82%)

1870.05 hits per line

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

68.31
/src/Source/VectorTilesSource.js
1
import { featureFilter } from '@mapbox/mapbox-gl-style-spec';
1✔
2
import Style from 'Core/Style';
1✔
3
import TMSSource from 'Source/TMSSource';
1✔
4
import URLBuilder from 'Provider/URLBuilder';
1✔
5
import Fetcher from 'Provider/Fetcher';
1✔
6
import urlParser from 'Parser/MapBoxUrlParser';
51✔
7

8
function toTMSUrl(url) {
9
    return url.replace(/\{/g, '${');
6✔
10
}
11

12
function fetchSourceData(source, url) {
NEW
13
    return source.fetcher(url, source.networkOptions)
×
NEW
14
        .then(f => f, err => source.handlingError(err));
×
15
}
16

17
function concatenatedParseData(source, files, out, extent) {
NEW
18
    const collections = [];
×
NEW
19
    return Promise.resolve(files.forEach((file) => {
×
NEW
20
        file.extent = extent;
×
NEW
21
        source.parser(file, { out, in: source }).then((collection) => { collections.push(collection); });
×
22
    })).then(() => {
NEW
UNCOV
23
        const collection = collections[0];
×
NEW
UNCOV
24
        collections.forEach((col) => {
×
NEW
UNCOV
25
            col.features.forEach((feature) => {
×
NEW
UNCOV
26
                collection.features.push(feature);
×
27
            });
28
        });
NEW
UNCOV
29
        return Promise.resolve(collection);
×
30
    });
31
}
32

33
/**
34
 * @classdesc
35
 * VectorTilesSource are object containing informations on how to fetch vector
36
 * tiles resources.
37
 *
38
 * @property {function} filter - function to filter vector tiles layers, the
39
 * parameter function is a layer.
40
 * @property {boolean} [symbolToCircle=false] - If true, all symbols from a tile
41
 * will be considered as circle, and render as circles.
42
 */
43
class VectorTilesSource extends TMSSource {
2✔
44
    /**
45
     * @param {Object} source - An object that can contain all properties of a
46
     * VectorTilesSource and {@link Source}.
47
     * @param {string|Object} source.style - The URL of the JSON style, of the
48
     * JSON style directly.
49
     * @param {string} [source.sprite] - The base URL to load informations about
50
     * the sprite of the style. If this is set, it overrides the `sprite` value
51
     * of the `source.style`. A style's sprite property supplies a URL template
52
     * for loading small images.
53
     * ```js
54
     * {
55
     *      sprite: 'http//:xxxxx/maps/sprites/'
56
     * }
57
     * ```
58
     * A valid sprite source must supply two types of files:
59
     * * An index file, which is a JSON document containing a description of each image contained in the sprite.
60
     * * Image files, which are PNG images containing the sprite data.
61
     *
62
     * For more specification : [the Mapbox sprite Specification](https://docs.mapbox.com/mapbox-gl-js/style-spec/sprite/)
63
     *
64
     * @param {string} [source.url] - The base URL to load the tiles. If no url
65
     * is specified, it reads it from the loaded style. Read [the Mapbox Style
66
     * Specification](https://docs.mapbox.com/mapbox-gl-js/style-spec/sources/)
67
     * for more informations.
68
     * @param {string} [source.accessToken] - Mapbox access token
69
     * @constructor
70
     */
71
    constructor(source) {
9✔
72
        source.format = 'application/x-protobuf;type=mapbox-vector';
9✔
73
        source.crs = 'EPSG:3857';
9✔
74
        source.isInverted = true;
9✔
75
        source.url = source.url || '.';
9✔
76
        super(source);
9✔
77
        const ffilter = source.filter || (() => true);
9✔
78
        this.layers = {};
9✔
79
        this.styles = {};
9✔
80
        let promise;
81
        this.isVectorTileSource = true;
9✔
82

83
        this.accessToken = source.accessToken;
9✔
84

85
        if (source.style) {
9✔
86
            if (typeof source.style == 'string') {
8✔
87
                const styleUrl = urlParser.normalizeStyleURL(source.style, this.accessToken);
1✔
88
                promise = Fetcher.json(styleUrl, this.networkOptions);
1✔
89
            } else {
90
                promise = Promise.resolve(source.style);
7✔
91
            }
92
        } else {
93
            throw new Error('New VectorTilesSource: style is required');
1✔
94
        }
95

96
        this.whenReady = promise.then((style) => {
8✔
97
            this.jsonStyle = style;
8✔
98
            const baseurl = source.sprite || style.sprite;
8✔
99
            if (baseurl) {
8✔
100
                const spriteUrl = urlParser.normalizeSpriteURL(baseurl, '', '.json', this.accessToken);
1✔
101
                return Fetcher.json(spriteUrl, this.networkOptions).then((sprites) => {
1✔
102
                    this.sprites = sprites;
1✔
103
                    const imgUrl = urlParser.normalizeSpriteURL(baseurl, '', '.png', this.accessToken);
1✔
104
                    this.sprites.source = imgUrl;
1✔
105
                    return style;
1✔
106
                });
107
            }
108

109
            return style;
7✔
110
        }).then((style) => {
111
            style.layers.forEach((layer, order) => {
8✔
112
                layer.sourceUid = this.uid;
10✔
113
                if (layer.type === 'background') {
10✔
114
                    this.backgroundLayer = layer;
2✔
115
                } else if (ffilter(layer)) {
8!
116
                    const style = new Style().setFromVectorTileLayer(layer, this.sprites, order, this.symbolToCircle);
8✔
117
                    style.zoom.min = layer.minzoom || 0;
8✔
118
                    style.zoom.max = layer.maxzoom || 24;
8✔
119
                    this.styles[layer.id] = style;
8✔
120

121
                    if (!this.layers[layer['source-layer']]) {
8✔
122
                        this.layers[layer['source-layer']] = [];
4✔
123
                    }
124
                    this.layers[layer['source-layer']].push({
8✔
125
                        id: layer.id,
126
                        order,
127
                        filterExpression: featureFilter(layer.filter),
128
                        zoom: {
129
                            min: layer.minzoom || 0,
13✔
130
                            max: layer.maxzoom || 24,
15✔
131
                        },
132
                    });
133
                }
134
            });
135

136
            if (this.url == '.') {
8✔
137
                const TMSUrlList = Object.values(style.sources).map((source) => {
4✔
138
                    if (source.url) {
6✔
139
                        const urlSource = urlParser.normalizeSourceURL(source.url, this.accessToken);
1✔
140
                        return Fetcher.json(urlSource, this.networkOptions).then((tileJSON) => {
1✔
141
                            if (tileJSON.tiles[0]) {
1!
142
                                return toTMSUrl(tileJSON.tiles[0]);
1✔
143
                            }
144
                        });
145
                    } else if (source.tiles) {
5!
146
                        return Promise.resolve(toTMSUrl(source.tiles[0]));
5✔
147
                    }
NEW
148
                    return Promise.reject();
×
149
                });
150
                return Promise.all(TMSUrlList);
4✔
151
            }
152
            return (Promise.resolve([this.url]));
4✔
153
        }).then((TMSUrlList) => {
154
            this.url = new Set(TMSUrlList);
8✔
155
        });
8✔
156
    }
1✔
157

NEW
158
    urlFromExtent(extent) {
×
NEW
UNCOV
159
        return this.url.map((url) => {
×
NEW
160
            const options = {
×
161
                tileMatrixCallback: this.tileMatrixCallback,
162
                url,
163
            };
NEW
164
            return URLBuilder.xyz(extent, options);
×
165
        });
166
    }
167

168
    onLayerAdded(options) {
×
169
        super.onLayerAdded(options);
×
170
        if (options.out.style) {
×
171
            if (options.out.isFeatureGeometryLayer && options.out.accurate) {
×
172
                console.warn('With VectorTilesSource and FeatureGeometryLayer, the accurate option is always false');
×
173
                options.out.accurate = false;
×
174
            }
175
            const keys = Object.keys(this.styles);
×
176

177
            keys.forEach((k) => { this.styles[k].parent = options.out.style; });
×
178
        }
179
    }
180

NEW
181
    loadData(extent, out) {
×
NEW
182
        const cache = this._featuresCaches[out.crs];
×
NEW
183
        const key = this.requestToKey(extent);
×
184
        // try to get parsed data from cache
NEW
185
        let features = cache.getByArray(key);
×
NEW
186
        if (!features) {
×
187
            // otherwise fetch/parse the data
NEW
UNCOV
188
            features = cache.setByArray(
×
NEW
189
                Promise.all(this.urlFromExtent(extent).map(url => fetchSourceData(this, url)))
×
NEW
UNCOV
190
                    .then(files => concatenatedParseData(this, files, out, extent),
×
NEW
UNCOV
191
                        err => this.handlingError(err)), key);
×
192
            /* istanbul ignore next */
193
            if (this.onParsedFile) {
194
                features.then((feat) => {
195
                    this.onParsedFile(feat);
196
                    console.warn('Source.onParsedFile was deprecated');
197
                    return feat;
198
                });
199
            }
200
        }
NEW
UNCOV
201
        return features;
×
202
    }
1✔
203
}
204

205
export default VectorTilesSource;
1✔
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

© 2025 Coveralls, Inc