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

geographika / cpsi-mapview / 6275612987

22 Sep 2023 02:33PM UTC coverage: 19.833%. Remained the same
6275612987

push

github

geographika
Remove raf.polyfill.js as only required for IE9 or less

372 of 2475 branches covered (0.0%)

Branch coverage included in aggregate %.

1176 of 5330 relevant lines covered (22.06%)

1.93 hits per line

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

32.06
/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;
6✔
59
        me.getFeaturesFromSourceAndTriggerWfs = me.getFeaturesFromSourceAndTriggerWfs.bind(me);
6✔
60
        me.getGeometryFromPolygonAndTriggerWfs = me.getGeometryFromPolygonAndTriggerWfs.bind(me);
6✔
61
        me.onQueryLayerVisibilityChange = me.onQueryLayerVisibilityChange.bind(me);
6✔
62
        me.callParent(arguments);
6✔
63
    },
64

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

76
        if (!view.queryLayer) {
2!
77
            Ext.Logger.warn('No queryLayer found in the map for the SpatialQueryButton with the name: ' + view.queryLayerName);
2✔
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;
2✔
90
        var view = me.getView();
2✔
91

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

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

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

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

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

132
                me.modifiyQueryInteraction = new ol.interaction.Modify({
2✔
133
                    source: permanentLayerSource
134
                });
135
                me.snapQueryInteraction = new ol.interaction.Snap({
2✔
136
                    source: permanentLayerSource
137
                });
138
                me.map.addInteraction(me.modifiyQueryInteraction);
2✔
139
                me.map.addInteraction(me.snapQueryInteraction);
2✔
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);
2✔
148
        }
149
        if (pressed) {
2!
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);
2✔
162
            me.map.getViewport().removeEventListener('contextmenu', me.contextHandler);
2✔
163
            if (view.displayPermanently) {
2!
164
                me.modifiyQueryInteraction.setActive(false);
2✔
165
                me.snapQueryInteraction.setActive(false);
2✔
166
                me.drawQueryInteraction.un('drawend', me.getFeaturesFromSourceAndTriggerWfs);
2✔
167
                me.modifiyQueryInteraction.un('modifyend', me.getFeaturesFromSourceAndTriggerWfs);
2✔
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
                handler: function () {
191
                    var view = me.getView();
×
192
                    // remove the spatial filter on the layer by firing an event
193
                    view.fireEvent('cmv-spatial-query-filter', null);
×
194
                    // now remove the polygon from the layer
195
                    me.onClearAssociatedPermanentLayer();
×
196
                },
197
                scope: me
198
            }]
199
        });
200
        menu.showAt(evt.pageX, evt.pageY);
×
201
    },
202
    /**
203
     * Connects the change:visible event of the query layer
204
     * to the permanent layer. Thereby, when the query layer
205
     * visibility is changed, the visibility of the permanent layer
206
     * changes accordingly.
207
     */
208
    connectQueryLayer: function () {
209
        var me = this;
2✔
210
        var view = me.getView();
2✔
211
        var layerKey = view.getVectorLayerKey();
2✔
212
        if (!layerKey) {
2!
213
            return;
2✔
214
        }
215
        if (view.queryLayer) {
×
216
            view.queryLayer.on('change:visible', me.onQueryLayerVisibilityChange);
×
217
        }
218
    },
219

220
    /**
221
     * Event handler for the change:visible event of the
222
     * query layer.
223
     * @param {ol.Object.event} evt change:visible event of layer
224
     */
225
    onQueryLayerVisibilityChange: function (evt) {
226
        var me = this;
×
227
        var visible = evt.target.getVisible();
×
228
        if (visible) {
×
229
            me.onShowAssociatedPermanentLayer();
×
230
        } else {
231
            me.onHideAssociatedPermanentLayer();
×
232
        }
233
    },
234

235
    /**
236
    * Creates a Filter object from the passed geometry and queryLayer
237
    *
238
    * @param  {ol.geom.Geometry} geometry The geometry
239
    * @return {Ext.util.Filter}       A filter spatial
240
    * @private
241
    */
242
    createSpatialFilter: function (geometry) {
243
        var me = this;
×
244
        var filter = null;
×
245

246
        var view = me.getView();
×
247
        if (!view.queryLayer) {
×
248
            return;
×
249
        }
250

251
        var mapComp = me.mapComponent || BasiGX.util.Map.getMapComponent();
×
252
        var projString = mapComp.getMap().getView().getProjection().getCode();
×
253
        var geomFieldName = view.queryLayer.get('geomFieldName') ||
×
254
            view.queryLayer.getSource().get('geomFieldName') ||
255
            'the_geom';
256

257
        if (!Ext.isEmpty(geometry)) {
×
258
            filter = GeoExt.util.OGCFilter.createSpatialFilter(view.spatialOperator, geomFieldName, geometry, projString);
×
259
        }
260

261
        return filter;
×
262

263
    },
264

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

286
    /**
287
     * Helper method to create a polygon geometry from drawn irregular polygon.
288
     *
289
     * @param {Ext.Event} evt The add-Event containing drawn feature
290
     */
