UNPKG

@geogirafe/lib-geoportal

Version:

GeoGirafe is a flexible application to build online geoportals.

212 lines (211 loc) 9.08 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; import { isListFilterOperator, isTwoSidedFilterOperator, isValuelessFilterOperator, logicalFilterOperators } from '../../models/filter.js'; import { DrawingShape } from '../../tools/drawing/drawingFeature.js'; import DrawingState from '../../tools/drawing/drawingState.js'; import { v4 as uuidv4 } from 'uuid'; import WfsFilterCondition from '../../tools/wfs/wfsfiltercondition.js'; import { isAreaLikeGeometryTypeOrUnknown, isGeometry } from '../../models/xmlTypes.js'; import { UsedInTemplateOnly } from '../../decorators.js'; class FilterConditionElement { context; id; applied; attribute; attributeDisplayName; attributeInputType; availableOperators; operator; value; value2; choices; logicalOperator; filterConditionInstance; geometryChangeHandler; static drawingStateLocation = 'advancedFilterDrawing'; drawingState; spatialOperatorsByDrawingShape = [ { shape: DrawingShape.Point, supportedOperators: ['contains', 'intersects'] }, { shape: DrawingShape.Polyline, supportedOperators: ['contains', 'intersects'] }, { shape: DrawingShape.Polygon, supportedOperators: ['contains', 'intersects', 'within'] }, { shape: DrawingShape.Square, supportedOperators: ['contains', 'intersects', 'within'] }, { shape: DrawingShape.Rectangle, supportedOperators: ['contains', 'intersects', 'within'] }, { shape: DrawingShape.Disk, supportedOperators: ['contains', 'intersects', 'within'] } ]; constructor(context) { this.context = context; this.id = uuidv4(); this.applied = false; if (!this.context.stateManager.state.extendedState[FilterConditionElement.drawingStateLocation]) { this.context.stateManager.state.extendedState[FilterConditionElement.drawingStateLocation] = new DrawingState(); } this.drawingState = this.context.stateManager.state.extendedState[FilterConditionElement.drawingStateLocation]; // Init available tools in the drawing toolbar this.drawingState.tools = this.spatialOperatorsByDrawingShape.map((c) => { return { shape: c.shape, enabled: false }; }); } setLogicalOperator(operator) { this.logicalOperator = logicalFilterOperators.find((op) => op.operator === operator)?.operator; } setAttribute(attribute, attributeDisplayName, attributeInputType, availableOperators, choices) { this.reset(); this.attribute = attribute; this.attributeDisplayName = attributeDisplayName; this.attributeInputType = attributeInputType; this.availableOperators = availableOperators; this.choices = choices; this.updateDrawingToolbar(); } setOperator(operator) { this.operator = this.availableOperators?.find((op) => op.operator === operator)?.operator; if (!this.operator) { console.warn(`Invalid operator ${operator} for attribute ${this.attribute?.name}`); } this.updateDrawingToolbar(); } updateDrawingToolbar() { if (this.attribute && isGeometry(this.attribute.type)) { this.context.stateManager.batchChanges(() => { for (const drawingTool of this.drawingState.tools) { drawingTool.enabled = this.getSupportedDrawingToolsByOperator(this.operator).includes(drawingTool.shape); } }); this.registerGeometryListener(); } } getSupportedDrawingToolsByOperator(operator) { return this.spatialOperatorsByDrawingShape .filter((c) => (operator ? c.supportedOperators.includes(operator) : false)) .map((c) => c.shape); } registerGeometryListener() { if (this.geometryChangeHandler) { return; } this.geometryChangeHandler = (_old, newFeatures) => { if (newFeatures.length > 0) { this.value = JSON.stringify({ ...newFeatures[0].geojson, properties: { tool: DrawingShape[newFeatures[0].type] } }); } else { this.value = undefined; } }; this.context.stateManager.subscribe(`extendedState.${FilterConditionElement.drawingStateLocation}.features`, this.geometryChangeHandler); } resetDrawingToolbar() { if (this.geometryChangeHandler) { this.context.stateManager.unsubscribe(this.geometryChangeHandler); this.geometryChangeHandler = undefined; } // Remove geometry in map this.drawingState.activeTool = null; this.drawingState.features = []; } reset() { this.applied = false; this.attribute = undefined; this.attributeDisplayName = undefined; this.attributeInputType = undefined; this.operator = undefined; this.value = undefined; this.value2 = undefined; this.choices = undefined; this.availableOperators = undefined; this.filterConditionInstance = undefined; this.resetDrawingToolbar(); } remove() { this.resetDrawingToolbar(); } isValid() { return (!!this.attribute && !!this.operator && (!!this.value || isValuelessFilterOperator(this.operator)) && (!!this.value2 || !isTwoSidedFilterOperator(this.operator))); } apply() { if (this.isValid()) { this.filterConditionInstance = new WfsFilterCondition(this.attribute.name, this.operator, this.value, this.value2, this.attribute.type); this.resetDrawingToolbar(); this.applied = true; } return this.applied; } i18n(key) { return this.context.i18nManager.getTranslation(key); } // Helper functions for UI elements isOperatorSelectorEnabled() { return !!this.attribute; } isValueInputVisible() { return (!!this.attribute && (!this.operator || (this.operator && !isValuelessFilterOperator(this.operator))) && !this.isGeometryToolbarVisible() && !this.isChoicesListVisible()); } isValue2InputVisible() { return !!this.attribute && !!this.operator && isTwoSidedFilterOperator(this.operator); } isChoicesListVisible() { return !!this.attribute && !!this.choices && !!this.operator && isListFilterOperator(this.operator); } isGeometryToolbarVisible() { return !!this.attribute && this.attributeInputType === 'geometry'; } /** * Check if the operator can be used with the current spatial attribute type */ isSpatialOperatorEnabled(operator) { // If the operator isn't `contains`, there is no restriction necessary if (!this.attribute || operator !== 'contains') { return true; } // `Contains` only makes sense with area like geometry types return isAreaLikeGeometryTypeOrUnknown(this.attribute.type); } /** * Converts a filter condition to its text representation, using the filterCondition instances * toTextRepresentation method and adding the logical operator if it is defined. */ toText() { if (!this.filterConditionInstance || !this.attribute) { return ''; } const logicalOperator = this.logicalOperator ? logicalFilterOperators.find((op) => op.operator === this.logicalOperator).displayName : ''; const filterExpression = this.filterConditionInstance.toTextRepresentation(this.context, this.attributeDisplayName); return `${this.i18n(logicalOperator)} ${filterExpression}`; } } __decorate([ UsedInTemplateOnly() ], FilterConditionElement.prototype, "isOperatorSelectorEnabled", null); __decorate([ UsedInTemplateOnly() ], FilterConditionElement.prototype, "isValueInputVisible", null); __decorate([ UsedInTemplateOnly() ], FilterConditionElement.prototype, "isValue2InputVisible", null); __decorate([ UsedInTemplateOnly() ], FilterConditionElement.prototype, "isChoicesListVisible", null); __decorate([ UsedInTemplateOnly() ], FilterConditionElement.prototype, "isGeometryToolbarVisible", null); __decorate([ UsedInTemplateOnly() ], FilterConditionElement.prototype, "isSpatialOperatorEnabled", null); __decorate([ UsedInTemplateOnly() ], FilterConditionElement.prototype, "toText", null); export default FilterConditionElement;