thingsboard/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js

685 lines
35 KiB
JavaScript
Raw Normal View History

2019-02-26 12:32:37 +02:00
/*
2019-03-01 10:08:00 +02:00
* Copyright © 2016-2018 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 MultiOptionsPolyline from '../../../../vendor/leaflet-multi-options-polyline/Leaflet.MultiOptionsPolyline';
import GeometryUtil from '../../../../vendor/leaflet-geometryutil/leaflet-geometryutil';
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*/
function tripAnimationController($document, $scope, $http, $timeout, $filter, $log) {
let vm = this;
//const varsRegex = /\$\{([^\}]*)\}/g;
//let icon;
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;
L.MultiOptionsPolyline = MultiOptionsPolyline;
L.GeometryUtil = GeometryUtil;
L.multiOptionsPolyline = function (latlngs, options) {
return new MultiOptionsPolyline(latlngs, options);
};
$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);
//vm.map = L.map(vm.ctx.$element[0]).setView([0, 0], 2);
vm.map = new TbOpenStreetMap(vm.ctx.$element, vm.utils, initCallback, 2, null, null, vm.staticSettings.mapProvider);
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;
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({
iconUrl: "data:image/png;base64,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
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();
}
if (trip.polyline) {
trip.polyline.remove();
}
if (trip.points && trip.points.length) {
trip.points.forEach(function (point) {
point.remove();
})
}
})
}
let normalizedTimeRange = createNormalizedTime(vm.data, 1000);
createNormalizedTrips(normalizedTimeRange, vm.datasources);
createTripsOnMap();
vm.trips.forEach(function (trip) {
vm.map.extendBounds(vm.map.bounds, trip.polyline);
vm.map.fitBounds(vm.map.bounds);
})
}
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)) {
trip.marker.setLatLng(trip.timeRange[vm.index].latLng);
trip.marker.setRotationAngle(trip.timeRange[vm.index].h + vm.staticSettings.rotationAngle);
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);
}
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;
}
$log.log(vm);
}