Commit 02e46d9e authored by Pedro Eduardo Trujillo's avatar Pedro Eduardo Trujillo
Browse files

Reimplementa tracking en nuevo diseño de mapa

Reorganiza toda la lógica existente de manejo de datos de seguimiento
(tracking) en nuevas extensiones del diseño de mapa, de tal manera que
sea modular y reutilizable por completo o en partes desde otros
componentes, como la vista de tracking general (pendiente de adaptar).
Por el momento, soporta la carga de datos de seguimiento desde
actividades (en su vista detalle) y prepara el terrero para los datos de
seguimiento acústico.

De paso, habilita la posibilidad de realizar búsquedas por texto en el
listado de elementos de tracking. Fix #104. Por ahora falla la petición
de filtrado, se corregirán los parámetros de búsqueda para que filtre
correctamente.

Elimina basurilla de salida por consola.
parent 986c6035
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -100,7 +100,6 @@ define([
				target = this._getSelectionTarget(),
				selectEvent = this.simpleSelection ? 'SELECT_SINGLE_ITEM' : 'SELECT_ITEM';

			console.log('sele', selectEvent, {itemId, item, target})
			this._emitEvt(selectEvent, {itemId, item, target});
		},

@@ -110,7 +109,6 @@ define([
				item = req.item,
				target = this._getSelectionTarget();

			console.log('desele', {itemId, item, target})
			this._emitEvt('DESELECT_ITEM', {itemId, item, target});
		},

+0 −2
Original line number Diff line number Diff line
@@ -133,8 +133,6 @@ define([

		_valueChanged: function(res) {

			//console.log(res);

			var value = res.value || res[this.propertyName];

			this.contentTemplateNode.innerHTML = templateFilterColorRamp({
+1 −1
Original line number Diff line number Diff line
@@ -137,7 +137,7 @@ define([

		_cancelCallback: function(id) {

			//console.log("cancel con id = ", id);
			// TODO
		},

		_subRemove: function(res) {
+144 −0
Original line number Diff line number Diff line
define([
	'dojo/_base/declare'
	, 'dojo/_base/lang'
	, 'src/component/components/ProgressSlider/ProgressSlider'
], function(
	declare
	, lang
	, ProgressSlider
) {

	return declare(null, {
		// summary:
		//   Lógica de diseño para añadir un componente ProgressSlider, para visualizar datos de forma progresiva
		//   sobre el mapa.
		//   Debe asociarse como mixin a un componente al instanciarlo, junto con la parte de controlador y alguna
		//   maquetación de este diseño.

		postMixInProperties: function() {

			const defaultConfig = {
				events: {
					SET_PROGRESS_MAX: 'setProgressMax',
					SET_PROGRESS_MIN: 'setProgressMin',
					SET_PROGRESS_TIMEOUT: 'setProgressTimeout',
					SET_PROGRESS_DELTA: 'setProgressDelta',
					PRESS_PROGRESS_BUTTON: 'pressProgressButton'
				},
				topbarNodeClasses: 'mediumSolidContainer.rounded.barSliderContainer'
			};

			this._mergeOwnAttributes(defaultConfig);

			this.inherited(arguments);
		},

		_setConfigurations: function() {

			this.inherited(arguments);

			const parentChannel = this.getChannel();

			this.mergeComponentAttribute('progressSliderConfig', {
				parentChannel,
				props: {
					showValue: true,
					valueInTooltip: false
				}
			});
		},

		createDesignControllerComponents: function() {

			const inheritedComponents = this.inherited(arguments);

			const progressSlider = this._createDesignProgressSliderComponent();

			return lang.mixin(inheritedComponents, {progressSlider});
		},

		_createDesignProgressSliderComponent: function() {

			return new ProgressSlider(this.progressSliderConfig);
		},

		_setOwnCallbacksForEvents: function() {

			this.inherited(arguments);

			this.on('ME_OR_ANCESTOR_HIDDEN', () => this._addProgressSliderComponentOnHide());
		},

		_defineSubscriptions: function() {

			this.inherited(arguments);

			const progressSliderInstance = this.getComponentInstance('progressSlider');

			this.subscriptionsConfig.push({
				channel: progressSliderInstance.getChannel('CHANGE_VALUE'),
				callback: '_subProgressSliderChangeValue'
			});
		},

		_definePublications: function() {

			this.inherited(arguments);

			const progressSliderInstance = this.getComponentInstance('progressSlider');

			this.publicationsConfig.push({
				event: 'SET_PROGRESS_MAX',
				channel: progressSliderInstance.getChannel('SET_MAX')
			},{
				event: 'SET_PROGRESS_MIN',
				channel: progressSliderInstance.getChannel('SET_MIN')
			},{
				event: 'SET_PROGRESS_TIMEOUT',
				channel: progressSliderInstance.getChannel('SET_TIMEOUT')
			},{
				event: 'SET_PROGRESS_DELTA',
				channel: progressSliderInstance.getChannel('SET_DELTA')
			},{
				event: 'PRESS_PROGRESS_BUTTON',
				channel: progressSliderInstance.getChannel('BUTTON_ACTION')
			});
		},

		populateDesignLayoutNodes: function() {

			this.inherited(arguments);

			const progressSliderInstance = this.getComponentInstance('progressSlider'),
				topbarNode = this.getLayoutNode('topbar');

			this._publish(progressSliderInstance.getChannel('SHOW'), {
				node: topbarNode
			});
		},

		_subProgressSliderChangeValue: function(res) {

			this._onProgressSliderChangeValue?.(res);
		},

		_updateProgressSliderLimits: function(/*Object*/ limits, /*Boolean?*/ reset) {

			this._emitEvt('SET_PROGRESS_MIN', {
				value: limits?.min,
				reset: !!reset
			});

			this._emitEvt('SET_PROGRESS_MAX', {
				value: limits?.max
			});
		},

		_addProgressSliderComponentOnHide: function() {

			this._emitEvt('PRESS_PROGRESS_BUTTON', {
				key: 'PAUSE'
			});
		}
	});
});
+242 −0
Original line number Diff line number Diff line
define([
	'd3'
	, 'dojo/_base/declare'
	, 'moment'
	, 'src/design/map/_AddBrowserComponent'
	, 'src/design/map/_AddProgressSliderComponent'
	, 'src/design/map/_AddTrackingMapLayerComponents'
	, 'src/design/map/_AddTrackingSettingsComponent'
	, 'src/redmicConfig'
	, 'templates/ActivityList'
	, 'templates/AnimalList'
	, 'templates/TrackingPlatformList'
], function(
	d3
	, declare
	, moment
	, _AddBrowserComponent
	, _AddProgressSliderComponent
	, _AddTrackingMapLayerComponents
	, _AddTrackingSettingsComponent
	, redmicConfig
	, TemplateActivityList
	, TemplateAnimalList
	, TemplatePlatformList
) {

	return declare([_AddBrowserComponent, _AddTrackingSettingsComponent, _AddProgressSliderComponent,
		_AddTrackingMapLayerComponents], {
		// summary:
		//   Lógica de diseño para añadir los componentes necesarios para visualizar datos de seguimiento sobre el mapa.
		//   Debe asociarse como mixin a un componente al instanciarlo, junto con la parte de controlador y alguna
		//   maquetación de este diseño.

		postMixInProperties: function() {

			this.inherited(arguments);

			const defaultConfig = {
				typeGroupProperty: 'category',
				idProperty: 'uuid',
				enabledBrowserExtensions: {
					selectionManager: true,
					multiTemplate: true
				},
				browserTabIconClass: 'fr fr-track',
				_availableColors: d3.schemePaired,
				_colorsUsage: {},
				_trackingDataLimits: {}
			};

			this._mergeOwnAttributes(defaultConfig);
		},

		_setConfigurations: function() {

			this.inherited(arguments);

			this.mergeComponentAttribute('browserConfig', {
				rowConfig: {
					buttonsConfig: {
						listButton: [{
							icon: 'fa-tint',
							btnId: 'colorPicker',
							title: 'color',
							condition: item => item.color,
							startup: (nodeIcon, item) => {
								if (!item.color) {
									return;
								}
								const iconStyle = `color:${item.color} !important; text-shadow: 0px 0px 3px white;`;
								nodeIcon.setAttribute('style', iconStyle);
							}
						},{
							icon: 'fa-info-circle',
							btnId: 'details',
							title: 'info',
							href: [
								redmicConfig.viewPaths.activityDetails,
								redmicConfig.viewPaths.platformDetails,
								redmicConfig.viewPaths.animalDetails
							],
							chooseHref: item => {
								if (item.activityType) {
									return 0;
								}
								if (item.platformType) {
									return 1;
								}
								if (item.lifeStage) {
									return 2;
								}
							},
							condition: item => item.activityType || item.platformType || item.lifeStage
						}]
					},
					selectionIdProperty: this.idProperty
				},
				idProperty: this.idProperty,
				existsPropertyWithTemplate: true,
				template: TemplateActivityList,
				templatesByTypeGroup: {
					activityType: TemplateActivityList,
					taxon: TemplateAnimalList,
					platformType: TemplatePlatformList
				}
			});

			this.mergeComponentAttribute('queryOnMapConfig', {
				typeGroupProperty: this.typeGroupProperty
			});
		},

		_onItemSelected: function(res) {

			this.inherited(arguments);

			const itemId = res.itemId,
				activityId = this.pathVariableId,
				color = this._getFreeColor(itemId);

			this._addTrackingLayer?.({
				[this.idProperty]: itemId,
				activityId,
				color
			});
			this._updateBrowserItem(itemId, {color});
		},

		_onItemDeselected: function(res) {

			this.inherited(arguments);

			const itemId = res.itemId;

			this._releaseColor(itemId);

			this._removeTrackingLayer?.(itemId);
			this._updateBrowserItem(itemId, {
				color: null
			});
		},

		_getFreeColor: function(itemId) {

			const color = this._availableColors.find(
				(_color, index) => !Object.values(this._colorsUsage).includes(index));

			if (color) {
				this._colorsUsage[itemId] = this._availableColors.indexOf(color);
			}
			return color;
		},

		_releaseColor: function(itemId) {

			delete this._colorsUsage[itemId];
		},

		_updateBrowserItem: function(itemId, data) {

			data[this.idProperty] = itemId;

			const target = this._getTarget?.();

			this._emitEvt('INJECT_ITEM', {data, target});
		},

		_setTrackingItemLineLimits: function(lineLimits) {

			const itemId = lineLimits.layerId,
				itemLineId = lineLimits.lineId,
				count = lineLimits.count,
				start = moment(lineLimits.start),
				end = moment(lineLimits.end),
				itemLimits = this._getTrackingItemLimits(itemId);

			itemLimits[itemLineId] = {count, start, end};
		},

		_getTrackingItemLimits: function(itemId) {

			const trackingItemLimits = this._trackingDataLimits[itemId] ?? {};
			this._trackingDataLimits[itemId] = trackingItemLimits;

			return trackingItemLimits;
		},

		_applyTrackingDataLimits: function(/*Boolean?*/ reset) {

			const limits = this._getTrackingDataRange();

			this._updateProgressSliderLimits?.(limits, reset);
		},

		_getTrackingDataRange: function() {

			const limits = {
				max: 0,
				min: 0
			};

			Object.values(this._trackingDataLimits).forEach(itemLimits =>
				Object.values(itemLimits).forEach(itemLineLimits =>
					this._evaluateItemLineLimits(itemLineLimits, limits)));

			return limits;
		},

		_evaluateItemLineLimits: function(itemLineLimits, limits) {

			if (!this.timeMode) {
				const count = itemLineLimits.count;

				if (count > limits.max) {
					limits.max = count;
				}

				return;
			}

			const start = itemLineLimits.start,
				end = itemLineLimits.end;

			if (!limits.min || start.isBefore(limits.min)) {
				limits.min = start;
			}
			if (!limits.max || end.isAfter(limits.max)) {
				limits.max = end;
			}
		},

		_deleteTrackingItemLimits: function(itemId) {

			delete this._trackingDataLimits[itemId];
		},

		// TODO sigue aqui
		_startupColorIcon: function(nodeIcon, item) {

		}
	});
});
Loading