diff --git a/ui-ngx/angular.json b/ui-ngx/angular.json index 4b7bc54618..2ca77a91ec 100644 --- a/ui-ngx/angular.json +++ b/ui-ngx/angular.json @@ -38,7 +38,8 @@ "src/app/shared/components/json-form/react/json-form.scss", "node_modules/rc-select/assets/index.less", "node_modules/jstree-bootstrap-theme/dist/themes/proton/style.min.css", - "node_modules/leaflet/dist/leaflet.css" + "node_modules/leaflet/dist/leaflet.css", + "src/app/modules/home/components/widget/lib/maps/markers.scss" ], "stylePreprocessorOptions": { "includePaths": [ diff --git a/ui-ngx/src/app/core/schema-utils.ts b/ui-ngx/src/app/core/schema-utils.ts new file mode 100644 index 0000000000..fbe995b4b2 --- /dev/null +++ b/ui-ngx/src/app/core/schema-utils.ts @@ -0,0 +1,65 @@ + +export function initSchema() { + return { + schema: { + type: "object", + properties: {}, + required: [] + }, + form: [], + groupInfoes: [] + }; +} + +export function addGroupInfo(schema, title: string) { + schema.groupInfoes.push({ + "formIndex": schema.groupInfoes?.length || 0, + "GroupTitle": title + }); +} + +export function addToSchema(schema, newSchema) { + Object.assign(schema.schema.properties, newSchema.schema.properties); + schema.schema.required = schema.schema.required.concat(newSchema.schema.required); + schema.form.push(newSchema.form); +} + +export function mergeSchemes(schemes: any[]) { + return schemes.reduce((finalSchema, schema) => { + return { + schema: { + properties: { + ...finalSchema.schema.properties, + ...schema.schema.properties + }, + required: [ + ...finalSchema.schema.required, + ...schema.schema.required + ] + }, + form: [ + ...finalSchema.form, + ...schema.form + ] + } + }, initSchema()); +} + +export function addCondition(schema, condition: String) { + schema.form = schema.form.map(element => { + if (typeof element === 'string') { + return { + key: element, + condition: condition + } + } + if (typeof element == 'object') { + if (element.condition) { + element.condition += ' && ' + condition + } + else element.condition = condition; + } + return element; + }); + return schema; +} \ No newline at end of file diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index a1c4c8024e..e2320d593b 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -452,54 +452,55 @@ export function aspectCache(imageUrl: string): Observable { export function parseArray(input: any[]): any[] { let alliases: any = _(input).groupBy(el => el?.datasource?.aliasName).values().value(); return alliases.map((alliasArray, dsIndex) => - alliasArray[0].data.map((el, i) => { - const obj = { - aliasName: alliasArray[0]?.datasource?.aliasName, - $datasource: alliasArray[0]?.datasource, - dsIndex: dsIndex, - time: el[0] - }; - alliasArray.forEach(el => { - obj[el?.dataKey?.label] = el?.data[i][1]; - obj[el?.dataKey?.label + '|ts'] = el?.data[0][0]; - if (el?.dataKey?.label == 'type') { - obj['deviceType'] = el?.data[0][1]; - } - }); - return obj; - }) - ); -} - -export function parseData(input: any[]): any[] { - return _(input).groupBy(el => el?.datasource?.aliasName).values().value().map((alliasArray, i) => { + alliasArray[0].data.map((el, i) => { const obj = { - aliasName: alliasArray[0]?.datasource?.aliasName, - entityName: alliasArray[0]?.datasource?.entityName, - $datasource: alliasArray[0]?.datasource, - dsIndex: i + aliasName: alliasArray[0]?.datasource?.aliasName, + entityName: alliasArray[0]?.datasource?.entityName, + $datasource: alliasArray[0]?.datasource, + dsIndex: dsIndex, + time: el[0] }; alliasArray.forEach(el => { - obj[el?.dataKey?.label] = el?.data[0][1]; - obj[el?.dataKey?.label + '|ts'] = el?.data[0][0]; - if (el?.dataKey?.label == 'type') { - obj['deviceType'] = el?.data[0][1]; - } + obj[el?.dataKey?.label] = el?.data[i][1]; + obj[el?.dataKey?.label + '|ts'] = el?.data[0][0]; + if (el?.dataKey?.label == 'type') { + obj['deviceType'] = el?.data[0][1]; + } }); return obj; + }) + ); +} + +export function parseData(input: any[]): any[] { + return _(input).groupBy(el => el?.datasource?.aliasName).values().value().map((alliasArray, i) => { + const obj = { + aliasName: alliasArray[0]?.datasource?.aliasName, + entityName: alliasArray[0]?.datasource?.entityName, + $datasource: alliasArray[0]?.datasource, + dsIndex: i + }; + alliasArray.forEach(el => { + obj[el?.dataKey?.label] = el?.data[0][1]; + obj[el?.dataKey?.label + '|ts'] = el?.data[0][0]; + if (el?.dataKey?.label == 'type') { + obj['deviceType'] = el?.data[0][1]; + } + }); + return obj; }); } export function safeExecute(func: Function, params = []) { let res = null; if (func && typeof (func) == "function") { - try { - res = func(...params); - } - catch (err) { - console.error(err); - res = null; - } + try { + res = func(...params); + } + catch (err) { + console.error(err); + res = null; + } } return res; } @@ -507,13 +508,13 @@ export function safeExecute(func: Function, params = []) { export function parseFunction(source: string, params: string[] = []): Function { let res = null; if (source?.length) { - try { - res = new Function(...params, source); - } - catch (err) { - console.error(err); - res = null; - } + try { + res = new Function(...params, source); + } + catch (err) { + console.error(err); + res = null; + } } return res; } \ No newline at end of file diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts index 397b71fe2e..919fbb6aba 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet-map.ts @@ -122,6 +122,11 @@ export default abstract class LeafletMap { ////Markers updateMarkers(markersData) { markersData.forEach(data => { + if(data.rotationAngle){ + this.options.icon= L.divIcon({ + html: `
` + }) + } if (this.markers.get(data.aliasName)) { this.updateMarker(data.aliasName, data, markersData, this.options as MarkerSettings) } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts index 8256c7b275..c49406c65e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-models.ts @@ -18,6 +18,7 @@ export interface MapOptions { useDefaultCenterPosition?: boolean, gmDefaultMapType?: string, useLabelFunction: string; + icon?: any; } export enum MapProviders { @@ -29,6 +30,7 @@ export enum MapProviders { } export interface MarkerSettings extends MapOptions { + icon?: any; showLabel?: boolean, draggable?: boolean, displayTooltip?: boolean, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget.interface.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget.interface.ts index 51b137e2dc..d0a1949445 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget.interface.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget.interface.ts @@ -8,7 +8,8 @@ export interface MapWidgetInterface { } export interface MapWidgetStaticInterface { - settingsSchema(mapProvider, drawRoutes): Object; + settingsSchema(mapProvider?, drawRoutes?): Object; + getProvidersSchema():Object dataKeySettingsSchema(): Object; actionSources(): Object; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts index 3ba7c80b08..178418fb55 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-widget2.ts @@ -15,6 +15,7 @@ import { import { MapWidgetStaticInterface, MapWidgetInterface } from './map-widget.interface'; import { OpenStreetMap, TencentMap, GoogleMap, HEREMap, ImageMap } from './providers'; import { parseFunction, parseArray, parseData } from '@app/core/utils'; +import { initSchema, addToSchema, mergeSchemes, addCondition, addGroupInfo } from '@app/core/schema-utils'; export class MapWidgetController implements MapWidgetInterface { @@ -73,7 +74,7 @@ export class MapWidgetController implements MapWidgetInterface { this.map.updateMarkers(parseData(this.data)); } - public updateHistoryData(dataSources){ + public updateHistoryData(dataSources) { dataSources.map() } @@ -93,90 +94,28 @@ export class MapWidgetController implements MapWidgetInterface { return {}; } + public static getProvidersSchema(){ + return mergeSchemes([mapProviderSchema, + ...Object.values(providerSets)?.map( + setting => addCondition(setting?.schema, `model.provider === '${setting.name}'`))]) + } + public static settingsSchema(mapProvider, drawRoutes): Object { //const providerInfo = providerSets[mapProvider]; let schema = initSchema(); + addToSchema(schema,this.getProvidersSchema()); - function initSchema() { - return { - schema: { - type: "object", - properties: {}, - required: [] - }, - form: [], - groupInfoes: [] - }; - } - - function addGroupInfo(title: string) { - schema.groupInfoes.push({ - "formIndex": schema.groupInfoes?.length || 0, - "GroupTitle": title - }); - } - - function addToSchema(newSchema) { - Object.assign(schema.schema.properties, newSchema.schema.properties); - schema.schema.required = schema.schema.required.concat(newSchema.schema.required); - schema.form.push(newSchema.form);//schema.form.concat(commonMapSettingsSchema.form); - } - - function mergeSchemes(schemes: any[]) { - return schemes.reduce((finalSchema, schema) => { - return { - schema: { - properties: { - ...finalSchema.schema.properties, - ...schema.schema.properties - }, - required: [ - ...finalSchema.schema.required, - ...schema.schema.required - ] - }, - form: [ - ...finalSchema.form, - ...schema.form - ] - } - }, initSchema()); - } - - function addCondition(schema, condition: String) { - schema.form = schema.form.map(element => { - if (typeof element === 'string') { - return { - key: element, - condition: condition - } - } - if (typeof element == 'object') { - if (element.condition) { - element.condition += ' && ' + condition - } - else element.condition = condition; - } - return element; - }); - return schema; - } - - addToSchema(mergeSchemes([mapProviderSchema, - ...Object.values(providerSets)?.map( - setting => addCondition(setting?.schema, `model.provider === '${setting.name}'`))])); - - addGroupInfo("Map Provider Settings"); - addToSchema(commonMapSettingsSchema); - addGroupInfo("Common Map Settings"); + addGroupInfo(schema, "Map Provider Settings"); + addToSchema(schema, commonMapSettingsSchema); + addGroupInfo(schema, "Common Map Settings"); if (drawRoutes) { - addToSchema(routeMapSettingsSchema); - addGroupInfo("Route Map Settings"); + addToSchema(schema, routeMapSettingsSchema); + addGroupInfo(schema, "Route Map Settings"); } else if (mapProvider !== 'image-map') { let clusteringSchema = mergeSchemes([markerClusteringSettingsSchemaLeaflet, markerClusteringSettingsSchema]) - addToSchema(clusteringSchema); - addGroupInfo("Markers Clustering Settings"); + addToSchema(schema, clusteringSchema); + addGroupInfo(schema, "Markers Clustering Settings"); } console.log(11, schema); @@ -243,7 +182,7 @@ const defaultSettings = { latKeyName: 'latitude', lngKeyName: 'longitude', polygonKeyName: 'coordinates', - showLabel: true, + showLabel: false, label: "${entityName}", showTooltip: false, useDefaultCenterPosition: false, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/maps-utils.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/maps-utils.ts index 5034fbe8f1..8d2828b649 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/maps-utils.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/maps-utils.ts @@ -30,6 +30,12 @@ export function interpolateArray(originData, interpolatedIntervals) { return (intermediateMoment - firsMoment) / (secondMoment - firsMoment); }; + function findAngle(startPoint, endPoint) { + let angle = -Math.atan2(endPoint.latitude - startPoint.longitude, endPoint.longitude - startPoint.latitude); + angle = angle * 180 / Math.PI; + return parseInt(angle.toFixed(2)); + } + const result = {}; for (let i = 1, j = 0; i < originData.length, j < interpolatedIntervals.length;) { @@ -37,10 +43,16 @@ export function interpolateArray(originData, interpolatedIntervals) { while (originData[i].time < currentTime) i++; const before = originData[i - 1]; const after = originData[i]; - result[currentTime] = (interpolateOnPointSegment( + const interpolation = interpolateOnPointSegment( new L.Point(before.latitude, before.longitude), new L.Point(after.latitude, after.longitude), - getRatio(before.time, after.time, currentTime))); + getRatio(before.time, after.time, currentTime)); + result[currentTime] = ({ + ...originData[i], + rotationAngle: findAngle(before, after), + latitude: interpolation.x, + longitude: interpolation.y + }); j++; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss new file mode 100644 index 0000000000..df1213f03d --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.scss @@ -0,0 +1,34 @@ + +.arrow{ + background:#222; + text-align:center; + font-size:180%; + margin:2em; + font-family: Calibri, arial, sans-serif; + color:white; + padding-top:1.8em; + display:inline-block;/* or block */ + position:relative; + border-color:white; + text-decoration:none; + transition:all .3s ease-out; +} +.arrow:before{ + content:'▲'; + font-size:.9em; + position:absolute; + top:0; + left:50%; + margin-left:-.7em; + border:solid .13em white; + border-radius:10em; + width:1.4em; + height:1.4em; + line-height:1.3em; + border-color:inherit; + transition:transform .5s ease-in; +} +.arrow:hover{ + color:pink; + border-color:pink; +} \ No newline at end of file diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts index 6a1e1513e6..cf1bc95703 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/markers.ts @@ -25,7 +25,7 @@ export class Marker { this.leafletMarker.setIcon(iconInfo.icon); if (settings.showLabel) { this.tooltipOffset = [0, -iconInfo.size[1] + 10]; - this.updateMarkerLabel(settings) + // this.updateMarkerLabel(settings) } this.leafletMarker.addTo(map) @@ -55,8 +55,6 @@ export class Marker { this.leafletMarker.setLatLng(position); } - - updateMarkerLabel(settings) { function getText(template, data) { @@ -74,7 +72,7 @@ export class Marker { return res; } - + this.leafletMarker.unbindTooltip(); if (settings.showLabel) { if (settings.useLabelFunction) { @@ -104,9 +102,20 @@ export class Marker { } createMarkerIcon(onMarkerIconReady) { - const currentImage = this.settings.useMarkerImageFunction ? - safeExecute(this.settings.markerImageFunction, [this.data, this.settings.markerImages, this.dataSources, this.data.dsIndex]) : this.settings.currentImage; - // var opMap = this; + + if (this.settings.icon) { + onMarkerIconReady({ + size: [30,30], + icon: this.settings.icon, + }); + return; + } + + let currentImage = this.settings.useMarkerImageFunction ? + safeExecute(this.settings.markerImageFunction, + [this.data, this.settings.markerImages, this.dataSources, this.data.dsIndex]) : this.settings.currentImage; + + if (currentImage && currentImage.url) { aspectCache(currentImage.url).subscribe( (aspect) => { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts index bd2ef9b7ab..3b40ef089c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/schemes.ts @@ -856,4 +856,373 @@ export const mapProviderSchema = ] } ] -}; \ No newline at end of file +}; + + +export const tripAnimationSchema = { + "schema": { + "title": "Openstreet Map Configuration", + "type": "object", + "properties": { + "normalizationStep": { + "title": "Normalization data step (ms)", + "type": "number", + "default": 1000 + }, + "latKeyName": { + "title": "Latitude key name", + "type": "string", + "default": "latitude" + }, + "lngKeyName": { + "title": "Longitude key name", + "type": "string", + "default": "longitude" + }, + "polKeyName": { + "title": "Polygon key name", + "type": "string", + "default": "coordinates" + }, + "showLabel": { + "title": "Show label", + "type": "boolean", + "default": true + }, + "label": { + "title": "Label (pattern examples: '${entityName}', '${entityName}: (Text ${keyName} units.)' )", + "type": "string", + "default": "${entityName}" + }, + "useLabelFunction": { + "title": "Use label function", + "type": "boolean", + "default": false + }, + "labelFunction": { + "title": "Label function: f(data, dsData, dsIndex)", + "type": "string" + }, + "showTooltip": { + "title": "Show tooltip", + "type": "boolean", + "default": true + }, + "tooltipColor": { + "title": "Tooltip background color", + "type": "string", + "default": "#fff" + }, + "tooltipFontColor": { + "title": "Tooltip font color", + "type": "string", + "default": "#000" + }, + "tooltipOpacity": { + "title": "Tooltip opacity (0-1)", + "type": "number", + "default": 1 + }, + "tooltipPattern": { + "title": "Tooltip (for ex. 'Text ${keyName} units.' or Link text')", + "type": "string", + "default": "${entityName}

Latitude: ${latitude:7}
Longitude: ${longitude:7}" + }, + "useTooltipFunction": { + "title": "Use tooltip function", + "type": "boolean", + "default": false + }, + "tooltipFunction": { + "title": "Tooltip function: f(data, dsData, dsIndex)", + "type": "string" + }, + "color": { + "title": "Path color", + "type": "string" + }, + "strokeWeight": { + "title": "Stroke weight", + "type": "number", + "default": 2 + }, + "strokeOpacity": { + "title": "Stroke opacity", + "type": "number", + "default": 1 + }, + "useColorFunction": { + "title": "Use path color function", + "type": "boolean", + "default": false + }, + "colorFunction": { + "title": "Path color function: f(data, dsData, dsIndex)", + "type": "string" + }, + "usePolylineDecorator": { + "title": "Use path decorator", + "type": "boolean", + "default": false + }, + "decoratorSymbol": { + "title": "Decorator symbol", + "type": "string", + "default": "arrowHead" + }, + "decoratorSymbolSize": { + "title": "Decorator symbol size (px)", + "type": "number", + "default": 10 + }, + "useDecoratorCustomColor": { + "title": "Use path decorator custom color", + "type": "boolean", + "default": false + }, + "decoratorCustomColor": { + "title": "Decorator custom color", + "type": "string", + "default": "#000" + }, + "decoratorOffset": { + "title": "Decorator offset", + "type": "string", + "default": "20px" + }, + "endDecoratorOffset": { + "title": "End decorator offset", + "type": "string", + "default": "20px" + }, + "decoratorRepeat": { + "title": "Decorator repeat", + "type": "string", + "default": "20px" + }, + "showPolygon": { + "title": "Show polygon", + "type": "boolean", + "default": false + }, + "polygonTooltipPattern": { + "title": "Tooltip (for ex. 'Text ${keyName} units.' or Link text')", + "type": "string", + "default": "${entityName}

TimeStamp: ${ts:7}" + }, + "usePolygonTooltipFunction": { + "title": "Use polygon tooltip function", + "type": "boolean", + "default": false + }, + "polygonTooltipFunction": { + "title": "Polygon tooltip function: f(data, dsData, dsIndex)", + "type": "string" + }, + "polygonColor": { + "title": "Polygon color", + "type": "string" + }, + "polygonOpacity": { + "title": "Polygon opacity", + "type": "number", + "default": 0.5 + }, + "polygonStrokeColor": { + "title": "Polygon border color", + "type": "string" + }, + "polygonStrokeOpacity": { + "title": "Polygon border opacity", + "type": "number", + "default": 1 + }, + "polygonStrokeWeight": { + "title": "Polygon border weight", + "type": "number", + "default": 1 + }, + "usePolygonColorFunction": { + "title": "Use polygon color function", + "type": "boolean", + "default": false + }, + "polygonColorFunction": { + "title": "Polygon Color function: f(data, dsData, dsIndex)", + "type": "string" + }, + "showPoints": { + "title": "Show points", + "type": "boolean", + "default": false + }, + "pointColor": { + "title": "Point color", + "type": "string" + }, + "pointSize": { + "title": "Point size (px)", + "type": "number", + "default": 10 + }, + "usePointAsAnchor": { + "title": "Use point as anchor", + "type": "boolean", + "default": false + }, + "pointAsAnchorFunction": { + "title": "Point as anchor function: f(data, dsData, dsIndex)", + "type": "string" + }, + "pointTooltipOnRightPanel": { + "title": "Independant point tooltip", + "type": "boolean", + "default": true + }, + "autocloseTooltip": { + "title": "Auto-close point popup", + "type": "boolean", + "default": true + }, + "markerImage": { + "title": "Custom marker image", + "type": "string" + }, + "markerImageSize": { + "title": "Custom marker image size (px)", + "type": "number", + "default": 34 + }, + "rotationAngle": { + "title": "Set additional rotation angle for marker (deg)", + "type": "number", + "default": 180 + }, + "useMarkerImageFunction": { + "title": "Use marker image function", + "type": "boolean", + "default": false + }, + "markerImageFunction": { + "title": "Marker image function: f(data, images, dsData, dsIndex)", + "type": "string" + }, + "markerImages": { + "title": "Marker images", + "type": "array", + "items": { + "title": "Marker image", + "type": "string" + } + } + }, + "required": [] + }, + "form": [{ + "key": "mapProvider", + "type": "rc-select", + "multiple": false, + "items": [{ + "value": "OpenStreetMap.Mapnik", + "label": "OpenStreetMap.Mapnik (Default)" + }, { + "value": "OpenStreetMap.BlackAndWhite", + "label": "OpenStreetMap.BlackAndWhite" + }, { + "value": "OpenStreetMap.HOT", + "label": "OpenStreetMap.HOT" + }, { + "value": "Esri.WorldStreetMap", + "label": "Esri.WorldStreetMap" + }, { + "value": "Esri.WorldTopoMap", + "label": "Esri.WorldTopoMap" + }, { + "value": "CartoDB.Positron", + "label": "CartoDB.Positron" + }, { + "value": "CartoDB.DarkMatter", + "label": "CartoDB.DarkMatter" + }] + }, "normalizationStep", "latKeyName", "lngKeyName", "polKeyName", "showLabel", "label", "useLabelFunction", { + "key": "labelFunction", + "type": "javascript" + }, "showTooltip", { + "key": "tooltipColor", + "type": "color" + }, { + "key": "tooltipFontColor", + "type": "color" + }, "tooltipOpacity", { + "key": "tooltipPattern", + "type": "textarea" + }, "useTooltipFunction", { + "key": "tooltipFunction", + "type": "javascript" + }, { + "key": "color", + "type": "color" + }, "useColorFunction", { + "key": "colorFunction", + "type": "javascript" + }, "usePolylineDecorator", { + "key": "decoratorSymbol", + "type": "rc-select", + "multiple": false, + "items": [{ + "value": "arrowHead", + "label": "Arrow" + }, { + "value": "dash", + "label": "Dash" + }] + }, "decoratorSymbolSize", "useDecoratorCustomColor", { + "key": "decoratorCustomColor", + "type": "color" + }, { + "key": "decoratorOffset", + "type": "textarea" + }, { + "key": "endDecoratorOffset", + "type": "textarea" + }, { + "key": "decoratorRepeat", + "type": "textarea" + }, "strokeWeight", "strokeOpacity", "showPolygon", { + "key": "polygonTooltipPattern", + "type": "textarea" + }, "usePolygonTooltipFunction", { + "key": "polygonTooltipFunction", + "type": "javascript" + }, { + "key": "polygonColor", + "type": "color" + }, "polygonOpacity", { + "key": "polygonStrokeColor", + "type": "color" + }, "polygonStrokeOpacity", "polygonStrokeWeight", "usePolygonColorFunction", { + "key": "polygonColorFunction", + "type": "javascript" + }, "showPoints", { + "key": "pointColor", + "type": "color" + }, "pointSize", "usePointAsAnchor", { + "key": "pointAsAnchorFunction", + "type": "javascript" + }, "pointTooltipOnRightPanel", "autocloseTooltip", { + "key": "markerImage", + "type": "image" + }, "markerImageSize", "rotationAngle", "useMarkerImageFunction", + { + "key": "markerImageFunction", + "type": "javascript" + }, { + "key": "markerImages", + "items": [ + { + "key": "markerImages[]", + "type": "image" + } + ] + }] +} \ No newline at end of file diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html index a1a7dbb30a..4489d3b880 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.html @@ -1,4 +1,3 @@
-
{{historicalData?.lenth}}
- diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts index 6903bbfa65..99bc56a1b4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts @@ -1,8 +1,12 @@ import { Component, OnInit, Input, ViewChild, AfterViewInit, ChangeDetectorRef } from '@angular/core'; -import { MapWidgetController } from '../lib/maps/map-widget2'; +import { MapWidgetController, TbMapWidgetV2 } from '../lib/maps/map-widget2'; import { MapProviders } from '../lib/maps/map-models'; import { parseArray } from '@app/core/utils'; import { interpolateArray } from '../lib/maps/maps-utils'; +import tinycolor from "tinycolor2"; +import { initSchema, addToSchema, addGroupInfo } from '@app/core/schema-utils'; +import { tripAnimationSchema } from '../lib/maps/schemes'; +import L from 'leaflet'; @Component({ selector: 'trip-animation', @@ -18,35 +22,45 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { mapWidget: MapWidgetController; historicalData; intervals; - normalizationStep = 500; + normalizationStep = 1000; interpolatedData = []; - + widgetConfig; + settings; constructor(private cd: ChangeDetectorRef) { } ngOnInit(): void { + this.widgetConfig = this.ctx.widgetConfig; + const settings = { + normalizationStep: 1000, + buttonColor: tinycolor(this.widgetConfig.color).setAlpha(0.54).toRgbString(), + disabledButtonColor: tinycolor(this.widgetConfig.color).setAlpha(0.3).toRgbString(), + rotationAngle: 0 + } + this.settings = { ...settings, ...this.ctx.settings }; + //this.ctx.settings = settings; + console.log("TripAnimationComponent -> ngOnInit -> this.ctx.settings", this.ctx.settings) let subscription = this.ctx.subscriptions[Object.keys(this.ctx.subscriptions)[0]]; if (subscription) subscription.callbacks.onDataUpdated = (updated) => { this.historicalData = parseArray(this.ctx.data); - this.historicalData.forEach(el => { - console.log("TripAnimationComponent -> if -> el", el) + this.historicalData.forEach(ds => ds.forEach(el => { el.longitude += (Math.random() - 0.5) el.latitude += (Math.random() - 0.5) - }); + })); this.calculateIntervals(); + this.timeUpdated(this.intervals[0]); this.cd.detectChanges(); + this.mapWidget.map.map.invalidateSize(); } } ngAfterViewInit() { this.mapWidget = new MapWidgetController(MapProviders.openstreet, false, this.ctx, this.mapContainer.nativeElement); - this.mapWidget.data } timeUpdated(time) { - //this.mapWidget.ma - const currentPosition = this.interpolatedData.map(dataSource=>dataSource[time]); - console.log("TripAnimationComponent -> timeUpdated -> currentPosition", currentPosition) + const currentPosition = this.interpolatedData.map(dataSource => dataSource[time]); + this.mapWidget.map.updateMarkers(currentPosition); } calculateIntervals() { @@ -57,9 +71,17 @@ export class TripAnimationComponent implements OnInit, AfterViewInit { } this.intervals.push(dataSource[dataSource.length - 1]?.time); this.interpolatedData[index] = interpolateArray(dataSource, this.intervals); - console.log("TripAnimationComponent -> calculateIntervals -> this.intervals", this.intervals) - }); } + static getSettingsSchema() { + let schema = initSchema(); + addToSchema(schema, TbMapWidgetV2.getProvidersSchema()); + addGroupInfo(schema, "Map Provider Settings"); + addToSchema(schema, tripAnimationSchema); + addGroupInfo(schema, "Trip Animation Settings"); + return schema; + } } + +export let TbTripAnimationWidget = TripAnimationComponent; \ No newline at end of file diff --git a/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.ts b/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.ts index 8ae52c9611..7380a5dde5 100644 --- a/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.ts +++ b/ui-ngx/src/app/shared/components/time/history-selector/history-selector.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit, OnChanges, Input, Output, EventEmitter, ChangeDetectorRef } from '@angular/core'; -import { interval } from 'rxjs'; +import { interval, Subscription } from 'rxjs'; import { filter, tap } from 'rxjs/operators'; @Component({ @@ -34,23 +34,25 @@ export class HistorySelectorComponent implements OnInit, OnChanges { play() { this.playing = true; - this.interval = interval(1000 / this.speed) - .pipe( - filter(() => this.playing), - tap(() => this.index++)).subscribe(() => { - if (this.index < this.maxTimeIndex) { - this.cd.detectChanges(); - this.onTimeUpdated.emit(this.intervals[this.index]); - } - else { - this.interval.complete(); - } - }, err => { - console.log(err); - }, () => { - this.index = this.minTimeIndex; - this.playing = false; - }) + if (!this.interval) + this.interval = interval(1000 / this.speed) + .pipe( + filter(() => this.playing), + tap(() => this.index++)).subscribe(() => { + if (this.index < this.maxTimeIndex) { + this.cd.detectChanges(); + this.onTimeUpdated.emit(this.intervals[this.index]); + } + else { + this.interval.complete(); + } + }, err => { + console.log(err); + }, () => { + this.index = this.minTimeIndex; + this.playing = false; + this.interval = null; + }); } pause() { diff --git a/ui-ngx/src/polyfills.ts b/ui-ngx/src/polyfills.ts index 3c909f0979..dd78865e00 100644 --- a/ui-ngx/src/polyfills.ts +++ b/ui-ngx/src/polyfills.ts @@ -93,6 +93,7 @@ import { TbAnalogueRadialGauge } from '@home/components/widget/lib/analogue-radi import { TbAnalogueLinearGauge } from '@home/components/widget/lib/analogue-linear-gauge'; import { TbCanvasDigitalGauge } from '@home/components/widget/lib/digital-gauge'; import { TbMapWidgetV2 } from '@home/components/widget/lib/maps/map-widget2'; +import { TbTripAnimationWidget } from '@app/modules/home/components/widget/trip-animation/trip-animation.component'; import * as tinycolor_ from 'tinycolor2'; @@ -106,3 +107,5 @@ const tinycolor = tinycolor_; (window as any).TbAnalogueLinearGauge = TbAnalogueLinearGauge; (window as any).TbCanvasDigitalGauge = TbCanvasDigitalGauge; (window as any).TbMapWidgetV2 = TbMapWidgetV2; +(window as any).TbTripAnimationWidget = TbTripAnimationWidget; +console.log("TbTripAnimationWidget", TbTripAnimationWidget)