Commit 68241299 authored by Pedro Eduardo Trujillo's avatar Pedro Eduardo Trujillo
Browse files

Refactoriza capas de mapa y controla errores

Refactoriza implementación GridLayerImpl del componente MapLayer.
Adapta otras implementaciones de capa para hacer uso de la nueva
petición de datos, sin utilizar Filter.

Revisa vistas que hacen uso de las capas, para adaptar su configuración.

Independiza diferentes servicios de petición de datos de los de consulta
de información por elemento, haciendo explícito el uso de sufijos como
'_search'.

Controla errores de petición debido a parámetros con valores anidados a
nulo y por el uso de parámetros no soportados por algunos servicios.
parent 9236f581
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -83,11 +83,12 @@ define([

		_onRequestPermissionError: function(res) {

			const url = res.url,
				isGetTokenTarget = url.includes(redmicConfig.services.getOauthToken) ||
					url.includes(redmicConfig.services.getOidToken),
			const url = res.url;

				isNotApiTarget = !requestedTarget.includes(this.apiUrl);
			const isGetTokenTarget = url.includes(redmicConfig.services.getOauthToken) ||
				url.includes(redmicConfig.services.getOidToken);

			const isNotApiTarget = !url.includes(this.apiUrl);

			if (isGetTokenTarget || isNotApiTarget) {
				return;
+14 −4
Original line number Diff line number Diff line
@@ -120,12 +120,22 @@ define([
		},

		_filterQueryParamsForRequestBodyData: function(_key, value) {
			// summary:
			//   Evita el paso hacia los parámetros de filtrado de valores nulos, arrays vacíos y objetos con todas sus
			//   propiedades con valor nulo.

			const isNullValue = value === null;
			if (isNullValue) {
				return;
			}

			const isEmptyArray = value instanceof Array && !value.length,
				isNullValue = value === null;
			const isEmptyArray = value instanceof Array && !value.length;
			if (isEmptyArray) {
				return;
			}

			// evita arrays vacíos y valores nulos en los campos de filtro
			if (isEmptyArray || isNullValue) {
			const isObjectWithNullProps = value instanceof Object && !Object.values(value).some(v => v !== null);
			if (isObjectWithNullProps) {
				return;
			}

+106 −117
Original line number Diff line number Diff line
define([
	'd3'
	, 'dojo/_base/declare'
	, 'dojo/_base/lang'
	, 'dojo/aspect'
	, 'leaflet'
	, 'src/component/filter/Filter'
	, 'src/component/map/layer/_D3MapProjection'
	, 'src/component/map/layer/MapLayer'
	, 'src/util/Credentials'
], function(
	d3
	, declare
	, lang
	, aspect
	, L
	, Filter
	, _D3MapProjection
	, MapLayer
	, Credentials
) {

	return declare([MapLayer, _D3MapProjection], {
		// summary:
		//   Implementación de capa de rejilla.

		constructor: function() {

			aspect.before(this, "_initialize", lang.hitch(this, this._initializeGridLayerImpl));
			aspect.before(this, "_afterSetConfigurations", lang.hitch(this, this._setGridLayerConfigurations));
		},

		postMixInProperties: function() {

			const defaultConfig = {
@@ -51,42 +37,52 @@ define([
			this.inherited(arguments);
		},

		_setGridLayerConfigurations: function() {
		_setConfigurations: function() {

			this.inherited(arguments);

			this.targetPathParams = {
				grid: this.currentGridLayer
			};

			this.filterConfig = this._merge([{
				initQuery: {
			this.targetQueryParams = {
				terms: {
					confidences: this.confidences
				}
				}
			}, this.filterConfig || {}]);
			};
		},

		_initializeGridLayerImpl: function() {
		_onCurrentGridLayerPropSet: function() {

			this.infoFilter = new Filter({
				parentChannel: this.getChannel()
			});
			this.targetPathParams.grid = this.currentGridLayer;
			this._redraw();
		},

		setStyle: function(geoJsonStyle) {
			//hara cosas
		_onConfidencesPropSet: function() {

			this.targetQueryParams.terms.confidences = this.confidences;
			this._redraw();
		},

		_onSelectionPropSet: function() {

			this.targetQueryParams.terms.selection = this.selection;
			this._redraw();
		},

		clear: function() {

			if (this._globalG) {
				this._globalG.selectAll("g").remove();
				this._globalG.remove();
			}
			this._globalG?.selectAll('g').remove();
			this._globalG?.remove();

			this.svg && this.svg.remove();
			this.svg?.remove();
		},

		_addNewData: function(geoJsonData, moduleContext) {

			// todo - hay que limpiar si no llegan datos nuevos
			if (!this._mapInstance || (!geoJsonData || !geoJsonData.features || !geoJsonData.features.length)) {
			if (!this._mapInstance || !geoJsonData?.features?.length) {
				this.clear();
				return;
			}

@@ -97,15 +93,15 @@ define([

			this.svg = this._getSvgElement();

			this._globalG = this.svg.append("svg:g")
				.attr("class", "leaflet-zoom-hide");
			this._globalG = this.svg.append('svg:g')
				.attr('class', 'leaflet-zoom-hide');

			this.path = this._getGeoPath();

			var featureG = this._globalG.selectAll("path")
			const featureG = this._globalG.selectAll('path')
				.data(geoJsonData.features)
				.enter().append("svg:g")
					.attr('gridId', lang.hitch(this, function(d) { return d.id; }))
				.enter().append('svg:g')
					.attr('gridId', d => d.id)
					.on('mouseout', function(evt) {

						this.firstChild.setAttribute('class', 'grid-distribution');
@@ -113,134 +109,127 @@ define([
					.on('mouseover', function(evt) {

						this.firstChild.setAttribute('class', 'grid-distribution-select');
					}),
					});

				feature = featureG.append("svg:path")
					.attr("class", "grid-distribution"),
			const feature = featureG.append('svg:path')
				.attr('class', 'grid-distribution');

				text = featureG.append("svg:text");
			const text = featureG.append('svg:text');

			this._mapInstance.on("viewreset", lang.hitch(this, this._redrawByZoom, geoJsonData, feature, text));
			this._mapInstance.on('viewreset', () => this._redrawByZoom(geoJsonData, feature, text));
			this._redrawByZoom(geoJsonData, feature, text);
		},

		_getTextContent: function(d) {
			// Retorna el texto que se va a mostrar en la cuadrícula

			if (this.currentMode === 1) {
				return d.properties.registerCount;	// Número de citas
			}

			if (this.currentMode === 2) {
				return d.properties.taxonCount;//_getUniqueResults(d.properties.data).length;	// Número de species
			}

			return "";
		},

		_redrawByZoom: function(geojson, feature, text) {

			var bounds = this.path.bounds(geojson),
			const bounds = this.path.bounds(geojson),
				topLeft = bounds[0],
				bottomRight = bounds[1];

			// Se cambia los atributos con respecto al zoom
			this.svg.attr("width", bottomRight[0] - topLeft[0])
				.attr("height", bottomRight[1] - topLeft[1])
				.style("left", topLeft[0] + "px")
				.style("top", topLeft[1] + "px");
			this.svg.attr('width', bottomRight[0] - topLeft[0])
				.attr('height', bottomRight[1] - topLeft[1])
				.style('left', `${topLeft[0]}px`)
				.style('top', `${topLeft[1]}px`);

			this._globalG.attr("transform", "translate(" + -topLeft[0] + "," + -topLeft[1] + ")");
			this._globalG.attr('transform', `translate(${-topLeft[0]},${-topLeft[1]})`);

			// Se establece el texto que se va a mostrar en la cuadrícula
			text
				.attr("class", "count-text")
				.attr("style", lang.hitch(this, function(d) {

					return "font-size:" + this._getFontByZoom() + "px";
				}))
				.attr("transform", lang.hitch(this, function(d) {

					var centroid = this.path.centroid(d),
						x = centroid[0],
						y = centroid[1];
				.attr('class', 'count-text')
				.attr('style', () => `font-size:${this._getFontByZoom()}px`)
				.attr('transform', d => {

					return "translate(" + x + "," + y + ")" ;
				}))
				.text(lang.hitch(this, function(d) {
					const centroid = this.path.centroid(d);

					return lang.hitch(this, this._getTextContent)(d);
				}));
					return `translate(${centroid[0]},${centroid[1]})`
				})
				.text(d => this._getTextContent.call(this, d));

			feature.attr("d", this.path);
			feature.attr('d', this.path);
		},

		_getFontByZoom: function() {

			var zoom = this._mapInstance.getZoom(),
			const zoom = this._mapInstance.getZoom(),
				zoomMin = this.scale[this.currentGridLayer].zoom,
				factor = this.scale[this.currentGridLayer].factor;

			return zoom >= zoomMin ? ((Math.pow(2, zoom) / 10000) * factor) : 0;
		},

		_requestLayerInfo: function(res) {
		_getTextContent: function(d) {
			// Retorna el texto que se va a mostrar en la cuadrícula

			var pos = res.latLng;
			if (this.currentMode === 1) {
				return d.properties.registerCount;	// Número de citas
			}

			if (!pos || !this._globalG) {
				this._emitLayerInfo();
				return;
			if (this.currentMode === 2) {
				return d.properties.taxonCount;//_getUniqueResults(d.properties.data).length;	// Número de species
			}

			var elementsClicked = this._globalG.selectAll("g")
				.filter(function(d, i) {
			return '';
		},

					return L.polygon(d.geometry.coordinates).getBounds().contains([pos.lng, pos.lat]);
				});
		_requestLayerInfo: function(res) {

			if (elementsClicked.size()) {
				var element = d3.select(elementsClicked.node()),
					id = element.attr("gridId"),
					selectionId = Credentials.get("selectIds")[this.target.replace("/" + this.currentGridLayer, "")];
			const pos = res.latLng;

				this.infoTarget = this.target + "/" + id;
			if (!pos || !this._globalG) {
				this._emitLayerInfo();
				return;
			}

				this._publish(this.infoFilter.getChannel('SET_PROPS'), {
					target: this.infoTarget
				});
			const elementsClicked = this._globalG.selectAll('g')
				.filter((d, i) => L.polygon(d.geometry.coordinates).getBounds().contains([pos.lng, pos.lat]));

				this._emitAddToQuery(selectionId);
			} else {
			if (!elementsClicked.size()) {
				this._emitLayerInfo();
				return;
			}
		},

		_emitLayerInfo: function(info) {
			const element = d3.select(elementsClicked.node()),
				gridId = element.attr('gridId');

			this._emitEvt('LAYER_INFO', {
				layerId: this.layerId,
				layerLabel: this.layerLabel,
				info: info
			});
			this._requestInfoData(gridId);
		},

		_emitAddToQuery: function(selectionId) {
		_requestInfoData: function(gridId) {

			const path = {
				grid: this.currentGridLayer,
				tile: gridId
			};

			this._publish(this.infoFilter.getChannel("ADD_TO_QUERY"), {
				query: {
			const query = {
				terms: {
						selection: selectionId,
					selection: this.selection,
					confidences: this.confidences
				}
				},
			};

			this._emitEvt('REQUEST', {
				method: 'POST',
				target: this.infoTarget,
				params: {path, query},
				requesterId: this.getOwnChannel()
			});

		},

		_processLayerInfo: function(data) {

			this._emitLayerInfo(data);
		},

		_emitLayerInfo: function(info) {

			this._emitEvt('LAYER_INFO', {
				layerId: this.layerId,
				layerLabel: this.layerLabel,
				info: info
			});
		}
	});
});
+1 −3
Original line number Diff line number Diff line
@@ -32,8 +32,7 @@ define([
			// TODO realmente se quiere evitar límites? puede causar fallos en el lado del servicio
			// preferible mostrar aviso si se llega al límite
			const query = {
				size: null,
				qFlags: [1]
				size: null
			};

			this._emitEvt('ADD_REQUEST_PARAMS', {
@@ -67,7 +66,6 @@ define([
			this._emitEvt('REQUEST', {
				method: 'POST',
				target: this.target,
				action: '_search',
				params: {path, query},
				requesterId: this.getOwnChannel()
			});
+1 −1
Original line number Diff line number Diff line
@@ -119,7 +119,7 @@ define([

			if (category === 0) {
				templatePopup = SpeciesDistributionPopup;
				targetPopup = redmicConfig.services.citationAll;
				targetPopup = redmicConfig.services.citationInfo;
				parseData = this._parseCitationData;
			} else {
				templatePopup = TrackingSecondaryList;
Loading