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

iTowns / itowns / 10902507646

17 Sep 2024 11:56AM UTC coverage: 86.931% (-0.03%) from 86.964%
10902507646

push

github

Desplandis
release v2.44.2

2791 of 3694 branches covered (75.55%)

Branch coverage included in aggregate %.

24241 of 27402 relevant lines covered (88.46%)

1027.5 hits per line

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

96.6
/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

1✔
13
/** @private */
1✔
14
export const supportedParsers = new Map([
1✔
15
    ['application/geo+json', GeoJsonParser.parse],
1✔
16
    ['application/json', GeoJsonParser.parse],
1✔
17
    ['application/kml', KMLParser.parse],
1✔
18
    ['application/gpx', GpxParser.parse],
1✔
19
    ['application/x-protobuf;type=mapbox-vector', VectorTileParser.parse],
1✔
20
    ['application/gtx', GTXParser.parse],
1✔
21
    ['application/isg', ISGParser.parse],
1✔
22
    ['application/gdf', GDFParser.parse],
1✔
23
]);
1✔
24

1✔
25
const noCache = { getByArray: () => {}, setByArray: a => a, clear: () => {} };
1✔
26

1✔
27
/**
1✔
28
 * @property {string} crs - data crs projection.
1✔
29
 * @property {boolean} isInverted - This option is to be set to the
1✔
30
 * correct value, true or false (default being false), if the computation of
1✔
31
 * the coordinates needs to be inverted to same scheme as OSM, Google Maps
1✔
32
 * or other system. See [this link](
1✔
33
 * https://alastaira.wordpress.com/2011/07/06/converting-tms-tile-coordinates-to-googlebingosm-tile-coordinates)
1✔
34
 * for more informations.
1✔
35
 *
1✔
36
 */
1✔
37
class InformationsData {
1✔
38
    constructor(options) {
1✔
39
        /* istanbul ignore next */
128✔
40
        if (options.projection) {
128!
41
            console.warn('Source projection parameter is deprecated, use crs instead.');
×
42
            options.crs = options.crs || options.projection;
×
43
        }
×
44
        if (options.crs) {
128✔
45
            CRS.isValid(options.crs);
44✔
46
        }
44✔
47
        this.crs = options.crs;
128✔
48
    }
128✔
49
}
1✔
50
/**
1✔
51
 * This interface describes parsing options.
1✔
52
 * @typedef {Object} ParsingOptions
1✔
53
 * @property {Source} in - data informations contained in the file.
1✔
54
 * @property {FeatureBuildingOptions|Layer} out - options indicates how the features should be built.
1✔
55
 */
1✔
56

1✔
57
let uid = 0;
1✔
58

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

128✔
112
        if (!source.url) {
128✔
113
            throw new Error('New Source: url is required');
2✔
114
        }
2✔
115

126✔
116
        this.uid = uid++;
126✔
117

126✔
118
        this.url = source.url;
126✔
119
        this.format = source.format;
126✔
120
        this.fetcher = source.fetcher || Fetcher.get(source.format);
128✔
121
        this.parser = source.parser || supportedParsers.get(source.format) || ((d, opt) => { d.extent = opt.extent; return d; });
128✔
122
        this.isVectorSource = (source.parser || supportedParsers.get(source.format)) != undefined;
128✔
123
        this.networkOptions = source.networkOptions || { crossOrigin: 'anonymous' };
128✔
124
        this.attribution = source.attribution;
128✔
125
        /** @type {Promise<any>} */
128✔
126
        this.whenReady = Promise.resolve();
128✔
127
        this._featuresCaches = {};
128✔
128
        if (source.extent && !(source.extent.isExtent)) {
128✔
129
            this.extent = new Extent(this.crs, source.extent);
3✔
130
        } else {
128✔
131
            this.extent = source.extent;
123✔
132
        }
123✔
133
    }
126✔
134

1✔
135
    handlingError(err) {
1✔
136
        throw new Error(err);
2✔
137
    }
2✔
138

