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

iTowns / itowns / 11295619330

11 Oct 2024 04:06PM UTC coverage: 86.935% (-0.001%) from 86.936%
11295619330

Pull #2436

github

web-flow
Merge b6e923f75 into cfb9d0f51
Pull Request #2436: refacto: migrate Crs to typescript

2804 of 3720 branches covered (75.38%)

Branch coverage included in aggregate %.

182 of 187 new or added lines in 20 files covered. (97.33%)

69 existing lines in 11 files now uncovered.

24377 of 27546 relevant lines covered (88.5%)

1022.7 hits per line

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

92.68
/src/Source/WFSSource.js
1
import Source from 'Source/Source';
1✔
2
import URLBuilder from 'Provider/URLBuilder';
1✔
3
import CRS from 'Core/Geographic/Crs';
1✔
4
import Extent from 'Core/Geographic/Extent';
1✔
5

1✔
6
const _extent = new Extent('EPSG:4326', [0, 0, 0, 0]);
1✔
7

1✔
8
/**
1✔
9
 * An object defining the source of resources to get from a
1✔
10
 * [WFS](http://www.opengeospatial.org/standards/wfs) server. It inherits
1✔
11
 * from {@link Source}.
1✔
12
 *
1✔
13
 * @extends Source
1✔
14
 *
1✔
15
 * @property {boolean} isWFSSource - Used to checkout whether this source is a
1✔
16
 * WFSSource. Default is true. You should not change this, as it is used
1✔
17
 * internally for optimisation.
1✔
18
 * @property {string} typeName - The name of the feature to get, used in the
1✔
19
 * generation of the url.
1✔
20
 * @property {string} version - The version of the WFS server to request on.
1✔
21
 * Default value is '2.0.2'.
1✔
22
 * @property {Object} zoom - Object containing the minimum and maximum values of
1✔
23
 * the level, to zoom in the source.
1✔
24
 * @property {number} zoom.min - The minimum level of the source. Default value
1✔
25
 * is 0.
1✔
26
 * @property {number} zoom.max - The maximum level of the source. Default value
1✔
27
 * is 21.
1✔
28
 * @property {string} bboxDigits - The bbox digits precision used in URL
1✔
29
 * @property {Object} vendorSpecific - An object containing vendor specific
1✔
30
 * parameters. See for example a [list of these parameters for GeoServer]{@link
1✔
31
 * https://docs.geoserver.org/latest/en/user/services/wfs/vendor.html}. This
1✔
32
 * object is read simply with the `key` being the name of the parameter and
1✔
33
 * `value` being the value of the parameter. If used, this property should be
1✔
34
 * set in the constructor parameters.
1✔
35
 *
1✔
36
 * @example
1✔
37
 * // Add color layer with WFS source
1✔
38
 * // Create the source
1✔
39
 * const wfsSource = new itowns.WFSSource({
1✔
40
 *     url: 'https://data.geopf.fr/wfs/ows?',
1✔
41
 *     version: '2.0.0',
1✔
42
 *     typeName: 'BDTOPO_BDD_WLD_WGS84G:bati_remarquable',
1✔
43
 *     crs: 'EPSG:4326',
1✔
44
 *     extent: {
1✔
45
 *         west: 4.568,
1✔
46
 *         east: 5.18,
1✔
47
 *         south: 45.437,
1✔
48
 *         north: 46.03,
1✔
49
 *     },
1✔
50
 *     zoom: { min: 14, max: 14 },
1✔
51
 *     format: 'application/json',
1✔
52
 * });
1✔
53
 *
1✔
54
 * // Create the layer
1✔
55
 * const colorlayer = new itowns.ColorLayer('color_build', {
1✔
56
 *     style: {
1✔
57
 *         fill: 'red',
1✔
58
 *         fillOpacity: 0.5,
1✔
59
 *         stroke: 'white',
1✔
60
 *     },
1✔
61
 *     source: wfsSource,
1✔
62
 * });
1✔
63
 *
1✔
64
 * // Add the layer
1✔
65
 * view.addLayer(colorlayer);
1✔
66
 *
1✔
67
 * @example
1✔
68
 * // Add geometry layer with WFS source
1✔
69
 * // Create the source
1✔
70
 * const wfsSource = new itowns.WFSSource({
1✔
71
 *     url: 'https://data.geopf.fr/wfs/ows?',
1✔
72
 *     version: '2.0.0',
1✔
73
 *     typeName: 'BDTOPO_BDD_WLD_WGS84G:bati_remarquable',
1✔
74
 *     crs: 'EPSG:4326',
1✔
75
 *     extent: {
1✔
76
 *         west: 4.568,
1✔
77
 *         east: 5.18,
1✔
78
 *         south: 45.437,
1✔
79
 *         north: 46.03,
1✔
80
 *     },
1✔
81
 *     zoom: { min: 14, max: 14 },
1✔
82
 *     format: 'application/json',
1✔
83
 * });
1✔
84
 *
1✔
85
 * // Create the layer
1✔
86
 * const geometryLayer = new itowns.FeatureGeometryLayer('mesh_build', {
1✔
87
 *     style: {
1✔
88
 *         fill: {
1✔
89
 *             color: new itowns.THREE.Color(0xffcc00),
1✔
90
 *             base_altitude: (p) => p.altitude,
1✔
91
 *             extrusion_height: (p) => p.height,
1✔
92
 *         }
1✔
93
 *     },
1✔
94
 *     source: wfsSource,
1✔
95
 *     zoom: { min: 14 },
1✔
96
 * };
1✔
97
 *
1✔
98
 * // Add the layer
1✔
99
 * view.addLayer(geometryLayer);
1✔
100
 */
