Browse Source

UI: Map: Marker shape visualization.

pull/12723/head
Igor Kulikov 2 years ago
parent
commit
09d14440fa
  1. 144
      ui-ngx/src/app/modules/home/components/widget/lib/maps/map-data-layer.ts
  2. 60
      ui-ngx/src/app/modules/home/components/widget/lib/maps/map.models.ts
  3. 6
      ui-ngx/src/app/modules/home/components/widget/lib/maps/map.scss
  4. 143
      ui-ngx/src/app/modules/home/components/widget/lib/maps/marker-shape.models.ts
  5. 13
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.html
  6. 15
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.ts
  7. 34
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.html
  8. 204
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.ts
  9. 38
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shapes.component.html
  10. 39
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shapes.component.scss
  11. 84
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shapes.component.ts
  12. 6
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts
  13. 6
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  14. 19
      ui-ngx/src/assets/markers/shape1.svg
  15. 16
      ui-ngx/src/assets/markers/shape10.svg
  16. 17
      ui-ngx/src/assets/markers/shape2.svg
  17. 19
      ui-ngx/src/assets/markers/shape3.svg
  18. 21
      ui-ngx/src/assets/markers/shape4.svg
  19. 20
      ui-ngx/src/assets/markers/shape5.svg
  20. 22
      ui-ngx/src/assets/markers/shape6.svg
  21. 28
      ui-ngx/src/assets/markers/shape7.svg
  22. 17
      ui-ngx/src/assets/markers/shape8.svg
  23. 19
      ui-ngx/src/assets/markers/shape9.svg

144
ui-ngx/src/app/modules/home/components/widget/lib/maps/map-data-layer.ts