1✔
139
    /**
1✔
140
     * Generates an url from an extent. This url is a link to fetch the
1✔
141
     * resources inside the extent.
1✔
142
     *
1✔
143
     * @param {Extent} extent - Extent to convert in url.
1✔
144

1✔
145
     * @return {string} The URL constructed from the extent.
1✔
146
     */
1✔
147
    // eslint-disable-next-line
1✔
148
    urlFromExtent(extent) {
1✔
149
        throw new Error('In extended Source, you have to implement the method urlFromExtent!');
1✔
150
    }
1✔
151

1✔
152
    requestToKey(extent) {
1✔
153
        return [extent.zoom, extent.row, extent.col];
28✔
154
    }
28✔
155

1✔
156
    /**
1✔
157
     * Load  data from cache or Fetch/Parse data.
1✔
158
     * The loaded data is a Feature or Texture.
1✔
159
     *
1✔
160
     * @param      {Extent}  extent   extent requested parsed data.
1✔
161
     * @param      {FeatureBuildingOptions|Layer}  out     The feature returned options
1✔
162
     * @return     {FeatureCollection|Texture}  The parsed data.
1✔
163
     */
1✔
164
    loadData(extent, out) {
1✔
165
        const cache = this._featuresCaches[out.crs];
8✔
166
        const key = this.requestToKey(extent);
8✔
167
        // try to get parsed data from cache
8✔
168
        let features = cache.getByArray(key);
8✔
169
        if (!features) {
8✔
170
            // otherwise fetch/parse the data
8✔
171
            features = cache.setByArray(
8✔
172
                this.fetcher(this.urlFromExtent(extent), this.networkOptions)
8✔
173
                    .then(file => this.parser(file, { out, in: this, extent }))
8✔
174
                    .catch(err => this.handlingError(err)),
8✔
175
                key);
8✔
176

8✔
177
            /* istanbul ignore next */
8✔
178
            if (this.onParsedFile) {
8✔
179
                features.then((feat) => {
3✔
180
                    this.onParsedFile(feat);
3✔
181
                    console.warn('Source.onParsedFile was deprecated');
3✔
182
                    return feat;
3✔
183
                });
3✔
184
            }
3✔
185
        }
8✔
186
        return features;
8✔
187
    }
8✔
188

1✔
189
    /**
1✔
190
     * Called when layer added.
1✔
191
     *
1✔
192
     * @param {object} options
1✔
193
     */
1✔
194
    onLayerAdded(options) {
1✔
195
        // Added new cache by crs
91✔
196
        if (!this._featuresCaches[options.out.crs]) {
91✔
197
            // Cache feature only if it's vector data, the feature are cached in source.
83✔
198
            // It's not necessary to cache raster in Source,
83✔
199
            // because it's already cached on layer.
83✔
200
            this._featuresCaches[options.out.crs] = this.isVectorSource ? new Cache() : noCache;
83✔
201
        }
83✔
202
    }
91✔
203

1✔
204
    /**
1✔
205
     * Called when layer removed.
1✔
206
     *
1✔
207
     * @param {options}  [options={}] options
1✔
208
     */
1✔
209
    onLayerRemoved(options = {}) {
1!
210
        // delete unused cache
2✔
211
        const unusedCache = this._featuresCaches[options.unusedCrs];
2✔
212
        if (unusedCache) {
2!
213
            unusedCache.clear();
×
214
            delete this._featuresCaches[options.unusedCrs];
×
215
        }
×
216
    }
2✔
217

1✔
218
    /**
1✔
219
     * Tests if an extent is inside the source limits.
1✔
220
     *
1✔
221
     * @param {Extent} extent - Extent to test.
1✔
222

1✔
223
     * @return {boolean} True if the extent is inside the limit, false otherwise.
1✔
224
     */
1✔
225
    // eslint-disable-next-line
1✔
226
    extentInsideLimit(extent) {
1✔
227
        throw new Error('In extented Source, you have to implement the method extentInsideLimit!');
1✔
228
    }
1✔
229
}
1✔
230

1✔
231
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