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

iTowns / itowns / 5390187276

pending completion
5390187276

push

github

gchoqueux
fix(CRS): more robust parameter tests

3402 of 5132 branches covered (66.29%)

Branch coverage included in aggregate %.

12 of 12 new or added lines in 1 file covered. (100.0%)

7377 of 9030 relevant lines covered (81.69%)

1467.12 hits per line

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

92.39
/src/Source/Source.js
1
import Extent from 'Core/Geographic/Extent';
1✔
2
import GeoJsonParser from 'Parser/GeoJsonParser';
1✔
3
import KMLParser from 'Parser/KMLParser';
1✔
4
import GDFParser from 'Parser/GDFParser';
1✔
5
import GpxParser from 'Parser/GpxParser';
1✔
6
import GTXParser from 'Parser/GTXParser';
1✔
7
import ISGParser from 'Parser/ISGParser';
1✔
8
import VectorTileParser from 'Parser/VectorTileParser';
1✔
9
import Fetcher from 'Provider/Fetcher';
1✔
10
import Cache from 'Core/Scheduler/Cache';
1✔
11
import CRS from 'Core/Geographic/Crs';
1✔
12

13
export const supportedFetchers = new Map([
1✔
14
    ['image/x-bil;bits=32', Fetcher.textureFloat],
15
    ['geojson', Fetcher.json],
16
    ['application/json', Fetcher.json],
17
    ['application/kml', Fetcher.xml],
18
    ['application/gpx', Fetcher.xml],
19
    ['application/x-protobuf;type=mapbox-vector', Fetcher.arrayBuffer],
20
    ['application/gtx', Fetcher.arrayBuffer],
21
    ['application/isg', Fetcher.text],
22
    ['application/gdf', Fetcher.text],
23
]);
24

25
export const supportedParsers = new Map([
1✔
26
    ['geojson', GeoJsonParser.parse],
27
    ['application/json', GeoJsonParser.parse],
28
    ['application/kml', KMLParser.parse],
29
    ['application/gpx', GpxParser.parse],
30
    ['application/x-protobuf;type=mapbox-vector', VectorTileParser.parse],
31
    ['application/gtx', GTXParser.parse],
32
    ['application/isg', ISGParser.parse],
33
    ['application/gdf', GDFParser.parse],
34
]);
35

36
const noCache = { getByArray: () => {}, setByArray: a => a, clear: () => {} };
9✔
37

38
/**
39
 * @property {string} crs - data crs projection.
40
 * @property {boolean} isInverted - This option is to be set to the
41
 * correct value, true or false (default being false), if the computation of
42
 * the coordinates needs to be inverted to same scheme as OSM, Google Maps
43
 * or other system. See [this link]{@link
44
 * https://alastaira.wordpress.com/2011/07/06/converting-tms-tile-coordinates-to-googlebingosm-tile-coordinates}
45
 * for more informations.
46
 *
47
 */
48
class InformationsData {
49
    constructor(options) {
116✔
50
        /* istanbul ignore next */
51
        if (options.projection) {
52
            console.warn('Source projection parameter is deprecated, use crs instead.');
53
            options.crs = options.crs || options.projection;
54
        }
55
        if (options.crs) {
116✔
56
            CRS.isValid(options.crs);
43✔
57
        }
58
        this.crs = options.crs;
116✔
59
    }
60
}
61
/**
62
 * This class describes parsing options.
63
 * @property {InformationsData|Source} in - data informations contained in the file.
64
 * @property {FeatureBuildingOptions|Layer} out - options indicates how the features should be built.
65
 */
66
// eslint-disable-next-line
67
class /* istanbul ignore next */ ParsingOptions {}
68

69
function fetchSourceData(source, extent) {
70
    const url = source.urlFromExtent(extent);
12✔
71

72
    return source.fetcher(url, source.networkOptions).then((f) => {
12✔
73
        f.extent = extent;
12✔
74
        return f;
12✔
75
    }, err => source.handlingError(err));
×
76
}
77

78
let uid = 0;
1✔
79

80
/**
81
 * @classdesc
82
 * Sources are object containing informations on how to fetch resources, from a
83
 * set source.
84
 *
85
 * To extend a Source, it is necessary to implement two functions:
86
 * `urlFromExtent` and `extentInsideLimit`.
87
 *
88
 * @property {boolean} isSource - Used to checkout whether this source is a
89
 * Source. Default is true. You should not change this, as it is used internally
90
 * for optimisation.
91
 * @property {number} uid - Unique uid mainly used to store data linked to this
92
 * source into Cache.
93
 * @property {string} url - The url of the resources that are fetched.
94
 * @property {string} format - The format of the resources that are fetched.
95
 * @property {function} fetcher - The method used to fetch the resources from
96
 * the source. iTowns provides some methods in {@link Fetcher}, but it can be
97
 * specified a custom one. This method should return a `Promise` containing the
98
 * fetched resource. If this property is set, it overrides the chosen fetcher
99
 * method with `format`.
100
 * @property {Object} networkOptions - Fetch options (passed directly to
101
 * `fetch()`), see [the syntax for more information]{@link
102
 * https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Syntax}.
103
 * By default, set to `{ crossOrigin: 'anonymous' }`.
104
 * @property {string} crs - The crs projection of the resources.
105
 * @property {string} attribution - The intellectual property rights for the
106
 * resources.
107
 * @property {Extent} extent - The extent of the resources.
108
 * @property {function} parser - The method used to parse the resources attached
109
 * to the layer. iTowns provides some parsers, visible in the `Parser/` folder.
110
 * If the method is custom, it should return a `Promise` containing the parsed
111
 * resource. If this property is set, it overrides the default selected parser
112
 * method with `source.format`. If `source.format` is also empty, no parsing
113
 * action is done.
114
 * <br><br>
115
 * When calling this method, two parameters are passed:
116
 * <ul>
117
 *  <li>the fetched data, i.e. the data to parse</li>
118
 *  <li>an {@link ParsingOptions}  containing severals properties, set when this method is
119
 *  called: it is specific to each call, so the value of each property can vary
120
 *  depending on the current fetched tile for example</li>
121
 * </ul>
122
 */