@ -15,8 +15,8 @@
/// ///
import { import {
BaseMarkerShapeSettings,
CirclesDataLayerSettings, CirclesDataLayerSettings,
createColorMarkerURI,
DataLayerColorSettings, DataLayerColorSettings,
DataLayerColorType, DataLayerColorType,
DataLayerPatternSettings, DataLayerPatternSettings,
@ -34,18 +34,22 @@ import {
MapStringFunction, MapStringFunction,
MapType, MapType,
MarkerIconInfo, MarkerIconInfo,
MarkerIconSettings,
MarkerImageFunction, MarkerImageFunction,
MarkerImageInfo, MarkerImageInfo,
MarkerImageSettings, MarkerImageSettings,
MarkerImageType, MarkerImageType,
MarkersDataLayerSettings, MarkersDataLayerSettings,
MarkerShapeSettings,
MarkerType, MarkerType,
PolygonsDataLayerSettings, processTooltipTemplate, ShapeDataLayerSettings, PolygonsDataLayerSettings,
processTooltipTemplate,
ShapeDataLayerSettings,
TbCircleData, TbCircleData,
TbMapDatasource TbMapDatasource
} from '@home/components/widget/lib/maps/map.models'; } from '@home/components/widget/lib/maps/map.models';
import { TbMap } from '@home/components/widget/lib/maps/map'; import { TbMap } from '@home/components/widget/lib/maps/map';
import { Datasource, FormattedData } from '@shared/models/widget.models'; import { FormattedData } from '@shared/models/widget.models';
import { forkJoin, Observable, of } from 'rxjs'; import { forkJoin, Observable, of } from 'rxjs';
import { import {
createLabelFromPattern, createLabelFromPattern,
@ -59,13 +63,20 @@ import {
parseTbFunction, parseTbFunction,
safeExecuteTbFunction safeExecuteTbFunction
} from '@core/utils'; } from '@core/utils';
import L, { LatLngBounds, PathOptions } from 'leaflet'; import L, { divIcon, LatLngBounds } from 'leaflet';
import { CompiledTbFunction } from '@shared/models/js-function.models'; import { CompiledTbFunction } from '@shared/models/js-function.models';
import { catchError, map } from 'rxjs/operators'; import { catchError, map, switchMap } from 'rxjs/operators';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import { WidgetContext } from '@home/models/widget-component.models'; import { WidgetContext } from '@home/models/widget-component.models';
import { ImagePipe } from '@shared/pipe/image.pipe'; import { ImagePipe } from '@shared/pipe/image.pipe';
import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe'; import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe';
import {
createColorMarkerIconElement,
createColorMarkerShapeURI,
MarkerShape
} from '@home/components/widget/lib/maps/marker-shape.models';
import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
abstract class TbDataLayerItem<S extends MapDataLayerSettings, L extends TbMapDataLayer<S,L>> { abstract class TbDataLayerItem<S extends MapDataLayerSettings, L extends TbMapDataLayer<S,L>> {
@ -317,7 +328,7 @@ export abstract class TbMapDataLayer<S extends MapDataLayerSettings, L extends T
const layerData = dsData.filter(d => d.$datasource.mapDataIds.includes(this.mapDataId)); const layerData = dsData.filter(d => d.$datasource.mapDataIds.includes(this.mapDataId));
const rawItems = layerData.filter(d => this.isValidLayerData(d)); const rawItems = layerData.filter(d => this.isValidLayerData(d));
const toDelete = new Set(Array.from(this.layerItems.keys())); const toDelete = new Set(Array.from(this.layerItems.keys()));
rawItems.forEach((data, index) => { rawItems.forEach((data) => {
let layerItem = this.layerItems.get(data.entityId); let layerItem = this.layerItems.get(data.entityId);
if (layerItem) { if (layerItem) {
layerItem.update(data, dsData); layerItem.update(data, dsData);
@ -428,8 +439,10 @@ abstract class MarkerIconProcessor<S> {
static fromSettings(dataLayer: TbMarkersDataLayer, static fromSettings(dataLayer: TbMarkersDataLayer,
settings: MarkersDataLayerSettings): MarkerIconProcessor<any> { settings: MarkersDataLayerSettings): MarkerIconProcessor<any> {
switch (settings.markerType) { switch (settings.markerType) {
case MarkerType.default: case MarkerType.shape:
return new ColorMarkerIconProcessor(dataLayer, settings.markerColor); return new ShapeMarkerIconProcessor(dataLayer, settings.markerShape);
case MarkerType.icon:
return new IconMarkerIconProcessor(dataLayer, settings.markerIcon);
case MarkerType.image: case MarkerType.image:
return new ImageMarkerIconProcessor(dataLayer, settings.markerImage); return new ImageMarkerIconProcessor(dataLayer, settings.markerImage);
} }
@ -445,46 +458,80 @@ abstract class MarkerIconProcessor<S> {
} }
class ColorMarkerIconProcessor extends MarkerIconProcessor<DataLayerColorSettings> { abstract class BaseColorMarkerShapeProcessor<S extends BaseMarkerShapeSettings> extends MarkerIconProcessor<S> {
private markerColorFunction: CompiledTbFunction<MapStringFunction>; private markerColorFunction: CompiledTbFunction<MapStringFunction>;
private defaultMarkerIconInfo: MarkerIconInfo; private defaultMarkerIconInfo: MarkerIconInfo;
constructor(protected dataLayer: TbMarkersDataLayer, protected constructor(protected dataLayer: TbMarkersDataLayer,
protected settings: DataLayerColorSettings) { protected settings: S) {
super(dataLayer, settings); super(dataLayer, settings);
} }
public setup(): Observable<void> { public setup(): Observable<void> {
if (this.settings.type === DataLayerColorType.function) { const colorSettings = this.settings.color;
return parseTbFunction<MapStringFunction>(this.dataLayer.getCtx().http, this.settings.colorFunction, ['data', 'dsData']).pipe( if (colorSettings.type === DataLayerColorType.function) {
return parseTbFunction<MapStringFunction>(this.dataLayer.getCtx().http, colorSettings.colorFunction, ['data', 'dsData']).pipe(
map((parsed) => { map((parsed) => {
this.markerColorFunction = parsed; this.markerColorFunction = parsed;
return null; return null;
}) })
); );
} else { } else {
const color = tinycolor(this.settings.color); const color = tinycolor(colorSettings.color);
this.defaultMarkerIconInfo = this.dataLayer.createColoredMarkerIcon(color); return this.createMarkerShape(color, this.settings.size).pipe(
return of(null) map((info) => {
this.defaultMarkerIconInfo = info;
return null;
}
));
} }
} }
public createMarkerIcon(data: FormattedData<TbMapDatasource>, dsData: FormattedData<TbMapDatasource>[]): Observable<MarkerIconInfo> { public createMarkerIcon(data: FormattedData<TbMapDatasource>, dsData: FormattedData<TbMapDatasource>[]): Observable<MarkerIconInfo> {
if (this.settings.type === DataLayerColorType.function) { const colorSettings = this.settings.color;
if (colorSettings.type === DataLayerColorType.function) {
const functionColor = safeExecuteTbFunction(this.markerColorFunction, [data, dsData]); const functionColor = safeExecuteTbFunction(this.markerColorFunction, [data, dsData]);
let color: tinycolor.Instance; let color: tinycolor.Instance;
if (isDefinedAndNotNull(functionColor)) { if (isDefinedAndNotNull(functionColor)) {
color = tinycolor(functionColor); color = tinycolor(functionColor);
} else { } else {
color = tinycolor(this.settings.color); color = tinycolor(colorSettings.color);
} }
return of(this.dataLayer.createColoredMarkerIcon(color)); return this.createMarkerShape(color, this.settings.size);
} else { } else {
return of(this.defaultMarkerIconInfo); return of(this.defaultMarkerIconInfo);
} }
} }
protected abstract createMarkerShape(color: tinycolor.Instance, size: number): Observable<MarkerIconInfo>;
}
class ShapeMarkerIconProcessor extends BaseColorMarkerShapeProcessor<MarkerShapeSettings> {
constructor(protected dataLayer: TbMarkersDataLayer,
protected settings: MarkerShapeSettings) {
super(dataLayer, settings);
}
protected createMarkerShape(color: tinycolor.Instance, size: number): Observable<MarkerIconInfo> {
return this.dataLayer.createColoredMarkerShape(this.settings.shape, color, size);
}
}
class IconMarkerIconProcessor extends BaseColorMarkerShapeProcessor<MarkerIconSettings> {
constructor(protected dataLayer: TbMarkersDataLayer,
protected settings: MarkerIconSettings) {
super(dataLayer, settings);
}
protected createMarkerShape(color: tinycolor.Instance, size: number): Observable<MarkerIconInfo> {
return this.dataLayer.createColoredMarkerIcon(this.settings.icon, color, size);
}
} }
class ImageMarkerIconProcessor extends MarkerIconProcessor<MarkerImageSettings> { class ImageMarkerIconProcessor extends MarkerIconProcessor<MarkerImageSettings> {
@ -532,7 +579,7 @@ class ImageMarkerIconProcessor extends MarkerIconProcessor<MarkerImageSettings>
private loadMarkerIconInfo(image: MarkerImageInfo): Observable<MarkerIconInfo> { private loadMarkerIconInfo(image: MarkerImageInfo): Observable<MarkerIconInfo> {
if (image && image.url) { if (image && image.url) {
return loadImageWithAspect(this.dataLayer.getCtx().$injector.get(ImagePipe), image.url).pipe( return loadImageWithAspect(this.dataLayer.getCtx().$injector.get(ImagePipe), image.url).pipe(
map((aspectImage) => { switchMap((aspectImage) => {
if (aspectImage?.aspect) { if (aspectImage?.aspect) {
let width: number; let width: number;
let height: number; let height: number;
@ -561,15 +608,15 @@ class ImageMarkerIconProcessor extends MarkerIconProcessor<MarkerImageSettings>
size: [width, height], size: [width, height],
icon icon
}; };
return iconInfo; return of(iconInfo);
} else { } else {
return this.dataLayer.createDefaultMarkerIcon(); return this.dataLayer.createDefaultMarkerIcon();
} }
}), }),
catchError(() => of(this.dataLayer.createDefaultMarkerIcon())) catchError(() => this.dataLayer.createDefaultMarkerIcon())
); );
} else { } else {
return of(this.dataLayer.createDefaultMarkerIcon()); return this.dataLayer.createDefaultMarkerIcon();
} }
} }
@ -644,24 +691,42 @@ export class TbMarkersDataLayer extends TbMapDataLayer<MarkersDataLayerSettings,
} }
} }
public createDefaultMarkerIcon(): MarkerIconInfo { public createDefaultMarkerIcon(): Observable<MarkerIconInfo> {
const color = this.settings.markerColor.color || '#FE7569'; const color = this.settings.markerShape?.color?.color || '#307FE5';
return this.createColoredMarkerIcon(tinycolor(color)); return this.createColoredMarkerShape(MarkerShape.markerShape1, tinycolor(color));
} }
public createColoredMarkerIcon(color: tinycolor.Instance): MarkerIconInfo { public createColoredMarkerShape(shape: MarkerShape, color: tinycolor.Instance, size = 34): Observable<MarkerIconInfo> {
return { return createColorMarkerShapeURI(this.getCtx().$injector.get(MatIconRegistry), this.getCtx().$injector.get(DomSanitizer), shape, color).pipe(
size: [21, 34], map((iconUrl) => {
icon: L.icon({ return {
iconUrl: createColorMarkerURI(color), size: [size, size],
iconSize: [21, 34], icon: L.icon({
iconAnchor: [21 * this.markerOffset[0], 34 * this.markerOffset[1]], iconUrl,
popupAnchor: [21 * this.tooltipOffset[0], 34 * this.tooltipOffset[1]], iconSize: [size, size],
shadowUrl: 'assets/shadow.png', iconAnchor: [size * this.markerOffset[0], size * this.markerOffset[1]],
shadowSize: [40, 37], popupAnchor: [size * this.tooltipOffset[0], size * this.tooltipOffset[1]]
shadowAnchor: [12, 35] })
};
}) })
}; );
}
public createColoredMarkerIcon(icon: string, color: tinycolor.Instance, size = 34): Observable<MarkerIconInfo> {
return createColorMarkerIconElement(this.getCtx().$injector.get(MatIconRegistry), this.getCtx().$injector.get(DomSanitizer), icon, color).pipe(
map((element) => {
return {
size: [size, size],
icon: L.divIcon({
html: element.outerHTML,
className: 'tb-marker-div-icon',
iconSize: [size, size],
iconAnchor: [size * this.markerOffset[0], size * this.markerOffset[1]],
popupAnchor: [size * this.tooltipOffset[0], size * this.tooltipOffset[1]]
})
};
})
);
} }
public extractLocation(data: FormattedData<TbMapDatasource>): L.LatLng { public extractLocation(data: FormattedData<TbMapDatasource>): L.LatLng {
@ -757,7 +822,7 @@ abstract class TbShapesDataLayer<S extends ShapeDataLayerSettings, L extends TbM
public getShapeStyle(data: FormattedData<TbMapDatasource>, dsData: FormattedData<TbMapDatasource>[]): L.PathOptions { public getShapeStyle(data: FormattedData<TbMapDatasource>, dsData: FormattedData<TbMapDatasource>[]): L.PathOptions {
const fill = this.fillColorProcessor.processColor(data, dsData); const fill = this.fillColorProcessor.processColor(data, dsData);
const stroke = this.strokeColorProcessor.processColor(data, dsData); const stroke = this.strokeColorProcessor.processColor(data, dsData);
const style: L.PathOptions = { return {
fill: true, fill: true,
fillColor: fill, fillColor: fill,
color: stroke, color: stroke,
@ -765,7 +830,6 @@ abstract class TbShapesDataLayer<S extends ShapeDataLayerSettings, L extends TbM
fillOpacity: 1, fillOpacity: 1,
opacity: 1 opacity: 1
}; };
return style;
} }
} }

60
ui-ngx/src/app/modules/home/components/widget/lib/maps/map.models.ts

@ -19,25 +19,12 @@ import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { guid, hashCode, isDefinedAndNotNull, isString, mergeDeep } from '@core/utils'; import { guid, hashCode, isDefinedAndNotNull, isString, mergeDeep } from '@core/utils';
import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms';
import { materialColors } from '@shared/models/material.models'; import { materialColors } from '@shared/models/material.models';
import L, { BaseIconOptions, Icon } from 'leaflet'; import L from 'leaflet';
import { TbFunction } from '@shared/models/js-function.models'; import { TbFunction } from '@shared/models/js-function.models';
import { Observable, Observer, of, switchMap } from 'rxjs'; import { Observable, Observer, of, switchMap } from 'rxjs';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { ImagePipe } from '@shared/pipe/image.pipe'; import { ImagePipe } from '@shared/pipe/image.pipe';
import tinycolor from 'tinycolor2'; import { MarkerShape } from '@home/components/widget/lib/maps/marker-shape.models';
export const createColorMarkerURI = (color: tinycolor.Instance): string => {
const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="-191.35 -351.18 1083.58 1730.46">` +
`<path fill-rule="evenodd" clip-rule="evenodd" fill="#${color.toHex()}" stroke="#000" stroke-width="37" ` +
`stroke-miterlimit="10" d="M351.833 1360.78c-38.766-190.3-107.116-348.665-189.903-495.44C100.523 756.469 ` +
`29.386 655.978-36.434 550.404c-21.972-35.244-40.934-72.477-62.047-109.054-42.216-73.137-76.444-157.935-74.269-267.932 ` +
`2.125-107.473 33.208-193.685 78.03-264.173C-21-206.69 102.481-301.745 268.164-326.724c135.466-20.425 262.475 14.082 ` +
`352.543 66.747 73.6 43.038 130.596 100.528 173.92 168.28 45.22 70.716 76.36 154.26 78.971 263.233 1.337 55.83-7.805 ` +
`107.532-20.684 150.417-13.034 43.41-33.996 79.695-52.646 118.455-36.406 75.659-82.049 144.981-127.855 214.345-136.437 ` +
`206.606-264.496 417.31-320.58 706.028z"/><circle fill-rule="evenodd" ` +
`clip-rule="evenodd" cx="352.891" cy="225.779" r="183.332"/></svg>`;
return 'data:image/svg+xml;base64,' + btoa(svg);
}
export enum MapType { export enum MapType {
geoMap = 'geoMap', geoMap = 'geoMap',
@ -183,7 +170,8 @@ export const mapDataLayerValidator = (type: MapDataLayerType): ValidatorFn => {
}; };
export enum MarkerType { export enum MarkerType {
default = 'default', shape = 'shape',
icon = 'icon',
image = 'image' image = 'image'
} }
@ -211,11 +199,25 @@ export interface MarkerImageSettings {
images?: string[]; images?: string[];
} }
export interface BaseMarkerShapeSettings {
size: number;
color: DataLayerColorSettings;
}
export interface MarkerShapeSettings extends BaseMarkerShapeSettings {
shape: MarkerShape;
}
export interface MarkerIconSettings extends BaseMarkerShapeSettings {
icon: string;
}
export interface MarkersDataLayerSettings extends MapDataLayerSettings { export interface MarkersDataLayerSettings extends MapDataLayerSettings {
xKey: DataKey; xKey: DataKey;
yKey: DataKey; yKey: DataKey;
markerType: MarkerType; markerType: MarkerType;
markerColor: DataLayerColorSettings; markerShape?: MarkerShapeSettings;
markerIcon?: MarkerIconSettings;
markerImage?: MarkerImageSettings; markerImage?: MarkerImageSettings;
markerOffsetX: number; markerOffsetX: number;
markerOffsetY: number; markerOffsetY: number;
@ -267,14 +269,26 @@ export const defaultMarkersDataLayerSettings = (mapType: MapType, functionsOnly
} as MarkersDataLayerSettings, defaultBaseMarkersDataLayerSettings as MarkersDataLayerSettings); } as MarkersDataLayerSettings, defaultBaseMarkersDataLayerSettings as MarkersDataLayerSettings);
export const defaultBaseMarkersDataLayerSettings: Partial<MarkersDataLayerSettings> = mergeDeep({ export const defaultBaseMarkersDataLayerSettings: Partial<MarkersDataLayerSettings> = mergeDeep({
markerType: MarkerType.default, markerType: MarkerType.shape,
markerColor: { markerShape: {
type: DataLayerColorType.constant, shape: MarkerShape.markerShape1,
color: '#307FE5', size: 34,
color: {
type: DataLayerColorType.constant,
color: '#307FE5',
}
},
markerIcon: {
icon: 'mdi:lightbulb-on',
size: 48,
color: {
type: DataLayerColorType.constant,
color: '#307FE5',
}
}, },
markerImage: { markerImage: {
type: MarkerImageType.image, type: MarkerImageType.image,
image: createColorMarkerURI(tinycolor('#307FE5')), image: '/assets/markers/shape1.svg',
imageSize: 34 imageSize: 34
}, },
markerOffsetX: 0.5, markerOffsetX: 0.5,
@ -720,7 +734,7 @@ export interface MarkerImageInfo {
} }
export interface MarkerIconInfo { export interface MarkerIconInfo {
icon: Icon<BaseIconOptions>; icon: L.Icon<L.BaseIconOptions>;
size: [number, number]; size: [number, number];
} }

6
ui-ngx/src/app/modules/home/components/widget/lib/maps/map.scss

@ -95,6 +95,12 @@
} }
} }
} }
.leaflet-marker-icon {
&.tb-marker-div-icon {
background: none;
border: none;
}
}
} }
.tb-map-sidebar { .tb-map-sidebar {
.tb-layers, .tb-groups { .tb-layers, .tb-groups {

143
ui-ngx/src/app/modules/home/components/widget/lib/maps/marker-shape.models.ts

@ -0,0 +1,143 @@
///
/// Copyright © 2016-2024 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import tinycolor from 'tinycolor2';
import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
import { Observable, of, switchMap } from 'rxjs';
import { catchError, map, take } from 'rxjs/operators';
import { isSvgIcon, splitIconName } from '@shared/models/icon.models';
import { Element, Text, G } from '@svgdotjs/svg.js';
export enum MarkerShape {
markerShape1 = 'markerShape1',
markerShape2 = 'markerShape2',
markerShape3 = 'markerShape3',
markerShape4 = 'markerShape4',
markerShape5 = 'markerShape5',
markerShape6 = 'markerShape6',
markerShape7 = 'markerShape7',
markerShape8 = 'markerShape8',
markerShape9 = 'markerShape9',
markerShape10 = 'markerShape10'
}
export const markerShapeMap = new Map<MarkerShape, string>(
[
[MarkerShape.markerShape1, '/assets/markers/shape1.svg'],
[MarkerShape.markerShape2, '/assets/markers/shape2.svg'],
[MarkerShape.markerShape3, '/assets/markers/shape3.svg'],
[MarkerShape.markerShape4, '/assets/markers/shape4.svg'],
[MarkerShape.markerShape5, '/assets/markers/shape5.svg'],
[MarkerShape.markerShape6, '/assets/markers/shape6.svg'],
[MarkerShape.markerShape7, '/assets/markers/shape7.svg'],
[MarkerShape.markerShape8, '/assets/markers/shape8.svg'],
[MarkerShape.markerShape9, '/assets/markers/shape9.svg'],
[MarkerShape.markerShape10, '/assets/markers/shape10.svg']
]
);
const createColorMarkerShape = (iconRegistry: MatIconRegistry, domSanitizer: DomSanitizer, shape: MarkerShape, color: tinycolor.Instance): Observable<SVGElement> => {
const markerAssetUrl = markerShapeMap.get(shape);
const safeUrl = domSanitizer.bypassSecurityTrustResourceUrl(markerAssetUrl);
return iconRegistry.getSvgIconFromUrl(safeUrl).pipe(
map((svgElement) => {
const colorElements = Array.from(svgElement.getElementsByClassName('marker-color'));
colorElements.forEach(el => {
el.setAttribute('fill', '#'+color.toHex());
});
const strokeElements = Array.from(svgElement.getElementsByClassName('marker-stroke'));
strokeElements.forEach(el => {
el.setAttribute('stroke', '#'+color.toHex());
});
return svgElement;
})
);
}
export const createColorMarkerShapeURI = (iconRegistry: MatIconRegistry, domSanitizer: DomSanitizer, shape: MarkerShape, color: tinycolor.Instance): Observable<string> => {
return createColorMarkerShape(iconRegistry, domSanitizer, shape, color).pipe(
map((svgElement) => {
const svg = svgElement.outerHTML;
return 'data:image/svg+xml;base64,' + btoa(svg);
})
);
}
const createIconElement = (iconRegistry: MatIconRegistry, icon: string, size: number, color: tinycolor.Instance): Observable<Element> => {
const isSvg = isSvgIcon(icon);
const iconColor = tinycolor.mix(color, tinycolor('rgba(0,0,0,0.38)'));
if (isSvg) {
const [namespace, iconName] = splitIconName(icon);
return iconRegistry
.getNamedSvgIcon(iconName, namespace)
.pipe(
take(1),
map((svgElement) => {
const element = new Element(svgElement.firstChild);
element.fill('#'+iconColor.toHex());
//const box = element.bbox();
const scale = size / 24;//box.height;
element.scale(scale);
return element;
}),
catchError(() => of(null))
);
} else {
const iconName = splitIconName(icon)[1];
const textElement = new Text(document.createElementNS('http://www.w3.org/2000/svg', 'text'));
const fontSetClasses = (
iconRegistry.getDefaultFontSetClass()
).filter(className => className.length > 0);
fontSetClasses.forEach(className => textElement.addClass(className));
textElement.font({size: `${size}px`});
textElement.attr({
style: `font-size: ${size}px`,
'text-anchor': 'start'
});
textElement.fill('#'+iconColor.toHex());
const tspan = textElement.tspan(iconName);
tspan.attr({
'dominant-baseline': 'hanging'
});
return of(textElement);
}
}
export const createColorMarkerIconElement = (iconRegistry: MatIconRegistry, domSanitizer: DomSanitizer, icon: string, color: tinycolor.Instance): Observable<SVGElement> => {
return createColorMarkerShape(iconRegistry, domSanitizer, MarkerShape.markerShape6, color).pipe(
switchMap((svgElement) => {
return createIconElement(iconRegistry, icon, 12, color).pipe(
map((iconElement) => {
let elements = svgElement.getElementsByClassName('marker-icon-container');
if (iconElement && elements.length) {
const iconContainer = new G(elements[0] as SVGGElement);
iconContainer.add(iconElement);
const box = iconElement.bbox();
iconElement.translate(-box.cx, -box.cy);
}
elements = svgElement.getElementsByClassName('marker-icon-background');
if (elements.length) {
(elements[0] as SVGGElement).style.display = '';
}
return svgElement;
})
);
})
);
}

13
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.html

@ -181,13 +181,18 @@
<div class="flex flex-row items-center justify-between"> <div class="flex flex-row items-center justify-between">
<div class="tb-form-panel-title">{{ 'widgets.maps.data-layer.marker.marker-type' | translate }}</div> <div class="tb-form-panel-title">{{ 'widgets.maps.data-layer.marker.marker-type' | translate }}</div>
<tb-toggle-select formControlName="markerType"> <tb-toggle-select formControlName="markerType">
<tb-toggle-option [value]="MarkerType.default">{{ 'widgets.maps.data-layer.marker.marker-type-default' | translate }}</tb-toggle-option> <tb-toggle-option [value]="MarkerType.shape">{{ 'widgets.maps.data-layer.marker.marker-type-shape' | translate }}</tb-toggle-option>
<tb-toggle-option [value]="MarkerType.icon">{{ 'widgets.maps.data-layer.marker.marker-type-icon' | translate }}</tb-toggle-option>
<tb-toggle-option [value]="MarkerType.image">{{ 'widgets.maps.data-layer.marker.marker-type-image' | translate }}</tb-toggle-option> <tb-toggle-option [value]="MarkerType.image">{{ 'widgets.maps.data-layer.marker.marker-type-image' | translate }}</tb-toggle-option>
</tb-toggle-select> </tb-toggle-select>
</div> </div>
<div *ngIf="dataLayerFormGroup.get('markerType').value === MarkerType.default" class="tb-form-row space-between"> <div *ngIf="dataLayerFormGroup.get('markerType').value === MarkerType.shape" class="tb-form-row space-between">
<div translate>widgets.maps.data-layer.color</div> <div translate>widgets.maps.data-layer.marker.shape</div>
<tb-data-layer-color-settings formControlName="markerColor"></tb-data-layer-color-settings> <tb-marker-shape-settings formControlName="markerShape" [markerType]="MarkerType.shape"></tb-marker-shape-settings>
</div>
<div *ngIf="dataLayerFormGroup.get('markerType').value === MarkerType.icon" class="tb-form-row space-between">
<div translate>widgets.maps.data-layer.marker.icon</div>
<tb-marker-shape-settings formControlName="markerIcon" [markerType]="MarkerType.icon"></tb-marker-shape-settings>
</div> </div>
<div *ngIf="dataLayerFormGroup.get('markerType').value === MarkerType.image" class="tb-form-row space-between"> <div *ngIf="dataLayerFormGroup.get('markerType').value === MarkerType.image" class="tb-form-row space-between">
<div translate>widgets.maps.data-layer.marker.image</div> <div translate>widgets.maps.data-layer.marker.image</div>

15
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-data-layer-dialog.component.ts

@ -114,7 +114,8 @@ export class MapDataLayerDialogComponent extends DialogComponent<MapDataLayerDia
this.dataLayerFormGroup.addControl('xKey', this.fb.control(markersDataLayer.xKey, Validators.required)); this.dataLayerFormGroup.addControl('xKey', this.fb.control(markersDataLayer.xKey, Validators.required));
this.dataLayerFormGroup.addControl('yKey', this.fb.control(markersDataLayer.yKey, Validators.required)) this.dataLayerFormGroup.addControl('yKey', this.fb.control(markersDataLayer.yKey, Validators.required))
this.dataLayerFormGroup.addControl('markerType', this.fb.control(markersDataLayer.markerType, Validators.required)); this.dataLayerFormGroup.addControl('markerType', this.fb.control(markersDataLayer.markerType, Validators.required));
this.dataLayerFormGroup.addControl('markerColor', this.fb.control(markersDataLayer.markerColor, Validators.required)); this.dataLayerFormGroup.addControl('markerShape', this.fb.control(markersDataLayer.markerShape, Validators.required));
this.dataLayerFormGroup.addControl('markerIcon', this.fb.control(markersDataLayer.markerIcon, Validators.required));
this.dataLayerFormGroup.addControl('markerImage', this.fb.control(markersDataLayer.markerImage, Validators.required)); this.dataLayerFormGroup.addControl('markerImage', this.fb.control(markersDataLayer.markerImage, Validators.required));
this.dataLayerFormGroup.addControl('markerOffsetX', this.fb.control(markersDataLayer.markerOffsetX)); this.dataLayerFormGroup.addControl('markerOffsetX', this.fb.control(markersDataLayer.markerOffsetX));
this.dataLayerFormGroup.addControl('markerOffsetY', this.fb.control(markersDataLayer.markerOffsetY)); this.dataLayerFormGroup.addControl('markerOffsetY', this.fb.control(markersDataLayer.markerOffsetY));
@ -209,11 +210,17 @@ export class MapDataLayerDialogComponent extends DialogComponent<MapDataLayerDia
} }
if (this.dataLayerType === 'markers') { if (this.dataLayerType === 'markers') {
const markerType: MarkerType = this.dataLayerFormGroup.get('markerType').value; const markerType: MarkerType = this.dataLayerFormGroup.get('markerType').value;
if (markerType === MarkerType.default) { if (markerType === MarkerType.shape) {
this.dataLayerFormGroup.get('markerColor').enable({emitEvent: false}); this.dataLayerFormGroup.get('markerShape').enable({emitEvent: false});
this.dataLayerFormGroup.get('markerIcon').disable({emitEvent: false});
this.dataLayerFormGroup.get('markerImage').disable({emitEvent: false});
} else if (markerType === MarkerType.icon) {
this.dataLayerFormGroup.get('markerShape').disable({emitEvent: false});
this.dataLayerFormGroup.get('markerIcon').enable({emitEvent: false});
this.dataLayerFormGroup.get('markerImage').disable({emitEvent: false}); this.dataLayerFormGroup.get('markerImage').disable({emitEvent: false});
} else { } else {
this.dataLayerFormGroup.get('markerColor').disable({emitEvent: false}); this.dataLayerFormGroup.get('markerShape').disable({emitEvent: false});
this.dataLayerFormGroup.get('markerIcon').disable({emitEvent: false});
this.dataLayerFormGroup.get('markerImage').enable({emitEvent: false}); this.dataLayerFormGroup.get('markerImage').enable({emitEvent: false});
} }
} }

34
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.html

@ -0,0 +1,34 @@
<!--
Copyright © 2016-2024 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<div class="flex flex-row items-center justify-start gap-2" [formGroup]="shapeSettingsFormGroup">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="size" type="number" min="1" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
<button type="button"
mat-stroked-button
class="tb-box-button"
[disabled]="disabled"
#matButton
(click)="openShapePopup($event, matButton)">
<img *ngIf="markerType === MarkerType.shape" matButtonIcon width="24px" height="24px" style="object-fit: contain;" [src]="shapePreview$ | async" [class.disabled]="disabled"/>
<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 formControlName="color"></tb-data-layer-color-settings>
</div>

204
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.ts

@ -0,0 +1,204 @@
///
/// Copyright © 2016-2024 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import {
ChangeDetectorRef,
Component,
DestroyRef,
forwardRef,
Input,
OnInit,
Renderer2,
ViewContainerRef
} from '@angular/core';
import {
ControlValueAccessor,
NG_VALUE_ACCESSOR,
UntypedFormBuilder,
UntypedFormGroup,
Validators
} from '@angular/forms';
import { MatButton } from '@angular/material/button';
import { TbPopoverService } from '@shared/components/popover.service';
import { MarkerIconSettings, MarkerShapeSettings, MarkerType } from '@home/components/widget/lib/maps/map.models';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { Observable } from 'rxjs';
import { DomSanitizer, SafeHtml, SafeUrl } from '@angular/platform-browser';
import { MatIconRegistry } from '@angular/material/icon';
import {
createColorMarkerIconElement,
createColorMarkerShapeURI
} from '@home/components/widget/lib/maps/marker-shape.models';
import tinycolor from 'tinycolor2';
import { map, share } from 'rxjs/operators';
import { MarkerShapesComponent } from '@home/components/widget/lib/settings/common/map/marker-shapes.component';
import { MaterialIconsComponent } from '@shared/components/material-icons.component';
@Component({
selector: 'tb-marker-shape-settings',
templateUrl: './marker-shape-settings.component.html',
styleUrls: [],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => MarkerShapeSettingsComponent),
multi: true
}
]
})
export class MarkerShapeSettingsComponent implements ControlValueAccessor, OnInit {
MarkerType = MarkerType;
@Input()
disabled: boolean;
@Input()
markerType: MarkerType;
modelValue: MarkerShapeSettings | MarkerIconSettings;
public shapeSettingsFormGroup: UntypedFormGroup;
public shapePreview$: Observable<SafeUrl>;
public iconPreview$: Observable<SafeHtml>;
private propagateChange: (v: any) => void = () => { };
constructor(private popoverService: TbPopoverService,
private fb: UntypedFormBuilder,
private destroyRef: DestroyRef,
private iconRegistry: MatIconRegistry,
private domSanitizer: DomSanitizer,
private renderer: Renderer2,
private cd: ChangeDetectorRef,
private viewContainerRef: ViewContainerRef) {}
ngOnInit(): void {
this.shapeSettingsFormGroup = this.fb.group({
size: [null, [Validators.required, Validators.min(1)]],
color: [null, [Validators.required]]
});
if (this.markerType === MarkerType.shape) {
this.shapeSettingsFormGroup.addControl('shape', this.fb.control(null, [Validators.required]));
}
if (this.markerType === MarkerType.icon) {
this.shapeSettingsFormGroup.addControl('icon', this.fb.control(null, [Validators.required]));
}
this.shapeSettingsFormGroup.valueChanges.pipe(
takeUntilDestroyed(this.destroyRef)
).subscribe(() => {
this.updateModel();
});
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (isDisabled) {
this.shapeSettingsFormGroup.disable({emitEvent: false});
} else {
this.shapeSettingsFormGroup.enable({emitEvent: false});
}
}
writeValue(value: MarkerShapeSettings | MarkerIconSettings): void {
this.modelValue = value;
this.shapeSettingsFormGroup.patchValue(
value, {emitEvent: false}
);
this.updatePreview();
}
openShapePopup($event: Event, matButton: MatButton) {
if ($event) {
$event.stopPropagation();
}
const trigger = matButton._elementRef.nativeElement;
if (this.popoverService.hasPopover(trigger)) {
this.popoverService.hidePopover(trigger);
} else {
if (this.markerType === MarkerType.shape) {
const ctx: any = {
shape: (this.modelValue as MarkerShapeSettings).shape,
color: this.modelValue.color.color
};
const markerShapesPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, MarkerShapesComponent, 'left', true, null,
ctx,
{},
{}, {}, true);
markerShapesPopover.tbComponentRef.instance.popover = markerShapesPopover;
markerShapesPopover.tbComponentRef.instance.markerShapeSelected.subscribe((shape) => {
markerShapesPopover.hide();
this.shapeSettingsFormGroup.get('shape').patchValue(
shape
);
});
} else if (this.markerType === MarkerType.icon) {
const ctx: any = {
selectedIcon: (this.modelValue as MarkerIconSettings).icon,
iconClearButton: false
};
const materialIconsPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, MaterialIconsComponent, 'left', true, null,
ctx,
{},
{}, {}, true);
materialIconsPopover.tbComponentRef.instance.popover = materialIconsPopover;
materialIconsPopover.tbComponentRef.instance.iconSelected.subscribe((icon) => {
materialIconsPopover.hide();
this.shapeSettingsFormGroup.get('icon').patchValue(
icon
);
});
}
}
}
private updateModel() {
this.modelValue = this.shapeSettingsFormGroup.getRawValue();
this.propagateChange(this.modelValue);
this.updatePreview();
}
private updatePreview() {
const color = this.modelValue.color.color;
if (this.markerType === MarkerType.shape) {
const shape = (this.modelValue as MarkerShapeSettings).shape;
this.shapePreview$ = createColorMarkerShapeURI(this.iconRegistry, this.domSanitizer, shape, tinycolor(color)).pipe(
map((url) => {
return this.domSanitizer.bypassSecurityTrustUrl(url);
}),
share()
);
} else if (this.markerType === MarkerType.icon) {
const icon = (this.modelValue as MarkerIconSettings).icon;
this.iconPreview$ = createColorMarkerIconElement(this.iconRegistry, this.domSanitizer, icon, tinycolor(color)).pipe(
map((element) => {
return this.domSanitizer.bypassSecurityTrustHtml(element.outerHTML);
}),
share()
);
}
}
}

