2019-02-26 12:32:37 +02:00
|
|
|
/*
|
2019-03-01 10:29:46 +02:00
|
|
|
* Copyright © 2016-2019 The Thingsboard Authors
|
2019-02-26 12:32:37 +02:00
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
import './trip-animation-widget.scss';
|
|
|
|
|
import template from "./trip-animation-widget.tpl.html";
|
|
|
|
|
import TbOpenStreetMap from '../openstreet-map';
|
|
|
|
|
import L from 'leaflet';
|
|
|
|
|
//import tinycolor from 'tinycolor2';
|
|
|
|
|
import tinycolor from "tinycolor2";
|
|
|
|
|
import {fillPatternWithActions, isNumber, padValue, processPattern} from "../widget-utils";
|
|
|
|
|
//import {fillPatternWithActions, isNumber, padValue, processPattern, fillPattern} from "../widget-utils";
|
|
|
|
|
|
|
|
|
|
(function () {
|
|
|
|
|
// save these original methods before they are overwritten
|
|
|
|
|
var proto_initIcon = L.Marker.prototype._initIcon;
|
|
|
|
|
var proto_setPos = L.Marker.prototype._setPos;
|
|
|
|
|
|
|
|
|
|
var oldIE = (L.DomUtil.TRANSFORM === 'msTransform');
|
|
|
|
|
|
|
|
|
|
L.Marker.addInitHook(function () {
|
|
|
|
|
var iconOptions = this.options.icon && this.options.icon.options;
|
|
|
|
|
var iconAnchor = iconOptions && this.options.icon.options.iconAnchor;
|
|
|
|
|
if (iconAnchor) {
|
|
|
|
|
iconAnchor = (iconAnchor[0] + 'px ' + iconAnchor[1] + 'px');
|
|
|
|
|
}
|
|
|
|
|
this.options.rotationOrigin = this.options.rotationOrigin || iconAnchor || 'center bottom';
|
|
|
|
|
this.options.rotationAngle = this.options.rotationAngle || 0;
|
|
|
|
|
|
|
|
|
|
// Ensure marker keeps rotated during dragging
|
|
|
|
|
this.on('drag', function (e) {
|
|
|
|
|
e.target._applyRotation();
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
L.Marker.include({
|
|
|
|
|
_initIcon: function () {
|
|
|
|
|
proto_initIcon.call(this);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_setPos: function (pos) {
|
|
|
|
|
proto_setPos.call(this, pos);
|
|
|
|
|
this._applyRotation();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
_applyRotation: function () {
|
|
|
|
|
if (this.options.rotationAngle) {
|
|
|
|
|
this._icon.style[L.DomUtil.TRANSFORM + 'Origin'] = this.options.rotationOrigin;
|
|
|
|
|
|
|
|
|
|
if (oldIE) {
|
|
|
|
|
// for IE 9, use the 2D rotation
|
|
|
|
|
this._icon.style[L.DomUtil.TRANSFORM] = 'rotate(' + this.options.rotationAngle + 'deg)';
|
|
|
|
|
} else {
|
|
|
|
|
// for modern browsers, prefer the 3D accelerated version
|
|
|
|
|
let rotation = ' rotateZ(' + this.options.rotationAngle + 'deg)';
|
|
|
|
|
if (!this._icon.style[L.DomUtil.TRANSFORM].includes(rotation)) {
|
|
|
|
|
this._icon.style[L.DomUtil.TRANSFORM] += rotation;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
setRotationAngle: function (angle) {
|
|
|
|
|
this.options.rotationAngle = angle;
|
|
|
|
|
this.update();
|
|
|
|
|
return this;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
setRotationOrigin: function (origin) {
|
|
|
|
|
this.options.rotationOrigin = origin;
|
|
|
|
|
this.update();
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
})();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default angular.module('thingsboard.widgets.tripAnimation', [])
|
|
|
|
|
.directive('tripAnimation', tripAnimationWidget)
|
|
|
|
|
.filter('tripAnimation', function ($filter) {
|
|
|
|
|
return function (label) {
|
|
|
|
|
label = label.toString();
|
|
|
|
|
|
|
|
|
|
let translateSelector = "widgets.tripAnimation." + label;
|
|
|
|
|
let translation = $filter('translate')(translateSelector);
|
|
|
|
|
|
|
|
|
|
if (translation !== translateSelector) {
|
|
|
|
|
return translation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return label;
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.name;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*@ngInject*/
|
|
|
|
|
function tripAnimationWidget() {
|
|
|
|
|
return {
|
|
|
|
|
restrict: "E",
|
|
|
|
|
scope: true,
|
|
|
|
|
bindToController: {
|
|
|
|
|
ctx: '=',
|
|
|
|
|
self: '='
|
|
|
|
|
},
|
|
|
|
|
controller: tripAnimationController,
|
|
|
|
|
controllerAs: 'vm',
|
|
|
|
|
templateUrl: template
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*@ngInject*/
|
2019-03-18 13:38:17 +02:00
|
|
|
function tripAnimationController($document, $scope, $http, $timeout, $filter) {
|
2019-02-26 12:32:37 +02:00
|
|
|
let vm = this;
|
|
|
|
|
//const varsRegex = /\$\{([^\}]*)\}/g;
|
|
|
|
|
//let icon;
|
|
|
|
|
|
2019-03-07 18:00:49 +02:00
|
|
|
vm.initBounds = true;
|
|
|
|
|
|
2019-02-26 12:32:37 +02:00
|
|
|
vm.markers = [];
|
|
|
|
|
vm.index = 0;
|
|
|
|
|
vm.dsIndex = 0;
|
|
|
|
|
vm.isPlaying = false;
|
|
|
|
|
vm.minTime = 0;
|
|
|
|
|
vm.maxTime = 0;
|
|
|
|
|
vm.isPLaying = false;
|
|
|
|
|
vm.trackingLine = {
|
|
|
|
|
"type": "FeatureCollection",
|
|
|
|
|
features: []
|
|
|
|
|
};
|
|
|
|
|
vm.speeds = [1, 5, 10, 25];
|
|
|
|
|
vm.speed = 1;
|
|
|
|
|
vm.trips = [];
|
|
|
|
|
vm.activeTripIndex = 0;
|
|
|
|
|
|
|
|
|
|
vm.showHideTooltip = showHideTooltip;
|
|
|
|
|
vm.recalculateTrips = recalculateTrips;
|
|
|
|
|
|
|
|
|
|
$scope.$watch('vm.ctx', function () {
|
|
|
|
|
if (vm.ctx) {
|
|
|
|
|
vm.utils = vm.ctx.$scope.$injector.get('utils');
|
|
|
|
|
vm.settings = vm.ctx.settings;
|
|
|
|
|
vm.widgetConfig = vm.ctx.widgetConfig;
|
|
|
|
|
vm.data = vm.ctx.data;
|
|
|
|
|
vm.datasources = vm.ctx.datasources;
|
|
|
|
|
configureStaticSettings();
|
|
|
|
|
initialize();
|
|
|
|
|
initializeCallbacks();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function initializeCallbacks() {
|
|
|
|
|
vm.self.onDataUpdated = function () {
|
|
|
|
|
createUpdatePath();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
vm.self.onResize = function () {
|
|
|
|
|
resize();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
vm.self.typeParameters = function () {
|
|
|
|
|
return {
|
|
|
|
|
maxDatasources: 1, // Maximum allowed datasources for this widget, -1 - unlimited
|
|
|
|
|
maxDataKeys: -1 //Maximum allowed data keys for this widget, -1 - unlimited
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function resize() {
|
|
|
|
|
if (vm.map) {
|
|
|
|
|
vm.map.invalidateSize();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function initCallback() {
|
|
|
|
|
//createUpdatePath();
|
|
|
|
|
//resize();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vm.playMove = function (play) {
|
|
|
|
|
if (play && vm.isPLaying) return;
|
|
|
|
|
if (play || vm.isPLaying) vm.isPLaying = true;
|
|
|
|
|
if (vm.isPLaying) {
|
|
|
|
|
if (vm.index + 1 > vm.maxTime) return;
|
|
|
|
|
vm.index++;
|
|
|
|
|
vm.trips.forEach(function (trip) {
|
|
|
|
|
moveMarker(trip);
|
|
|
|
|
});
|
|
|
|
|
vm.timeout = $timeout(function () {
|
|
|
|
|
vm.playMove();
|
|
|
|
|
}, 1000 / vm.speed)
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vm.stopPlay = function () {
|
|
|
|
|
vm.isPLaying = false;
|
|
|
|
|
$timeout.cancel(vm.timeout);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function recalculateTrips() {
|
|
|
|
|
vm.trips.forEach(function (value) {
|
|
|
|
|
moveMarker(value);
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function findAngle(lat1, lng1, lat2, lng2) {
|
|
|
|
|
let angle = Math.atan2(0, 0) - Math.atan2(lat2 - lat1, lng2 - lng1);
|
|
|
|
|
angle = angle * 180 / Math.PI;
|
|
|
|
|
return parseInt(angle.toFixed(2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function initialize() {
|
|
|
|
|
$scope.currentDate = $filter('date')(0, "yyyy.MM.dd HH:mm:ss");
|
|
|
|
|
|
|
|
|
|
vm.self.actionSources = [vm.searchAction];
|
|
|
|
|
vm.endpoint = vm.ctx.settings.endpointUrl;
|
|
|
|
|
$scope.title = vm.ctx.widgetConfig.title;
|
|
|
|
|
vm.utils = vm.self.ctx.$scope.$injector.get('utils');
|
|
|
|
|
|
|
|
|
|
vm.showTimestamp = vm.settings.showTimestamp !== false;
|
|
|
|
|
vm.ctx.$element = angular.element("#heat-map", vm.ctx.$container);
|
2019-03-07 18:00:49 +02:00
|
|
|
vm.defaultZoomLevel = 2;
|
|
|
|
|
if (vm.ctx.settings.defaultZoomLevel) {
|
|
|
|
|
if (vm.ctx.settings.defaultZoomLevel > 0 && vm.ctx.settings.defaultZoomLevel < 21) {
|
|
|
|
|
vm.defaultZoomLevel = Math.floor(vm.ctx.settings.defaultZoomLevel);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
vm.dontFitMapBounds = vm.ctx.settings.fitMapBounds === false;
|
|
|
|
|
vm.map = new TbOpenStreetMap(vm.ctx.$element, vm.utils, initCallback, vm.defaultZoomLevel, vm.dontFitMapBounds, null, vm.staticSettings.mapProvider);
|
2019-02-26 12:32:37 +02:00
|
|
|
vm.map.bounds = vm.map.createBounds();
|
|
|
|
|
vm.map.invalidateSize(true);
|
|
|
|
|
vm.map.bounds = vm.map.createBounds();
|
|
|
|
|
|
|
|
|
|
vm.tooltipActionsMap = {};
|
|
|
|
|
var descriptors = vm.ctx.actionsApi.getActionDescriptors('tooltipAction');
|
|
|
|
|
descriptors.forEach(function (descriptor) {
|
|
|
|
|
if (descriptor) vm.tooltipActionsMap[descriptor.name] = descriptor;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function configureStaticSettings() {
|
|
|
|
|
let staticSettings = {};
|
|
|
|
|
vm.staticSettings = staticSettings;
|
|
|
|
|
//Calculate General Settings
|
|
|
|
|
staticSettings.mapProvider = vm.ctx.settings.mapProvider || "OpenStreetMap.Mapnik";
|
|
|
|
|
staticSettings.latKeyName = vm.ctx.settings.latKeyName || "latitude";
|
|
|
|
|
staticSettings.lngKeyName = vm.ctx.settings.lngKeyName || "longitude";
|
|
|
|
|
staticSettings.rotationAngle = vm.ctx.settings.rotationAngle || 0;
|
|
|
|
|
staticSettings.displayTooltip = vm.ctx.settings.showTooltip || false;
|
2019-03-07 18:00:49 +02:00
|
|
|
staticSettings.defaultZoomLevel = vm.ctx.settings.defaultZoomLevel || true;
|
2019-02-26 12:32:37 +02:00
|
|
|
staticSettings.showTooltip = false;
|
|
|
|
|
staticSettings.label = vm.ctx.settings.label || "${entityName}";
|
|
|
|
|
staticSettings.useLabelFunction = vm.ctx.settings.useLabelFunction || false;
|
|
|
|
|
staticSettings.showLabel = vm.ctx.settings.showLabel || false;
|
|
|
|
|
staticSettings.useTooltipFunction = vm.ctx.settings.useTooltipFunction || false;
|
|
|
|
|
staticSettings.tooltipPattern = vm.ctx.settings.tooltipPattern || "<b>${entityName}</b><br/><br/><b>Latitude:</b> ${latitude:7}<br/><b>Longitude:</b> ${longitude:7}<br/><b>Start Time:</b> ${maxTime}<br/><b>End Time:</b> ${minTime}";
|
|
|
|
|
staticSettings.tooltipOpacity = vm.ctx.settings.tooltipOpacity || 1;
|
|
|
|
|
staticSettings.tooltipColor = vm.ctx.settings.tooltipColor ? tinycolor(vm.ctx.settings.tooltipColor).toHexString() : "#ffffff";
|
|
|
|
|
staticSettings.tooltipFontColor = vm.ctx.settings.tooltipFontColor ? tinycolor(vm.ctx.settings.tooltipFontColor).toHexString() : "#000000";
|
|
|
|
|
staticSettings.pathColor = vm.ctx.settings.color ? tinycolor(vm.ctx.settings.color).toHexString() : "#ff6300";
|
|
|
|
|
staticSettings.pathWeight = vm.ctx.settings.strokeWeight || 1;
|
|
|
|
|
staticSettings.pathOpacity = vm.ctx.settings.strokeOpacity || 1;
|
|
|
|
|
staticSettings.usePathColorFunction = vm.ctx.settings.useColorFunction || false;
|
|
|
|
|
staticSettings.showPoints = vm.ctx.settings.showPoints || false;
|
|
|
|
|
staticSettings.pointSize = vm.ctx.settings.pointSize || 1;
|
|
|
|
|
staticSettings.markerImageSize = vm.ctx.settings.markerImageSize || 20;
|
|
|
|
|
staticSettings.useMarkerImageFunction = vm.ctx.settings.useMarkerImageFunction || false;
|
|
|
|
|
staticSettings.pointColor = vm.ctx.settings.pointColor ? tinycolor(vm.ctx.settings.pointColor).toHexString() : "#ff6300";
|
|
|
|
|
staticSettings.markerImages = vm.ctx.settings.markerImages || [];
|
|
|
|
|
staticSettings.icon = L.icon({
|
2019-03-07 18:00:49 +02:00
|
|
|
iconUrl: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKoAAACqCAYAAAA9dtSCAAAAhnpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjadY7LDcAwCEPvTNERCBA+40RVI3WDjl+iNMqp7wCWBZbheu4Ox6AggVRzDVVMJCSopXCcMGIhLGPnnHybSyraNjBNoeGGsg/l8xeV1bWbmGnVU0/KdLqY2HPmH4xUHDVih7S2Gv34q8ULVzos2Vmq5r4AAAoGaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/Pgo8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA0LjQuMC1FeGl2MiI+CiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyIKICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIgogICBleGlmOlBpeGVsWERpbWVuc2lvbj0iMTcwIgogICBleGlmOlBpeGVsWURpbWVuc2lvbj0iMTcwIgogICB0aWZmOkltYWdlV2lkdGg9IjE3MCIKICAgdGlmZjpJbWFnZUhlaWdodD0iMTcwIgogICB0aWZmOk9yaWVudGF0aW9uPSIxIi8+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgCjw/eHBhY2tldCBlbmQ9InciPz7hlLlNAAAABHNCSVQICAgIfAhkiAAAIABJREFUeNrtnXmcXFWZ97/Pubeq1+wJSQghhHQ2FUFlFVdUlEXAAVFBQZh3cAy4ESGbCBHIQiTKxHUW4FVwGcAFFMRhkWEZfZkBZJQkTRASIGHJQpbequ49z/vHre7cqrpVXd1da3edz6c+XX1rv+d3f+f3/M5zniPUW87WulAnTnN5i8IBYpnsttKoSZoVpitMFssoIIbSqIILxFIvVVGsQjdCQoSEKvtweMkIrwh0+gm6fMtWA7s2XicP1s92/ib1U7C/TfmCThrXyvm+5TgnzgwRWtUyDksL0GJigIJq8LevaWFnWMz+YzYJCHsRusSwHej2etiA8HT7Klld7406UAFou1yPdVyOclxm
|
2019-02-26 12:32:37 +02:00
|
|
|
iconSize: [30, 30],
|
|
|
|
|
iconAnchor: [15, 15]
|
|
|
|
|
});
|
|
|
|
|
if (angular.isDefined(vm.ctx.settings.markerImage)) {
|
|
|
|
|
staticSettings.icon = L.icon({
|
|
|
|
|
iconUrl: vm.ctx.settings.markerImage,
|
|
|
|
|
iconSize: [staticSettings.markerImageSize, staticSettings.markerImageSize],
|
|
|
|
|
iconAnchor: [(staticSettings.markerImageSize / 2), (staticSettings.markerImageSize / 2)]
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (staticSettings.usePathColorFunction && angular.isDefined(vm.ctx.settings.colorFunction)) {
|
|
|
|
|
staticSettings.colorFunction = new Function('data, dsData, dsIndex', vm.ctx.settings.colorFunction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (staticSettings.useLabelFunction && angular.isDefined(vm.ctx.settings.labelFunction)) {
|
|
|
|
|
staticSettings.labelFunction = new Function('data, dsData, dsIndex', vm.ctx.settings.labelFunction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (staticSettings.useTooltipFunction && angular.isDefined(vm.ctx.settings.tooltipFunction)) {
|
|
|
|
|
staticSettings.tooltipFunction = new Function('data, dsData, dsIndex', vm.ctx.settings.tooltipFunction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (staticSettings.useMarkerImageFunction && angular.isDefined(vm.ctx.settings.markerImageFunction)) {
|
|
|
|
|
staticSettings.markerImageFunction = new Function('data, images, dsData, dsIndex', vm.ctx.settings.markerImageFunction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!staticSettings.useMarkerImageFunction &&
|
|
|
|
|
angular.isDefined(vm.ctx.settings.markerImage) &&
|
|
|
|
|
vm.ctx.settings.markerImage.length > 0) {
|
|
|
|
|
staticSettings.useMarkerImage = true;
|
|
|
|
|
let url = vm.ctx.settings.markerImage;
|
|
|
|
|
let size = staticSettings.markerImageSize || 20;
|
|
|
|
|
staticSettings.currentImage = {
|
|
|
|
|
url: url,
|
|
|
|
|
size: size
|
|
|
|
|
};
|
|
|
|
|
vm.utils.loadImageAspect(staticSettings.currentImage.url).then(
|
|
|
|
|
(aspect) => {
|
|
|
|
|
if (aspect) {
|
|
|
|
|
let width;
|
|
|
|
|
let height;
|
|
|
|
|
if (aspect > 1) {
|
|
|
|
|
width = staticSettings.currentImage.size;
|
|
|
|
|
height = staticSettings.currentImage.size / aspect;
|
|
|
|
|
} else {
|
|
|
|
|
width = staticSettings.currentImage.size * aspect;
|
|
|
|
|
height = staticSettings.currentImage.size;
|
|
|
|
|
}
|
|
|
|
|
staticSettings.icon = L.icon({
|
|
|
|
|
iconUrl: staticSettings.currentImage.url,
|
|
|
|
|
iconSize: [width, height],
|
|
|
|
|
iconAnchor: [width / 2, height / 2]
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (vm.trips) {
|
|
|
|
|
vm.trips.forEach(function (trip) {
|
|
|
|
|
if (trip.marker) {
|
|
|
|
|
trip.marker.setIcon(staticSettings.icon);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function configureTripSettings(trip) {
|
|
|
|
|
trip.settings = {};
|
|
|
|
|
trip.settings.color = calculateColor(trip);
|
|
|
|
|
trip.settings.strokeWeight = vm.staticSettings.pathWeight;
|
|
|
|
|
trip.settings.strokeOpacity = vm.staticSettings.pathOpacity;
|
|
|
|
|
trip.settings.pointColor = vm.staticSettings.pointColor;
|
|
|
|
|
trip.settings.pointSize = vm.staticSettings.pointSize;
|
|
|
|
|
trip.settings.labelText = calculateLabel(trip);
|
|
|
|
|
trip.settings.tooltipText = calculateTooltip(trip);
|
|
|
|
|
trip.settings.icon = calculateIcon(trip);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function calculateLabel(trip) {
|
|
|
|
|
let label = '';
|
|
|
|
|
if (vm.staticSettings.showLabel) {
|
|
|
|
|
let labelReplaceInfo;
|
|
|
|
|
let labelText = vm.staticSettings.label;
|
|
|
|
|
if (vm.staticSettings.useLabelFunction && angular.isDefined(vm.staticSettings.labelFunction)) {
|
|
|
|
|
try {
|
|
|
|
|
labelText = vm.staticSettings.labelFunction(vm.ctx.data, trip.timeRange[vm.index], trip.dsIndex);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
labelText = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
labelText = vm.utils.createLabelFromDatasource(trip.dataSource, labelText);
|
|
|
|
|
labelReplaceInfo = processPattern(labelText, vm.ctx.datasources, trip.dSIndex);
|
|
|
|
|
label = fillPattern(labelText, labelReplaceInfo, trip.timeRange[vm.index]);
|
|
|
|
|
if (vm.staticSettings.useLabelFunction && angular.isDefined(vm.staticSettings.labelFunction)) {
|
|
|
|
|
try {
|
|
|
|
|
labelText = vm.staticSettings.labelFunction(vm.ctx.data, trip.timeRange[vm.index], trip.dSIndex);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
labelText = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return label;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function calculateTooltip(trip) {
|
|
|
|
|
let tooltip = '';
|
|
|
|
|
if (vm.staticSettings.displayTooltip) {
|
|
|
|
|
let tooltipReplaceInfo;
|
|
|
|
|
let tooltipText = vm.staticSettings.tooltipPattern;
|
|
|
|
|
if (vm.staticSettings.useTooltipFunction && angular.isDefined(vm.staticSettings.tooltipFunction)) {
|
|
|
|
|
try {
|
|
|
|
|
tooltipText = vm.staticSettings.tooltipFunction(vm.ctx.data, trip.timeRange[vm.index], trip.dSIndex);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
tooltipText = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
tooltipText = vm.utils.createLabelFromDatasource(trip.dataSource, tooltipText);
|
|
|
|
|
tooltipReplaceInfo = processPattern(tooltipText, vm.ctx.datasources, trip.dSIndex);
|
|
|
|
|
tooltip = fillPattern(tooltipText, tooltipReplaceInfo, trip.timeRange[vm.index]);
|
|
|
|
|
tooltip = fillPatternWithActions(tooltip, 'onTooltipAction', null);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return tooltip;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function calculateColor(trip) {
|
|
|
|
|
let color = vm.staticSettings.pathColor;
|
|
|
|
|
let colorFn;
|
|
|
|
|
if (vm.staticSettings.usePathColorFunction && angular.isDefined(vm.staticSettings.colorFunction)) {
|
|
|
|
|
try {
|
|
|
|
|
colorFn = vm.staticSettings.colorFunction(vm.ctx.data, trip.timeRange[vm.index], trip.dSIndex);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
colorFn = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (colorFn && colorFn !== color && trip.polyline) {
|
|
|
|
|
trip.polyline.setStyle({color: colorFn});
|
|
|
|
|
}
|
|
|
|
|
return colorFn || color;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function calculateIcon(trip) {
|
|
|
|
|
let icon = vm.staticSettings.icon;
|
|
|
|
|
if (vm.staticSettings.useMarkerImageFunction && angular.isDefined(vm.staticSettings.markerImageFunction)) {
|
|
|
|
|
let rawIcon;
|
|
|
|
|
try {
|
|
|
|
|
rawIcon = vm.staticSettings.markerImageFunction(vm.ctx.data, vm.staticSettings.markerImages, trip.timeRange[vm.index], trip.dSIndex);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
rawIcon = null;
|
|
|
|
|
}
|
|
|
|
|
if (rawIcon) {
|
|
|
|
|
vm.utils.loadImageAspect(rawIcon).then(
|
|
|
|
|
(aspect) => {
|
|
|
|
|
if (aspect) {
|
|
|
|
|
let width;
|
|
|
|
|
let height;
|
|
|
|
|
if (aspect > 1) {
|
|
|
|
|
width = rawIcon.size;
|
|
|
|
|
height = rawIcon.size / aspect;
|
|
|
|
|
} else {
|
|
|
|
|
width = rawIcon.size * aspect;
|
|
|
|
|
height = rawIcon.size;
|
|
|
|
|
}
|
|
|
|
|
icon = L.icon({
|
|
|
|
|
iconUrl: rawIcon,
|
|
|
|
|
iconSize: [width, height],
|
|
|
|
|
iconAnchor: [width / 2, height / 2]
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
if (trip.marker) {
|
|
|
|
|
trip.marker.setIcon(icon);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return icon;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createUpdatePath() {
|
|
|
|
|
if (vm.trips && vm.map) {
|
|
|
|
|
vm.trips.forEach(function (trip) {
|
|
|
|
|
if (trip.marker) {
|
|
|
|
|
trip.marker.remove();
|
2019-03-07 18:00:49 +02:00
|
|
|
delete trip.marker;
|
2019-02-26 12:32:37 +02:00
|
|
|
}
|
|
|
|
|
if (trip.polyline) {
|
|
|
|
|
trip.polyline.remove();
|
2019-03-07 18:00:49 +02:00
|
|
|
delete trip.polyline;
|
2019-02-26 12:32:37 +02:00
|
|
|
}
|
|
|
|
|
if (trip.points && trip.points.length) {
|
|
|
|
|
trip.points.forEach(function (point) {
|
|
|
|
|
point.remove();
|
2019-03-07 18:00:49 +02:00
|
|
|
});
|
|
|
|
|
delete trip.points;
|
2019-02-26 12:32:37 +02:00
|
|
|
}
|
2019-03-07 18:00:49 +02:00
|
|
|
});
|
|
|
|
|
vm.initBounds = true;
|
2019-02-26 12:32:37 +02:00
|
|
|
}
|
|
|
|
|
let normalizedTimeRange = createNormalizedTime(vm.data, 1000);
|
|
|
|
|
createNormalizedTrips(normalizedTimeRange, vm.datasources);
|
|
|
|
|
createTripsOnMap();
|
2019-03-07 18:00:49 +02:00
|
|
|
if (vm.initBounds && !vm.initTrips) {
|
|
|
|
|
vm.trips.forEach(function (trip) {
|
|
|
|
|
vm.map.extendBounds(vm.map.bounds, trip.polyline);
|
|
|
|
|
vm.initBounds = !vm.datasources.every(
|
|
|
|
|
function (ds) {
|
|
|
|
|
return ds.dataReceived === true;
|
|
|
|
|
});
|
|
|
|
|
vm.initTrips = vm.trips.every(function (trip) {
|
|
|
|
|
return angular.isDefined(trip.marker) && angular.isDefined(trip.polyline);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2019-02-26 12:32:37 +02:00
|
|
|
vm.map.fitBounds(vm.map.bounds);
|
2019-03-07 18:00:49 +02:00
|
|
|
}
|
2019-02-26 12:32:37 +02:00
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function fillPattern(pattern, replaceInfo, currentNormalizedValue) {
|
|
|
|
|
let text = angular.copy(pattern);
|
|
|
|
|
let reg = /\$\{([^\}]*)\}/g;
|
|
|
|
|
if (replaceInfo) {
|
|
|
|
|
for (let v = 0; v < replaceInfo.variables.length; v++) {
|
|
|
|
|
let variableInfo = replaceInfo.variables[v];
|
|
|
|
|
let label = reg.exec(pattern)[1].split(":")[0];
|
|
|
|
|
let txtVal = '';
|
|
|
|
|
if (label.length > -1 && angular.isDefined(currentNormalizedValue[label])) {
|
|
|
|
|
let varData = currentNormalizedValue[label];
|
|
|
|
|
if (isNumber(varData)) {
|
|
|
|
|
txtVal = padValue(varData, variableInfo.valDec, 0);
|
|
|
|
|
} else {
|
|
|
|
|
txtVal = varData;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
text = text.split(variableInfo.variable).join(txtVal);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return text;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createNormalizedTime(data, step) {
|
|
|
|
|
if (!step) step = 1000;
|
|
|
|
|
let max_time = null;
|
|
|
|
|
let min_time = null;
|
|
|
|
|
let normalizedArray = [];
|
|
|
|
|
if (data && data.length > 0) {
|
|
|
|
|
vm.data.forEach(function (data) {
|
|
|
|
|
if (data.data.length > 0) {
|
|
|
|
|
data.data.forEach(function (sData) {
|
|
|
|
|
if (max_time === null) {
|
|
|
|
|
max_time = sData[0];
|
|
|
|
|
} else if (max_time < sData[0]) {
|
|
|
|
|
max_time = sData[0]
|
|
|
|
|
}
|
|
|
|
|
if (min_time === null) {
|
|
|
|
|
min_time = sData[0];
|
|
|
|
|
} else if (min_time > sData[0]) {
|
|
|
|
|
min_time = sData[0];
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
for (let i = min_time; i < max_time; i += step) {
|
|
|
|
|
normalizedArray.push({ts: i})
|
|
|
|
|
}
|
|
|
|
|
if (normalizedArray[normalizedArray.length - 1] && normalizedArray[normalizedArray.length - 1].ts !== max_time) normalizedArray.push({ts: max_time});
|
|
|
|
|
}
|
|
|
|
|
vm.maxTime = normalizedArray.length - 1;
|
|
|
|
|
vm.minTime = 0;
|
|
|
|
|
return normalizedArray;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createNormalizedTrips(timeRange, dataSources) {
|
|
|
|
|
vm.trips = [];
|
|
|
|
|
if (timeRange && timeRange.length > 0 && dataSources && dataSources.length > 0 && vm.data && vm.data.length > 0) {
|
|
|
|
|
dataSources.forEach(function (dS, index) {
|
|
|
|
|
vm.trips.push({
|
|
|
|
|
dataSource: dS,
|
|
|
|
|
dSIndex: index,
|
|
|
|
|
timeRange: angular.copy(timeRange)
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
vm.data.forEach(function (data) {
|
|
|
|
|
let ds = data.datasource;
|
|
|
|
|
let tripIndex = vm.trips.findIndex(function (el) {
|
|
|
|
|
return el.dataSource.entityId === ds.entityId;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (tripIndex > -1) {
|
2019-02-26 15:52:22 +02:00
|
|
|
createNormalizedValue(data.data, data.dataKey.label, vm.trips[tripIndex].timeRange);
|
2019-02-26 12:32:37 +02:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
createNormalizedLatLngs();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createNormalizedValue(dataArray, dataKey, timeRangeArray) {
|
|
|
|
|
timeRangeArray.forEach(function (timeStamp) {
|
|
|
|
|
let targetTDiff = null;
|
|
|
|
|
let value = null;
|
|
|
|
|
for (let i = 0; i < dataArray.length; i++) {
|
|
|
|
|
let tDiff = dataArray[i][0] - timeStamp.ts;
|
|
|
|
|
if (targetTDiff === null || (tDiff <= 0 && targetTDiff < tDiff)) {
|
|
|
|
|
targetTDiff = tDiff;
|
|
|
|
|
value = dataArray[i][1];
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (value !== null) timeStamp[dataKey] = value;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createNormalizedLatLngs() {
|
|
|
|
|
vm.trips.forEach(function (el) {
|
|
|
|
|
el.latLngs = [];
|
|
|
|
|
el.timeRange.forEach(function (data) {
|
|
|
|
|
let lat = data[vm.staticSettings.latKeyName];
|
|
|
|
|
let lng = data[vm.staticSettings.lngKeyName];
|
|
|
|
|
if (lat && lng && vm.map) {
|
|
|
|
|
data.latLng = vm.map.createLatLng(lat, lng);
|
|
|
|
|
}
|
|
|
|
|
el.latLngs.push(data.latLng);
|
|
|
|
|
});
|
|
|
|
|
addAngleForTip(el);
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function addAngleForTip(trip) {
|
|
|
|
|
if (trip.timeRange && trip.timeRange.length > 0) {
|
|
|
|
|
trip.timeRange.forEach(function (point, index) {
|
|
|
|
|
let nextPoint, prevPoint;
|
|
|
|
|
nextPoint = index === (trip.timeRange.length - 1) ? trip.timeRange[index] : trip.timeRange[index + 1];
|
|
|
|
|
prevPoint = index === 0 ? trip.timeRange[0] : trip.timeRange[index - 1];
|
|
|
|
|
point.h = findAngle(prevPoint[vm.staticSettings.latKeyName], prevPoint[vm.staticSettings.lngKeyName], nextPoint[vm.staticSettings.latKeyName], nextPoint[vm.staticSettings.lngKeyName]);
|
|
|
|
|
point.h += vm.staticSettings.rotationAngle;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createTripsOnMap() {
|
|
|
|
|
if (vm.trips.length > 0) {
|
|
|
|
|
vm.trips.forEach(function (trip) {
|
|
|
|
|
if (trip.timeRange.length > 0 && trip.latLngs.every(el => angular.isDefined(el))) {
|
|
|
|
|
configureTripSettings(trip, vm.index);
|
|
|
|
|
if (vm.staticSettings.showPoints) {
|
|
|
|
|
trip.points = [];
|
|
|
|
|
trip.latLngs.forEach(function (latLng) {
|
|
|
|
|
let point = L.circleMarker(latLng, {
|
|
|
|
|
color: trip.settings.pointColor,
|
|
|
|
|
radius: trip.settings.pointSize
|
|
|
|
|
}).addTo(vm.map.map);
|
|
|
|
|
trip.points.push(point);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (angular.isUndefined(trip.marker)) {
|
|
|
|
|
trip.polyline = vm.map.createPolyline(trip.latLngs, trip.settings);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (trip.timeRange && trip.timeRange.length && angular.isUndefined(trip.marker)) {
|
|
|
|
|
trip.marker = L.marker(trip.timeRange[vm.index].latLng).addTo(vm.map.map);
|
|
|
|
|
trip.marker.setZIndexOffset(1000);
|
|
|
|
|
trip.marker.setIcon(vm.staticSettings.icon);
|
|
|
|
|
trip.marker.setRotationOrigin('center center');
|
|
|
|
|
// trip.marker.addTo(vm.map.map);
|
|
|
|
|
trip.marker.on('click', function () {
|
|
|
|
|
showHideTooltip(trip);
|
|
|
|
|
});
|
|
|
|
|
moveMarker(trip);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function moveMarker(trip) {
|
|
|
|
|
if (angular.isDefined(trip.marker)) {
|
2019-03-07 18:00:49 +02:00
|
|
|
trip.markerAngleIsSet = true;
|
2019-02-26 12:32:37 +02:00
|
|
|
trip.marker.setLatLng(trip.timeRange[vm.index].latLng);
|
2019-03-07 18:00:49 +02:00
|
|
|
trip.marker.setRotationAngle(trip.timeRange[vm.index].h);
|
2019-02-26 12:32:37 +02:00
|
|
|
trip.marker.update();
|
|
|
|
|
} else {
|
|
|
|
|
if (trip.timeRange && trip.timeRange.length) {
|
|
|
|
|
trip.marker = L.marker(trip.timeRange[vm.index].latLng);
|
|
|
|
|
trip.marker.setZIndexOffset(1000);
|
|
|
|
|
trip.marker.setIcon(vm.staticSettings.icon);
|
|
|
|
|
trip.marker.setRotationOrigin('center center');
|
|
|
|
|
trip.marker.addTo(vm.map.map);
|
|
|
|
|
trip.marker.on('click', function () {
|
|
|
|
|
showHideTooltip(trip);
|
|
|
|
|
});
|
|
|
|
|
trip.marker.update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
configureTripSettings(trip);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-07 18:00:49 +02:00
|
|
|
|
2019-02-26 12:32:37 +02:00
|
|
|
function showHideTooltip(trip) {
|
|
|
|
|
if (vm.staticSettings.displayTooltip) {
|
|
|
|
|
if (vm.staticSettings.showTooltip && trip && vm.activeTripIndex !== trip.dSIndex) {
|
|
|
|
|
vm.staticSettings.showTooltip = true;
|
|
|
|
|
} else {
|
|
|
|
|
vm.staticSettings.showTooltip = !vm.staticSettings.showTooltip;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (trip && vm.activeTripIndex !== trip.dSIndex) vm.activeTripIndex = trip.dSIndex;
|
|
|
|
|
}
|
|
|
|
|
}
|