123
class Source extends InformationsData {
124
    /**
125
     * @param {Object} source - An object that can contain all properties of a
126
     * Source. Only the `url` property is mandatory.
127
     *
128
     * @constructor
129
     * @extends InformationsData
130
     */
131
    constructor(source) {
230✔
132
        super(source);
116✔
133
        this.isSource = true;
116✔
134

135
        if (!source.url) {
116✔
136
            throw new Error('New Source: url is required');
2✔
137
        }
138

139
        this.uid = uid++;
114✔
140

141
        this.url = source.url;
114✔
142
        this.format = source.format;
114✔
143
        this.fetcher = source.fetcher || supportedFetchers.get(source.format) || Fetcher.texture;
114✔
144
        this.parser = source.parser || supportedParsers.get(source.format) || (d => d);
114✔
145
        this.isVectorSource = (source.parser || supportedParsers.get(source.format)) != undefined;
114✔
146
        this.networkOptions = source.networkOptions || { crossOrigin: 'anonymous' };
114✔
147
        this.attribution = source.attribution;
114✔
148
        this.whenReady = Promise.resolve();
114✔
149
        this._featuresCaches = {};
114✔
150
        if (source.extent && !(source.extent.isExtent)) {
114✔
151
            this.extent = new Extent(this.crs, source.extent);
3✔
152
        } else {
153
            this.extent = source.extent;
111✔
154
        }
155
    }
156

157
    handlingError(err) {
158
        throw new Error(err);
1✔
159
    }
160

161
    /**
162
     * Generates an url from an extent. This url is a link to fetch the
163
     * resources inside the extent.
164
     *
165
     * @param {Extent} extent - Extent to convert in url.
166

167
     * @return {string} The URL constructed from the extent.
168
     */
169
    // eslint-disable-next-line
170
    urlFromExtent(extent) {
171
        throw new Error('In extended Source, you have to implement the method urlFromExtent!');
1✔
172
    }
173

174
    requestToKey(extent) {
175
        return [extent.zoom, extent.row, extent.col];
27✔
176
    }
177

178
    /**
179
     * Load  data from cache or Fetch/Parse data.
180
     * The loaded data is a Feature or Texture.
181
     *
182
     * @param      {Extent}  extent   extent requested parsed data.
183
     * @param      {FeatureBuildingOptions|Layer}  out     The feature returned options
184
     * @return     {FeatureCollection|Texture}  The parsed data.
185
     */
186
    loadData(extent, out) {
12✔
187
        const cache = this._featuresCaches[out.crs];
12✔
188
        const key = this.requestToKey(extent);
12✔
189
        // try to get parsed data from cache
190
        let features = cache.getByArray(key);
12✔
191
        if (!features) {
12!
192
            // otherwise fetch/parse the data
193
            features = cache.setByArray(fetchSourceData(this, extent).then(file => this.parser(file, { out, in: this }),
12✔
194
                err => this.handlingError(err)), key);
×
195
            /* istanbul ignore next */
196
            if (this.onParsedFile) {
197
                features.then((feat) => {
198
                    this.onParsedFile(feat);
199
                    console.warn('Source.onParsedFile was deprecated');
200
                    return feat;
201
                });
202
            }
203
        }
204
        return features;
12✔
205
    }
206

207
    /**
208
     * Called when layer added.
209
     *
210
     * @param {object} options
211
     */
212
    onLayerAdded(options) {
213
        // Added new cache by crs
214
        if (!this._featuresCaches[options.out.crs]) {
80✔
215
            // Cache feature only if it's vector data, the feature are cached in source.
216
            // It's not necessary to cache raster in Source,
217
            // because it's already cached on layer.
218
            this._featuresCaches[options.out.crs] = this.isVectorSource ? new Cache() : noCache;
73✔
219
        }
220
    }
221

222
    /**
223
     * Called when layer removed.
224
     *
225
     * @param {options}  [options={}] options
226
     */
227
    onLayerRemoved(options = {}) {
2!
228
        // delete unused cache
229
        const unusedCache = this._featuresCaches[options.unusedCrs];
2✔
230
        if (unusedCache) {
2!
231
            unusedCache.clear();
×
232
            delete this._featuresCaches[options.unusedCrs];
×
233
        }
234
    }
235

236
    /**
237
     * Tests if an extent is inside the source limits.
238
     *
239
     * @param {Extent} extent - Extent to test.
240

241
     * @return {boolean} True if the extent is inside the limit, false otherwise.
242
     */
243
    // eslint-disable-next-line
244
    extentInsideLimit(extent) {
245
        throw new Error('In extented Source, you have to implement the method extentInsideLimit!');
1✔
246
    }
247
}
248

249
export default Source;
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