38
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shapes.component.html

@ -0,0 +1,38 @@
<!--
Copyright © 2016-2024 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<div class="tb-marker-shapes-panel">
<div class="tb-marker-shapes-title" translate>widgets.maps.data-layer.marker.marker-shapes</div>
<div class="flex flex-row flex-wrap gap-3">
<ng-container *ngFor="let shapeInfo of shapes">
<button *ngIf="shapeInfo.shape === shape"
class="tb-select-shape-button"
mat-raised-button
(click)="selectShape(shapeInfo.shape)"
type="button">
<img matButtonIcon class="tb-marker-shape" [src]="shapeInfo.url$ | async"/>
</button>
<button *ngIf="shapeInfo.shape !== shape"
class="tb-select-shape-button"
mat-button
(click)="selectShape(shapeInfo.shape)"
type="button">
<img matButtonIcon class="tb-marker-shape" [src]="shapeInfo.url$ | async"/>
</button>
</ng-container>
</div>
</div>

39
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shapes.component.scss

@ -0,0 +1,39 @@
/**
* Copyright © 2016-2024 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.tb-marker-shapes-panel {
width: 100%;
display: flex;
flex-direction: column;
gap: 16px;
.tb-marker-shapes-title {
font-size: 16px;
font-weight: 500;
line-height: 24px;
letter-spacing: 0.25px;
color: rgba(0, 0, 0, 0.87);
}
button.mat-mdc-button-base.tb-select-shape-button {
width: 42px;
min-width: 42px;
height: 42px;
padding: 4px;
img.tb-marker-shape {
width: 34px;
height: 34px;
object-fit: contain;
}
}
}

84
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shapes.component.ts

@ -0,0 +1,84 @@
///
/// Copyright © 2016-2024 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { PageComponent } from '@shared/components/page.component';
import { TbPopoverComponent } from '@shared/components/popover.component';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { createColorMarkerShapeURI, MarkerShape } from '@home/components/widget/lib/maps/marker-shape.models';
import { Observable } from 'rxjs';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
import { MatIconRegistry } from '@angular/material/icon';
import tinycolor from 'tinycolor2';
import { map, share } from 'rxjs/operators';
interface MarkerShapeInfo {
shape: MarkerShape;
url$: Observable<SafeUrl>;
}
@Component({
selector: 'tb-marker-shapes',
templateUrl: './marker-shapes.component.html',
providers: [],
styleUrls: ['./marker-shapes.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class MarkerShapesComponent extends PageComponent implements OnInit {
@Input()
shape: MarkerShape;
@Input()
color: string;
@Input()
popover: TbPopoverComponent<MarkerShapesComponent>;
@Output()
markerShapeSelected = new EventEmitter<MarkerShape>();
shapes: MarkerShapeInfo[];
constructor(protected store: Store<AppState>,
private iconRegistry: MatIconRegistry,
private domSanitizer: DomSanitizer) {
super(store);
}
ngOnInit(): void {
this.shapes = (Object.keys(MarkerShape) as MarkerShape[]).map((shape) => {
return {
shape,
url$: createColorMarkerShapeURI(this.iconRegistry, this.domSanitizer, shape, tinycolor(this.color)).pipe(
map((url) => {
return this.domSanitizer.bypassSecurityTrustUrl(url);
}),
share()
)
};
});
}
cancel() {
this.popover?.hide();
}
selectShape(shape: MarkerShape) {
this.markerShapeSelected.emit(shape);
}
}

6
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts

@ -219,6 +219,10 @@ import {
import { import {
DataLayerPatternSettingsComponent DataLayerPatternSettingsComponent
} from '@home/components/widget/lib/settings/common/map/data-layer-pattern-settings.component'; } from '@home/components/widget/lib/settings/common/map/data-layer-pattern-settings.component';
import {
MarkerShapeSettingsComponent
} from '@home/components/widget/lib/settings/common/map/marker-shape-settings.component';
import { MarkerShapesComponent } from '@home/components/widget/lib/settings/common/map/marker-shapes.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -295,6 +299,8 @@ import {
DataLayerColorSettingsComponent, DataLayerColorSettingsComponent,
DataLayerColorSettingsPanelComponent, DataLayerColorSettingsPanelComponent,
DataLayerPatternSettingsComponent, DataLayerPatternSettingsComponent,
MarkerShapeSettingsComponent,
MarkerShapesComponent,
MarkerImageSettingsComponent, MarkerImageSettingsComponent,
MarkerImageSettingsPanelComponent, MarkerImageSettingsPanelComponent,
MapDataLayerDialogComponent, MapDataLayerDialogComponent,

6
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -6911,9 +6911,13 @@
"marker-configuration": "Marker configuration", "marker-configuration": "Marker configuration",
"remove-marker": "Remove marker", "remove-marker": "Remove marker",
"marker-type": "Marker type", "marker-type": "Marker type",
"marker-type-default": "Default", "marker-type-shape": "Shape",
"marker-type-icon": "Icon",
"marker-type-image": "Image", "marker-type-image": "Image",
"shape": "Shape",
"icon": "Icon",
"image": "Image", "image": "Image",
"marker-shapes": "Marker shapes",
"marker-image": "Marker image", "marker-image": "Marker image",
"marker-image-type-image": "Image", "marker-image-type-image": "Image",
"marker-image-type-function": "Function", "marker-image-type-function": "Function",

19
ui-ngx/src/assets/markers/shape1.svg

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" width="34" height="34" viewBox="0 0 34 34" fill="none">
<g filter="url(#filter0_bf_8816_263887)">
<path d="M19 24.5C17.4075 27.4125 17 33 17 33C17 33 27.0858 32.1955 30.9992 27.4998C34 23.8992 31.9992 19 27.9992 19C23.9993 19 21.1929 20.4894 19 24.5Z" fill="black" fill-opacity="0.24"/>
</g>
<mask id="path-2-inside-1_8816_263887" fill="white">
<path fill-rule="evenodd" clip-rule="evenodd" d="M28 11.9C28.0037 5.32761 24.2902 0 17 0C9.70983 0 5.9963 5.32761 6 11.9C6.00473 20.2937 17 34 17 34C17 34 27.9953 20.2937 28 11.9ZM21.25 10.625C21.25 12.9722 19.3472 14.875 17 14.875C14.6528 14.875 12.75 12.9722 12.75 10.625C12.75 8.27779 14.6528 6.375 17 6.375C19.3472 6.375 21.25 8.27779 21.25 10.625Z"/>
</mask>
<path class="marker-color" fill-rule="evenodd" clip-rule="evenodd" d="M28 11.9C28.0037 5.32761 24.2902 0 17 0C9.70983 0 5.9963 5.32761 6 11.9C6.00473 20.2937 17 34 17 34C17 34 27.9953 20.2937 28 11.9ZM21.25 10.625C21.25 12.9722 19.3472 14.875 17 14.875C14.6528 14.875 12.75 12.9722 12.75 10.625C12.75 8.27779 14.6528 6.375 17 6.375C19.3472 6.375 21.25 8.27779 21.25 10.625Z" fill="#307FE5"/>
<path d="M28 11.9L29.0625 11.9006L28 11.9ZM6 11.9L7.0625 11.8994L6 11.9ZM17 34L16.1712 34.6649L17 35.698L17.8288 34.6649L17 34ZM17 1.0625C20.3641 1.0625 22.8085 2.28006 24.4273 4.17539C26.0652 6.09323 26.9392 8.80331 26.9375 11.8994L29.0625 11.9006C29.0644 8.4243 28.0835 5.18438 26.0431 2.79532C23.9835 0.383742 20.9261 -1.0625 17 -1.0625V1.0625ZM7.0625 11.8994C7.06076 8.80331 7.93477 6.09323 9.57274 4.17539C11.1915 2.28006 13.6359 1.0625 17 1.0625V-1.0625C13.0739 -1.0625 10.0165 0.383741 7.95686 2.79532C5.91645 5.18438 4.93555 8.4243 4.9375 11.9006L7.0625 11.8994ZM17 34C17.8288 33.3351 17.8288 33.3352 17.8288 33.3352C17.8288 33.3352 17.8288 33.3351 17.8287 33.335C17.8285 33.3348 17.8281 33.3343 17.8276 33.3336C17.8265 33.3323 17.8248 33.3301 17.8224 33.3271C17.8176 33.3212 17.8103 33.312 17.8004 33.2995C17.7807 33.2747 17.7509 33.2371 17.7118 33.1874C17.6335 33.0878 17.5178 32.9395 17.37 32.7472C17.0742 32.3624 16.6503 31.8017 16.1409 31.1019C15.1214 29.7014 13.7634 27.7495 12.4071 25.5415C11.049 23.3306 9.70388 20.8813 8.70091 18.4841C7.69109 16.0706 7.06357 13.7921 7.0625 11.8994L4.9375 11.9006C4.9388 14.2048 5.68746 16.7873 6.74058 19.3043C7.80055 21.8378 9.20516 24.3889 10.5964 26.6538C11.9895 28.9216 13.3807 30.9209 14.4229 32.3526C14.9444 33.0689 15.3795 33.6446 15.6851 34.0422C15.8379 34.241 15.9584 34.3954 16.0412 34.5007C16.0826 34.5534 16.1146 34.5938 16.1365 34.6213C16.1474 34.6351 16.1559 34.6456 16.1617 34.6529C16.1646 34.6566 16.1668 34.6594 16.1684 34.6614C16.1692 34.6624 16.1699 34.6632 16.1703 34.6637C16.1706 34.664 16.1708 34.6643 16.1709 34.6645C16.1711 34.6647 16.1712 34.6649 17 34ZM26.9375 11.8994C26.9364 13.7921 26.3089 16.0706 25.2991 18.4841C24.2961 20.8813 22.951 23.3306 21.5929 25.5415C20.2366 27.7495 18.8786 29.7014 17.8591 31.1019C17.3497 31.8017 16.9258 32.3624 16.63 32.7472C16.4822 32.9395 16.3665 33.0878 16.2882 33.1874C16.2491 33.2371 16.2193 33.2747 16.1996 33.2995C16.1897 33.312 16.1824 33.3212 16.1776 33.3271C16.1752 33.3301 16.1735 33.3323 16.1724 33.3336C16.1719 33.3343 16.1715 33.3348 16.1713 33.335C16.1712 33.3351 16.1712 33.3352 16.1712 33.3352C16.1712 33.3352 16.1712 33.3351 17 34C17.8288 34.6649 17.8289 34.6647 17.8291 34.6645C17.8292 34.6643 17.8294 34.664 17.8297 34.6637C17.8301 34.6632 17.8308 34.6624 17.8316 34.6614C17.8332 34.6594 17.8354 34.6566 17.8383 34.6529C17.8441 34.6456 17.8526 34.6351 17.8635 34.6213C17.8854 34.5938 17.9174 34.5534 17.9588 34.5007C18.0416 34.3954 18.1621 34.241 18.3149 34.0422C18.6205 33.6446 19.0556 33.0689 19.5771 32.3526C20.6193 30.9209 22.0105 28.9216 23.4036 26.6538C24.7948 24.3889 26.1995 21.8378 27.2594 19.3043C28.3125 16.7873 29.0612 14.2048 29.0625 11.9006L26.9375 11.8994ZM17 15.9375C19.934 15.9375 22.3125 13.559 22.3125 10.625H20.1875C20.1875 12.3854 18.7604 13.8125 17 13.8125V15.9375ZM11.6875 10.625C11.6875 13.559 14.066 15.9375 17 15.9375V13.8125C15.2396 13.8125 13.8125 12.3854 13.8125 10.625H11.6875ZM17 5.3125C14.066 5.3125 11.6875 7.69099 11.6875 10.625H13.8125C13.8125 8.86459 15.2396 7.4375 17 7.4375V5.3125ZM22.3125 10.625C22.3125 7.69099 19.934 5.3125 17 5.3125V7.4375C18.7604 7.4375 20.1875 8.86459 20.1875 10.625H22.3125Z" fill="black" fill-opacity="0.38" mask="url(#path-2-inside-1_8816_263887)"/>
<defs>
<filter id="filter0_bf_8816_263887" x="12.75" y="14.75" width="23.9434" height="22.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feGaussianBlur in="BackgroundImageFix" stdDeviation="2.125"/>
<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_8816_263887"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_8816_263887" result="shape"/>
<feGaussianBlur stdDeviation="0.5" result="effect2_foregroundBlur_8816_263887"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.9 KiB

16
ui-ngx/src/assets/markers/shape10.svg

@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" width="34" height="35" viewBox="0 0 34 35" fill="none">
<g filter="url(#filter0_bf_8825_264681)">
<path d="M11.6613 30.2966C10.8905 30.3394 10.7464 31.4155 11.4788 31.6596L17 33.5L22.5212 31.6596C23.2536 31.4155 23.1095 30.3394 22.3387 30.2966L17 30L11.6613 30.2966Z" fill="black" fill-opacity="0.24"/>
</g>
<rect x="16" width="2" height="34" fill="#575757"/>
<path class="marker-color" d="M18.5 0H32.7925C33.2379 0 33.461 0.538571 33.146 0.853553L26.9996 7L33.146 13.1464C33.461 13.4614 33.2379 14 32.7925 14H18.5V0Z" fill="#307FE5"/>
<defs>
<filter id="filter0_bf_8825_264681" x="7" y="26" width="20" height="11.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feGaussianBlur in="BackgroundImageFix" stdDeviation="2"/>
<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_8825_264681"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_8825_264681" result="shape"/>
<feGaussianBlur stdDeviation="0.5" result="effect2_foregroundBlur_8825_264681"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

17
ui-ngx/src/assets/markers/shape2.svg

@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" width="34" height="34" viewBox="0 0 34 34" fill="none">
<g filter="url(#filter0_bf_8816_263882)">
<path d="M19 24.5C17.4075 27.4125 17 33 17 33C17 33 27.0858 32.1955 30.9992 27.4998C34 23.8992 31.9992 19 27.9992 19C23.9993 19 21.1929 20.4894 19 24.5Z" fill="black" fill-opacity="0.24"/>
</g>
<path class="marker-color" d="M16.8812 33.8865C16.8452 33.7872 16.6641 33.1184 16.4788 32.4005C15.8927 30.1293 14.8789 27.6872 13.5032 25.2321C12.7133 23.8226 12.5705 23.598 10.2629 20.135C6.53418 14.5396 5.8789 12.9684 6.01669 9.95493C6.14303 7.19334 7.10838 5.12431 9.20388 3.12359C10.9433 1.46297 12.8739 0.5051 15.2223 0.13773C21.0423 -0.772682 26.6886 2.92621 27.8326 8.39854C28.0993 9.67434 28.0401 11.87 27.7068 13.0629C27.3412 14.3714 25.8745 17.0188 23.8016 20.1115C20.0603 25.6936 18.6436 28.4817 17.5828 32.3508C17.1722 33.8487 17.0023 34.2205 16.8812 33.8865Z" fill="#307FE5"/>
<path d="M10.2663 20.1328L10.705 19.8404C13.012 23.3025 13.1655 23.5428 13.9666 24.9724L13.5032 25.2321L13.9666 24.9724C15.3604 27.4598 16.3936 29.9445 16.9932 32.2677C17.0031 32.3062 17.013 32.3445 17.0229 32.3826C17.0383 32.3272 17.0542 32.2698 17.0705 32.2103C18.1532 28.2612 19.6055 25.4179 23.3603 19.8157L23.8016 20.1115L23.3604 19.8157C24.3907 18.2785 25.2672 16.8565 25.9298 15.6607C26.5985 14.4537 27.0302 13.5105 27.1952 12.9199C27.3454 12.3823 27.4411 11.5835 27.4636 10.7475C27.4861 9.91291 27.4344 9.08999 27.3126 8.50725C26.2313 3.33526 20.8692 -0.207891 15.3044 0.662597C13.0643 1.01301 11.2327 1.92108 9.57073 3.50784M10.2663 20.1328L6.54738 9.97919C6.66715 7.36131 7.56888 5.41915 9.57073 3.50784M10.2663 20.1328L10.705 19.8404C8.83761 17.0382 7.77024 15.287 7.18016 13.8723M10.2663 20.1328L7.18016 13.8723M9.57073 3.50784L9.20388 3.12359L9.57073 3.50784ZM7.18016 13.8723C6.60389 12.4906 6.48125 11.4256 6.54738 9.97921L7.18016 13.8723Z" stroke="black" stroke-opacity="0.38" stroke-width="1.0625"/>
<path d="M20 11C20 12.6568 18.6569 14 17 14C15.3432 14 14 12.6568 14 11C14 9.3431 15.3431 8 17 8C18.6569 8 20 9.3431 20 11Z" fill="black" fill-opacity="0.38"/>
<defs>
<filter id="filter0_bf_8816_263882" x="12.75" y="14.75" width="23.9434" height="22.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feGaussianBlur in="BackgroundImageFix" stdDeviation="2.125"/>
<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_8816_263882"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_8816_263882" result="shape"/>
<feGaussianBlur stdDeviation="0.5" result="effect2_foregroundBlur_8816_263882"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

19
ui-ngx/src/assets/markers/shape3.svg

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" width="34" height="34" viewBox="0 0 34 34" fill="none">
<g filter="url(#filter0_bf_8816_263884)">
<path d="M19 24.5C17.4075 27.4125 17 33 17 33C17 33 27.0858 32.1955 30.9992 27.4998C34 23.8992 31.9992 19 27.9992 19C23.9993 19 21.1929 20.4894 19 24.5Z" fill="black" fill-opacity="0.24"/>
</g>
<mask id="path-2-inside-1_8816_263884" fill="white">
<path fill-rule="evenodd" clip-rule="evenodd" d="M30 12.9625C30 6.39011 25.6157 0 17 0C8.38434 0 4 6.39011 4 12.9625C4 20.1875 17 34 17 34C17 34 30 20.1875 30 12.9625ZM21.25 12.75C21.25 15.0972 19.3472 17 17 17C14.6528 17 12.75 15.0972 12.75 12.75C12.75 10.4028 14.6528 8.5 17 8.5C19.3472 8.5 21.25 10.4028 21.25 12.75Z"/>
</mask>
<path class="marker-color" fill-rule="evenodd" clip-rule="evenodd" d="M30 12.9625C30 6.39011 25.6157 0 17 0C8.38434 0 4 6.39011 4 12.9625C4 20.1875 17 34 17 34C17 34 30 20.1875 30 12.9625ZM21.25 12.75C21.25 15.0972 19.3472 17 17 17C14.6528 17 12.75 15.0972 12.75 12.75C12.75 10.4028 14.6528 8.5 17 8.5C19.3472 8.5 21.25 10.4028 21.25 12.75Z" fill="#307FE5"/>
<path d="M17 34L16.2263 34.7282L17 35.5503L17.7737 34.7282L17 34ZM17 1.0625C21.024 1.0625 23.9804 2.54472 25.9404 4.72663C27.9167 6.92661 28.9375 9.90415 28.9375 12.9625H31.0625C31.0625 9.44846 29.8911 5.94475 27.5213 3.30657C25.1352 0.650333 21.5917 -1.0625 17 -1.0625V1.0625ZM5.0625 12.9625C5.0625 9.90415 6.08332 6.92661 8.05955 4.72663C10.0195 2.54472 12.976 1.0625 17 1.0625V-1.0625C12.4083 -1.0625 8.86479 0.650333 6.47871 3.30657C4.10885 5.94475 2.9375 9.44846 2.9375 12.9625H5.0625ZM17 34C17.7737 33.2718 17.7738 33.2718 17.7737 33.2718C17.7737 33.2718 17.7736 33.2717 17.7735 33.2716C17.7732 33.2713 17.7728 33.2708 17.7721 33.2701C17.7708 33.2687 17.7687 33.2664 17.7658 33.2634C17.76 33.2572 17.7512 33.2478 17.7395 33.2352C17.7159 33.21 17.6805 33.1719 17.634 33.1216C17.5409 33.021 17.4036 32.8717 17.2283 32.6784C16.8776 32.292 16.3754 31.7304 15.772 31.0335C14.5644 29.6385 12.9568 27.7069 11.3516 25.5553C9.74351 23.3998 8.15401 21.0451 6.97106 18.802C5.77119 16.5269 5.0625 14.4999 5.0625 12.9625H2.9375C2.9375 15.0376 3.85381 17.4466 5.09144 19.7933C6.34599 22.1721 8.00649 24.6252 9.64839 26.826C11.2932 29.0306 12.9355 31.0036 14.1654 32.4243C14.7809 33.1352 15.2942 33.7092 15.6545 34.1063C15.8347 34.3049 15.9766 34.4593 16.074 34.5646C16.1227 34.6173 16.1603 34.6576 16.1859 34.6851C16.1988 34.6988 16.2086 34.7094 16.2154 34.7166C16.2187 34.7202 16.2213 34.7229 16.2232 34.7249C16.2241 34.7259 16.2248 34.7266 16.2253 34.7272C16.2256 34.7274 16.2258 34.7277 16.226 34.7278C16.2261 34.7281 16.2263 34.7282 17 34ZM28.9375 12.9625C28.9375 14.4999 28.2288 16.5269 27.0289 18.802C25.846 21.0451 24.2565 23.3998 22.6484 25.5553C21.0432 27.7069 19.4355 29.6385 18.2279 31.0335C17.6246 31.7304 17.1224 32.292 16.7717 32.6784C16.5964 32.8717 16.4591 33.021 16.366 33.1216C16.3195 33.1719 16.2841 33.21 16.2605 33.2352C16.2488 33.2478 16.2399 33.2572 16.2342 33.2634C16.2313 33.2664 16.2292 33.2687 16.2279 33.2701C16.2272 33.2708 16.2268 33.2713 16.2265 33.2716C16.2264 33.2717 16.2263 33.2718 16.2262 33.2718C16.2262 33.2718 16.2263 33.2718 17 34C17.7737 34.7282 17.7739 34.7281 17.774 34.7278C17.7742 34.7277 17.7744 34.7274 17.7747 34.7272C17.7752 34.7266 17.7759 34.7259 17.7768 34.7249C17.7787 34.7229 17.7813 34.7202 17.7846 34.7166C17.7914 34.7094 17.8012 34.6988 17.814 34.6851C17.8397 34.6576 17.8773 34.6173 17.926 34.5646C18.0234 34.4593 18.1653 34.3049 18.3455 34.1063C18.7058 33.7092 19.2191 33.1352 19.8345 32.4243C21.0644 31.0036 22.7068 29.0306 24.3516 26.826C25.9935 24.6252 27.654 22.1721 28.9086 19.7933C30.1462 17.4466 31.0625 15.0376 31.0625 12.9625H28.9375ZM17 18.0625C19.934 18.0625 22.3125 15.684 22.3125 12.75H20.1875C20.1875 14.5104 18.7604 15.9375 17 15.9375V18.0625ZM11.6875 12.75C11.6875 15.684 14.066 18.0625 17 18.0625V15.9375C15.2396 15.9375 13.8125 14.5104 13.8125 12.75H11.6875ZM17 7.4375C14.066 7.4375 11.6875 9.81599 11.6875 12.75H13.8125C13.8125 10.9896 15.2396 9.5625 17 9.5625V7.4375ZM22.3125 12.75C22.3125 9.81599 19.934 7.4375 17 7.4375V9.5625C18.7604 9.5625 20.1875 10.9896 20.1875 12.75H22.3125Z" fill="black" fill-opacity="0.38" mask="url(#path-2-inside-1_8816_263884)"/>
<defs>
<filter id="filter0_bf_8816_263884" x="12.75" y="14.75" width="23.9434" height="22.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feGaussianBlur in="BackgroundImageFix" stdDeviation="2.125"/>
<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_8816_263884"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_8816_263884" result="shape"/>
<feGaussianBlur stdDeviation="0.5" result="effect2_foregroundBlur_8816_263884"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

21
ui-ngx/src/assets/markers/shape4.svg

@ -0,0 +1,21 @@
<svg xmlns="http://www.w3.org/2000/svg" width="34" height="34" viewBox="0 0 34 34" fill="none">
<g filter="url(#filter0_bf_8816_263886)">
<path d="M19 24.5C17.4075 27.4125 17 33 17 33C17 33 27.0858 32.1955 30.9992 27.4998C34 23.8992 31.9992 19 27.9992 19C23.9993 19 21.1929 20.4894 19 24.5Z" fill="black" fill-opacity="0.24"/>
</g>
<mask id="path-2-inside-1_8816_263886" fill="white">
<path fill-rule="evenodd" clip-rule="evenodd" d="M30 12.9625C30 6.39011 25.6157 0 17 0C8.38434 0 4 6.39011 4 12.9625C4 20.1875 17 34 17 34C17 34 30 20.1875 30 12.9625ZM24 13C24 16.866 20.866 20 17 20C13.134 20 10 16.866 10 13C10 9.13401 13.134 6 17 6C20.866 6 24 9.13401 24 13Z"/>
</mask>
<path class="marker-color" fill-rule="evenodd" clip-rule="evenodd" d="M30 12.9625C30 6.39011 25.6157 0 17 0C8.38434 0 4 6.39011 4 12.9625C4 20.1875 17 34 17 34C17 34 30 20.1875 30 12.9625ZM24 13C24 16.866 20.866 20 17 20C13.134 20 10 16.866 10 13C10 9.13401 13.134 6 17 6C20.866 6 24 9.13401 24 13Z" fill="#307FE5"/>
<path d="M17 34L16.2263 34.7282L17 35.5503L17.7737 34.7282L17 34ZM17 1.0625C21.024 1.0625 23.9804 2.54472 25.9404 4.72663C27.9167 6.92661 28.9375 9.90415 28.9375 12.9625H31.0625C31.0625 9.44846 29.8911 5.94475 27.5213 3.30657C25.1352 0.650333 21.5917 -1.0625 17 -1.0625V1.0625ZM5.0625 12.9625C5.0625 9.90415 6.08332 6.92661 8.05955 4.72663C10.0195 2.54472 12.976 1.0625 17 1.0625V-1.0625C12.4083 -1.0625 8.86479 0.650333 6.47871 3.30657C4.10885 5.94475 2.9375 9.44846 2.9375 12.9625H5.0625ZM17 34C17.7737 33.2718 17.7738 33.2718 17.7737 33.2718C17.7737 33.2718 17.7736 33.2717 17.7735 33.2716C17.7732 33.2713 17.7728 33.2708 17.7721 33.2701C17.7708 33.2687 17.7687 33.2664 17.7658 33.2634C17.76 33.2572 17.7512 33.2478 17.7395 33.2352C17.7159 33.21 17.6805 33.1719 17.634 33.1216C17.5409 33.021 17.4036 32.8717 17.2283 32.6784C16.8776 32.292 16.3754 31.7304 15.772 31.0335C14.5644 29.6385 12.9568 27.7069 11.3516 25.5553C9.74351 23.3998 8.15401 21.0451 6.97106 18.802C5.77119 16.5269 5.0625 14.4999 5.0625 12.9625H2.9375C2.9375 15.0376 3.85381 17.4466 5.09144 19.7933C6.34599 22.1721 8.00649 24.6252 9.64839 26.826C11.2932 29.0306 12.9355 31.0036 14.1654 32.4243C14.7809 33.1352 15.2942 33.7092 15.6545 34.1063C15.8347 34.3049 15.9766 34.4593 16.074 34.5646C16.1227 34.6173 16.1603 34.6576 16.1859 34.6851C16.1988 34.6988 16.2086 34.7094 16.2154 34.7166C16.2187 34.7202 16.2213 34.7229 16.2232 34.7249C16.2241 34.7259 16.2248 34.7266 16.2253 34.7272C16.2256 34.7274 16.2258 34.7277 16.226 34.7278C16.2261 34.7281 16.2263 34.7282 17 34ZM28.9375 12.9625C28.9375 14.4999 28.2288 16.5269 27.0289 18.802C25.846 21.0451 24.2565 23.3998 22.6484 25.5553C21.0432 27.7069 19.4355 29.6385 18.2279 31.0335C17.6246 31.7304 17.1224 32.292 16.7717 32.6784C16.5964 32.8717 16.4591 33.021 16.366 33.1216C16.3195 33.1719 16.2841 33.21 16.2605 33.2352C16.2488 33.2478 16.2399 33.2572 16.2342 33.2634C16.2313 33.2664 16.2292 33.2687 16.2279 33.2701C16.2272 33.2708 16.2268 33.2713 16.2265 33.2716C16.2264 33.2717 16.2263 33.2718 16.2262 33.2718C16.2262 33.2718 16.2263 33.2718 17 34C17.7737 34.7282 17.7739 34.7281 17.774 34.7278C17.7742 34.7277 17.7744 34.7274 17.7747 34.7272C17.7752 34.7266 17.7759 34.7259 17.7768 34.7249C17.7787 34.7229 17.7813 34.7202 17.7846 34.7166C17.7914 34.7094 17.8012 34.6988 17.814 34.6851C17.8397 34.6576 17.8773 34.6173 17.926 34.5646C18.0234 34.4593 18.1653 34.3049 18.3455 34.1063C18.7058 33.7092 19.2191 33.1352 19.8345 32.4243C21.0644 31.0036 22.7068 29.0306 24.3516 26.826C25.9935 24.6252 27.654 22.1721 28.9086 19.7933C30.1462 17.4466 31.0625 15.0376 31.0625 12.9625H28.9375ZM17 21.0625C21.4528 21.0625 25.0625 17.4528 25.0625 13H22.9375C22.9375 16.2792 20.2792 18.9375 17 18.9375V21.0625ZM8.9375 13C8.9375 17.4528 12.5472 21.0625 17 21.0625V18.9375C13.7208 18.9375 11.0625 16.2792 11.0625 13H8.9375ZM17 4.9375C12.5472 4.9375 8.9375 8.5472 8.9375 13H11.0625C11.0625 9.72081 13.7208 7.0625 17 7.0625V4.9375ZM25.0625 13C25.0625 8.5472 21.4528 4.9375 17 4.9375V7.0625C20.2792 7.0625 22.9375 9.72081 22.9375 13H25.0625Z" fill="black" fill-opacity="0.38" mask="url(#path-2-inside-1_8816_263886)"/>
<path class="marker-color" d="M17 19C20.3137 19 23 16.3137 23 13C23 9.68629 20.3137 7 17 7C13.6863 7 11 9.68629 11 13C11 16.3137 13.6863 19 17 19Z" fill="#307FE5"/>
<path d="M22.5278 13C22.5278 16.0529 20.0529 18.5278 17 18.5278C13.9471 18.5278 11.4722 16.0529 11.4722 13C11.4722 9.94709 13.9471 7.47222 17 7.47222C20.0529 7.47222 22.5278 9.94709 22.5278 13Z" stroke="black" stroke-opacity="0.38" stroke-width="0.944444"/>
<defs>
<filter id="filter0_bf_8816_263886" x="12.75" y="14.75" width="23.9434" height="22.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feGaussianBlur in="BackgroundImageFix" stdDeviation="2.125"/>
<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_8816_263886"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_8816_263886" result="shape"/>
<feGaussianBlur stdDeviation="0.5" result="effect2_foregroundBlur_8816_263886"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.0 KiB

20
ui-ngx/src/assets/markers/shape5.svg

@ -0,0 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg" width="34" height="34" viewBox="0 0 34 34" fill="none">
<g filter="url(#filter0_bf_8826_264716)">
<path d="M19 24.5C17.4075 27.4125 17 33 17 33C17 33 27.0858 32.1955 30.9992 27.4998C34 23.8992 31.9992 19 27.9992 19C23.9993 19 21.1929 20.4894 19 24.5Z" fill="black" fill-opacity="0.24"/>
</g>
<path class="marker-color" d="M9 25L17 34L25 25C25 25 23 27 17 27C11 27 9 25 9 25Z" fill="#307FE5"/>
<path d="M9 25L17 34L25 25C25 25 23 27 17 27C11 27 9 25 9 25Z" fill="black" fill-opacity="0.38"/>
<mask id="path-3-inside-1_8826_264716" fill="white">
<path d="M30 13C30 20.1797 24.1797 26 17 26C9.8203 26 4 20.1797 4 13C4 5.8203 9.8203 0 17 0C24.1797 0 30 5.8203 30 13ZM9.99998 13C9.99998 16.866 13.134 20 17 20C20.866 20 24 16.866 24 13C24 9.13399 20.866 5.99998 17 5.99998C13.134 5.99998 9.99998 9.13399 9.99998 13Z"/>
</mask>
<path class="marker-color" d="M30 13C30 20.1797 24.1797 26 17 26C9.8203 26 4 20.1797 4 13C4 5.8203 9.8203 0 17 0C24.1797 0 30 5.8203 30 13ZM9.99998 13C9.99998 16.866 13.134 20 17 20C20.866 20 24 16.866 24 13C24 9.13399 20.866 5.99998 17 5.99998C13.134 5.99998 9.99998 9.13399 9.99998 13Z" fill="#307FE5" stroke="black" stroke-opacity="0.38" stroke-width="2" mask="url(#path-3-inside-1_8826_264716)"/>
<defs>
<filter id="filter0_bf_8826_264716" x="12.75" y="14.75" width="23.9434" height="22.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feGaussianBlur in="BackgroundImageFix" stdDeviation="2.125"/>
<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_8826_264716"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_8826_264716" result="shape"/>
<feGaussianBlur stdDeviation="0.5" result="effect2_foregroundBlur_8826_264716"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

22
ui-ngx/src/assets/markers/shape6.svg

@ -0,0 +1,22 @@
<svg xmlns="http://www.w3.org/2000/svg" width="34" height="34" viewBox="0 0 34 34" fill="none">
<g filter="url(#filter0_bf_8817_262071)">
<path d="M19 24.5C17.4075 27.4125 17 33 17 33C17 33 27.0858 32.1955 30.9992 27.4998C34 23.8992 31.9992 19 27.9992 19C23.9993 19 21.1929 20.4894 19 24.5Z" fill="black" fill-opacity="0.24"/>
</g>
<mask id="path-2-inside-1_8817_262071" fill="white">
<path fill-rule="evenodd" clip-rule="evenodd" d="M30 12.9625C30 6.39011 25.6157 0 17 0C8.38434 0 4 6.39011 4 12.9625C4 25 17 34 17 34C17 34 30 25 30 12.9625ZM26 13C26 17.9706 21.9706 22 17 22C12.0294 22 8 17.9706 8 13C8 8.02944 12.0294 4 17 4C21.9706 4 26 8.02944 26 13Z"/>
</mask>
<path class="marker-color" fill-rule="evenodd" clip-rule="evenodd" d="M30 12.9625C30 6.39011 25.6157 0 17 0C8.38434 0 4 6.39011 4 12.9625C4 25 17 34 17 34C17 34 30 25 30 12.9625ZM26 13C26 17.9706 21.9706 22 17 22C12.0294 22 8 17.9706 8 13C8 8.02944 12.0294 4 17 4C21.9706 4 26 8.02944 26 13Z" fill="#307FE5"/>
<path d="M17 34L16.3952 34.8736L17 35.2923L17.6048 34.8736L17 34ZM17 1.0625C21.024 1.0625 23.9805 2.54472 25.9405 4.72663C27.9167 6.92661 28.9375 9.90415 28.9375 12.9625H31.0625C31.0625 9.44846 29.8911 5.94475 27.5213 3.30657C25.1352 0.650333 21.5917 -1.0625 17 -1.0625V1.0625ZM5.0625 12.9625C5.0625 9.90415 6.08332 6.92661 8.05955 4.72663C10.0195 2.54472 12.976 1.0625 17 1.0625V-1.0625C12.4083 -1.0625 8.86479 0.650333 6.47871 3.30657C4.10885 5.94475 2.9375 9.44846 2.9375 12.9625H5.0625ZM17 34C17.6048 33.1264 17.605 33.1266 17.6052 33.1267C17.6052 33.1267 17.6053 33.1268 17.6053 33.1268C17.6052 33.1267 17.605 33.1266 17.6046 33.1263C17.6037 33.1257 17.6021 33.1245 17.5997 33.1229C17.5949 33.1195 17.587 33.114 17.5762 33.1063C17.5546 33.091 17.5211 33.0672 17.4766 33.035C17.3876 32.9706 17.2545 32.8729 17.0835 32.7432C16.7414 32.4838 16.2486 32.0971 15.6553 31.5948C14.4672 30.5889 12.884 29.126 11.3033 27.2999C8.11939 23.6215 5.0625 18.605 5.0625 12.9625H2.9375C2.9375 19.3575 6.38061 24.8597 9.69665 28.6907C11.366 30.6193 13.0328 32.1588 14.2822 33.2166C14.9077 33.7461 15.4305 34.1565 15.7993 34.4363C15.9838 34.5763 16.13 34.6836 16.2314 34.7569C16.2821 34.7936 16.3216 34.8218 16.3492 34.8413C16.363 34.851 16.3738 34.8586 16.3815 34.864C16.3853 34.8667 16.3884 34.8688 16.3907 34.8704C16.3918 34.8712 16.3928 34.8719 16.3935 34.8724C16.3939 34.8727 16.3943 34.873 16.3945 34.8731C16.3949 34.8734 16.3952 34.8736 17 34ZM28.9375 12.9625C28.9375 18.605 25.8806 23.6215 22.6966 27.2999C21.116 29.126 19.5328 30.5889 18.3447 31.5948C17.7514 32.0971 17.2586 32.4838 16.9165 32.7432C16.7455 32.8729 16.6124 32.9706 16.5234 33.035C16.4789 33.0672 16.4454 33.091 16.4238 33.1063C16.413 33.114 16.4051 33.1195 16.4003 33.1229C16.3979 33.1245 16.3963 33.1257 16.3954 33.1263C16.395 33.1266 16.3948 33.1267 16.3947 33.1268C16.3947 33.1268 16.3948 33.1267 16.3948 33.1267C16.395 33.1266 16.3952 33.1264 17 34C17.6048 34.8736 17.6051 34.8734 17.6055 34.8731C17.6057 34.873 17.6061 34.8727 17.6065 34.8724C17.6072 34.8719 17.6082 34.8712 17.6093 34.8704C17.6116 34.8688 17.6147 34.8667 17.6185 34.864C17.6262 34.8586 17.637 34.851 17.6508 34.8413C17.6784 34.8218 17.7179 34.7936 17.7686 34.7569C17.87 34.6836 18.0162 34.5763 18.2007 34.4363C18.5695 34.1565 19.0923 33.7461 19.7178 33.2166C20.9672 32.1588 22.634 30.6193 24.3034 28.6907C27.6194 24.8597 31.0625 19.3575 31.0625 12.9625H28.9375ZM17 23.0625C22.5574 23.0625 27.0625 18.5574 27.0625 13H24.9375C24.9375 17.3838 21.3838 20.9375 17 20.9375V23.0625ZM6.9375 13C6.9375 18.5574 11.4426 23.0625 17 23.0625V20.9375C12.6162 20.9375 9.0625 17.3838 9.0625 13H6.9375ZM17 2.9375C11.4426 2.9375 6.9375 7.44263 6.9375 13H9.0625C9.0625 8.61624 12.6162 5.0625 17 5.0625V2.9375ZM27.0625 13C27.0625 7.44263 22.5574 2.9375 17 2.9375V5.0625C21.3838 5.0625 24.9375 8.61624 24.9375 13H27.0625Z" fill="black" fill-opacity="0.38" mask="url(#path-2-inside-1_8817_262071)"/>
<circle class="marker-icon-background" style="display: none;" cx="17" cy="13" r="9" fill="#fff"></circle>
<g class="marker-icon-container" transform="translate(17,13)">
</g>
<defs>
<filter id="filter0_bf_8817_262071" x="12.75" y="14.75" width="23.9434" height="22.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feGaussianBlur in="BackgroundImageFix" stdDeviation="2.125"/>
<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_8817_262071"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_8817_262071" result="shape"/>
<feGaussianBlur stdDeviation="0.5" result="effect2_foregroundBlur_8817_262071"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

28
ui-ngx/src/assets/markers/shape7.svg

@ -0,0 +1,28 @@
<svg xmlns="http://www.w3.org/2000/svg" width="34" height="34" viewBox="0 0 34 34" fill="none">
<g filter="url(#filter0_bf_8816_263885)">
<path d="M19 24.5C17.4075 27.4125 17 33 17 33C17 33 27.0858 32.1955 30.9992 27.4998C34 23.8992 31.9992 19 27.9992 19C23.9993 19 21.1929 20.4894 19 24.5Z" fill="black" fill-opacity="0.24"/>
</g>
<path class="marker-color" d="M9.5 23L17 34L24.5 23C24.5 23 22 25.5 17 25.5C12 25.5 9.5 23 9.5 23Z" fill="#307FE5"/>
<path d="M9.5 23L17 34L24.5 23C24.5 23 22 25.5 17 25.5C12 25.5 9.5 23 9.5 23Z" fill="black" fill-opacity="0.38"/>
<path class="marker-color" d="M28 13C28 19.0749 23.0753 24 17 24C10.9251 24 6 19.0753 6 13C6 6.92506 10.9247 2 17 2C23.0749 2 28 6.92473 28 13Z" fill="#307FE5"/>
<path d="M28 13C28 19.0749 23.0753 24 17 24C10.9251 24 6 19.0753 6 13C6 6.92506 10.9247 2 17 2C23.0749 2 28 6.92473 28 13Z" fill="url(#paint0_radial_8816_263885)"/>
<path class="marker-stroke" d="M28 13C28 19.0749 23.0753 24 17 24C10.9251 24 6 19.0753 6 13C6 6.92506 10.9247 2 17 2C23.0749 2 28 6.92473 28 13Z" stroke="#307FE5" stroke-width="3.1875"/>
<path d="M28 13C28 19.0749 23.0753 24 17 24C10.9251 24 6 19.0753 6 13C6 6.92506 10.9247 2 17 2C23.0749 2 28 6.92473 28 13Z" stroke="url(#paint1_linear_8816_263885)" stroke-width="3.1875"/>
<defs>
<filter id="filter0_bf_8816_263885" x="12.75" y="14.75" width="23.9434" height="22.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feGaussianBlur in="BackgroundImageFix" stdDeviation="2.125"/>
<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_8816_263885"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_8816_263885" result="shape"/>
<feGaussianBlur stdDeviation="0.5" result="effect2_foregroundBlur_8816_263885"/>
</filter>
<radialGradient id="paint0_radial_8816_263885" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(21.4 5.3) rotate(126.87) scale(13.75 14.648)">
<stop stop-opacity="0.25"/>
<stop offset="1" stop-opacity="0"/>
</radialGradient>
<linearGradient id="paint1_linear_8816_263885" x1="9.3" y1="20.7" x2="21.95" y2="3.1" gradientUnits="userSpaceOnUse">
<stop stop-opacity="0.25"/>
<stop offset="1" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

17
ui-ngx/src/assets/markers/shape8.svg

@ -0,0 +1,17 @@
<svg xmlns="http://www.w3.org/2000/svg" width="34" height="35" viewBox="0 0 34 35" fill="none">
<circle class="marker-color" cx="17" cy="8" r="8" fill="#307FE5"/>
<g filter="url(#filter0_bf_8816_263881)">
<path d="M11.6613 30.2966C10.8905 30.3394 10.7464 31.4155 11.4788 31.6596L17 33.5L22.5212 31.6596C23.2536 31.4155 23.1095 30.3394 22.3387 30.2966L17 30L11.6613 30.2966Z" fill="black" fill-opacity="0.24"/>
</g>
<circle cx="20" cy="5" r="1" fill="white"/>
<rect x="16" y="16" width="2" height="18" fill="#575757"/>
<defs>
<filter id="filter0_bf_8816_263881" x="7" y="26" width="20" height="11.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feGaussianBlur in="BackgroundImageFix" stdDeviation="2"/>
<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_8816_263881"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_8816_263881" result="shape"/>
<feGaussianBlur stdDeviation="0.5" result="effect2_foregroundBlur_8816_263881"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

19
ui-ngx/src/assets/markers/shape9.svg

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" width="34" height="35" viewBox="0 0 34 35" fill="none">
<g filter="url(#filter0_bf_8817_262059)">
<path d="M11.6613 30.2966C10.8905 30.3394 10.7464 31.4155 11.4788 31.6596L17 33.5L22.5212 31.6596C23.2536 31.4155 23.1095 30.3394 22.3387 30.2966L17 30L11.6613 30.2966Z" fill="black" fill-opacity="0.24"/>
</g>
<path class="marker-color" d="M23.9551 5.67547e-07C23.9551 0.85254 23.7799 1.69673 23.4394 2.48438C23.099 3.27202 22.6 3.98769 21.9709 4.59053C19.3203 7.1305 14.6797 7.1305 12.0291 4.59053C11.4 3.98769 10.901 3.27202 10.5606 2.48438C10.2201 1.69673 10.0449 0.85254 10.0449 0L23.9551 5.67547e-07Z" fill="#307FE5"/>
<path class="marker-color" d="M26 20C26 18.8674 25.7672 17.9327 25.3149 16.8863C24.8626 15.84 24.1997 14.8892 23.364 14.0884C19.8889 10.7584 14.1111 10.7584 10.636 14.0884C9.80031 14.8892 9.13738 15.84 8.68508 16.8863C8.23279 17.9327 8 18.8674 8 20L26 20Z" fill="#307FE5"/>
<path class="marker-color" d="M13.5558 5.68641H20.4442L20.6593 12.3206H13.3407L13.5558 5.68641Z" fill="#307FE5"/>
<path d="M21.5413 15.1083C21.7082 15.5465 21.9575 16.817 21.5568 16.9696C21.1562 17.1223 20.1818 15.5475 19.8243 15.1441C19.3333 14.5891 18.9 13.6576 19.8587 13.6026C20.8175 13.5476 21.3743 14.6702 21.5413 15.1083Z" fill="white"/>
<rect x="16" y="20" width="2" height="14" fill="#575757"/>
<defs>
<filter id="filter0_bf_8817_262059" x="7" y="26" width="20" height="11.5" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feGaussianBlur in="BackgroundImageFix" stdDeviation="2"/>
<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_8817_262059"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_8817_262059" result="shape"/>
<feGaussianBlur stdDeviation="0.5" result="effect2_foregroundBlur_8817_262059"/>
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

Loading…
Cancel
Save