1✔
101
class WFSSource extends Source {
1✔
102
    /**
1✔
103
     * @param {Object} source - An object that can contain all properties of a
1✔
104
     * WFSSource and {@link Source}. `url`, `typeName` and `crs` are
1✔
105
     * mandatory.
1✔
106
     */
1✔
107
    constructor(source) {
1✔
108
        if (source.projection) {
7!
109
            console.warn('WFSSource projection parameter is deprecated, use crs instead.');
×
110
            source.crs = source.crs || source.projection;
×
UNCOV
111
        }
×
112
        if (!source.typeName) {
7✔
113
            throw new Error('source.typeName is required in wfs source.');
1✔
114
        }
1✔
115

6✔
116
        if (!source.crs) {
7✔
117
            throw new Error('source.crs is required in wfs source');
1✔
118
        }
1✔
119

5✔
120
        source.format = source.format || 'application/json';
7✔
121

7✔
122
        super(source);
7✔
123

7✔
124
        this.isWFSSource = true;
7✔
125
        this.typeName = source.typeName;
7✔
126
        this.version = source.version || '2.0.2';
7✔
127
        this.bboxDigits = source.bboxDigits;
7✔
128

7✔
129
        // Add ? at the end of the url if it is not already in the given URL
7✔
130
        if (!this.url.endsWith('?')) {
7✔
131
            this.url = `${this.url}?`;
5✔
132
        }
5✔
133
        this.url = `${source.url
5✔
134
        }SERVICE=WFS&REQUEST=GetFeature&typeName=${this.typeName
5✔
135
        }&VERSION=${this.version
5✔
136
        }&SRSNAME=${this.crs
5✔
137
        }&outputFormat=${this.format
5✔
138
        }&BBOX=%bbox,${this.crs}`;
5✔
139

5✔
140
        this.zoom = { min: 0, max: Infinity };
5✔
141

5✔
142
        this.vendorSpecific = source.vendorSpecific;
5✔
143
        for (const name in this.vendorSpecific) {
7✔
144
            if (Object.prototype.hasOwnProperty.call(this.vendorSpecific, name)) {
9✔
145
                this.url = `${this.url}&${name}=${this.vendorSpecific[name]}`;
9✔
146
            }
9✔
147
        }
9✔
148
    }
3✔
149

1✔
150
    handlingError(err) {
1✔
151
        if (err.response && err.response.status == 400) {
1!
152
            return err.response.text().then((text) => {
×
153
                const getCapUrl = `${this.url}SERVICE=WFS&REQUEST=GetCapabilities&VERSION=${this.version}`;
×
154
                const xml = new DOMParser().parseFromString(text, 'application/xml');
×
155
                const errorElem = xml.querySelector('Exception');
×
156
                const errorCode = errorElem.getAttribute('exceptionCode');
×
157
                const errorMessage = errorElem.querySelector('ExceptionText').textContent;
×
158
                console.error(`Source ${this.typeName}: bad request when fetching data. Server says: "${errorCode}: ${errorMessage}". \nReviewing ${getCapUrl} may help.`, err);
×
159
            });
×
UNCOV
160
        }
×
161
        return super.handlingError(err);
1✔
162
    }
1✔
163

1✔
164
    requestToKey(extent) {
1✔
165
        if (CRS.isTms(extent.crs)) {
8✔
166
            return super.requestToKey(extent);
7✔
167
        } else {
8✔
168
            return [extent.zoom, extent.south, extent.west];
1✔
169
        }
1✔
170
    }
8✔
171

1✔
172
    urlFromExtent(extentOrTile) {
1✔
173
        const extent = extentOrTile.isExtent ?
4✔
174
            extentOrTile.as(this.crs, _extent) :
4✔
175
            extentOrTile.toExtent(this.crs, _extent);
4✔
176
        return URLBuilder.bbox(extent, this);
4✔
177
    }
4✔
178

1✔
179
    extentInsideLimit(extent) {
1✔
180
        return this.extent.intersectsExtent(extent);
4✔
181
    }
4✔
182
}
1✔
183

1✔
184
export default WFSSource;
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

© 2026 Coveralls, Inc