291
    getGeometryFromPolygonAndTriggerWfs: function (evt) {
292
        var me = this;
×
293
        var geometry = evt.element.getGeometry();
×
294
        var view = me.getView();
×
295

296
        var filter = me.createSpatialFilter(geometry);
×
297
        view.fireEvent('cmv-spatial-query-filter', filter);
×
298
        if (view.triggerWfsRequest === true) {
×
299
            this.buildAndRequestQuery(geometry);
×
300
        }
301
    },
302

303
    /**
304
     * Build query / filter and call WFS
305
     *
306
     * @param {ol.geom.Geometry} geometry The geometry
307
     */
308
    buildAndRequestQuery: function (geometry) {
309
        var me = this;
×
310
        var view = me.getView();
×
311
        if (!view.queryLayer) {
×
312
            return;
×
313
        }
314

315
        var mapComp = me.mapComponent || BasiGX.util.Map.getMapComponent();
×
316

317
        var projString = mapComp.getMap().getView().getProjection().getCode();
×
318
        var geomFieldName = view.queryLayer.get('geomFieldName') ||
×
319
            view.queryLayer.getSource().get('geomFieldName') ||
320
            'the_geom';
321
        var url = view.queryLayer.get('url') ||
×
322
            view.queryLayer.getSource().getUrl() ||
323
            view.queryLayer.getSource().getUrls()[0];
324

325
        var featureType = view.queryLayer.get('featureType') ||
×
326
            BasiGX.util.Object.layersFromParams(
327
                view.queryLayer.getSource().getParams()
328
            );
329

330
        if (!Ext.isEmpty(geometry)) {
×
331
            var filter = GeoExt.util.OGCFilter.getOgcFilter(
×
332
                geomFieldName, view.spatialOperator, geometry, '1.1.0', projString);
333

334
            mapComp.setLoading(true);
×
335
            BasiGX.util.WFS.executeWfsGetFeature(
×
336
                url,
337
                view.queryLayer,
338
                projString,
339
                null,
340
                geomFieldName,
341
                filter,
342
                null,
343
                me.onWfsExecuteSuccess,
344
                me.onWfsExecuteFailure,
345
                me,
346
                null,
347
                featureType
348
            );
349
        }
350
    },
351

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

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

391
    /**
392
     * Handles clearing the permanentLayer of the instance.
393
     */
394
    onClearAssociatedPermanentLayer: function () {
395
        var me = this;
×
396
        var layerKey = me.getView().getVectorLayerKey();
×
397
        if (!me.map) {
×
398
            return;
×
399
        }
400
        if (!layerKey) {
×
401
            return;
×
402
        }
403
        CpsiMapview.view.button.SpatialQueryButton.clearAssociatedPermanentLayer(me.map, layerKey);
×
404
    },
405

406
    /**
407
     * Handles showing the permanentLayer of the instance.
408
     */
409
    onShowAssociatedPermanentLayer: function () {
410
        var me = this;
×
411
        var layerKey = me.getView().getVectorLayerKey();
×
412
        if (!me.map) {
×
413
            return;
×
414
        }
415
        if (!layerKey) {
×
416
            return;
×
417
        }
418
        CpsiMapview.view.button.SpatialQueryButton.showAssociatedPermanentLayer(me.map, layerKey);
×
419
    },
420

421
    /**
422
     * Handles hiding the permanentLayer of the instance.
423
     */
424
    onHideAssociatedPermanentLayer: function () {
425
        var me = this;
×
426
        var layerKey = me.getView().getVectorLayerKey();
×
427
        if (!me.map) {
×
428
            return;
×
429
        }
430
        if (!layerKey) {
×
431
            return;
×
432
        }
433
        CpsiMapview.view.button.SpatialQueryButton.hideAssociatedPermanentLayer(me.map, layerKey);
×
434
    },
435

436
    onBeforeDestroy: function () {
437
        var me = this;
2✔
438
        var view = me.getView();
2✔
439

440
        // detoggle button
441
        me.onSpatialQueryBtnToggle(view, false);
2✔
442

443
        if (me.modifiyQueryInteraction) {
2!
444
            me.map.removeInteraction(me.modifiyQueryInteraction);
2✔
445
        }
446

447
        if (me.snapQueryInteraction) {
2!
448
            me.map.removeInteraction(me.snapQueryInteraction);
2✔
449
        }
450

451
        if (me.drawQueryInteraction) {
2!
452
            me.map.removeInteraction(me.drawQueryInteraction);
2✔
453
        }
454

455
        if (me.permanentLayer && me.permanentLayerCreatedByTool) {
2!
456
            me.map.removeLayer(me.permanentLayer);
2✔
457
        }
458
    },
459

460
    init: function () {
461

462
        var me = this;
6✔
463

464
        // create an object for the contextmenu eventhandler
465
        // so it can be removed correctly
466
        me.contextHandler = {
6✔
467
            handleEvent: me.showContextMenu,
468
            scope: me
469
        };
470
    }
471
});
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