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

geographika / cpsi-mapview / 12356785512

16 Dec 2024 04:17PM UTC coverage: 26.211% (+2.1%) from 24.092%
12356785512

push

github

geographika
Disable SSL

487 of 2328 branches covered (20.92%)

Branch coverage included in aggregate %.

1445 of 5043 relevant lines covered (28.65%)

1.16 hits per line

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

36.12
/app/controller/button/SpatialQueryButtonController.js
1
/**
2
* This class is the controller for the button 'SpatialQueryButton'
3
 */
4
Ext.define('CpsiMapview.controller.button.SpatialQueryButtonController', {
1✔
5
    extend: 'Ext.app.ViewController',
6

7
    requires: ['BasiGX.util.Layer'],
8

9
    alias: 'controller.cmv_spatial_query_btn',
10

11
    /**
12
     * The {ol.interaction.Draw} used to draw the geometry used in the spatial
13
     * query
14
     * @property{ol.interaction.Draw}
15
     */
16
    drawQueryInteraction: null,
17

18
    /**
19
     * The {ol.interaction.Modify} used to modify the geometry used in the spatial
20
     * query
21
     * @property{ol.interaction.Modify}
22
     */
23
    modifiyQueryInteraction: null,
24

25
    /**
26
     * The {ol.interaction.Snap} used to snap to the points of the geometry used
27
     * in the spatial query
28
     * @property{ol.interaction.Snap}
29
     */
30
    snapQueryInteraction: null,
31

32
    /**
33
     * The layer that contains the geometry used in the spatial query, if
34
     * displayPermanently is set to true
35
     * @property{ol.layer.Vector}
36
     */
37
    permanentLayer: null,
38

39
    /**
40
     * Flag indicating if the layer was created directly by the tool or
41
     * is an existing layer passed as a configuration option
42
     * @property {boolean}
43
     */
44
    permanentLayerCreatedByTool: false,
45

46
    /**
47
    * The OpenLayers map. If not given, will be auto-detected
48
    */
49
    map: null,
50

51
    /**
52
     * The BasiGX mapComponent. If not given, will be auto-detected
53
     */
54
    mapComponent: null,
55

56

57
    constructor: function () {
58
        var me = this;
12✔
59
        me.getFeaturesFromSourceAndTriggerWfs = me.getFeaturesFromSourceAndTriggerWfs.bind(me);
12✔
60
        me.getGeometryFromPolygonAndTriggerWfs = me.getGeometryFromPolygonAndTriggerWfs.bind(me);
12✔
61
        me.onQueryLayerVisibilityChange = me.onQueryLayerVisibilityChange.bind(me);
12✔
62
        me.callParent(arguments);
12✔
63
    },
64

65
    /**
66
     * Function to determine the query layer if not yet defined in class
67
     */
68
    findQueryLayer: function () {
69
        var me = this;
6✔
70
        var view = me.getView();
6✔
71
        if (!view.queryLayer && view.queryLayerName) {
6!
72
            view.queryLayer = BasiGX.util.Layer.
×
73
                getLayerByName(view.queryLayerName);
74
        }
75

76
        if (!view.queryLayer) {
6!
77
            Ext.Logger.warn('No queryLayer found in the map for the SpatialQueryButton with the name: ' + view.queryLayerName);
6✔
78
        }
79
    },
80

81
    /**
82
     * Activates #drawQueryInteraction on button toggle to draw polygon
83
     * selection geometry that will be used for filtering.
84
     *
85
     * @param {Ext.button.Button} btn The toggled select by polygon button.
86
     * @param {Boolean} pressed The toggle state.
87
     */
88
    onSpatialQueryBtnToggle: function (btn, pressed) {
89
        var me = this;
6✔
90
        var view = me.getView();
6✔
91

92
        if (view.map && view.map instanceof ol.Map) {
6!
93
            me.map = view.map;
×
94
        } else {
95
            // guess map as fallback
96
            me.map = BasiGX.util.Map.getMapComponent().map;
6✔
97
        }
98

99
        if (!view.queryLayer) {
6!
100
            me.findQueryLayer();
6✔
101
        }
102

103
        var geometryFunction;
104
        var type = view.drawGeometryType;
6✔
105
        if (view.spatialOperator === 'bbox') {
6!
106
            type = 'Circle';
×
107
            geometryFunction = ol.interaction.Draw.createBox();
×
108
        }
109

110
        var vectorLayerKey = view.getVectorLayerKey();
6✔
111
        me.permanentLayer = CpsiMapview.view.button.SpatialQueryButton.findAssociatedPermanentLayer(me.map, vectorLayerKey);
6✔
112
        if (me.permanentLayer === undefined) {
6!
113
            me.permanentLayerCreatedByTool = true; // add flag indicating the tool will handle the destruction of the layer
6✔
114
            me.permanentLayer = new ol.layer.Vector({ source: new ol.source.Vector() });
6✔
115
            me.permanentLayer.set('associatedLayerKey', vectorLayerKey);
6✔
116
            me.permanentLayer.set('isSpatialQueryLayer', true);
6✔
117
            me.permanentLayer.set('name', vectorLayerKey + '_spatialfilter');
6✔
118
            // connect hide and show to query layer hide and show
119
            me.connectQueryLayer();
6✔
120
        }
121

122
        var permanentLayerSource = me.permanentLayer.getSource();
6✔
123
        if (!me.drawQueryInteraction) {
6!
124
            if (view.displayPermanently) {
6!
125
                me.map.addLayer(me.permanentLayer);
6✔
126
                me.drawQueryInteraction = new ol.interaction.Draw({
6✔
127
                    source: permanentLayerSource,
128
                    geometryFunction: geometryFunction,
129
                    type: type
130
                });
131

132
                me.modifiyQueryInteraction = new ol.interaction.Modify({
6✔
133
                    source: permanentLayerSource
134
                });
135
                me.snapQueryInteraction = new ol.interaction.Snap({
6✔
136
                    source: permanentLayerSource
137
                });
138
                me.map.addInteraction(me.modifiyQueryInteraction);
6✔
139
                me.map.addInteraction(me.snapQueryInteraction);
6✔
140
            } else {
141
                me.drawQueryInteraction = new ol.interaction.Draw({
×
142
                    features: view.queryFeatures,
143
                    geometryFunction: geometryFunction,
144
                    type: type
145
                });
146
            }
147
            me.map.addInteraction(me.drawQueryInteraction);
6✔
148
        }
149
        if (pressed) {
6!
150
            me.drawQueryInteraction.setActive(true);
×
151
            me.map.getViewport().addEventListener('contextmenu', me.contextHandler);
×
152
            if (view.displayPermanently) {
×
153
                me.modifiyQueryInteraction.setActive(true);
×
154
                me.snapQueryInteraction.setActive(true);
×
155
                me.drawQueryInteraction.on('drawend', me.getFeaturesFromSourceAndTriggerWfs);
×
156
                me.modifiyQueryInteraction.on('modifyend', me.getFeaturesFromSourceAndTriggerWfs);
×
157
            } else {
158
                view.queryFeatures.on('add', me.getGeometryFromPolygonAndTriggerWfs);
×
159
            }
160
        } else {
161
            me.drawQueryInteraction.setActive(false);
6✔
162
            me.map.getViewport().removeEventListener('contextmenu', me.contextHandler);
6✔
163
            if (view.displayPermanently) {
6!
164
                me.modifiyQueryInteraction.setActive(false);
6✔
165
                me.snapQueryInteraction.setActive(false);
6✔
166
                me.drawQueryInteraction.un('drawend', me.getFeaturesFromSourceAndTriggerWfs);
6✔
167
                me.modifiyQueryInteraction.un('modifyend', me.getFeaturesFromSourceAndTriggerWfs);
6✔
168
            } else {
169
                view.queryFeatures.un('add', me.getGeometryFromPolygonAndTriggerWfs);
×
170
            }
171
        }
172
    },
173

174
    /**
175
     * Method shows the context menu on mouse right click
176
     * @param {Event} evt The browser event
177
     */
178
    showContextMenu: function (evt) {
179
        // suppress default browser behaviour
180
        evt.preventDefault();
×
181

182
        var me = this.scope;
×
183

184
        var menu = Ext.create('Ext.menu.Menu', {
×
185
            width: 100,
186
            plain: true,
187
            renderTo: Ext.getBody(),
188
            items: [{
189
                text: 'Clear Feature',
190
                scope: me,
191
                handler: function () {
192
                    var view = me.getView();
×
193
                    // remove the spatial filter on the layer by firing an event
194
                    view.fireEvent('cmv-spatial-query-filter', null);
×
195
                    // now remove the polygon from the layer
196
                    me.onClearAssociatedPermanentLayer();
×
197
                }
198
            }, {
199
                text: 'Cancel Drawing',
200
                scope: me,
201
                handler: function () {
202
                    me.drawQueryInteraction.abortDrawing();
×
203
                }
204
            }]
205
        });
206
        menu.showAt(evt.pageX, evt.pageY);
×
207
    },
208
    /**
209
     * Connects the change:visible event of the query layer
210
     * to the permanent layer. Thereby, when the query layer
211
     * visibility is changed, the visibility of the permanent layer
212
     * changes accordingly.
213
     */
214
    connectQueryLayer: function () {
215
        var me = this;
6✔
216
        var view = me.getView();
6✔
217
        var layerKey = view.getVectorLayerKey();
6✔
218
        if (!layerKey) {
6!
219
            return;
6✔
220
        }
221
        if (view.queryLayer) {
×
222
            view.queryLayer.on('change:visible', me.onQueryLayerVisibilityChange);
×
223
        }
224
    },
225

226
    /**
227
     * Event handler for the change:visible event of the
228
     * query layer.
229
     * @param {ol.Object.event} evt change:visible event of layer
230
     */
231
    onQueryLayerVisibilityChange: function (evt) {
232
        var me = this;
×
233
        var visible = evt.target.getVisible();
×
234
        if (visible) {
×
235
            me.onShowAssociatedPermanentLayer();
×
236
        } else {
237
            me.onHideAssociatedPermanentLayer();
×
238
        }
239
    },
240

241
    /**
242
    * Creates a Filter object from the passed geometry and queryLayer
243
    *
244
    * @param  {ol.geom.Geometry} geometry The geometry
245
    * @return {Ext.util.Filter}       A filter spatial
246
    * @private
247
    */
248
    createSpatialFilter: function (geometry) {
249
        var me = this;
1✔
250
        var filter = null;
1✔
251

252
        var view = me.getView();
1✔
253
        if (!view.queryLayer) {
1!
254
            return;
1✔
255
        }
256

257
        var mapComp = me.mapComponent || BasiGX.util.Map.getMapComponent();
×
258
        var projString = mapComp.getMap().getView().getProjection().getCode();
×
259
        var geomFieldName = view.queryLayer.get('geomFieldName') ||
×
260
            view.queryLayer.getSource().get('geomFieldName') ||
261
            'the_geom';
262

263
        if (!Ext.isEmpty(geometry)) {
×
264
            filter = GeoExt.util.OGCFilter.createSpatialFilter(view.spatialOperator, geomFieldName, geometry, projString);
×
265
        }
266

267
        return filter;
×
268

269
    },
270

271
    /**
272
     * Handles the modifyend and drawend events of the draw layer
273
     * @param {ol.Object.event} evt ol modifyend or drawend event
274
     */
275
    getFeaturesFromSourceAndTriggerWfs: function (evt) {
276
        var me = this;
×
277
        var feature;
278
        if (evt.type === 'modifyend') {
×
279
            // We expect to only have one existing feature in source.
280
            // In case multiple features exist, we only use the one
281
            // that was added last
282
            feature = evt.features.getArray()[evt.features.getLength() - 1];
×
283
        } else if (evt.type === 'drawend') {
×
284
            // clear previously drawn features so that only one feature exists
285
            me.permanentLayer.getSource().clear();
×
286
            feature = evt.feature;
×
287
        }
288
        var fakeEvent = { element: feature };
×
289
        me.getGeometryFromPolygonAndTriggerWfs(fakeEvent);
×
290
    },
291

292
    /**
293
     * Helper method to create a polygon geometry from drawn irregular polygon.
294
     *
295
     * @param {Ext.Event} evt The add-Event containing drawn feature
296
     */
297
    getGeometryFromPolygonAndTriggerWfs: function (evt) {
298
        var me = this;
×
299
        var geometry = evt.element.getGeometry();
×
300
        var view = me.getView();
×
301

302
        var filter = me.createSpatialFilter(geometry);
×
303
        view.fireEvent('cmv-spatial-query-filter', filter);
×
304
        if (view.triggerWfsRequest === true) {
×
305
            this.buildAndRequestQuery(geometry);
×
306
        }
307
    },
308

309
    /**
310
     * Build query / filter and call WFS
311
     *
312
     * @param {ol.geom.Geometry} geometry The geometry
313
     */
314
    buildAndRequestQuery: function (geometry) {
315
        var me = this;
×
316
        var view = me.getView();
×
317
        if (!view.queryLayer) {
×
318
            return;
×
319
        }
320

321
        var mapComp = me.mapComponent || BasiGX.util.Map.getMapComponent();
×
322

323
        var projString = mapComp.getMap().getView().getProjection().getCode();
×
324
        var geomFieldName = view.queryLayer.get('geomFieldName') ||
×
325
            view.queryLayer.getSource().get('geomFieldName') ||
326
            'the_geom';
327
        var url = view.queryLayer.get('url') ||
×
328
            view.queryLayer.getSource().getUrl() ||
329
            view.queryLayer.getSource().getUrls()[0];
330

331
        var featureType = view.queryLayer.get('featureType') ||
×
332
            BasiGX.util.Object.layersFromParams(
333
                view.queryLayer.getSource().getParams()
334
            );
335

336
        if (!Ext.isEmpty(geometry)) {
×
337
            var filter = GeoExt.util.OGCFilter.getOgcFilter(
×
338
                geomFieldName, view.spatialOperator, geometry, '1.1.0', projString);
339

340
            mapComp.setLoading(true);
×
341
            BasiGX.util.WFS.executeWfsGetFeature(
×
342
                url,
343
                view.queryLayer,
344
                projString,
345
                null,
346
                geomFieldName,
347
                filter,
348
                null,
349
                me.onWfsExecuteSuccess,
350
                me.onWfsExecuteFailure,
351
                me,
352
                null,
353
                featureType
354
            );
355
        }
356
    },
357

358
    /**
359
     * Handle a successful WFS request.
360
     *
361
     * @param {XMLHttpRequest.response} response The response of the AJAX call.
362
     */
363
    onWfsExecuteSuccess: function (response) {
364
        var me = this;
×
365
        var view = me.getView();
×
366
        var mapComp = me.mapComponent || BasiGX.util.Map.getMapComponent();
×
367
        mapComp.setLoading(false);
×
368
        var wfsResponse = response.responseText;
×
369
        if (wfsResponse.indexOf('Exception') > 0) {
×
370
            // something got wrong and we probably have an exception, that we
371
            // try to handle...
372
            BasiGX.util.WFS.handleWfsExecuteException(wfsResponse);
×
373
            view.fireEvent('cmv-spatial-query-error', decodedResponse);
×
374
        } else {
375
            var decodedResponse = Ext.decode(wfsResponse);
×
376
            view.fireEvent('cmv-spatial-query-success', decodedResponse);
×
377
        }
378
    },
379

380
    /**
381
     * Handle WFS GetFeature failure.
382
     *
383
     * @param {XMLHttpRequest.response} response The response of the AJAX call.
384
     */
385
    onWfsExecuteFailure: function (response) {
386
        var me = this;
×
387
        var view = me.getView();
×
388
        var responseTxt;
389
        if (response && response.responseText) {
×
390
            responseTxt = response.responseText;
×
391
        }
392
        var mapComp = me.mapComponent || BasiGX.util.Map.getMapComponent();
×
393
        mapComp.setLoading(false);
×
394
        view.fireEvent('cmv-spatial-query-error', responseTxt);
×
395
    },
396

397
    /**
398
     * Handles clearing the permanentLayer of the instance.
399
     */
400
    onClearAssociatedPermanentLayer: function () {
401
        var me = this;
1✔
402
        var layerKey = me.getView().getVectorLayerKey();
1✔
403
        if (!me.map) {
1!
404
            return;
1✔
405
        }
406
        if (!layerKey) {
×
407
            return;
×
408
        }
409
        CpsiMapview.view.button.SpatialQueryButton.clearAssociatedPermanentLayer(me.map, layerKey);
×
410
    },
411

412
    /**
413
     * Handles showing the permanentLayer of the instance.
414
     */
415
    onShowAssociatedPermanentLayer: function () {
416
        var me = this;
×
417
        var layerKey = me.getView().getVectorLayerKey();
×
418
        if (!me.map) {
×
419
            return;
×
420
        }
421
        if (!layerKey) {
×
422
            return;
×
423
        }
424
        CpsiMapview.view.button.SpatialQueryButton.showAssociatedPermanentLayer(me.map, layerKey);
×
425
    },
426

427
    /**
428
     * Handles hiding the permanentLayer of the instance.
429
     */
430
    onHideAssociatedPermanentLayer: function () {
431
        var me = this;
×
432
        var layerKey = me.getView().getVectorLayerKey();
×
433
        if (!me.map) {
×
434
            return;
×
435
        }
436
        if (!layerKey) {
×
437
            return;
×
438
        }
439
        CpsiMapview.view.button.SpatialQueryButton.hideAssociatedPermanentLayer(me.map, layerKey);
×
440
    },
441

442
    onBeforeDestroy: function () {
443
        var me = this;
6✔
444
        var view = me.getView();
6✔
445

446
        // detoggle button
447
        me.onSpatialQueryBtnToggle(view, false);
6✔
448

449
        if (me.modifiyQueryInteraction) {
6!
450
            me.map.removeInteraction(me.modifiyQueryInteraction);
6✔
451
        }
452

453
        if (me.snapQueryInteraction) {
6!
454
            me.map.removeInteraction(me.snapQueryInteraction);
6✔
455
        }
456

457
        if (me.drawQueryInteraction) {
6!
458
            me.map.removeInteraction(me.drawQueryInteraction);
6✔
459
        }
460

461
        if (me.permanentLayer && me.permanentLayerCreatedByTool) {
6!
462
            me.map.removeLayer(me.permanentLayer);
6✔
463
        }
464
    },
465

466
    init: function () {
467

468
        var me = this;
11✔
469

470
        // create an object for the contextmenu eventhandler
471
        // so it can be removed correctly
472
        me.contextHandler = {
11✔
473
            handleEvent: me.showContextMenu,
474
            scope: me
475
        };
476
    }
477
});
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