Skip to content

Commit

Permalink
feat(ogc-filter): Provide operator at the field scale (#608)
Browse files Browse the repository at this point in the history
* feat(ogc-filter)Provide allowed operator at the field scale

* wip

* wip

* feat(ogc-filter) provide tooltip for operators

* wip

* wip

* wip

* i18n(geo locale) wip

Co-authored-by: Pierre-Étienne Lord <[email protected]>
  • Loading branch information
pelord and Pierre-Étienne Lord authored Mar 31, 2020
1 parent 8cb8b02 commit 1950c95
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 88 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import olSource from 'ol/source/Source';
import { DownloadOptions } from '../../../download/shared/download.interface';
import { OgcFilterOperatorType } from '../../../filter/shared/ogc-filter.enum';

export interface DataSourceOptions {
type?:
Expand Down Expand Up @@ -32,6 +33,7 @@ export interface SourceFieldsOptionsParams {
alias?: any;
values?: any;
excludeFromOgcFilters?: boolean;
allowedOperatorsType?: OgcFilterOperatorType;
}

export interface Legend {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
<div class="igo-col igo-col-90 igo-col-100-m">
<mat-select class="logical" [disabled]="!currentFilter.active" (selectionChange)="refreshFilters()" [(ngModel)]="currentFilter.parentLogical"
*ngIf="activeFilters.indexOf(currentFilter) !== 0 && currentFilter.active===true">
<mat-option value="And">{{'igo.geo.operators.And' | translate}}</mat-option>
<mat-option value="Or">{{'igo.geo.operators.Or' | translate}}</mat-option>
<mat-option tooltip-position="above" matTooltipShowDelay="500" [matTooltip]="'igo.geo.operators.tooltip.And' | translate" value="And">{{'igo.geo.operators.And' | translate}}</mat-option>
<mat-option tooltip-position="above" matTooltipShowDelay="500" [matTooltip]="'igo.geo.operators.tooltip.Or' | translate" value="Or">{{'igo.geo.operators.Or' | translate}}</mat-option>
</mat-select>
</div>
<!-- NON SPATIAL -->
<div class="igo-col igo-col-90 igo-col-100-m" *ngIf="(currentFilter.operator !== 'Intersects' && currentFilter.operator !== 'Contains' && currentFilter.operator !== 'Within')">
<span *ngIf="fields && fields.length > 0 && fields[0].name !== ''">
<span *ngIf="(fields$ | async) && (fields$| async).length > 0 && (fields$| async)[0].name !== ''">
<mat-select [disabled]="!currentFilter.active" *ngIf="['Contains','Intersects','Within'].indexOf(currentFilter.operator) === -1"
[(ngModel)]="currentFilter.propertyName" tooltip-position="below" matTooltipShowDelay="500" [matTooltip]="'igo.geo.sourceFields.selectField' | translate"
(selectionChange)="updateField()">
<mat-option *ngFor="let field of fields" [value]="field.name">{{field.alias}}</mat-option>
<mat-option *ngFor="let field of (fields$| async)" [value]="field.name">{{field.alias}}</mat-option>
</mat-select>
</span>
<span *ngIf="fields && fields.length === 1 && fields[0].name === ''">
<span *ngIf=" (fields$| async) && (fields$| async).length === 1 && (fields$| async)[0].name === ''">
<mat-form-field>
<input [disabled]="!currentFilter.active" matInput #fieldPerUser (keyup)="changeProperty(currentFilter,'propertyName',fieldPerUser.value)"
(blur)="changeProperty(currentFilter,'propertyName',fieldPerUser.value)" [(ngModel)]="currentFilter.propertyName">
Expand All @@ -33,7 +33,7 @@
<mat-select
tooltip-position="below" matTooltipShowDelay="500" [matTooltip]="'igo.geo.filter.selectOperator' | translate"
[disabled]="!currentFilter.active" [(ngModel)]="currentFilter.operator" (selectionChange)="changeOperator(currentFilter)">
<mat-option *ngFor="let operator of ogcFilterOperators | keyvalue" [value]="operator.key">{{('igo.geo.operators.'+ operator.key) | translate}}</mat-option>
<mat-option *ngFor="let operator of (ogcFilterOperators$ | async) | keyvalue" [value]="operator.key" tooltip-position="above" matTooltipShowDelay="500" [matTooltip]="('igo.geo.operators.tooltip.'+ operator.key) | translate" >{{('igo.geo.operators.'+ operator.key) | translate}}</mat-option>
</mat-select>
</div>

Expand Down Expand Up @@ -169,7 +169,7 @@
<mat-select
matTooltipShowDelay="500" [matTooltip]="'igo.geo.filter.selectOperator' | translate" tooltip-position="below"
[disabled]="!currentFilter.active" [(ngModel)]="currentFilter.operator" (selectionChange)="changeOperator(currentFilter)">
<mat-option *ngFor="let operator of ogcFilterOperators | keyvalue" [value]="operator.key">{{('igo.geo.operators.'+ operator.key) | translate}}</mat-option>
<mat-option *ngFor="let operator of (ogcFilterOperators$ | async) | keyvalue" [value]="operator.key" tooltip-position="above" matTooltipShowDelay="500" [matTooltip]="('igo.geo.operators.tooltip.'+ operator.key) | translate" >{{('igo.geo.operators.'+ operator.key) | translate}}</mat-option>
</mat-select>
</div>
<div class="igo-col igo-col-90 igo-col-100-m" *ngIf="(currentFilter.operator === 'Intersects' || currentFilter.operator === 'Contains' || currentFilter.operator === 'Within')">
Expand All @@ -196,6 +196,10 @@
</div>
<!-- PropertySpatial -->

<!-- <mat-checkbox labelPosition='before' (change)="changeCaseSensitive($event)" [(ngModel)]="currentFilter.matchCase">
{{('igo.geo.operators.caseSensitive') | translate}}
</mat-checkbox> -->

<div class="igo-col igo-col-100 igo-col-100-m">
<div class="igo-layer-button-group">
<mat-slide-toggle class="example-margin" (change)="toggleFilterState($event,currentFilter,'active')" tooltip-position="below"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,38 +12,47 @@ import {
import { OgcFilterWriter } from '../../filter/shared/ogc-filter';
import { WktService } from '../../wkt/shared/wkt.service';
import { IgoMap } from '../../map';
import { OgcFilterOperatorType } from '../../filter/shared/ogc-filter.enum';
import { FloatLabelType } from '@angular/material';
import { BehaviorSubject } from 'rxjs';
import { SourceFieldsOptionsParams } from '../../datasource/shared/datasources/datasource.interface';

@Component({
selector: 'igo-ogc-filter-form',
templateUrl: './ogc-filter-form.component.html',
styleUrls: ['./ogc-filter-form.component.scss']
})
export class OgcFilterFormComponent implements OnInit {
public ogcFilterOperators;
public allOgcFilterOperators;
public ogcFilterOperators$ = new BehaviorSubject<{ [key: string]: any }>(undefined);
public igoSpatialSelectors;
public value = '';
public inputOperator;
public fields: any[];
// public fields: any[];
public fields$ = new BehaviorSubject<SourceFieldsOptionsParams[]>([]);
public values: any[];
public color = 'primary';
public snrc = '';
public disabled;
public baseOverlayName = 'ogcFilterOverlay_';
public currentFilter$ = new BehaviorSubject<any>(undefined);

@Input() refreshFilters: () => void;

@Input() datasource: OgcFilterableDataSource;

@Input() map: IgoMap;

@Input() currentFilter: any;
@Input()
set currentFilter(currentFilter: any) {
this.currentFilter$.next(currentFilter);
}
get currentFilter(): any {
return this.currentFilter$.value;
}

@Input() floatLabel: FloatLabelType = 'never';

get activeFilters() {
this.updateField();
return this.datasource.options.ogcFilters.interfaceOgcFilters.filter(
f => f.active === true
);
Expand All @@ -56,7 +65,8 @@ export class OgcFilterFormComponent implements OnInit {
// Need to work on regex on XML capabilities because
// comaparison operator's name varies between WFS servers...
// Ex: IsNull vs PropertyIsNull vs IsNil ...
this.ogcFilterOperators = new OgcFilterWriter().operators;
this.allOgcFilterOperators = new OgcFilterWriter().operators;
this.ogcFilterOperators$.next(this.allOgcFilterOperators);
this.igoSpatialSelectors = [
{
type: 'fixedExtent'
Expand All @@ -69,73 +79,30 @@ export class OgcFilterFormComponent implements OnInit {
}

ngOnInit() {
this.computeAllowedOperators();
}

computeAllowedOperators() {
let allowedOperators = this.datasource.options.ogcFilters.allowedOperatorsType;
let effectiveOperators: {} = {};

if (!allowedOperators) {
allowedOperators = OgcFilterOperatorType.BasicAndSpatial;
}

switch (allowedOperators.toLowerCase()) {
case 'all':
effectiveOperators = this.ogcFilterOperators;
break;
case 'spatial':
effectiveOperators = {
Intersects: { spatial: true, fieldRestrict: [] },
Within: { spatial: true, fieldRestrict: [] },
};
break;
case 'basicandspatial':
effectiveOperators = {
PropertyIsEqualTo: { spatial: false, fieldRestrict: [] },
PropertyIsNotEqualTo: { spatial: false, fieldRestrict: [] },
Intersects: { spatial: true, fieldRestrict: [] },
Within: { spatial: true, fieldRestrict: [] },
};
break;
case 'basic':
effectiveOperators = {
PropertyIsEqualTo: { spatial: false, fieldRestrict: [] },
PropertyIsNotEqualTo: { spatial: false, fieldRestrict: [] }
};
break;
case 'basicnumeric':
effectiveOperators = {
PropertyIsEqualTo: { spatial: false, fieldRestrict: [] },
PropertyIsNotEqualTo: { spatial: false, fieldRestrict: [] },
PropertyIsGreaterThan: { spatial: false, fieldRestrict: ['number'] },
PropertyIsGreaterThanOrEqualTo: { spatial: false, fieldRestrict: ['number'] },
PropertyIsLessThan: { spatial: false, fieldRestrict: ['number'] },
PropertyIsLessThanOrEqualTo: { spatial: false, fieldRestrict: ['number'] },
};
break;
default:
effectiveOperators = {
PropertyIsEqualTo: { spatial: false, fieldRestrict: [] },
PropertyIsNotEqualTo: { spatial: false, fieldRestrict: [] },
Intersects: { spatial: true, fieldRestrict: [] },
Within: { spatial: true, fieldRestrict: [] },
};
}

this.ogcFilterOperators = effectiveOperators;
this.updateField();
}

updateField() {
if (!this.datasource.options.sourceFields) {
return;
}
this.fields = this.datasource.options.sourceFields
.filter(sf => (sf.excludeFromOgcFilters === undefined || !sf.excludeFromOgcFilters));
this.fields.filter(f => f.name === this.currentFilter.propertyName)
const fields = this.datasource.options.sourceFields
.filter(sf => (sf.excludeFromOgcFilters === undefined || !sf.excludeFromOgcFilters));
fields.filter(f => f.name === this.currentFilter.propertyName)
.forEach(element => {
this.values = element.values !== undefined ? element.values.sort() : [];
});

this.fields$.next(fields);
const allowedOperators = new OgcFilterWriter().computeAllowedOperators(
fields,
this.currentFilter.propertyName,
this.datasource.options.ogcFilters.allowedOperatorsType);
this.ogcFilterOperators$.next(allowedOperators);
if (Object.keys(allowedOperators).indexOf(this.currentFilter$.value.operator) === -1) {
this.currentFilter$.value.operator = Object.keys(allowedOperators)[0];
}
this.refreshFilters();
}

toggleFilterState(event, filter: OgcInterfaceFilterOptions, property) {
Expand Down Expand Up @@ -182,12 +149,19 @@ export class OgcFilterFormComponent implements OnInit {
}

changeOperator(filter) {
if (this.ogcFilterOperators[filter.operator].spatial === false) {
if (this.ogcFilterOperators$.value[filter.operator].spatial === false) {
this.removeOverlayByID(filter.filterid);
}
this.refreshFilters();
}

// Issue with mapserver 7.2 and Postgis layers. Fixed in 7.4
// Due to this issue, the checkbox is hide.
changeCaseSensitive(matchCase) {
this.currentFilter.matchCase = matchCase.checked;
this.refreshFilters();
}

changeProperty(filter: OgcInterfaceFilterOptions, property, value) {
this.datasource.options.ogcFilters.interfaceOgcFilters
.filter(f => f.filterid === filter.filterid)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export class OgcFilterableItemComponent implements OnInit {
public hasPushButton: boolean = false;
showLegend$: BehaviorSubject<boolean> = new BehaviorSubject(false);

private ogcFilterWriter;

@Input() layer: Layer;

@Input() map: IgoMap;
Expand All @@ -51,7 +53,9 @@ export class OgcFilterableItemComponent implements OnInit {
constructor(
private ogcFilterService: OGCFilterService,
private downloadService: DownloadService
) {}
) {
this.ogcFilterWriter = new OgcFilterWriter();
}

ngOnInit() {
const ogcFilters = this.datasource.options.ogcFilters;
Expand Down Expand Up @@ -116,11 +120,17 @@ export class OgcFilterableItemComponent implements OnInit {
.fieldNameGeometry;
}
const status = arr.length === 0 ? true : false;
const allowedOperators = this.ogcFilterWriter.computeAllowedOperators(
this.datasource.options.sourceFields,
firstFieldName,
this.datasource.options.ogcFilters.allowedOperatorsType);
const firstOperatorName = Object.keys(allowedOperators)[0];

arr.push(
new OgcFilterWriter().addInterfaceFilter(
this.ogcFilterWriter.addInterfaceFilter(
{
propertyName: firstFieldName,
operator: 'PropertyIsEqualTo',
operator: firstOperatorName,
active: status,
igoSpatialSelector: 'fixedExtent',
srsName: this.map.projection,
Expand All @@ -142,7 +152,6 @@ export class OgcFilterableItemComponent implements OnInit {
this.lastRunOgcFilter = undefined;
}
const ogcFilters: OgcFiltersOptions = this.datasource.options.ogcFilters;
const ogcFilterWriter = new OgcFilterWriter();
const activeFilters = ogcFilters.interfaceOgcFilters.filter(
f => f.active === true
);
Expand All @@ -169,7 +178,7 @@ export class OgcFilterableItemComponent implements OnInit {
if (this.layer.dataSource.options.type === 'wfs') {
const ogcDataSource: any = this.layer.dataSource;
const ogcLayer: OgcFiltersOptions = ogcDataSource.options.ogcFilters;
ogcLayer.filters = ogcFilterWriter.rebuiltIgoOgcFilterObjectFromSequence(
ogcLayer.filters = this.ogcFilterWriter.rebuiltIgoOgcFilterObjectFromSequence(
activeFilters
);
this.layer.dataSource.ol.clear();
Expand All @@ -181,10 +190,10 @@ export class OgcFilterableItemComponent implements OnInit {
if (activeFilters.length >= 1) {
const ogcDataSource: any = this.layer.dataSource;
const ogcLayer: OgcFiltersOptions = ogcDataSource.options.ogcFilters;
ogcLayer.filters = ogcFilterWriter.rebuiltIgoOgcFilterObjectFromSequence(
ogcLayer.filters = this.ogcFilterWriter.rebuiltIgoOgcFilterObjectFromSequence(
activeFilters
);
rebuildFilter = ogcFilterWriter.buildFilter(
rebuildFilter = this.ogcFilterWriter.buildFilter(
ogcLayer.filters,
undefined,
undefined,
Expand Down
3 changes: 2 additions & 1 deletion packages/geo/src/lib/filter/shared/ogc-filter.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ export enum OgcFilterOperatorType {
Basic = 'Basic',
BasicAndSpatial = 'BasicAndSpatial',
Spatial = 'Spatial',
All = 'All'
All = 'All',
Time = 'time'
}
Loading

0 comments on commit 1950c95

Please sign in to comment.