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

geosolutions-it / MapStore2 / 14217089396

02 Apr 2025 10:11AM UTC coverage: 92.673% (+15.7%) from 76.984%
14217089396

push

github

web-flow
Fix #10819 Manager menu is merged into Login/user menu and Manager menu is now deprecated  (#10963)

245 of 385 branches covered (63.64%)

66 of 77 new or added lines in 3 files covered. (85.71%)

18 existing lines in 5 files now uncovered.

2011 of 2170 relevant lines covered (92.67%)

825.05 hits per line

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

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

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

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

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

30
    function _(dsc, scene) {
31

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

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

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

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

43
        this._ready = true;
1✔
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
        ready: {
145
            get: function() {
146
                return this._ready;
×
147
            }
148
        },
149
        credit: {
150
            get: function() {
151
                return this._credit;
1✔
152
            }
153
        },
154
        hasAlphaChannel: {
155
            get: function() {
156
                return true;
×
157
            }
158
        }
159
    });
160

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

177
    function gridPrecision(dDeg) {
178
        if (dDeg < 0.01) return 3;
55!
179
        if (dDeg < 0.1) return 2;
55!
180
        if (dDeg < 1) return 1;
55!
181
        return 0;
×
182
    }
183

184
    _.prototype._drawGrid = function(extent) {
1✔
185

186
        if (this._currentExtent && this._currentExtent.equals(extent)) {
1!
UNCOV
187
            return;
×
188
        }
189
        this._currentExtent = extent;
1✔
190

191
        this._polylines.removeAll();
1✔
192
        this._labels.removeAll();
1✔
193

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

204
        // round iteration limits to the computed grid interval
205
        let minLng = (extent.west < 0 ? Math.ceil(extent.west / dLng) : Math.floor(extent.west / dLng)) * dLng;
1!
206
        let minLat = (extent.south < 0 ? Math.ceil(extent.south / dLat) : Math.floor(extent.south / dLat)) * dLat;
1!
207
        let maxLng = (extent.east < 0 ? Math.ceil(extent.east / dLat) : Math.floor(extent.east / dLat)) * dLat;
1!
208
        let maxLat = (extent.north < 0 ? Math.ceil(extent.north / dLng) : Math.floor(extent.north / dLng)) * dLng;
1!
209

210
        // extend to make sure we cover for non refresh of tiles
211
        minLng = Math.max(minLng - 2 * dLng, -Math.PI);
1✔
212
        maxLng = Math.min(maxLng + 2 * dLng, Math.PI);
1✔
213
        minLat = Math.max(minLat - 2 * dLat, -Math.PI / 2);
1✔
214
        maxLat = Math.min(maxLat + 2 * dLng, Math.PI / 2);
1✔
215

216
        let ellipsoid = this._ellipsoid;
1✔
217
        let granularity = Cesium.Math.toRadians(1);
1✔
218

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

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

270
    _.prototype.requestImage = function() {
1✔
UNCOV
271
        if (this._show) {
×
UNCOV
272
            this._drawGrid(this._getExtentView());
×
273
        }
274

UNCOV
275
        return Promise.resolve(this._canvas);
×
276
    };
277

278
    _.prototype.setVisible = function(visible) {
1✔
279
        this._show = visible;
1✔
280
        if (!visible) {
1!
281
            this._polylines.removeAll();
×
282
            this._labels.removeAll();
×
283
        } else {
284
            this._currentExtent = null;
1✔
285
            this._drawGrid(this._getExtentView());
1✔
286
        }
287
    };
288

289
    _.prototype.isVisible = function() {
1✔
290
        return this._show;
×
291
    };
292

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

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

317
    _.prototype.destroy = function() {
1✔
318
        this._show = false;
1✔
319
        if (this._polylines) {
1!
320
            this._scene.primitives.remove(this._polylines);
1✔
321
        }
322
        if (this._labels) {
1!
323
            this._scene.primitives.remove(this._labels);
1✔
324
        }
325
    };
326

327
    return _;
1✔
328

329
})();
330

331
const createLayer = (options, map) => {
1✔
332
    const scene = map.scene;
1✔
333

334
    const grid = new Graticule({
1✔
335
        tileWidth: 512,
336
        tileHeight: 512,
337
        numLines: 10,
338
        ...options
339
    }, scene);
340

341
    if (options.visibility) {
1!
342
        grid.setVisible(true);
1✔
343
    }
344
    return grid;
1✔
345
};
346

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