Fix conflicts

This commit is contained in:
Igor Kulikov 2020-04-28 20:02:33 +03:00
commit 413ad261e2
22 changed files with 302 additions and 198 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1886,19 +1886,19 @@
"@types/geojson": "*"
}
},
"@types/leaflet-polylinedecorator": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@types/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz",
"integrity": "sha512-Z2BXZDjKEqHclwrAmhYdF1RwyFfa/NFxsoF79sitzaj5D/4YWHp/zDRcUZar5cQFKRgK66AYEIF7nKVuMzUGdw==",
"@types/leaflet-markercluster": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@types/leaflet-markercluster/-/leaflet-markercluster-1.0.3.tgz",
"integrity": "sha1-ZBUb5FP2SQ6HUVAEgt65YQZOeCw=",
"dev": true,
"requires": {
"@types/leaflet": "*"
}
},
"@types/leaflet.markercluster": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/@types/leaflet.markercluster/-/leaflet.markercluster-1.4.2.tgz",
"integrity": "sha512-QQ//hevAxMH2dlRQdRre7V/1G+TbtuDtZnZF/75TNwVIgklrsQVCIcS/cvLsl7UUryfPJ6xmoYHfFzK5iGVgpg==",
"@types/leaflet-polylinedecorator": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@types/leaflet-polylinedecorator/-/leaflet-polylinedecorator-1.6.0.tgz",
"integrity": "sha512-Z2BXZDjKEqHclwrAmhYdF1RwyFfa/NFxsoF79sitzaj5D/4YWHp/zDRcUZar5cQFKRgK66AYEIF7nKVuMzUGdw==",
"dev": true,
"requires": {
"@types/leaflet": "*"
@ -4873,9 +4873,9 @@
"dev": true
},
"electron-to-chromium": {
"version": "1.3.420",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.420.tgz",
"integrity": "sha512-iVmQhf25F+5bdAyDrfOmCMjyLlIwsr9UT/LyYPQ3J1Vrypr9IgHf2PxqlsnzicnRAYDev6S9cl1tYlDHZUHY/g==",
"version": "1.3.421",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.421.tgz",
"integrity": "sha512-ogxgmvHGfDuLA+GtgfK0jkFWlBb4MCZK2U1MM+l98sf4U3Ixtrfw1iC9w4mQqNvo+lHgM4pR62TqoT4QrvKJCw==",
"dev": true
},
"elliptic": {
@ -5946,9 +5946,9 @@
}
},
"graceful-fs": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
"dev": true
},
"hammerjs": {
@ -8881,9 +8881,9 @@
}
},
"npm-registry-fetch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.3.tgz",
"integrity": "sha512-WGvUx0lkKFhu9MbiGFuT9nG2NpfQ+4dCJwRwwtK2HK5izJEvwDxMeUyqbuMS7N/OkpVCqDorV6rO5E4V9F8lJw==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.4.tgz",
"integrity": "sha512-6jb34hX/iYNQebqWUHtU8YF6Cjb1H6ouTFPClYsyiW6lpFkljTpdeftm53rRojtja1rKAvKNIIiTS5Sjpw4wsA==",
"dev": true,
"requires": {
"JSONStream": "^1.3.4",
@ -10441,9 +10441,9 @@
}
},
"postcss-value-parser": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz",
"integrity": "sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg==",
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
"integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
"dev": true
},
"prepend-http": {

View File

@ -61,7 +61,7 @@
"leaflet-geometryutil": "^0.9.3",
"leaflet-polylinedecorator": "^1.6.0",
"leaflet-providers": "^1.9.1",
"leaflet.gridlayer.googlemutant": "^0.8.0",
"leaflet.gridlayer.googlemutant": "0.8.0",
"leaflet.markercluster": "^1.4.1",
"material-design-icons": "^3.0.1",
"messageformat": "^2.3.0",
@ -108,8 +108,8 @@
"@types/jstree": "^3.3.39",
"@types/jszip": "^3.1.7",
"@types/leaflet": "^1.5.12",
"@types/leaflet.markercluster": "^1.4.2",
"@types/leaflet-polylinedecorator": "^1.6.0",
"@types/leaflet-markercluster": "^1.0.3",
"@types/lodash": "^4.14.150",
"@types/raphael": "^2.3.0",
"@types/react": "^16.9.34",

View File

@ -62,19 +62,21 @@ export function mergeSchemes(schemes: JsonSettingsSchema[]): JsonSettingsSchema
}, initSchema());
}
export function addCondition(schema: JsonSettingsSchema, condition: string): JsonSettingsSchema {
export function addCondition(schema: JsonSettingsSchema, condition: string, exclude: string[] = []): JsonSettingsSchema {
schema.form = schema.form.map(element => {
if (typeof element === 'string') {
return {
key: element,
condition
if (!exclude.includes(element) && !exclude.includes(element.key)) {
if (typeof element === 'string') {
return {
key: element,
condition
}
}
}
if (typeof element === 'object') {
if (element.condition) {
element.condition += ' && ' + condition
if (typeof element === 'object') {
if (element.condition) {
element.condition += ' && ' + condition
}
else element.condition = condition;
}
else element.condition = condition;
}
return element;
});

View File

@ -15,8 +15,8 @@
///
import _ from 'lodash';
import { fromEvent, Observable, of, Subject } from 'rxjs';
import { finalize, map, share } from 'rxjs/operators';
import { Observable, Subject, fromEvent, of } from 'rxjs';
import { finalize, share, map } from 'rxjs/operators';
import base64js from 'base64-js';
export function onParentScrollOrWindowResize(el: Node): Observable<Event> {
@ -224,7 +224,7 @@ function scrollParents(node: Node): Node[] {
function hashCode(str) {
let hash = 0;
let i, char;
if (str.length == 0) return hash;
if (str.length === 0) return hash;
for (i = 0; i < str.length; i++) {
char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
@ -464,7 +464,7 @@ export function parseArray(input: any[]): any[] {
time: el[0],
deviceType: null
};
entityArray.forEach(entity => {
entityArray.filter(el => el.data.length).forEach(entity => {
obj[entity?.dataKey?.label] = entity?.data[i][1];
obj[entity?.dataKey?.label + '|ts'] = entity?.data[0][0];
if (entity?.dataKey?.label === 'type') {
@ -485,7 +485,7 @@ export function parseData(input: any[]): any[] {
dsIndex: i,
deviceType: null
};
entityArray.forEach(el => {
entityArray.filter(el => el.data.length).forEach(el => {
obj[el?.dataKey?.label] = el?.data[0][1];
obj[el?.dataKey?.label + '|ts'] = el?.data[0][0];
if (el?.dataKey?.label === 'type') {
@ -510,14 +510,13 @@ export function safeExecute(func: Function, params = []) {
return res;
}
export function parseFunction(source: any, params: string[] = []): Function {
export function parseFunction(source: any, params: string[] = ['def']): Function {
let res = null;
if (source?.length) {
try {
res = new Function(...params, source);
}
catch (err) {
console.error(err);
res = null;
}
}
@ -526,33 +525,34 @@ export function parseFunction(source: any, params: string[] = []): Function {
export function parseTemplate(template: string, data: object, translateFn?: (key: string) => string) {
let res = '';
let variables = '';
try {
if (template.match(/<link-act/g)) {
template = template.replace(/<link-act/g, '<a').replace(/link-act>/g, 'a>').replace(/name=(\'|")(.*?)(\'|")/g, `class='tb-custom-action' id='$2'`);
}
if (template.includes('i18n')) {
const translateRegexp = /\{i18n:(.*?)\}/;
template.match(new RegExp(translateRegexp.source, translateRegexp.flags + 'g')).forEach(match => {
template = template.replace(match, translateFn(match.match(translateRegexp)[1]));
if (translateFn) {
template = translateFn(template);
}
const formatted = template.match(/\$\{([^}]*)\:\d*\}/g);
if (formatted)
formatted.forEach(value => {
const [variable, digits] = value.replace('${', '').replace('}', '').split(':');
data[variable] = padValue(data[variable], +digits);
if (isNaN(data[variable])) data[value] = '';
template = template.replace(value, '${' + variable + '}');
});
const variables = template.match(/\$\{.*?\}/g);
if (variables) {
variables.forEach(variable => {
variable = variable.replace('${', '').replace('}', '');
if (!data[variable])
data[variable] = '';
})
}
const expressions = template.match(/\{(.*?)\}/g);
if (expressions) {
// TODO: not supported in IE
// const clearMatches = template.match(/(?<=\{)(.+?)(?=(\}|\:))/g);
const clearMatches = template.match(/\{(.+?)(\}|\:)/g);
for (const key in data) {
if (!key.includes('|'))
variables += `let ${key} = '${clearMatches[key] ? padValue(data[key], +clearMatches[key]) : data[key]}';`;
}
template = template.replace(/\:\d+\}/g, '}');
res = safeExecute(parseFunction(variables + ' return' + '`' + template + '`'));
}
else res = template;
const compiled = _.template(template);
res = compiled(data);
}
catch (ex) {
console.log(ex, variables, template)
console.log(ex, template)
}
return res;
}

View File

@ -14,19 +14,12 @@
/// limitations under the License.
///
import L, { LatLngBounds, LatLngTuple } from 'leaflet';
import L, { LatLngTuple, LatLngBounds, Point, MarkerClusterGroupOptions, markerClusterGroup } from 'leaflet';
import 'leaflet-providers';
import LM from 'leaflet.markercluster/dist/leaflet.markercluster';
import 'leaflet.markercluster/dist/leaflet.markercluster';
import {
FormattedData,
MapSettings,
MarkerSettings,
PolygonSettings,
PolylineSettings,
UnitedMapSettings
} from './map-models';
import { MapSettings, MarkerSettings, FormattedData, UnitedMapSettings, PolygonSettings, PolylineSettings } from './map-models';
import { Marker } from './markers';
import { BehaviorSubject, Observable } from 'rxjs';
import { filter } from 'rxjs/operators';
@ -48,7 +41,7 @@ export default abstract class LeafletMap {
bounds: L.LatLngBounds;
newMarker: L.Marker;
datasources: FormattedData[];
markersCluster: LM.markerClusterGroup;
markersCluster;
constructor(public $container: HTMLElement, options: UnitedMapSettings) {
this.options = options;
@ -72,7 +65,7 @@ export default abstract class LeafletMap {
setTimeout(options.initCallback, 0);
}
if (useClusterMarkers) {
const clusteringSettings: LM.MarkerClusterGroupOptions = {
const clusteringSettings: MarkerClusterGroupOptions = {
zoomToBoundsOnClick: zoomOnClick,
showCoverageOnHover,
removeOutsideVisibleBounds,
@ -85,7 +78,7 @@ export default abstract class LeafletMap {
if (maxZoom && maxZoom >= 0 && maxZoom < 19) {
clusteringSettings.disableClusteringAtZoom = Math.floor(maxZoom);
}
this.markersCluster = LM.markerClusterGroup(clusteringSettings);
this.markersCluster = markerClusterGroup(clusteringSettings);
this.ready$.subscribe(map => map.addLayer(this.markersCluster));
}
}
@ -213,7 +206,7 @@ export default abstract class LeafletMap {
});
this.map.fitBounds(bounds, { padding: padding || [50, 50], animate: false });
}
this.bounds = this.bounds.extend(bounds);
this.bounds = bounds;
}
}
@ -236,22 +229,20 @@ export default abstract class LeafletMap {
// Markers
updateMarkers(markersData) {
markersData.forEach(data => {
if (this.convertPosition(data)) {
if (data.rotationAngle || data.rotationAngle === 0) {
this.options.icon = L.divIcon({
html: `<div class="arrow" style="transform: translate(-10px, -10px) rotate(${data.rotationAngle}deg);"><div>`
})
}
else {
this.options.icon = null;
}
if (this.markers.get(data.entityName)) {
this.updateMarker(data.entityName, data, markersData, this.options)
}
else {
this.createMarker(data.entityName, data, markersData, this.options as MarkerSettings);
}
markersData.filter(mdata => !!this.convertPosition(mdata)).forEach(data => {
if (data.rotationAngle || data.rotationAngle === 0) {
this.options.icon = L.divIcon({
html: `<div class="arrow" style="transform: translate(-10px, -10px) rotate(${data.rotationAngle}deg);"><div>`
})
}
else {
this.options.icon = null;
}
if (this.markers.get(data.entityName)) {
this.updateMarker(data.entityName, data, markersData, this.options)
}
else {
this.createMarker(data.entityName, data, markersData, this.options as MarkerSettings);
}
});
}
@ -264,7 +255,7 @@ export default abstract class LeafletMap {
private createMarker(key: string, data: FormattedData, dataSources: FormattedData[], settings: MarkerSettings) {
this.ready$.subscribe(() => {
const newMarker = new Marker(this.convertPosition(data), settings, data, dataSources, this.dragMarker);
this.fitBounds(this.bounds.extend(newMarker.leafletMarker.getLatLng()), settings.draggableMarker && this.markers.size > 2);
this.fitBounds(this.bounds.extend(newMarker.leafletMarker.getLatLng()), settings.draggableMarker && this.markers.size < 2);
this.markers.set(key, newMarker);
if (this.options.useClusterMarkers) {
this.markersCluster.addLayer(newMarker.leafletMarker);
@ -299,6 +290,9 @@ export default abstract class LeafletMap {
}
}
setImageAlias(alias: Observable<any>) {
}
// Polyline
updatePolylines(polyData: FormattedData[][]) {
@ -328,7 +322,7 @@ export default abstract class LeafletMap {
updatePolyline(key: string, data: FormattedData[], dataSources: FormattedData[], settings: PolylineSettings) {
this.ready$.subscribe(() => {
this.polylines.get(key).updatePolyline(settings, data, dataSources);
this.polylines.get(key).updatePolyline(settings, data.map(el => this.convertPosition(el)), dataSources);
});
}

View File

@ -23,6 +23,7 @@ export type MapSettings = {
polygonKeyName: any;
draggableMarker: boolean;
initCallback?: () => any;
posFunction: (origXPos, origYPos) => { x, y };
defaultZoomLevel?: number;
disableScrollZooming?: boolean;
minZoomLevel?: number;
@ -31,6 +32,8 @@ export type MapSettings = {
lngKeyName?: string;
xPosKeyName?: string;
yPosKeyName?: string;
imageEntityAlias: string;
imageUrlAttribute: string;
mapProvider: MapProviders;
mapProviderHere: string;
mapUrl?: string;
@ -49,7 +52,9 @@ export type MapSettings = {
animate: boolean,
maxClusterRadius: number,
chunkedLoading: boolean,
removeOutsideVisibleBounds: boolean
removeOutsideVisibleBounds: boolean,
useCustomProvider: boolean,
customProviderTileUrl: string;
}
export enum MapProviders {

View File

@ -17,28 +17,28 @@
import { MapProviders, UnitedMapSettings } from './map-models';
import LeafletMap from './leaflet-map';
import {
commonMapSettingsSchema,
googleMapSettingsSchema,
hereMapSettingsSchema,
imageMapSettingsSchema,
mapPolygonSchema,
mapProviderSchema,
markerClusteringSettingsSchema,
markerClusteringSettingsSchemaLeaflet,
openstreetMapSettingsSchema,
routeMapSettingsSchema,
tencentMapSettingsSchema
openstreetMapSettingsSchema,
googleMapSettingsSchema,
imageMapSettingsSchema,
tencentMapSettingsSchema,
commonMapSettingsSchema,
routeMapSettingsSchema,
markerClusteringSettingsSchema,
markerClusteringSettingsSchemaLeaflet,
hereMapSettingsSchema,
mapProviderSchema,
mapPolygonSchema
} from './schemes';
import { MapWidgetInterface, MapWidgetStaticInterface } from './map-widget.interface';
import { GoogleMap, HEREMap, ImageMap, OpenStreetMap, TencentMap } from './providers';
import { parseArray, parseData, parseFunction, parseWithTranslation } from '@core/utils';
import { addCondition, addGroupInfo, addToSchema, initSchema, mergeSchemes } from '@core/schema-utils';
import { forkJoin } from 'rxjs';
import { MapWidgetStaticInterface, MapWidgetInterface } from './map-widget.interface';
import { OpenStreetMap, TencentMap, GoogleMap, HEREMap, ImageMap } from './providers';
import { parseFunction, parseArray, parseData, parseWithTranslation } from '@core/utils';
import { initSchema, addToSchema, mergeSchemes, addCondition, addGroupInfo } from '@core/schema-utils';
import { of, Subject } from 'rxjs';
import { WidgetContext } from '@app/modules/home/models/widget-component.models';
import { getDefCenterPosition } from './maps-utils';
import { JsonSettingsSchema, WidgetActionDescriptor } from '@shared/models/widget.models';
import { JsonSettingsSchema, WidgetActionDescriptor, DatasourceType, widgetType } from '@shared/models/widget.models';
import { EntityId } from '@shared/models/id/entity-id';
import { AttributeScope } from '@shared/models/telemetry/telemetry.models';
import { AttributeScope, DataKeyType, LatestTelemetry } from '@shared/models/telemetry/telemetry.models';
import { AttributeService } from '@core/http/attribute.service';
import { Type } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
@ -47,7 +47,7 @@ import { UtilsService } from '@core/services/utils.service';
// @dynamic
export class MapWidgetController implements MapWidgetInterface {
constructor(public mapProvider: MapProviders, private drawRoutes: boolean, public ctx: WidgetContext, $element: HTMLElement) {
constructor(public mapProvider: MapProviders, private drawRoutes: boolean, public ctx: WidgetContext, $element: HTMLElement, isEdit?) {
if (this.map) {
this.map.map.remove();
delete this.map;
@ -58,6 +58,9 @@ export class MapWidgetController implements MapWidgetInterface {
$element = ctx.$container[0];
}
this.settings = this.initSettings(ctx.settings);
if (isEdit) {
this.settings.draggableMarker = true;
}
this.settings.tooltipAction = this.getDescriptors('tooltipAction');
this.settings.markerClick = this.getDescriptors('markerClick');
this.settings.polygonClick = this.getDescriptors('polygonClick');
@ -69,6 +72,7 @@ export class MapWidgetController implements MapWidgetInterface {
}
parseWithTranslation.setTranslate(this.translate);
this.map = new MapClass($element, this.settings);
this.map.setImageAlias(this.subscribeForImageAttribute());
this.map.saveMarkerLocation = this.setMarkerLocation;
}
@ -85,26 +89,28 @@ export class MapWidgetController implements MapWidgetInterface {
public static getProvidersSchema(mapProvider: MapProviders) {
mapProviderSchema.schema.properties.provider.default = mapProvider;
return mergeSchemes([mapProviderSchema,
...Object.values(providerSets)?.map(
(setting: IProvider) => addCondition(setting?.schema, `model.provider === '${setting.name}'`))]);
...Object.keys(providerSets)?.map(
(key: string) => { const setting = providerSets[key]; return addCondition(setting?.schema, `model.provider === '${setting.name}'`) })]);
}
public static settingsSchema(mapProvider: MapProviders, drawRoutes: boolean): JsonSettingsSchema {
const schema = initSchema();
addToSchema(schema, this.getProvidersSchema(mapProvider));
if(mapProvider!=='image-map'){
addGroupInfo(schema, 'Map Provider Settings');
addToSchema(schema, mergeSchemes([commonMapSettingsSchema, addCondition(mapPolygonSchema, 'model.showPolygon === true')]));
addGroupInfo(schema, 'Map Provider Settings');
addToSchema(schema, addCondition(commonMapSettingsSchema, 'model.provider !== "image-map"'));
addGroupInfo(schema, 'Common Map Settings');
addToSchema(schema, addCondition(mapPolygonSchema, 'model.showPolygon === true', ['showPolygon']));
addGroupInfo(schema, 'Polygon Settings');
if (drawRoutes) {
addToSchema(schema, routeMapSettingsSchema);
addGroupInfo(schema, 'Route Map Settings');
} else if (mapProvider !== 'image-map') {
} else {
const clusteringSchema = mergeSchemes([markerClusteringSettingsSchema,
addCondition(markerClusteringSettingsSchemaLeaflet, `model.useClusterMarkers === true`)])
addCondition(markerClusteringSettingsSchemaLeaflet,
`model.useClusterMarkers === true && model.provider !== "image-map"`)])
addToSchema(schema, clusteringSchema);
addGroupInfo(schema, 'Markers Clustering Settings');
}}
}
return schema;
}
@ -125,9 +131,11 @@ export class MapWidgetController implements MapWidgetInterface {
};
}
translate = (key: string, defaultTranslation?: string):string => {
return (this.ctx.$injector.get(UtilsService).customTranslation(key, defaultTranslation || key)
|| this.ctx.$injector.get(TranslateService).instant(key));
translate = (key: string, defaultTranslation?: string): string => {
if (key)
return (this.ctx.$injector.get(UtilsService).customTranslation(key, defaultTranslation || key)
|| this.ctx.$injector.get(TranslateService).instant(key));
else return '';
}
getDescriptors(name: string): { [name: string]: ($event: Event) => void } {
@ -143,7 +151,7 @@ export class MapWidgetController implements MapWidgetInterface {
}
private onCustomAction(descriptor: WidgetActionDescriptor, $event: any) {
if ($event & $event.stopPropagation) {
if ($event && $event.stopPropagation) {
$event?.stopPropagation();
}
// safeExecute(parseFunction(descriptor.customFunction, ['$event', 'widgetContext']), [$event, this.ctx])
@ -156,29 +164,48 @@ export class MapWidgetController implements MapWidgetInterface {
setMarkerLocation = (e) => {
const attributeService = this.ctx.$injector.get(AttributeService);
forkJoin(
this.data.filter(data => !!e[data.dataKey.name])
.map(data => {
const entityId: EntityId = {
entityType: data.datasource.entityType,
id: data.datasource.entityId
};
return attributeService.saveEntityAttributes(
entityId,
AttributeScope.SHARED_SCOPE,
[{
key: data.dataKey.name,
value: e[data.dataKey.name]
}]
);
})).subscribe(res => {
});
const entityId: EntityId = {
entityType: e.$datasource.entityType,
id: e.$datasource.entityId
};
const attributes = [];
const timeseries = [];
const latLngProperties = [this.settings.latKeyName, this.settings.lngKeyName, this.settings.xPosKeyName, this.settings.yPosKeyName];
e.$datasource.dataKeys.forEach(key => {
if (latLngProperties.includes(key.name)) {
const value = {
key: key.name,
value: e[key.name]
};
if (key.type === DataKeyType.attribute) {
attributes.push(value)
}
if (key.type === DataKeyType.timeseries) {
timeseries.push(value)
}
}
});
if (timeseries.length) {
attributeService.saveEntityTimeseries(
entityId,
LatestTelemetry.LATEST_TELEMETRY,
timeseries
).subscribe(() => { });
}
if (attributes.length) {
attributeService.saveEntityAttributes(
entityId,
AttributeScope.SERVER_SCOPE,
attributes
).subscribe(() => { });
}
}
initSettings(settings: UnitedMapSettings): UnitedMapSettings {
const functionParams = ['data', 'dsData', 'dsIndex'];
this.provider = settings.provider || this.mapProvider;
if (!settings.mapProviderHere) {
if (this.provider === MapProviders.here && !settings.mapProviderHere) {
if (settings.mapProvider && hereProviders.includes(settings.mapProvider))
settings.mapProviderHere = settings.mapProvider
else settings.mapProviderHere = hereProviders[0];
@ -213,8 +240,7 @@ export class MapWidgetController implements MapWidgetInterface {
if (this.settings.draggableMarker) {
this.map.setDataSources(parseData(this.data));
}
else
this.map.updateMarkers(parseData(this.data));
this.map.updateMarkers(parseData(this.data));
}
resize() {
@ -222,6 +248,48 @@ export class MapWidgetController implements MapWidgetInterface {
this.map.onResize();
}
subscribeForImageAttribute() {
const imageEntityAlias = this.settings.imageEntityAlias;
const imageUrlAttribute = this.settings.imageUrlAttribute;
if (!imageEntityAlias || !imageUrlAttribute) {
return of(false);
}
const entityAliasId = this.ctx.aliasController.getEntityAliasId(imageEntityAlias);
if (!entityAliasId) {
return of(false);
}
const datasources = [
{
type: DatasourceType.entity,
name: imageEntityAlias,
aliasName: imageEntityAlias,
entityAliasId,
dataKeys: [
{
type: DataKeyType.attribute,
name: imageUrlAttribute,
label: imageUrlAttribute,
settings: {},
_hash: Math.random()
}
]
}
];
const result = new Subject();
const imageUrlSubscriptionOptions = {
datasources,
useDashboardTimewindow: false,
type: widgetType.latest,
callbacks: {
onDataUpdated: (subscription) => {
result.next(subscription?.data[0]?.data[0]);
}
}
};
this.ctx.subscriptionApi.createSubscription(imageUrlSubscriptionOptions, true).subscribe(() => { });
return result;
}
onDestroy() {
}
}

View File

@ -16,8 +16,10 @@
.arrow {
height: 30px;
width: 30px;
background-size: cover;
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtCAMAAAANxBKoAAACAVBMVEUAAAAAqv9AgP8ggP8udP8qgP8ndv8kbf8kgP8eeP8rcf8mc/8jdP8hev8me/8kdv8jcv8pcP8ic/8neP8leP8ofP8mef8pev8nef8oe/8nef8pef8qfv8qgf8qe/8mev8off8oev8oef8oe/8pev8qe/8oe/8off8pfP8oev8pev8qe/8qfP8pev8pe/8qfP8pe/8oev8pe/8qe/8qfP8qfP8qff8qff8qfP8qff8pe/8qff8qfP8qfP8pev8pev8JYf8KYP8UY/8UZf8WY/8WZv8YZP8bZP8fZv8fZ/8gZv8gZ/8hZP8iZ/8jaf8jav8kaP8kav8ka/8kbP8kbf8kb/8lbP8lbf8lbv8lb/8lcP8mb/8mcP8mcf8ncf8ncv8nc/8ndP8ndf8ocv4odP8odf8odv8od/8oeP8peP8pef8pev8qev8qe/8qfP8rbP8rfP8rff8tc/4vcP4xbv4zcf42dP49df4+gP4/fv5Rif5biP1ul/14mvx4nvyMrfuMrvuWsfuctvuguPuww/vD0fnH1vrI1frK2PrL2fnV3vnb4vnc5fnd5fnd5vne5fnj6vnl6/jm7Pno7fXo7fbo7ffo7fjp7fnp7vjq7vjs8fnt8Pjt8fjw8fXw8fbw8fjy8/jz9fn5+fj7+/f++/j/+/X/+/b/+/f/+/j//Pj//vhoUaHMAAAAQHRSTlMAAwQICwwNDg4REhQWFxscHTI1QkRGSktOU1RdYWFscXJzhYWKqre6wMHDw8PHx8rN09TW1uLi7e/x8vLz9fj5hfwW0QAAAnVJREFUSMeV1fdb00AYB/BzoQjurSjuvQcuFLcgWqTVtLVpL0GS2GuDuLeouPeAiLOuwOFf6WU0ucvq4/d52v6Qz/M+18u97wHgyfh5m5vUYlHt2rV8BojOqGUqonNhVgTegfxZE2JXoMAUFgXYsSoKy3YfnoIiUqxm8UwUnSoaT0WVUuPi6lCUz+ft/+pqNYwqsiwrlm8s45XBVpE7BQgFyeZLbB1ihVwmefjpDSjbi7HwziArCdlU/MArjDHfaestBh4dZs9/JBb/4kVbo5FEr/JaWRL4VPvZ39jMVV4q63qiCx7bIfDJtst/LYt/JnLldaNuACbS9JwiQj4Zu/3HlDr5nEyJivMcgPn0Nogwfaq1Z9igQ7pO9AuqNEJzQINTV5ZghjvywLFG6dYMVRptAF3uPvBc8xPsWH0Q44ccpEqjvaBoa0lI7/ts2kHdCsbDJ5jSSC2/SEU8856x+hDGd+JZujQquvp6ieT7Nyel0o/jCSgzTefq0y81I30f7PRr2i1fbWrd+98yXtMGfOt29wTyiebHpu83dZ+m3U969qSBeje5DHeod8Dx5PeYZ7/rPO8y0XLvk+1J8UcJyLzLScw5kTsgz8Xu2vXJV0uaOSfsGcznZZGcwdi1L5qV13HmDILV3tY1z3fbxa8Wv+Se74VEj/H3jmz0TvuVN4Z+x/ZORF8efU64s/CtUT0vCbk0d/DZTSgxPQ/WhswTSYTZrDNPllaaVQo1q/Y4k63mv+YgmFZxxk6gR/LsCngcO+6nR9lCrfcqqQ2/dxqD7rT1IXhxyB24O8BuCr9eq9axU7F7wYjoy3ty3TZVLaCC2rRxru/hPwVgtEdFK5vOAAAAAElFTkSuQmCC") no-repeat center center;
background-size: contain;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC0AAAAtCAMAAAANxBKoAAACAVBMVEUAAAAAqv9AgP8ggP8udP8qgP8ndv8kbf8kgP8eeP8rcf8mc/8jdP8hev8me/8kdv8jcv8pcP8ic/8neP8leP8ofP8mef8pev8nef8oe/8nef8pef8qfv8qgf8qe/8mev8off8oev8oef8oe/8pev8qe/8oe/8off8pfP8oev8pev8qe/8qfP8pev8pe/8qfP8pe/8oev8pe/8qe/8qfP8qfP8qff8qff8qfP8qff8pe/8qff8qfP8qfP8pev8pev8JYf8KYP8UY/8UZf8WY/8WZv8YZP8bZP8fZv8fZ/8gZv8gZ/8hZP8iZ/8jaf8jav8kaP8kav8ka/8kbP8kbf8kb/8lbP8lbf8lbv8lb/8lcP8mb/8mcP8mcf8ncf8ncv8nc/8ndP8ndf8ocv4odP8odf8odv8od/8oeP8peP8pef8pev8qev8qe/8qfP8rbP8rfP8rff8tc/4vcP4xbv4zcf42dP49df4+gP4/fv5Rif5biP1ul/14mvx4nvyMrfuMrvuWsfuctvuguPuww/vD0fnH1vrI1frK2PrL2fnV3vnb4vnc5fnd5fnd5vne5fnj6vnl6/jm7Pno7fXo7fbo7ffo7fjp7fnp7vjq7vjs8fnt8Pjt8fjw8fXw8fbw8fjy8/jz9fn5+fj7+/f++/j/+/X/+/b/+/f/+/j//Pj//vhoUaHMAAAAQHRSTlMAAwQICwwNDg4REhQWFxscHTI1QkRGSktOU1RdYWFscXJzhYWKqre6wMHDw8PHx8rN09TW1uLi7e/x8vLz9fj5hfwW0QAAAnVJREFUSMeV1fdb00AYB/BzoQjurSjuvQcuFLcgWqTVtLVpL0GS2GuDuLeouPeAiLOuwOFf6WU0ucvq4/d52v6Qz/M+18u97wHgyfh5m5vUYlHt2rV8BojOqGUqonNhVgTegfxZE2JXoMAUFgXYsSoKy3YfnoIiUqxm8UwUnSoaT0WVUuPi6lCUz+ft/+pqNYwqsiwrlm8s45XBVpE7BQgFyeZLbB1ihVwmefjpDSjbi7HwziArCdlU/MArjDHfaestBh4dZs9/JBb/4kVbo5FEr/JaWRL4VPvZ39jMVV4q63qiCx7bIfDJtst/LYt/JnLldaNuACbS9JwiQj4Zu/3HlDr5nEyJivMcgPn0Nogwfaq1Z9igQ7pO9AuqNEJzQINTV5ZghjvywLFG6dYMVRptAF3uPvBc8xPsWH0Q44ccpEqjvaBoa0lI7/ts2kHdCsbDJ5jSSC2/SEU8856x+hDGd+JZujQquvp6ieT7Nyel0o/jCSgzTefq0y81I30f7PRr2i1fbWrd+98yXtMGfOt29wTyiebHpu83dZ+m3U969qSBeje5DHeod8Dx5PeYZ7/rPO8y0XLvk+1J8UcJyLzLScw5kTsgz8Xu2vXJV0uaOSfsGcznZZGcwdi1L5qV13HmDILV3tY1z3fbxa8Wv+Se74VEj/H3jmz0TvuVN4Z+x/ZORF8efU64s/CtUT0vCbk0d/DZTSgxPQ/WhswTSYTZrDNPllaaVQo1q/Y4k63mv+YgmFZxxk6gR/LsCngcO+6nR9lCrfcqqQ2/dxqD7rT1IXhxyB24O8BuCr9eq9axU7F7wYjoy3ty3TZVLaCC2rRxru/hPwVgtEdFK5vOAAAAAElFTkSuQmCC");
background-position: center;
background-repeat: no-repeat;
}
.leaflet-div-icon,

View File

@ -150,7 +150,6 @@ export class Marker {
}
createDefaultMarkerIcon(color, onMarkerIconReady) {
const pinColor = color.substr(1);
const icon = L.icon({
iconUrl: 'https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|' + color,
iconSize: [21, 34],

View File

@ -73,11 +73,14 @@ export class Polyline {
getPolyStyle(settings: PolylineSettings): L.PolylineOptions {
return {
color: settings.useColorFunction ?
safeExecute(settings.colorFunction, [this.data, this.dataSources, this.data[0]?.dsIndex]) : settings.color,
safeExecute(settings.colorFunction,
[this.data, this.dataSources, this.dataSources[0]?.dsIndex]) : settings.color,
opacity: settings.useStrokeOpacityFunction ?
safeExecute(settings.strokeOpacityFunction, [this.data, this.dataSources, this.data[0]?.dsIndex]) : settings.strokeOpacity,
safeExecute(settings.strokeOpacityFunction,
[this.data, this.dataSources, this.dataSources[0]?.dsIndex]) : settings.strokeOpacity,
weight: settings.useStrokeWeightFunction ?
safeExecute(settings.strokeWeightFunction, [this.data, this.dataSources, this.data[0]?.dsIndex]) : settings.strokeWeight,
safeExecute(settings.strokeWeightFunction,
[this.data, this.dataSources, this.dataSources[0]?.dsIndex]) : settings.strokeWeight,
}
}

View File

@ -17,7 +17,9 @@
import L, { LatLngLiteral } from 'leaflet';
import LeafletMap from '../leaflet-map';
import { UnitedMapSettings } from '../map-models';
import { aspectCache } from '@app/core/utils';
import { aspectCache, parseFunction } from '@app/core/utils';
import { Observable } from 'rxjs';
import { map, filter, switchMap } from 'rxjs/operators';
const maxZoom = 4;// ?
@ -27,10 +29,13 @@ export class ImageMap extends LeafletMap {
aspect = 0;
width = 0;
height = 0;
imageUrl;
constructor($container: HTMLElement, options: UnitedMapSettings) {
super($container, options);
aspectCache(options.mapUrl).subscribe(aspect => {
options.posFunction = parseFunction(options.posFunction, ['origXPos', 'origYPos']) as ((origXPos, origYPos) => { x, y });
this.imageUrl = options.mapUrl;
aspectCache(this.imageUrl).subscribe(aspect => {
this.aspect = aspect;
this.onResize();
super.setMap(this.map);
@ -38,6 +43,16 @@ export class ImageMap extends LeafletMap {
});
}
setImageAlias(alias: Observable<any>) {
alias.pipe(filter(result => result), map(el => el[1]), switchMap(res => {
this.imageUrl = res;
return aspectCache(res);
})).subscribe(aspect => {
this.aspect = aspect;
this.onResize(true);
});
}
updateBounds(updateImage?, lastCenterPos?) {
const w = this.width;
const h = this.height;
@ -53,8 +68,7 @@ export class ImageMap extends LeafletMap {
if (this.imageOverlay) {
this.imageOverlay.setBounds(bounds);
} else {
this.imageOverlay = L.imageOverlay(this.options.mapUrl, bounds).addTo(this.map);
this.imageOverlay = L.imageOverlay(this.imageUrl, bounds).addTo(this.map);
}
const padding = 200 * maxZoom;
southWest = this.pointToLatLng(-padding, h + padding);
@ -116,6 +130,7 @@ export class ImageMap extends LeafletMap {
}
convertPosition(expression): L.LatLng {
if (isNaN(expression[this.options.xPosKeyName]) || isNaN(expression[this.options.yPosKeyName])) return null;
return this.pointToLatLng(
expression[this.options.xPosKeyName] * this.width,
expression[this.options.yPosKeyName] * this.height);
@ -129,10 +144,10 @@ export class ImageMap extends LeafletMap {
return L.CRS.Simple.latLngToPoint(latLng, maxZoom - 1);
}
/* convertToCustomFormat(position: L.LatLng): object {
convertToCustomFormat(position: L.LatLng): object {
return {
[this.options.xPosKeyName]: (position.lng + 180) / 360,
[this.options.yPosKeyName]: (position.lat + 180) / 360
}
}*/
}
}

View File

@ -22,7 +22,11 @@ export class OpenStreetMap extends LeafletMap {
constructor($container, options: UnitedMapSettings) {
super($container, options);
const map = L.map($container).setView(options?.defaultCenterPosition, options?.defaultZoomLevel);
const tileLayer = (L.tileLayer as any).provider(options.mapProvider || 'OpenStreetMap.Mapnik');
let tileLayer;
if (options.useCustomProvider)
tileLayer = L.tileLayer(options.customProviderTileUrl);
else
tileLayer = (L.tileLayer as any).provider(options.mapProvider || 'OpenStreetMap.Mapnik');
tileLayer.addTo(map);
super.setMap(map);
super.initSettings(options);

View File

@ -336,11 +336,6 @@ export const commonMapSettingsSchema =
title: 'Color function: f(data, dsData, dsIndex)',
type: 'string'
},
showPolygon: {
title: 'Show polygon',
type: 'boolean',
default: false
},
markerImage: {
title: 'Custom marker image',
type: 'string'
@ -439,8 +434,7 @@ export const commonMapSettingsSchema =
type: 'image'
}
]
},
'showPolygon',
}
]
};
@ -450,6 +444,11 @@ export const mapPolygonSchema =
title: 'Map Polygon Configuration',
type: 'object',
properties: {
showPolygon: {
title: 'Show polygon',
type: 'boolean',
default: false
},
polygonKeyName: {
title: 'Polygon key name',
type: 'string',
@ -491,6 +490,7 @@ export const mapPolygonSchema =
required: []
},
form: [
'showPolygon',
'polygonKeyName',
{
key: 'polygonColor',

View File

@ -17,7 +17,7 @@
-->
<div class="trip-animation-widget">
<div class="trip-animation-label-container" *ngIf="settings.showLabel">
{{label }}
{{label}}
</div>
<div class="trip-animation-container" fxLayout="column">
<div class="map" #map></div>

View File

@ -22,8 +22,8 @@ import { interpolateOnPointSegment } from 'leaflet-geometryutil';
import { AfterViewInit, ChangeDetectorRef, Component, Input, OnInit, SecurityContext, ViewChild } from '@angular/core';
import { MapWidgetController, TbMapWidgetV2 } from '../lib/maps/map-widget2';
import { MapProviders } from '../lib/maps/map-models';
import { parseArray, parseWithTranslation, safeExecute } from '@app/core/utils';
import { addGroupInfo, addToSchema, initSchema } from '@app/core/schema-utils';
import { parseArray, parseWithTranslation, safeExecute, parseTemplate } from '@app/core/utils';
import { initSchema, addToSchema, addGroupInfo } from '@app/core/schema-utils';
import { tripAnimationSchema } from '../lib/maps/schemes';
import { DomSanitizer } from '@angular/platform-browser';
import { WidgetContext } from '@app/modules/home/models/widget-component.models';
@ -100,8 +100,8 @@ export class TripAnimationComponent implements OnInit, AfterViewInit {
timeUpdated(time: number) {
const currentPosition = this.interpolatedData.map(dataSource => dataSource[time]);
this.activeTrip = currentPosition[0];
this.minTime = moment(this.historicalData[0][this.historicalData.length - 1]?.time).format('YYYY-MM-DD HH:mm:ss')
this.maxTime = moment(this.historicalData[0][0]?.time).format('YYYY-MM-DD HH:mm:ss')
this.minTime = moment(this.intervals[this.intervals.length - 1]).format('YYYY-MM-DD HH:mm:ss')
this.maxTime = moment(this.intervals[0]).format('YYYY-MM-DD HH:mm:ss')
this.calcLabel();
this.calcTooltip();
if (this.mapWidget) {

View File

@ -51,6 +51,16 @@
padding: 0 0 2px;
margin: 2px;
line-height: 24px;
mat-icon {
width: 24px;
height: 24px;
svg {
width: inherit;
height: inherit;
}
}
}
}
@ -80,24 +90,24 @@
mat-slider {
min-width: 80px;
}
}
button.mat-button.mat-icon-button {
width: 44px;
min-width: 44px;
height: 44px;
min-height: 44px;
margin: 0;
line-height: 28px;
.mat-icon-button {
width: 44px;
min-width: 44px;
height: 48px;
min-height: 48px;
margin: 0;
line-height: 28px;
mat-icon {
width: 28px;
height: 28px;
font-size: 28px;
mat-icon {
width: 24px;
height: 24px;
font-size: 24px;
svg {
width: inherit;
height: inherit;
}
svg {
width: inherit;
height: inherit;
}
}

View File

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core';
import { Component, OnInit, OnChanges, Input, Output, EventEmitter, ChangeDetectorRef } from '@angular/core';
import { interval } from 'rxjs';
import { filter } from 'rxjs/operators';
import { HistorySelectSettings } from '@app/modules/home/components/widget/lib/maps/map-models';

View File

@ -15,7 +15,7 @@
///
import { Pipe, PipeTransform } from '@angular/core';
import { parseWithTranslation } from '@app/core/utils';
import { parseTemplate, parseWithTranslation } from '@app/core/utils';
@Pipe({ name: 'tbParseTemplate' })
export class TbTemplatePipe implements PipeTransform {

View File

@ -2,7 +2,8 @@
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "../out-tsc/app",
"types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify", "react", "react-dom", "jstree", "raphael", "canvas-gauges"]
"types": ["node", "jquery", "flot", "tooltipster", "tinycolor2", "js-beautify",
"react", "react-dom", "jstree", "raphael", "canvas-gauges", "leaflet", "leaflet-markercluster"]
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true

View File

@ -11,7 +11,8 @@
},
"import-blacklist": [
true,
"rxjs/Rx"
"rxjs/Rx",
"^.*/public-api$"
],
"interface-name": false,
"max-classes-per-file": false,