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

geosolutions-it / MapStore2 / 19060241474

04 Nov 2025 06:46AM UTC coverage: 76.943% (+0.02%) from 76.92%
19060241474

Pull #11648

github

web-flow
Merge 763e0cf1e into 19e678788
Pull Request #11648: #11644: Implement dynamic request configurations

32057 of 49801 branches covered (64.37%)

201 of 222 new or added lines in 39 files covered. (90.54%)

4 existing lines in 3 files now uncovered.

39801 of 51728 relevant lines covered (76.94%)

39.94 hits per line

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

79.39
/web/client/components/map/cesium/plugins/GraticuleLayer.js
1
/**
2
 * Copyright 2015, GeoSolutions Sas.
3
 * All rights reserved.
4
 *
5
 * This source code is licensed under the BSD-style license found in the
6
 * LICENSE file in the root directory of this source tree.
7
 */
8

9
import Layers from '../../../../utils/cesium/Layers';
10
import * as Cesium from 'cesium';
11
import isEqual from 'lodash/isEqual';
12

13
/**
14
 * Created by thomas on 27/01/14.
15
 // [source 07APR2015: http://pad.geocento.com/AddOns/Graticule.js]
16
 */
17

18
const Graticule = (function() {
1✔
19

20
    let mins = [
1✔
21
        Cesium.Math.toRadians(0.05),
22
        Cesium.Math.toRadians(0.1),
23
        Cesium.Math.toRadians(0.2),
24
        Cesium.Math.toRadians(0.5),
25
        Cesium.Math.toRadians(1.0),
26
        Cesium.Math.toRadians(2.0),
27
        Cesium.Math.toRadians(5.0),
28
        Cesium.Math.toRadians(10.0)
29
    ];
30

31
    function _(dsc, scene) {
32

33
        let description = dsc || {};
1!
34

35
        this._tilingScheme = description.tilingScheme || new Cesium.GeographicTilingScheme();
1✔
36

37
        this._color = description.color &&
1!
38
            new Cesium.Color(description.color[0], description.color[1], description.color[2], description.color[3]) ||
39
            new Cesium.Color(1.0, 1.0, 1.0, 0.4);
40

41
        this._tileWidth = description.tileWidth || 256;
1!
42
        this._tileHeight = description.tileHeight || 256;
1!
43

44

45
        // default to decimal intervals
46
        this._sexagesimal = description.sexagesimal || false;
1✔
47
        this._numLines = description.numLines || 50;
1!
48

49
        this._scene = scene;
1✔
50
        this._labels = new Cesium.LabelCollection();
1✔
51
        scene.primitives.add(this._labels);
1✔
52
        this._polylines = new Cesium.PolylineCollection();
1✔
53
        scene.primitives.add(this._polylines);
1✔
54
        this._ellipsoid = scene.globe.ellipsoid;
1✔
55

56
        let canvas = document.createElement('canvas');
1✔
57
        canvas.width = 256;
1✔
58
        canvas.height = 256;
1✔
59
        this._canvas = canvas;
1✔
60

61
    }
62

63
    let definePropertyWorks = (function() {
1✔
64
        try {
1✔
65
            return 'x' in Object.defineProperty({}, 'x', {});
1✔
66
        } catch (e) {
67
            return false;
×
68
        }
69
    })();
70

71
    /**
72
     * Defines properties on an object, using Object.defineProperties if available,
73
     * otherwise returns the object unchanged.  This function should be used in
74
     * setup code to prevent errors from completely halting JavaScript execution
75
     * in legacy browsers.
76
     *
77
     * @private
78
     *
79
     * @exports defineProperties
80
     */
81
    let defineProperties = Object.defineProperties;
1✔
82
    if (!definePropertyWorks || !defineProperties) {
1!
83
        defineProperties = function(o) {
×
84
            return o;
×
85
        };
86
    }
87

88
    defineProperties(_.prototype, {
1✔
89
        url: {
90
            get: function() {
91
                return undefined;
×
92
            }
93
        },
94

95
        proxy: {
96
            get: function() {
97
                return undefined;
×
98
            }
99
        },
100

101
        tileWidth: {
102
            get: function() {
103
                return this._tileWidth;
2✔
104
            }
105
        },
106

107
        tileHeight: {
108
            get: function() {
109
                return this._tileHeight;
×
110
            }
111
        },
112

113
        maximumLevel: {
114
            get: function() {
115
                return 18;
2✔
116
            }
117
        },
118

119
        minimumLevel: {
120
            get: function() {
121
                return 0;
4✔
122
            }
123
        },
124
        tilingScheme: {
125
            get: function() {
126
                return this._tilingScheme;
11✔
127
            }
128
        },
129
        rectangle: {
130
            get: function() {
131
                return this._tilingScheme.rectangle;
2✔
132
            }
133
        },
134
        tileDiscardPolicy: {
135
            get: function() {
136
                return undefined;
×
137
            }
138
        },
139
        errorEvent: {
140
            get: function() {
141
                return this._errorEvent;
×
142
            }
143
        },
144
        credit: {
145
            get: function() {
146
                return this._credit;
1✔
147
            }
148
        },
149
        hasAlphaChannel: {
150
            get: function() {
151
                return true;
×
152
            }
153
        }
154
    });
155

156
    _.prototype.makeLabel = function(lng, lat, text, top) {
1✔
157
        this._labels.add({
55✔
158
            position: this._ellipsoid.cartographicToCartesian(new Cesium.Cartographic(lng, lat, 10.0)),
159
            text: text,
160
            font: 'normal',
161
            fillColor: this._color,
162
            outlineColor: this._color,
163
            style: Cesium.LabelStyle.FILL,
164
            pixelOffset: new Cesium.Cartesian2(5, top ? 5 : -5),
55✔
165
            eyeOffset: Cesium.Cartesian3.ZERO,
166
            horizontalOrigin: Cesium.HorizontalOrigin.LEFT,
167
            verticalOrigin: top ? Cesium.VerticalOrigin.BOTTOM : Cesium.VerticalOrigin.TOP,
55✔
168
            scale: 1.0
169
        });
170
    };
171

172
    function gridPrecision(dDeg) {
173
        if (dDeg < 0.01) return 3;
55!
174
        if (dDeg < 0.1) return 2;
55!
175
        if (dDeg < 1) return 1;
55!
176
        return 0;
×
177
    }
178

179
    _.prototype._drawGrid = function(extent) {
1✔
180

181
        if (this._currentExtent && this._currentExtent.equals(extent)) {
1!
182
            return;
×
183
        }
184
        this._currentExtent = extent;
1✔
185

186
        this._polylines.removeAll();
1✔
187
        this._labels.removeAll();
1✔
188

189
        let dLat = 0;
1✔
190
        let dLng = 0;
1✔
191
        // get the nearest to the calculated value
192
        for (let index = 0; index < mins.length && dLat < (extent.north - extent.south) / 10; index++) {
1✔
193
            dLat = mins[index];
8✔
194
        }
195
        for (let index = 0; index < mins.length && dLng < (extent.east - extent.west) / 10; index++) {
1✔
196
            dLng = mins[index];
8✔
197
        }
198

199
        // round iteration limits to the computed grid interval
200
        let minLng = (extent.west < 0 ? Math.ceil(extent.west / dLng) : Math.floor(extent.west / dLng)) * dLng;
1!
201
        let minLat = (extent.south < 0 ? Math.ceil(extent.south / dLat) : Math.floor(extent.south / dLat)) * dLat;
1!
202
        let maxLng = (extent.east < 0 ? Math.ceil(extent.east / dLat) : Math.floor(extent.east / dLat)) * dLat;
1!
203
        let maxLat = (extent.north < 0 ? Math.ceil(extent.north / dLng) : Math.floor(extent.north / dLng)) * dLng;
1!
204

205
        // extend to make sure we cover for non refresh of tiles
206
        minLng = Math.max(minLng - 2 * dLng, -Math.PI);
1✔
207
        maxLng = Math.min(maxLng + 2 * dLng, Math.PI);
1✔
208
        minLat = Math.max(minLat - 2 * dLat, -Math.PI / 2);
1✔
209
        maxLat = Math.min(maxLat + 2 * dLng, Math.PI / 2);
1✔
210

211
        let ellipsoid = this._ellipsoid;
1✔
212
        let granularity = Cesium.Math.toRadians(1);
1✔
213

214
        // labels positions
215
        let latitudeText = minLat + Math.floor((maxLat - minLat) / dLat / 2) * dLat;
1✔
216
        for (let lng = minLng; lng < maxLng; lng += dLng) {
1✔
217
            // draw meridian
218
            let path = [];
37✔
219
            for (let lat = minLat; lat < maxLat; lat += granularity) {
37✔
220
                path.push(new Cesium.Cartographic(lng, lat));
6,660✔
221
            }
222
            path.push(new Cesium.Cartographic(lng, maxLat));
37✔
223
            this._polylines.add({
37✔
224
                positions: ellipsoid.cartographicArrayToCartesianArray(path),
225
                width: 0.75,
226
                material: new Cesium.Material({
227
                    fabric: {
228
                        type: 'Color',
229
                        uniforms: {
230
                            color: this._color
231
                        }
232
                    }
233
                })
234
            });
235
            let degLng = Cesium.Math.toDegrees(lng);
37✔
236
            this.makeLabel(lng, latitudeText, this._sexagesimal ? this._decToSex(degLng) : degLng.toFixed(gridPrecision(dLng)), false);
37!
237
        }
238

239
        // lats
240
        let longitudeText = minLng + Math.floor((maxLng - minLng) / dLng / 2) * dLng;
1✔
241
        for (let lat = minLat; lat < maxLat; lat += dLat) {
1✔
242
            // draw parallels
243
            let path = [];
18✔
244
            for (let lng = minLng; lng < maxLng; lng += granularity) {
18✔
245
                path.push(new Cesium.Cartographic(lng, lat));
6,498✔
246
            }
247
            path.push(new Cesium.Cartographic(maxLng, lat));
18✔
248
            this._polylines.add({
18✔
249
                positions: ellipsoid.cartographicArrayToCartesianArray(path),
250
                width: 1,
251
                material: new Cesium.Material({
252
                    fabric: {
253
                        type: 'Color',
254
                        uniforms: {
255
                            color: this._color
256
                        }
257
                    }
258
                })
259
            });
260
            let degLat = Cesium.Math.toDegrees(lat);
18✔
261
            this.makeLabel(longitudeText, lat, this._sexagesimal ? this._decToSex(degLat) : degLat.toFixed(gridPrecision(dLat)), true);
18!
262
        }
263
    };
264

265
    _.prototype.requestImage = function() {
1✔
266
        if (this._show) {
×
267
            this._drawGrid(this._getExtentView());
×
268
        }
269

270
        return Promise.resolve(this._canvas);
×
271
    };
272

273
    _.prototype.setVisible = function(visible) {
1✔
274
        this._show = visible;
1✔
275
        if (!visible) {
1!
276
            this._polylines.removeAll();
×
277
            this._labels.removeAll();
×
278
        } else {
279
            this._currentExtent = null;
1✔
280
            this._drawGrid(this._getExtentView());
1✔
281
        }
282
    };
283

284
    _.prototype.isVisible = function() {
1✔
285
        return this._show;
×
286
    };
287

288
    _.prototype._decToSex = function(d) {
1✔
289
        let degs = Math.floor(d);
×
290
        let minimums = ((Math.abs(d) - degs) * 60.0).toFixed(2);
×
291
        if (minimums === "60.00") { degs += 1.0; mins = "0.00"; }
×
292
        return [degs, ":", minimums].join('');
×
293
    };
294

295
    _.prototype._getExtentView = function() {
1✔
296
        const camera = this._scene.camera;
1✔
297
        const canvas = this._scene.canvas;
1✔
298
        const corners = [
1✔
299
            camera.pickEllipsoid(new Cesium.Cartesian2(0, 0), this._ellipsoid),
300
            camera.pickEllipsoid(new Cesium.Cartesian2(canvas.width, 0), this._ellipsoid),
301
            camera.pickEllipsoid(new Cesium.Cartesian2(0, canvas.height), this._ellipsoid),
302
            camera.pickEllipsoid(new Cesium.Cartesian2(canvas.width, canvas.height), this._ellipsoid)
303
        ];
304
        for (let index = 0; index < 4; index++) {
1✔
305
            if (corners[index] === undefined) {
1!
306
                return Cesium.Rectangle.MAX_VALUE;
1✔
307
            }
308
        }
309
        return Cesium.Rectangle.fromCartographicArray(this._ellipsoid.cartesianArrayToCartographicArray(corners));
×
310
    };
311

312
    _.prototype.destroy = function() {
1✔
313
        this._show = false;
1✔
314
        if (this._polylines) {
1!
315
            this._scene.primitives.remove(this._polylines);
1✔
316
        }
317
        if (this._labels) {
1!
318
            this._scene.primitives.remove(this._labels);
1✔
319
        }
320
    };
321

322
    return _;
1✔
323

324
})();
325

326
const createLayer = (options, map) => {
1✔
327
    const scene = map.scene;
1✔
328

329
    const grid = new Graticule({
1✔
330
        tileWidth: 512,
331
        tileHeight: 512,
332
        numLines: 10,
333
        ...options
334
    }, scene);
335

336
    if (options.visibility) {
1!
337
        grid.setVisible(true);
1✔
338
    }
339
    return grid;
1✔
340
};
341

342
Layers.registerType('graticule', {
1✔
343
    create: createLayer,
344
    update: (layer, newOptions, oldOptions, map) => {
NEW
345
        if (newOptions.visibility !== oldOptions.visibility || !isEqual(oldOptions.security, newOptions.security)) {
×
346
            layer.setVisible(false); // clear all previous labels and primitive
×
347
            if (newOptions.visibility) {
×
348
                return createLayer(newOptions, map);
×
349
            }
350
        }
351
        return null;
×
352
    }
353
});
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