UI: Maps - add color range type to color settings.

This commit is contained in:
Igor Kulikov 2025-03-13 12:45:00 +02:00
parent 480e6a4935
commit 2d86e816f2
14 changed files with 314 additions and 65 deletions

View File

@ -15,15 +15,24 @@
///
import {
DataLayerColorSettings, DataLayerColorType,
DataLayerPatternSettings, DataLayerPatternType,
MapDataLayerSettings, MapDataLayerType, mapDataSourceSettingsToDatasource,
MapStringFunction, MapType,
DataLayerColorSettings,
DataLayerColorType,
DataLayerPatternSettings,
DataLayerPatternType,
MapDataLayerSettings,
MapDataLayerType,
mapDataSourceSettingsToDatasource,
MapStringFunction,
MapType,
TbMapDatasource
} from '@shared/models/widget/maps/map.models';
import {
createLabelFromPattern,
guid, isDefined,
guid,
isDefined,
isDefinedAndNotNull,
isNumber,
isNumeric,
mergeDeepIgnoreArray,
parseTbFunction,
safeExecuteTbFunction
@ -32,10 +41,11 @@ import L from 'leaflet';
import { CompiledTbFunction } from '@shared/models/js-function.models';
import { forkJoin, Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import { FormattedData } from '@shared/models/widget.models';
import { DataKey, FormattedData } from '@shared/models/widget.models';
import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe';
import { TbMap } from '@home/components/widget/lib/maps/map';
import { WidgetContext } from '@home/models/widget-component.models';
import { ColorRange } from '@shared/models/widget-settings.models';
export class DataLayerPatternProcessor {
@ -77,22 +87,26 @@ export class DataLayerColorProcessor {
private colorFunction: CompiledTbFunction<MapStringFunction>;
private color: string;
private rangeKey: DataKey;
private range: ColorRange[];
constructor(private dataLayer: TbMapDataLayer,
private settings: DataLayerColorSettings) {}
public setup(): Observable<void> {
this.color = this.settings.color;
if (this.settings.type === DataLayerColorType.function) {
if (this.settings.type === DataLayerColorType.range) {
this.rangeKey = this.settings.rangeKey;
this.range = this.settings.range;
} else if (this.settings.type === DataLayerColorType.function) {
return parseTbFunction<MapStringFunction>(this.dataLayer.getCtx().http, this.settings.colorFunction, ['data', 'dsData']).pipe(
map((parsed) => {
this.colorFunction = parsed;
return null;
})
);
} else {
return of(null)
}
return of(null)
}
public processColor(data: FormattedData<TbMapDatasource>, dsData: FormattedData<TbMapDatasource>[]): string {
@ -102,12 +116,33 @@ export class DataLayerColorProcessor {
if (!color) {
color = this.color;
}
} else if (this.settings.type === DataLayerColorType.range) {
color = this.color;
if (this.rangeKey && this.range?.length) {
const value = data[this.rangeKey.label];
if (isDefinedAndNotNull(value) && isNumeric(value)) {
const num = Number(value);
for (const range of this.range) {
if (DataLayerColorProcessor.constantRange(range) && range.from === num) {
color = range.color;
break;
} else if ((!isNumber(range.from) || num >= range.from) && (!isNumber(range.to) || num < range.to)) {
color = range.color;
break;
}
}
}
}
} else {
color = this.color;
}
return color;
}
static constantRange(range: ColorRange): boolean {
return isNumber(range.from) && isNumber(range.to) && range.from === range.to;
}
}
export abstract class TbDataLayerItem<S extends MapDataLayerSettings = MapDataLayerSettings, D extends TbMapDataLayer = TbMapDataLayer, L extends L.Layer = L.Layer> {
@ -169,6 +204,9 @@ export abstract class TbMapDataLayer<S extends MapDataLayerSettings = MapDataLay
public setup(): Observable<any> {
this.datasource = mapDataSourceSettingsToDatasource(this.settings);
this.datasource.dataKeys = this.settings.additionalDataKeys ? [...this.settings.additionalDataKeys] : [];
const colorRangeKeys = this.allColorSettings().filter(settings => settings.type === DataLayerColorType.range && settings.rangeKey)
.map(settings => settings.rangeKey);
this.datasource.dataKeys.push(...colorRangeKeys);
this.mapDataId = this.datasource.mapDataIds[0];
this.datasource = this.setupDatasource(this.datasource);
return forkJoin(
@ -251,6 +289,10 @@ export abstract class TbMapDataLayer<S extends MapDataLayerSettings = MapDataLay
return datasource;
}
protected allColorSettings(): DataLayerColorSettings[] {
return [];
}
protected onDataLayerEnabled(): void {}
protected onDataLayerDisabled(): void {}

View File

@ -17,11 +17,12 @@
import {
BaseMarkerShapeSettings,
ClusterMarkerColorFunction,
DataLayerColorSettings,
DataLayerColorType,
defaultBaseMarkersDataLayerSettings,
isValidLatLng,
loadImageWithAspect, MapDataLayerType,
MapStringFunction,
loadImageWithAspect,
MapDataLayerType,
MapType,
MarkerIconInfo,
MarkerIconSettings,
@ -53,17 +54,19 @@ import { ImagePipe } from '@shared/pipe/image.pipe';
import { TbMap } from '@home/components/widget/lib/maps/map';
import {
createColorMarkerIconElement,
createColorMarkerShapeURI, MarkerIconContainer,
createColorMarkerShapeURI,
MarkerIconContainer,
MarkerShape
} from '@shared/models/widget/maps/marker-shape.models';
import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
import {
TbLatestDataLayerItem,
TbLatestMapDataLayer, UnplacedMapDataItem
TbLatestMapDataLayer,
UnplacedMapDataItem
} from '@home/components/widget/lib/maps/data-layer/latest-map-data-layer';
import { TbImageMap } from '@home/components/widget/lib/maps/image-map';
import { TbMapDataLayer } from '@home/components/widget/lib/maps/data-layer/map-data-layer';
import { DataLayerColorProcessor, TbMapDataLayer } from '@home/components/widget/lib/maps/data-layer/map-data-layer';
export class MarkerDataProcessor<S extends MarkersDataLayerSettings = MarkersDataLayerSettings> {
@ -218,8 +221,7 @@ abstract class MarkerIconProcessor<S> {
abstract class BaseColorMarkerShapeProcessor<S extends BaseMarkerShapeSettings> extends MarkerIconProcessor<S> {
private markerColorFunction: CompiledTbFunction<MapStringFunction>;
private colorProcessor: DataLayerColorProcessor;
private defaultMarkerIconInfo: MarkerIconInfo;
protected constructor(protected dataProcessor: MarkerDataProcessor,
@ -229,40 +231,28 @@ abstract class BaseColorMarkerShapeProcessor<S extends BaseMarkerShapeSettings>
public setup(): Observable<void> {
const colorSettings = this.settings.color;
if (colorSettings.type === DataLayerColorType.function) {
return parseTbFunction<MapStringFunction>(this.dataProcessor.dataLayer.getCtx().http, colorSettings.colorFunction, ['data', 'dsData']).pipe(
map((parsed) => {
this.markerColorFunction = parsed;
return null;
})
);
} else {
this.colorProcessor = new DataLayerColorProcessor(this.dataProcessor.dataLayer, colorSettings);
const setup$: Observable<void>[] = [this.colorProcessor.setup()];
if (colorSettings.type === DataLayerColorType.constant) {
const color = tinycolor(colorSettings.color);
return this.createMarkerShape(color, 0, this.settings.size).pipe(
map((info) => {
this.defaultMarkerIconInfo = info;
return null;
}
));
setup$.push(
this.createMarkerShape(color, 0, this.settings.size).pipe(
map((info) => {
this.defaultMarkerIconInfo = info;
return null;
}))
);
}
return forkJoin(setup$).pipe(map(() => null));
}
public createMarkerIcon(data: FormattedData<TbMapDatasource>, dsData: FormattedData<TbMapDatasource>[], rotationAngle = 0): Observable<MarkerIconInfo> {
const colorSettings = this.settings.color;
let color: tinycolor.Instance;
if (colorSettings.type === DataLayerColorType.function) {
const functionColor = safeExecuteTbFunction(this.markerColorFunction, [data, dsData]);
if (isDefinedAndNotNull(functionColor)) {
color = tinycolor(functionColor);
} else {
color = tinycolor(colorSettings.color);
}
return this.createMarkerShape(color, rotationAngle, this.settings.size);
} else if (rotationAngle === 0) {
if (colorSettings.type === DataLayerColorType.constant && rotationAngle === 0) {
return of(this.defaultMarkerIconInfo);
} else {
color = tinycolor(colorSettings.color);
return this.createMarkerShape(color, rotationAngle, this.settings.size);
const color = this.colorProcessor.processColor(data, dsData);
return this.createMarkerShape(tinycolor(color), rotationAngle, this.settings.size);
}
}
@ -639,6 +629,15 @@ export class TbMarkersDataLayer extends TbLatestMapDataLayer<MarkersDataLayerSet
return datasource;
}
protected allColorSettings(): DataLayerColorSettings[] {
if (this.settings.markerType === MarkerType.shape) {
return [this.settings.markerShape.color];
} else if (this.settings.markerType === MarkerType.icon) {
return [this.settings.markerIcon.color];
}
return [];
}
protected defaultBaseSettings(map: TbMap<any>): Partial<MarkersDataLayerSettings> {
return defaultBaseMarkersDataLayerSettings(map.type());
}

View File

@ -14,7 +14,7 @@
/// limitations under the License.
///
import { ShapeDataLayerSettings, TbMapDatasource } from '@shared/models/widget/maps/map.models';
import { DataLayerColorSettings, ShapeDataLayerSettings, TbMapDatasource } from '@shared/models/widget/maps/map.models';
import L from 'leaflet';
import { TbMap } from '@home/components/widget/lib/maps/map';
import { forkJoin, Observable } from 'rxjs';
@ -45,6 +45,10 @@ export abstract class TbShapesDataLayer<S extends ShapeDataLayerSettings, L exte
};
}
protected allColorSettings(): DataLayerColorSettings[] {
return [this.settings.fillColor, this.settings.strokeColor];
}
protected doSetup(): Observable<any> {
this.fillColorProcessor = new DataLayerColorProcessor(this, this.settings.fillColor);
this.strokeColorProcessor = new DataLayerColorProcessor(this, this.settings.strokeColor);

View File

@ -16,16 +16,16 @@
import {
calculateInterpolationRatio,
calculateLastPoints,
calculateLastPoints, DataLayerColorSettings, DataLayerColorType,
defaultBaseTripsDataLayerSettings,
findRotationAngle,
interpolateLineSegment,
MapDataLayerType,
MapDataLayerType, MarkerType,
TbMapDatasource,
TripsDataLayerSettings
} from '@shared/models/widget/maps/map.models';
import { forkJoin, Observable } from 'rxjs';
import { FormattedData, WidgetActionType } from '@shared/models/widget.models';
import { DataKey, FormattedData, WidgetActionType } from '@shared/models/widget.models';
import { map } from 'rxjs/operators';
import L from 'leaflet';
import { deepClone, isDefined, isUndefined } from '@core/utils';
@ -530,9 +530,14 @@ export class TbTripsDataLayer extends TbMapDataLayer<TripsDataLayerSettings, TbT
protected setupDatasource(datasource: TbMapDatasource): TbMapDatasource {
datasource.dataKeys = [this.settings.xKey, this.settings.yKey];
const additionalKeys = this.allColorSettings().filter(settings => settings.type === DataLayerColorType.range && settings.rangeKey)
.map(settings => settings.rangeKey);
if (this.settings.additionalDataKeys?.length) {
const tsKeys = this.settings.additionalDataKeys.filter(key => key.type === DataKeyType.timeseries);
const latestKeys = this.settings.additionalDataKeys.filter(key => key.type !== DataKeyType.timeseries);
additionalKeys.push(...this.settings.additionalDataKeys);
}
if (additionalKeys.length) {
const tsKeys = additionalKeys.filter(key => key.type === DataKeyType.timeseries);
const latestKeys = additionalKeys.filter(key => key.type !== DataKeyType.timeseries);
datasource.dataKeys.push(...tsKeys);
if (latestKeys.length) {
datasource.latestDataKeys = latestKeys;
@ -541,6 +546,24 @@ export class TbTripsDataLayer extends TbMapDataLayer<TripsDataLayerSettings, TbT
return datasource;
}
protected allColorSettings(): DataLayerColorSettings[] {
const colorSettings: DataLayerColorSettings[] = [];
if (this.settings.showMarker) {
if (this.settings.markerType === MarkerType.shape) {
colorSettings.push(this.settings.markerShape.color);
} else if (this.settings.markerType === MarkerType.icon) {
colorSettings.push(this.settings.markerIcon.color);
}
}
if (this.settings.showPath) {
colorSettings.push(this.settings.pathStrokeColor);
}
if (this.settings.showPoints) {
colorSettings.push(this.settings.pointColor);
}
return colorSettings;
}
protected defaultBaseSettings(map: TbMap<any>): Partial<TripsDataLayerSettings> {
return defaultBaseTripsDataLayerSettings(map.type());
}

View File

@ -85,6 +85,10 @@ export class ColorRangeListComponent implements OnInit, ControlValueAccessor, On
@Input()
datasource: Datasource;
@Input()
@coerceBoolean()
simpleRange = false;
@Input()
@coerceBoolean()
advancedMode = false;
@ -133,7 +137,7 @@ export class ColorRangeListComponent implements OnInit, ControlValueAccessor, On
writeValue(value: any): void {
if (value) {
let rangeList: ColorRangeSettings = {};
if (isUndefined(value?.advancedMode) && value?.length) {
if (this.simpleRange || (isUndefined(value?.advancedMode) && value?.length)) {
rangeList.advancedMode = false;
rangeList.range = value;
} else {
@ -229,7 +233,11 @@ export class ColorRangeListComponent implements OnInit, ControlValueAccessor, On
}
updateModel() {
this.propagateChange(this.colorRangeListFormGroup.value);
if (this.simpleRange) {
this.propagateChange(this.colorRangeListFormGroup.get('range').value);
} else {
this.propagateChange(this.colorRangeListFormGroup.value);
}
}
}

View File

@ -22,6 +22,9 @@
<tb-toggle-option [value]="DataLayerColorType.constant">
{{ 'widgets.maps.data-layer.color-type-constant' | translate }}
</tb-toggle-option>
<tb-toggle-option [value]="DataLayerColorType.range">
{{ 'widgets.maps.data-layer.color-type-range' | translate }}
</tb-toggle-option>
<tb-toggle-option [value]="DataLayerColorType.function">
{{ 'widgets.maps.data-layer.color-type-function' | translate }}
</tb-toggle-option>
@ -35,6 +38,35 @@
</div>
<div class="tb-data-layer-color-settings-panel-body" [class.!hidden]="colorSettingsFormGroup.get('type').value !== DataLayerColorType.constant">
</div>
<div class="tb-data-layer-color-settings-panel-body" [class.!hidden]="colorSettingsFormGroup.get('type').value !== DataLayerColorType.range">
<tb-data-key-input
inlineField="false"
appearance="outline"
subscriptSizing="fixed"
label="{{ 'widgets.maps.data-layer.color-range-source-key' | translate }}"
required
requiredText="{{ 'widgets.maps.data-layer.color-range-source-key-required' }}"
[datasourceType]="dsType"
[entityAliasId]="dsEntityAliasId"
[deviceId]="dsDeviceId"
[aliasController]="context.aliasController"
[widgetType]="widgetType.latest"
[dataKeyType]="context.functionsOnly ? DataKeyType.function : null"
[dataKeyTypes]="[DataKeyType.attribute, DataKeyType.timeseries]"
[callbacks]="context.callbacks"
[generateKey]="context.generateDataKey"
(keyEdit)="editRangeKey()"
formControlName="rangeKey">
</tb-data-key-input>
<div class="tb-form-panel stroked">
<div translate>widgets.maps.data-layer.color-range</div>
<tb-color-range-list class="tb-color-ranges-panel"
simpleRange
formControlName="range"
[popover]="popover">
</tb-color-range-list>
</div>
</div>
<div class="tb-data-layer-color-settings-panel-body" [class.!hidden]="colorSettingsFormGroup.get('type').value !== DataLayerColorType.function">
<ng-container *ngTemplateOutlet="function"></ng-container>
</div>

View File

@ -16,6 +16,8 @@
@import '../../../../../../../../../scss/constants';
.tb-data-layer-color-settings-panel {
--mdc-outlined-text-field-outline-color: rgba(0,0,0,0.12);
--mat-form-field-trailing-icon-color: rgba(0,0,0,0.38);
width: 700px;
max-width: 90vw;
min-height: 300px;
@ -50,4 +52,14 @@
justify-content: flex-end;
align-items: flex-end;
}
.tb-color-ranges-panel {
flex: 1;
min-height: 0;
gap: 16px;
display: flex;
flex-direction: column;
.tb-color-ranges {
--mat-icon-color: rgba(0, 0, 0, 0.38);
}
}
}

View File

@ -17,12 +17,15 @@
import { Component, DestroyRef, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { TbPopoverComponent } from '@shared/components/popover.component';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { WidgetService } from '@core/http/widget.service';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { DataLayerColorSettings, DataLayerColorType } from '@shared/models/widget/maps/map.models';
import { DataLayerColorSettings, DataLayerColorType, MapType } from '@shared/models/widget/maps/map.models';
import { DataKey, DatasourceType, widgetType } from '@shared/models/widget.models';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { MapSettingsContext } from '@home/components/widget/lib/settings/common/map/map-settings.component.models';
@Component({
selector: 'tb-data-layer-color-settings-panel',
@ -33,9 +36,25 @@ import { DataLayerColorSettings, DataLayerColorType } from '@shared/models/widge
})
export class DataLayerColorSettingsPanelComponent extends PageComponent implements OnInit {
widgetType = widgetType;
DataKeyType = DataKeyType;
@Input()
colorSettings: DataLayerColorSettings;
@Input()
context: MapSettingsContext;
@Input()
dsType: DatasourceType;
@Input()
dsEntityAliasId: string;
@Input()
dsDeviceId: string;
@Input()
helpId = 'widget/lib/map/color_fn';
@ -63,14 +82,18 @@ export class DataLayerColorSettingsPanelComponent extends PageComponent implemen
{
type: [this.colorSettings?.type || DataLayerColorType.constant, []],
color: [this.colorSettings?.color, []],
rangeKey: [this.colorSettings?.rangeKey, [Validators.required]],
range: [this.colorSettings?.range, []],
colorFunction: [this.colorSettings?.colorFunction, []]
}
);
this.colorSettingsFormGroup.get('type').valueChanges.pipe(
takeUntilDestroyed(this.destroyRef)
).subscribe(() => {
this.updateValidators();
setTimeout(() => {this.popover?.updatePosition();}, 0);
});
this.updateValidators();
}
cancel() {
@ -82,4 +105,25 @@ export class DataLayerColorSettingsPanelComponent extends PageComponent implemen
this.colorSettingsApplied.emit(colorSettings);
}
public editRangeKey() {
const targetDataKey: DataKey = this.colorSettingsFormGroup.get('rangeKey').value;
this.context.editKey(targetDataKey,
this.dsDeviceId, this.dsEntityAliasId, widgetType.latest).subscribe(
(updatedDataKey) => {
if (updatedDataKey) {
this.colorSettingsFormGroup.get('rangeKey').patchValue(updatedDataKey);
this.colorSettingsFormGroup.markAsDirty();
}
}
);
}
private updateValidators() {
const type: DataLayerColorType = this.colorSettingsFormGroup.get('type').value;
if (type === DataLayerColorType.range) {
this.colorSettingsFormGroup.get('rangeKey').enable({emitEvent: false});
} else {
this.colorSettingsFormGroup.get('rangeKey').disable({emitEvent: false});
}
}
}

View File

@ -16,13 +16,15 @@
import { Component, forwardRef, Input, Renderer2, ViewContainerRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { ComponentStyle } from '@shared/models/widget-settings.models';
import { ColorType, ComponentStyle } from '@shared/models/widget-settings.models';
import { MatButton } from '@angular/material/button';
import { TbPopoverService } from '@shared/components/popover.service';
import { DataLayerColorSettings, DataLayerColorType } from '@shared/models/widget/maps/map.models';
import {
DataLayerColorSettingsPanelComponent
} from '@home/components/widget/lib/settings/common/map/data-layer-color-settings-panel.component';
import { MapSettingsContext } from '@home/components/widget/lib/settings/common/map/map-settings.component.models';
import { DatasourceType } from '@shared/models/widget.models';
@Component({
selector: 'tb-data-layer-color-settings',
@ -41,6 +43,18 @@ export class DataLayerColorSettingsComponent implements ControlValueAccessor {
@Input()
disabled: boolean;
@Input()
context: MapSettingsContext;
@Input()
dsType: DatasourceType;
@Input()
dsEntityAliasId: string;
@Input()
dsDeviceId: string;
@Input()
helpId = 'widget/lib/map/color_fn';
@ -85,6 +99,10 @@ export class DataLayerColorSettingsComponent implements ControlValueAccessor {
} else {
const ctx: any = {
colorSettings: this.modelValue,
context: this.context,
dsType: this.dsType,
dsEntityAliasId: this.dsEntityAliasId,
dsDeviceId: this.dsDeviceId,
helpId: this.helpId
};
const colorSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer,
@ -103,11 +121,23 @@ export class DataLayerColorSettingsComponent implements ControlValueAccessor {
}
private updateColorStyle() {
if (!this.disabled && this.modelValue) {
if (this.modelValue.type === DataLayerColorType.constant) {
this.colorStyle = {backgroundColor: this.modelValue.color};
if (!this.disabled && this.modelValue && this.modelValue.type !== DataLayerColorType.function) {
let colors: string[] = [this.modelValue.color];
const rangeList = this.modelValue.range;
if (this.modelValue.type === DataLayerColorType.range && rangeList?.length) {
const rangeColors = rangeList.slice(0, Math.min(2, rangeList.length)).map(r => r.color);
colors = colors.concat(rangeColors);
}
if (colors.length === 1) {
this.colorStyle = {backgroundColor: colors[0]};
} else {
this.colorStyle = {};
const gradientValues: string[] = [];
const step = 100 / colors.length;
for (let i = 0; i < colors.length; i++) {
gradientValues.push(`${colors[i]} ${step*i}%`);
gradientValues.push(`${colors[i]} ${step*(i+1)}%`);
}
this.colorStyle = {background: `linear-gradient(90deg, ${gradientValues.join(', ')})`};
}
} else {
this.colorStyle = {};

View File

@ -200,11 +200,21 @@
<ng-template matExpansionPanelContent>
<div *ngIf="dataLayerFormGroup.get('markerType').value === MarkerType.shape" class="tb-form-row space-between column-xs">
<div translate>widgets.maps.data-layer.marker.shape</div>
<tb-marker-shape-settings formControlName="markerShape" [trip]="dataLayerType === 'trips'" [markerType]="MarkerType.shape"></tb-marker-shape-settings>
<tb-marker-shape-settings formControlName="markerShape"
[context]="context"
[dsType]="dataLayerFormGroup.get('dsType').value"
[dsEntityAliasId]="dataLayerFormGroup.get('dsEntityAliasId').value"
[dsDeviceId]="dataLayerFormGroup.get('dsDeviceId').value"
[trip]="dataLayerType === 'trips'" [markerType]="MarkerType.shape"></tb-marker-shape-settings>
</div>
<div *ngIf="dataLayerFormGroup.get('markerType').value === MarkerType.icon" class="tb-form-row space-between column-xs">
<div translate>widgets.maps.data-layer.marker.icon</div>
<tb-marker-shape-settings formControlName="markerIcon" [trip]="dataLayerType === 'trips'" [markerType]="MarkerType.icon"></tb-marker-shape-settings>
<tb-marker-shape-settings formControlName="markerIcon"
[context]="context"
[dsType]="dataLayerFormGroup.get('dsType').value"
[dsEntityAliasId]="dataLayerFormGroup.get('dsEntityAliasId').value"
[dsDeviceId]="dataLayerFormGroup.get('dsDeviceId').value"
[trip]="dataLayerType === 'trips'" [markerType]="MarkerType.icon"></tb-marker-shape-settings>
</div>
<div *ngIf="dataLayerFormGroup.get('markerType').value === MarkerType.image" class="tb-form-row space-between">
<div translate>widgets.maps.data-layer.marker.image</div>
@ -275,7 +285,12 @@
<input matInput type="number" min="0" formControlName="pathStrokeWeight" placeholder="{{ 'widget-config.set' | translate }}">
<span matSuffix>px</span>
</mat-form-field>
<tb-data-layer-color-settings helpId="widget/lib/map/path_color_fn" formControlName="pathStrokeColor"></tb-data-layer-color-settings>
<tb-data-layer-color-settings
[context]="context"
[dsType]="dataLayerFormGroup.get('dsType').value"
[dsEntityAliasId]="dataLayerFormGroup.get('dsEntityAliasId').value"
[dsDeviceId]="dataLayerFormGroup.get('dsDeviceId').value"
helpId="widget/lib/map/path_color_fn" formControlName="pathStrokeColor"></tb-data-layer-color-settings>
</div>
</div>
<div class="tb-form-panel tb-slide-toggle stroked">
@ -361,7 +376,12 @@
<input matInput type="number" min="0" formControlName="pointSize" placeholder="{{ 'widget-config.set' | translate }}">
<span matSuffix>px</span>
</mat-form-field>
<tb-data-layer-color-settings helpId="widget/lib/map/path_point_color_fn" formControlName="pointColor"></tb-data-layer-color-settings>
<tb-data-layer-color-settings
[context]="context"
[dsType]="dataLayerFormGroup.get('dsType').value"
[dsEntityAliasId]="dataLayerFormGroup.get('dsEntityAliasId').value"
[dsDeviceId]="dataLayerFormGroup.get('dsDeviceId').value"
helpId="widget/lib/map/path_point_color_fn" formControlName="pointColor"></tb-data-layer-color-settings>
</div>
</div>
<tb-data-layer-pattern-settings
@ -379,7 +399,12 @@
<ng-container *ngIf="['polygons', 'circles'].includes(dataLayerType)">
<div class="tb-form-row space-between">
<div translate>widgets.maps.data-layer.fill-color</div>
<tb-data-layer-color-settings helpId="{{ dataLayerType === 'polygons' ? 'widget/lib/map/polygon_fill_color_fn' : 'widget/lib/map/circle_fill_color_fn' }}" formControlName="fillColor"></tb-data-layer-color-settings>
<tb-data-layer-color-settings
[context]="context"
[dsType]="dataLayerFormGroup.get('dsType').value"
[dsEntityAliasId]="dataLayerFormGroup.get('dsEntityAliasId').value"
[dsDeviceId]="dataLayerFormGroup.get('dsDeviceId').value"
helpId="{{ dataLayerType === 'polygons' ? 'widget/lib/map/polygon_fill_color_fn' : 'widget/lib/map/circle_fill_color_fn' }}" formControlName="fillColor"></tb-data-layer-color-settings>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.maps.data-layer.stroke</div>
@ -388,7 +413,12 @@
<input matInput type="number" min="0" formControlName="strokeWeight" placeholder="{{ 'widget-config.set' | translate }}">
<span matSuffix>px</span>
</mat-form-field>
<tb-data-layer-color-settings helpId="{{ dataLayerType === 'polygons' ? 'widget/lib/map/polygon_stroke_color_fn' : 'widget/lib/map/circle_stroke_color_fn' }}" formControlName="strokeColor"></tb-data-layer-color-settings>
<tb-data-layer-color-settings
[context]="context"
[dsType]="dataLayerFormGroup.get('dsType').value"
[dsEntityAliasId]="dataLayerFormGroup.get('dsEntityAliasId').value"
[dsDeviceId]="dataLayerFormGroup.get('dsDeviceId').value"
helpId="{{ dataLayerType === 'polygons' ? 'widget/lib/map/polygon_stroke_color_fn' : 'widget/lib/map/circle_stroke_color_fn' }}" formControlName="strokeColor"></tb-data-layer-color-settings>
</div>
</div>
</ng-container>

View File

@ -30,5 +30,9 @@
<div *ngIf="markerType === MarkerType.icon" matButtonIcon style="object-fit: contain; width: 24px; height: 24px;" [innerHTML]="iconPreview$ | async" [class.disabled]="disabled">
</div>
</button>
<tb-data-layer-color-settings helpId="widget/lib/map/color_fn" formControlName="color"></tb-data-layer-color-settings>
<tb-data-layer-color-settings [context]="context"
[dsType]="dsType"
[dsEntityAliasId]="dsEntityAliasId"
[dsDeviceId]="dsDeviceId"
helpId="widget/lib/map/color_fn" formControlName="color"></tb-data-layer-color-settings>
</div>

View File

@ -49,6 +49,8 @@ import { coerceBoolean } from '@shared/decorators/coercion';
import {
MarkerIconShapesComponent
} from '@home/components/widget/lib/settings/common/map/marker-icon-shapes.component';
import { MapSettingsContext } from '@home/components/widget/lib/settings/common/map/map-settings.component.models';
import { DatasourceType } from '@shared/models/widget.models';
@Component({
selector: 'tb-marker-shape-settings',
@ -69,6 +71,18 @@ export class MarkerShapeSettingsComponent implements ControlValueAccessor, OnIni
@Input()
disabled: boolean;
@Input()
context: MapSettingsContext;
@Input()
dsType: DatasourceType;
@Input()
dsEntityAliasId: string;
@Input()
dsDeviceId: string;
@Input()
markerType: MarkerType;

View File

@ -41,7 +41,7 @@ import { Observable, Observer, of, switchMap } from 'rxjs';
import { map } from 'rxjs/operators';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { MarkerIconContainer, MarkerShape } from '@shared/models/widget/maps/marker-shape.models';
import { DateFormatSettings, simpleDateFormat } from '@shared/models/widget-settings.models';
import { ColorRange, DateFormatSettings, simpleDateFormat } from '@shared/models/widget-settings.models';
export enum MapType {
geoMap = 'geoMap',
@ -233,12 +233,15 @@ export enum MarkerType {
export enum DataLayerColorType {
constant = 'constant',
range = 'range',
function = 'function'
}
export interface DataLayerColorSettings {
type: DataLayerColorType;
color: string;
rangeKey?: DataKey;
range?: ColorRange[];
colorFunction?: TbFunction;
}

View File

@ -7979,7 +7979,11 @@
"stroke": "Stroke",
"color-settings": "Color settings",
"color-type-constant": "Constant",
"color-type-range": "Range",
"color-type-function": "Function",
"color-range-source-key": "Color range source key",
"color-range-source-key-required": "Color range source key is required",
"color-range": "Color range",
"color-function": "Color function",
"label": "Label",
"tooltip": "Tooltip",