From b6300f43fa3407cac97dc0c0b429fec95bfe9f58 Mon Sep 17 00:00:00 2001 From: Maksym Dudnik Date: Tue, 26 Feb 2019 12:32:37 +0200 Subject: [PATCH 1/5] Trip Animation Widget --- ui/src/app/api/widget.service.js | 3 +- .../tripAnimation/trip-animation-widget.js | 686 ++++++++++++++++++ .../tripAnimation/trip-animation-widget.scss | 104 +++ .../trip-animation-widget.tpl.html | 49 ++ 4 files changed, 841 insertions(+), 1 deletion(-) create mode 100644 ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js create mode 100644 ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss create mode 100644 ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html diff --git a/ui/src/app/api/widget.service.js b/ui/src/app/api/widget.service.js index 4a09ffc336..edd2bee91a 100644 --- a/ui/src/app/api/widget.service.js +++ b/ui/src/app/api/widget.service.js @@ -32,6 +32,7 @@ import TbAnalogueCompass from '../widget/lib/analogue-compass'; import TbCanvasDigitalGauge from '../widget/lib/canvas-digital-gauge'; import TbMapWidget from '../widget/lib/map-widget'; import TbMapWidgetV2 from '../widget/lib/map-widget2'; +import TripAnimationWidget from '../widget/lib/tripAnimation/trip-animation-widget'; import 'jquery.terminal/js/jquery.terminal.min.js'; import 'jquery.terminal/css/jquery.terminal.min.css'; @@ -43,7 +44,7 @@ import thingsboardTypes from '../common/types.constant'; import thingsboardUtils from '../common/utils.service'; export default angular.module('thingsboard.api.widget', ['oc.lazyLoad', thingsboardLedLight, thingsboardTimeseriesTableWidget, - thingsboardAlarmsTableWidget, thingsboardEntitiesTableWidget, thingsboardExtensionsTableWidget, thingsboardRpcWidgets, thingsboardTypes, thingsboardUtils]) + thingsboardAlarmsTableWidget, thingsboardEntitiesTableWidget, thingsboardExtensionsTableWidget, thingsboardRpcWidgets, thingsboardTypes, thingsboardUtils, TripAnimationWidget]) .factory('widgetService', WidgetService) .name; diff --git a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js new file mode 100644 index 0000000000..a55e655bb3 --- /dev/null +++ b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js @@ -0,0 +1,686 @@ +/* + * Copyright © 2016-2019 The Thingsboard Authors + * + * 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 || "${entityName}

Latitude: ${latitude:7}
Longitude: ${longitude:7}
Start Time: ${maxTime}
End Time: ${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) { + createNormalizedValue(data.data, data.dataKey.name, vm.trips[tripIndex].timeRange); + } + }) + } + + 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); +} \ No newline at end of file diff --git a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss new file mode 100644 index 0000000000..85ddcfdb3c --- /dev/null +++ b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss @@ -0,0 +1,104 @@ +/** +* Copyright © 2016-2019 The Thingsboard Authors +* +* 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. +**/ +.heat-map-widget { + position: relative; + width: 100%; + height: 100%; + padding-top: 35px; +} + +.heat-map-info-panel { + position: absolute; + top: 0; + right: 0; + z-index: 2; + background-color: rgba(0, 0, 0, .3); + border-bottom-left-radius: 5px; + + .md-button { + min-width: auto; + } +} + +.heat-map-tooltip { + position: absolute; + top: 47px; + right: 0; + z-index: 2; + padding: 10px; + background-color: #fff; + border-top-left-radius: 10px; + border-bottom-left-radius: 10px; + transition: .3s ease-in-out; + + &-hidden { + transform: translateX(100%); + } +} + +.heat-map-title { + padding: 10px; +} + +.heat-map-control-panel { + position: absolute; + bottom: 0; + z-index: 2; + box-sizing: border-box; + width: 100%; + padding-right: 70px; + padding-left: 20px; + background: rgba(0, 0, 0, .3); + + md-slider-container { + button { + max-width: none; + + ng-md-icon { + width: 36px; + height: 36px; + + svg { + width: inherit; + height: inherit; + } + } + } + + .panel-timer { + max-width: none; + font-size: 20px; + font-weight: 600; + } + } +} + +.heat-map-container { + position: relative; + z-index: 1; + flex: 1; + width: 100%; +} + +#heat-map { + z-index: 1; + width: 100%; + height: 100%; + + .pointsLayerMarkerIcon { + border-radius: 50%; + } +} diff --git a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html new file mode 100644 index 0000000000..96e05902f4 --- /dev/null +++ b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html @@ -0,0 +1,49 @@ + + +
+
+ {{vm.trips[vm.activeTripIndex].settings.labelText}} +
+
+ + + + + + + {{ speed}} + + + + + +
{{vm.trips[0].timeRange[vm.index].ts | date:'medium'}} +
+
+
+
+
+
+ + + + + + +
+
+
+
+
\ No newline at end of file From c6786e03d93ff95ccbfa96b583424d051af423e3 Mon Sep 17 00:00:00 2001 From: Maksym Dudnik Date: Tue, 26 Feb 2019 15:52:22 +0200 Subject: [PATCH 2/5] Trip animation widget added to library --- .../data/json/system/widget_bundles/maps.json | 16 ++++++++++++++++ .../lib/tripAnimation/trip-animation-widget.js | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/application/src/main/data/json/system/widget_bundles/maps.json b/application/src/main/data/json/system/widget_bundles/maps.json index a873c7a7e6..963c9ad71e 100644 --- a/application/src/main/data/json/system/widget_bundles/maps.json +++ b/application/src/main/data/json/system/widget_bundles/maps.json @@ -116,6 +116,22 @@ "dataKeySettingsSchema": "{}\n", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"First point\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"latitude\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = prevValue || 15.833293;\\nif (time % 5000 < 500) {\\n value += Math.random() * 0.05 - 0.025;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"longitude\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.24727730589425012,\"funcBody\":\"var value = prevValue || -90.454350;\\nif (time % 5000 < 500) {\\n value += Math.random() * 0.05 - 0.025;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"temperature\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.8437014651129422,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"type\",\"color\":\"#ffc107\",\"settings\":{},\"_hash\":0.7558240907832925,\"funcBody\":\"return \\\"colorpin\\\";\"}]},{\"type\":\"function\",\"name\":\"Second Point\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"latitude\",\"color\":\"#607d8b\",\"settings\":{},\"_hash\":0.19266205227372524,\"funcBody\":\"var value = prevValue || 14.450463;\\nif (time % 4000 < 500) {\\n value += Math.random() * 0.05 - 0.025;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"longitude\",\"color\":\"#9c27b0\",\"settings\":{},\"_hash\":0.7995830793603149,\"funcBody\":\"var value = prevValue || -84.845334;\\nif (time % 4000 < 500) {\\n value += Math.random() * 0.05 - 0.025;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"temperature\",\"color\":\"#8bc34a\",\"settings\":{},\"_hash\":0.04902495467943502,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"type\",\"color\":\"#3f51b5\",\"settings\":{},\"_hash\":0.44120841439482095,\"funcBody\":\"return \\\"thermomether\\\";\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"tmDefaultMapType\":\"roadmap\",\"fitMapBounds\":true,\"latKeyName\":\"latitude\",\"lngKeyName\":\"longitude\",\"showLabel\":true,\"label\":\"${entityName}\",\"showTooltip\":true,\"autocloseTooltip\":true,\"tooltipPattern\":\"
${entityName}

Latitude: ${latitude:7}
Longitude: ${longitude:7}
Temperature: ${temperature} °C
See advanced settings for details
\",\"markerImageSize\":34,\"tmApiKey\":\"84d6d83e0e51e481e50454ccbe8986b\",\"color\":\"#fe7569\",\"useColorFunction\":true,\"colorFunction\":\"var type = dsData[dsIndex]['type'];\\nif (type == 'colorpin') {\\n\\tvar temperature = dsData[dsIndex]['temperature'];\\n\\tif (typeof temperature !== undefined) {\\n\\t var percent = (temperature + 60)/120 * 100;\\n\\t return tinycolor.mix('blue', 'red', amount = percent).toHexString();\\n\\t}\\n\\treturn 'blue';\\n}\\n\",\"useMarkerImageFunction\":true,\"markerImageFunction\":\"var type = dsData[dsIndex]['type'];\\nif (type == 'thermomether') {\\n\\tvar res = {\\n\\t url: images[0],\\n\\t size: 40\\n\\t}\\n\\tvar temperature = dsData[dsIndex]['temperature'];\\n\\tif (typeof temperature !== undefined) {\\n\\t var percent = (temperature + 60)/120;\\n\\t var index = Math.min(3, Math.floor(4 * percent));\\n\\t res.url = images[index];\\n\\t}\\n\\treturn res;\\n}\",\"markerImages\":[\"data:image/png;base64,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\",\"data:image/png;base64,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\",\"data:image/png;base64,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\",\"data:image/png;base64,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\"],\"labelFunction\":\"var deviceType = dsData[dsIndex]['deviceType'];\\r\\nif (typeof deviceType !== undefined) {\\r\\n if (deviceType == \\\"energy meter\\\") {\\r\\n return '${entityName}, ${energy:2} kWt';\\r\\n } else if (deviceType == \\\"thermometer\\\") {\\r\\n return '${entityName}, ${temperature:2} °C';\\r\\n }\\r\\n}\",\"tooltipFunction\":\"var deviceType = dsData[dsIndex]['deviceType'];\\r\\nif (typeof deviceType !== undefined) {\\r\\n if (deviceType == \\\"energy meter\\\") {\\r\\n return '${entityName}
Energy: ${energy:2} kWt
';\\r\\n } else if (deviceType == \\\"thermometer\\\") {\\r\\n return '${entityName}
Temperature: ${temperature:2} °C
';\\r\\n }\\r\\n}\"},\"title\":\"Tencent Maps\",\"dropShadow\":true,\"enableFullscreen\":true,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{}}" } + }, + { + "alias": "test", + "name": "Trip Animation", + "descriptor": { + "type": "timeseries", + "sizeX": 10, + "sizeY": 6.5, + "resources": [], + "templateHtml": "", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": " self.onInit = function() {\n var $scope = self.ctx.$scope;\n $scope.self = self;\n }\n \n \n self.actionSources = function () {\n return {\n 'tooltipAction': {\n name: 'widget-action.tooltip-tag-action',\n multiple: false\n }\n }\n };\n", + "settingsSchema": "{\n \"schema\": {\n \"title\": \"Openstreet Map Configuration\",\n \"type\": \"object\",\n \"properties\": {\n \"mapProvider\": {\n \"title\": \"Map provider\",\n \"type\": \"string\",\n \"default\": \"OpenStreetMap.Mapnik\"\n },\n \"latKeyName\": {\n \"title\": \"Latitude key name\",\n \"type\": \"string\",\n \"default\": \"latitude\"\n },\n \"lngKeyName\": {\n \"title\": \"Longitude key name\",\n \"type\": \"string\",\n \"default\": \"longitude\"\n },\n \"showLabel\": {\n \"title\": \"Show label\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"label\": {\n \"title\": \"Label (pattern examples: '${entityName}', '${entityName}: (Text ${keyName} units.)' )\",\n \"type\": \"string\",\n \"default\": \"${entityName}\"\n },\n \"useLabelFunction\": {\n \"title\": \"Use label function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"labelFunction\": {\n \"title\": \"Label function: f(data, dsData, dsIndex)\",\n \"type\": \"string\"\n },\n \"showTooltip\": {\n \"title\": \"Show tooltip\",\n \"type\": \"boolean\",\n \"default\": true\n },\n \"tooltipColor\": {\n \"title\": \"Tooltip background color\",\n \"type\": \"string\",\n \"default\": \"#fff\"\n },\n \"tooltipFontColor\": {\n \"title\": \"Tooltip font color\",\n \"type\": \"string\",\n \"default\": \"#000\"\n },\n \"tooltipOpacity\": {\n \"title\": \"Tooltip opacity (0-1)\",\n \"type\": \"number\",\n \"default\": 1 \n },\n \"tooltipPattern\": {\n \"title\": \"Tooltip (for ex. 'Text ${keyName} units.' or Link text')\",\n \"type\": \"string\",\n \"default\": \"${entityName}

Latitude: ${latitude:7}
Longitude: ${longitude:7}
End Time: ${maxTime}
Start Time: ${minTime}\"\n },\n \"useTooltipFunction\": {\n \"title\": \"Use tooltip function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"tooltipFunction\": {\n \"title\": \"Tooltip function: f(data, dsData, dsIndex)\",\n \"type\": \"string\"\n },\n \"color\": {\n \"title\": \"Path color\",\n \"type\": \"string\"\n },\n \"strokeWeight\": {\n \"title\": \"Stroke weight\",\n \"type\": \"number\",\n \"default\": 2\n },\n \"strokeOpacity\": {\n \"title\": \"Stroke opacity\",\n \"type\": \"number\",\n \"default\": 1\n },\n \"useColorFunction\": {\n \"title\": \"Use path color function\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"colorFunction\": {\n \"title\": \"Path color function: f(data, dsData, dsIndex)\",\n \"type\": \"string\"\n },\n \"showPoints\": {\n \"title\": \"Show points\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"pointColor\": {\n \"title\": \"Point color\",\n \"type\": \"string\"\n },\n \"pointSize\": {\n \"title\": \"Point size (px)\",\n \"type\": \"number\",\n \"default\": 10\n },\n \"defaultMarkerColor\": {\n \"title\": \"color for default marker\",\n \"type\": \"string\"\n },\n \"markerImage\": {\n \"title\": \"Custom marker image\",\n \"type\": \"string\"\n },\n \"markerImageSize\": {\n \"title\": \"Custom marker image size (px)\",\n \"type\": \"number\",\n \"default\": 34\n },\n \"rotationAngle\": {\n \"title\": \"Set additional rotation angle for marker (deg)\",\n \"type\": \"number\",\n \"default\": 180\n },\n \"useMarkerImageFunction\":{\n \"title\":\"Use marker image function\",\n \"type\":\"boolean\",\n \"default\":false\n },\n \"markerImageFunction\":{\n \"title\":\"Marker image function: f(data, images, dsData, dsIndex)\",\n \"type\":\"string\"\n },\n \"markerImages\":{\n \"title\":\"Marker images\",\n \"type\":\"array\",\n \"items\":{\n \"title\":\"Marker image\",\n \"type\":\"string\"\n }\n }\n },\n \"required\": []\n },\n \"form\": [{\n \"key\": \"mapProvider\",\n \"type\": \"rc-select\",\n \"multiple\": false,\n \"items\": [{\n \"value\": \"OpenStreetMap.Mapnik\",\n \"label\": \"OpenStreetMap.Mapnik (Default)\"\n }, {\n \"value\": \"OpenStreetMap.BlackAndWhite\",\n \"label\": \"OpenStreetMap.BlackAndWhite\"\n }, {\n \"value\": \"OpenStreetMap.HOT\",\n \"label\": \"OpenStreetMap.HOT\"\n }, {\n \"value\": \"Esri.WorldStreetMap\",\n \"label\": \"Esri.WorldStreetMap\"\n }, {\n \"value\": \"Esri.WorldTopoMap\",\n \"label\": \"Esri.WorldTopoMap\"\n }, {\n \"value\": \"CartoDB.Positron\",\n \"label\": \"CartoDB.Positron\"\n }, {\n \"value\": \"CartoDB.DarkMatter\",\n \"label\": \"CartoDB.DarkMatter\"\n }]\n }, \"latKeyName\", \"lngKeyName\", \"showLabel\", \"label\", \"useLabelFunction\", {\n \"key\": \"labelFunction\",\n \"type\": \"javascript\"\n }, \"showTooltip\", {\n \"key\": \"tooltipColor\",\n \"type\": \"color\"\n }, {\n \"key\": \"tooltipFontColor\",\n \"type\": \"color\"\n },\"tooltipOpacity\", {\n \"key\": \"tooltipPattern\",\n \"type\": \"textarea\"\n }, \"useTooltipFunction\", {\n \"key\": \"tooltipFunction\",\n \"type\": \"javascript\"\n }, {\n \"key\": \"color\",\n \"type\": \"color\"\n }, \"useColorFunction\", {\n \"key\": \"colorFunction\",\n \"type\": \"javascript\"\n }, \"strokeWeight\", \"strokeOpacity\", \"showPoints\",{\n \"key\": \"pointColor\",\n \"type\": \"color\"\n }, \"pointSize\", {\n \"key\": \"defaultMarkerColor\",\n \"type\": \"color\"\n }, {\n \"key\": \"markerImage\",\n \"type\": \"image\"\n }, \"markerImageSize\", \"rotationAngle\",\"useMarkerImageFunction\",\n {\n \"key\":\"markerImageFunction\",\n \"type\":\"javascript\"\n }, {\n \"key\":\"markerImages\",\n \"items\":[\n {\n \"key\":\"markerImages[]\",\n \"type\":\"image\"\n }\n ]\n }]\n}", + "dataKeySettingsSchema": "{}", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -1000) {\\n\\tvalue = -1000;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Trip Animation\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"legendConfig\":{\"position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false}}" + } } ] } \ No newline at end of file diff --git a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js index a55e655bb3..343ad7fd11 100644 --- a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js +++ b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js @@ -562,7 +562,7 @@ function tripAnimationController($document, $scope, $http, $timeout, $filter, $l }); if (tripIndex > -1) { - createNormalizedValue(data.data, data.dataKey.name, vm.trips[tripIndex].timeRange); + createNormalizedValue(data.data, data.dataKey.label, vm.trips[tripIndex].timeRange); } }) } From 5f8547d6351a67287d546e675169add620a49730 Mon Sep 17 00:00:00 2001 From: Maksym Dudnik Date: Fri, 1 Mar 2019 10:08:00 +0200 Subject: [PATCH 3/5] Licence Update fro trip animation --- .../lib/tripAnimation/trip-animation-widget.js | 3 +-- .../lib/tripAnimation/trip-animation-widget.scss | 15 +++++++++++++++ .../tripAnimation/trip-animation-widget.tpl.html | 8 ++++++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js index 343ad7fd11..015e3dd4c0 100644 --- a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js +++ b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2019 The Thingsboard Authors + * Copyright © 2016-2018 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,6 @@ * 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'; diff --git a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss index 85ddcfdb3c..2eb5b915d9 100644 --- a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss +++ b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss @@ -1,3 +1,18 @@ +/** + * Copyright © 2016-2018 The Thingsboard Authors + * + * 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. + */ /** * Copyright © 2016-2019 The Thingsboard Authors * diff --git a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html index 96e05902f4..42d4bcdcec 100644 --- a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html +++ b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html @@ -1,16 +1,20 @@ +-->
{{vm.trips[vm.activeTripIndex].settings.labelText}} From d7b6453bf0728badaa7c312320dc9c89b223e08e Mon Sep 17 00:00:00 2001 From: Maksym Dudnik Date: Fri, 1 Mar 2019 10:29:46 +0200 Subject: [PATCH 4/5] Revert "Licence Update fro trip animation" This reverts commit 5f8547d --- .../lib/tripAnimation/trip-animation-widget.js | 3 ++- .../lib/tripAnimation/trip-animation-widget.scss | 15 --------------- .../tripAnimation/trip-animation-widget.tpl.html | 8 ++------ 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js index 015e3dd4c0..343ad7fd11 100644 --- a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js +++ b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2018 The Thingsboard Authors + * Copyright © 2016-2019 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ * 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'; diff --git a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss index 2eb5b915d9..85ddcfdb3c 100644 --- a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss +++ b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss @@ -1,18 +1,3 @@ -/** - * Copyright © 2016-2018 The Thingsboard Authors - * - * 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. - */ /** * Copyright © 2016-2019 The Thingsboard Authors * diff --git a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html index 42d4bcdcec..96e05902f4 100644 --- a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html +++ b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html @@ -1,20 +1,16 @@ +
{{vm.trips[vm.activeTripIndex].settings.labelText}} From 3ffc455e6d3c9209785e3bedf38fdbe25311e6b4 Mon Sep 17 00:00:00 2001 From: Maksym Dudnik Date: Fri, 1 Mar 2019 10:31:00 +0200 Subject: [PATCH 5/5] Licence Update for trip animation" --- .../tripAnimation/trip-animation-widget.js | 1 - .../tripAnimation/trip-animation-widget.scss | 29 ++++++++++--------- .../trip-animation-widget.tpl.html | 6 +++- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js index 343ad7fd11..7bcde55ba1 100644 --- a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js +++ b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.js @@ -13,7 +13,6 @@ * 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'; diff --git a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss index 85ddcfdb3c..6fae2e611e 100644 --- a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss +++ b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.scss @@ -1,18 +1,19 @@ /** -* Copyright © 2016-2019 The Thingsboard Authors -* -* 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. -**/ + * Copyright © 2016-2019 The Thingsboard Authors + * + * 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. + */ + .heat-map-widget { position: relative; width: 100%; diff --git a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html index 96e05902f4..af6e729c01 100644 --- a/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html +++ b/ui/src/app/widget/lib/tripAnimation/trip-animation-widget.tpl.html @@ -1,16 +1,20 @@ +-->
{{vm.trips[vm.activeTripIndex].settings.labelText}}