1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2025-01-10 04:07:35 +02:00

Make map colors/icons configurable #587

#667
This commit is contained in:
Patrik J. Braun 2023-07-02 20:01:00 +02:00
parent 3fb31f17a8
commit b1a19df2c3
3 changed files with 236 additions and 36 deletions

View File

@ -318,6 +318,138 @@ export class MapLayers {
darkLayer: boolean = false;
}
export enum MapPathGroupTypes {
Transportation = 1, Sport, Custom
}
@SubConfigClass({tags: {client: true}, softReadonly: true})
export class SVGIconConfig {
constructor(viewBoxWidth: number = 512, path: string = '') {
this.viewBoxWidth = viewBoxWidth;
this.path = path;
}
@ConfigProperty({
tags: {
name: $localize`SBG icon viewBox with`,
priority: ConfigPriority.advanced
},
description: $localize`You need the with from the SVG viewBox (assuming height is 512). See: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox`,
})
viewBoxWidth: number = 512;
@ConfigProperty({
tags: {
name: $localize`SVG path`,
priority: ConfigPriority.advanced
},
description: $localize`Path element of the SVG icon. Icons used on the map: fontawesome.com/icons.`,
})
path: string = '';
}
@SubConfigClass({tags: {client: true}, softReadonly: true})
export class PathThemeConfig {
constructor(color: string = '', dashArray: string = '', svgIcon: SVGIconConfig = new SVGIconConfig()) {
this.color = color;
this.dashArray = dashArray;
this.svgIcon = svgIcon;
}
@ConfigProperty({
tags: {
name: $localize`Color`,
priority: ConfigPriority.advanced
},
description: $localize`Color of the path. Use any valid css colors.`,
})
color: string = '';
@ConfigProperty({
tags: {
name: $localize`Dash pattern`,
priority: ConfigPriority.advanced
},
description: $localize`Dash pattern of the path. Represents the spacing and length of the dash. Read more about dash array at: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray.`,
})
dashArray: string = '';
@ConfigProperty({
type: SVGIconConfig,
tags: {
name: $localize`Svg Icon`,
priority: ConfigPriority.advanced
},
description: $localize`Set the icon of the map marker pin.`,
})
svgIcon: SVGIconConfig = new SVGIconConfig();
}
@SubConfigClass({tags: {client: true}, softReadonly: true})
export class MapPathGroupThemeConfig {
constructor(matchers: string[] = [], theme: PathThemeConfig = new PathThemeConfig()) {
this.matchers = matchers;
this.theme = theme;
}
@ConfigProperty({
arrayType: 'string',
tags: {
name: $localize`Matcher`,
priority: ConfigPriority.advanced
},
description: $localize`List of regex string to match the name of the path. Case insensitive.`,
})
matchers: string[] = [];
@ConfigProperty({
type: PathThemeConfig,
tags: {
name: $localize`Path and icon theme`,
priority: ConfigPriority.advanced
},
description: $localize`List of regex string to match the name of the path.`,
})
theme: PathThemeConfig = new PathThemeConfig();
}
@SubConfigClass({tags: {client: true}, softReadonly: true})
export class MapPathGroupConfig {
constructor(name: string = '', matchers: MapPathGroupThemeConfig[] = []) {
this.name = name;
this.matchers = matchers;
}
@ConfigProperty({
tags: {
name: $localize`Name`,
priority: ConfigPriority.advanced
},
description: $localize`Name of the marker and path group on the map.`,
})
name: string = '';
@ConfigProperty({
arrayType: MapPathGroupThemeConfig,
tags: {
name: $localize`Matchers`,
priority: ConfigPriority.advanced
},
description: $localize`Matchers for a given map and path theme.`,
})
matchers: MapPathGroupThemeConfig[] = [];
}
@SubConfigClass({tags: {client: true}, softReadonly: true})
export class ClientMapConfig {
@ConfigProperty<boolean, ClientConfig, TAGS>({
@ -379,6 +511,39 @@ export class ClientMapConfig {
description: $localize`Maximum number of markers to be shown on the map preview on the gallery page.`,
})
maxPreviewMarkers: number = 50;
@ConfigProperty({
arrayType: MapPathGroupConfig,
tags: {
name: $localize`Path and marker group`,
priority: ConfigPriority.advanced
} as TAGS,
description: $localize`Markers are grouped and themed by these settings`,
})
MapPathGroupConfig: MapPathGroupConfig[] = [
new MapPathGroupConfig('Transportation',
[new MapPathGroupThemeConfig(
['flight', 'flying', 'drive', 'driving'],
new PathThemeConfig('var(--bs-orange)',
'4 8',
new SVGIconConfig(567, 'M482.3 192c34.2 0 93.7 29 93.7 64c0 36-59.5 64-93.7 64l-116.6 0L265.2 495.9c-5.7 10-16.3 16.1-27.8 16.1l-56.2 0c-10.6 0-18.3-10.2-15.4-20.4l49-171.6L112 320 68.8 377.6c-3 4-7.8 6.4-12.8 6.4l-42 0c-7.8 0-14-6.3-14-14c0-1.3 .2-2.6 .5-3.9L32 256 .5 145.9c-.4-1.3-.5-2.6-.5-3.9c0-7.8 6.3-14 14-14l42 0c5 0 9.8 2.4 12.8 6.4L112 192l102.9 0-49-171.6C162.9 10.2 170.6 0 181.2 0l56.2 0c11.5 0 22.1 6.2 27.8 16.1L365.7 192l116.6 0z')
)
)]),
new MapPathGroupConfig('Sport',
[new MapPathGroupThemeConfig(
['run', 'walk', 'hike', 'hiking', 'bike', 'biking', 'cycling', 'skiing'],
new PathThemeConfig('var(--bs-primary)',
'',
new SVGIconConfig(417, 'M320 48a48 48 0 1 0 -96 0 48 48 0 1 0 96 0zM125.7 175.5c9.9-9.9 23.4-15.5 37.5-15.5c1.9 0 3.8 .1 5.6 .3L137.6 254c-9.3 28 1.7 58.8 26.8 74.5l86.2 53.9-25.4 88.8c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l28.7-100.4c5.9-20.6-2.6-42.6-20.7-53.9L238 299l30.9-82.4 5.1 12.3C289 264.7 323.9 288 362.7 288H384c17.7 0 32-14.3 32-32s-14.3-32-32-32H362.7c-12.9 0-24.6-7.8-29.5-19.7l-6.3-15c-14.6-35.1-44.1-61.9-80.5-73.1l-48.7-15c-11.1-3.4-22.7-5.2-34.4-5.2c-31 0-60.8 12.3-82.7 34.3L57.4 153.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l23.1-23.1zM91.2 352H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h69.6c19 0 36.2-11.2 43.9-28.5L157 361.6l-9.5-6c-17.5-10.9-30.5-26.8-37.9-44.9L91.2 352z')
)
)]),
new MapPathGroupConfig('Other paths',
[new MapPathGroupThemeConfig(
[], // Match all
new PathThemeConfig('var(--bs-secondary)')
)])
];
}
@SubConfigClass({tags: {client: true}, softReadonly: true})

View File

@ -13,8 +13,8 @@ import {MapService} from '../map.service';
import {
control,
Control,
divIcon,
DivIcon,
divIcon,
icon,
latLng,
latLngBounds,
@ -113,33 +113,15 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy {
},
};
// ordered list
private pathLayersConfigOrdered = [
{
name: $localize`Transportation`,
matchers: [/flight/i, /flying/i, /drive/i, /driving/i] as RegExp[],
layer: layerGroup([]),
theme: {color: 'var(--bs-orange)', dashArray: '4 8'},
icon: null as DivIcon,
svgIcon: {
width: 567,
path: 'M482.3 192c34.2 0 93.7 29 93.7 64c0 36-59.5 64-93.7 64l-116.6 0L265.2 495.9c-5.7 10-16.3 16.1-27.8 16.1l-56.2 0c-10.6 0-18.3-10.2-15.4-20.4l49-171.6L112 320 68.8 377.6c-3 4-7.8 6.4-12.8 6.4l-42 0c-7.8 0-14-6.3-14-14c0-1.3 .2-2.6 .5-3.9L32 256 .5 145.9c-.4-1.3-.5-2.6-.5-3.9c0-7.8 6.3-14 14-14l42 0c5 0 9.8 2.4 12.8 6.4L112 192l102.9 0-49-171.6C162.9 10.2 170.6 0 181.2 0l56.2 0c11.5 0 22.1 6.2 27.8 16.1L365.7 192l116.6 0z'
}
},
{
name: $localize`Sport`,
matchers: [/run/i, /walk/i, /hike/i, /hiking/i, /bike/i, /biking/i, /cycling/i, /skiing/i] as RegExp[],
layer: layerGroup([]),
theme: {color: 'var(--bs-primary)'},
svgIcon: {
width: 417,
path: 'M320 48a48 48 0 1 0 -96 0 48 48 0 1 0 96 0zM125.7 175.5c9.9-9.9 23.4-15.5 37.5-15.5c1.9 0 3.8 .1 5.6 .3L137.6 254c-9.3 28 1.7 58.8 26.8 74.5l86.2 53.9-25.4 88.8c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l28.7-100.4c5.9-20.6-2.6-42.6-20.7-53.9L238 299l30.9-82.4 5.1 12.3C289 264.7 323.9 288 362.7 288H384c17.7 0 32-14.3 32-32s-14.3-32-32-32H362.7c-12.9 0-24.6-7.8-29.5-19.7l-6.3-15c-14.6-35.1-44.1-61.9-80.5-73.1l-48.7-15c-11.1-3.4-22.7-5.2-34.4-5.2c-31 0-60.8 12.3-82.7 34.3L57.4 153.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l23.1-23.1zM91.2 352H32c-17.7 0-32 14.3-32 32s14.3 32 32 32h69.6c19 0 36.2-11.2 43.9-28.5L157 361.6l-9.5-6c-17.5-10.9-30.5-26.8-37.9-44.9L91.2 352z'
}
},
{
name: $localize`Other paths`,
matchers: null as RegExp[], layer: layerGroup([]), theme: {color: 'var(--bs-secondary)'}
}
];
private pathLayersConfigOrdered: {
name: string,
layer: LayerGroup,
themes?: {
matchers?: RegExp[],
theme?: { color: string, dashArray: string },
icon?: DivIcon
}[],
}[] = [];
mapLayerControl: Control.Layers;
private thumbnailsOnLoad: ThumbnailBase[] = [];
private startPosition: Dimension = null;
@ -182,8 +164,45 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy {
}
setUpPathLayers() {
Config.Map.MapPathGroupConfig.forEach((conf, i) => {
let nameI18n = conf.name;
switch (conf.name) {
case 'Sport':
nameI18n = $localize`Sport`;
break;
case 'Transportation':
nameI18n = $localize`Transportation`;
break;
case 'Other paths':
nameI18n = $localize`Other paths`;
break;
}
const pl = {
name: nameI18n,
layer: layerGroup([]),
themes: conf.matchers.map(ths => {
return {
matchers: ths.matchers.map(s => new RegExp(s, 'i')),
theme: ths.theme,
icon: MarkerFactory.getSvgIcon({
color: ths.theme.color,
svgPath: ths.theme.svgIcon?.path,
width: ths.theme.svgIcon?.viewBoxWidth
})
};
})
};
this.pathLayersConfigOrdered.push(pl);
});
if (this.pathLayersConfigOrdered.length === 0) {
this.pathLayersConfigOrdered.push({name: $localize`Other paths`, layer: layerGroup([])});
}
this.pathLayersConfigOrdered.forEach(pl => {
pl.icon = MarkerFactory.getSvgIcon({color: pl.theme.color, svgPath: pl.svgIcon?.path, width: pl.svgIcon?.width});
this.mapLayersControlOption.overlays[pl.name] = pl.layer;
});
}
@ -524,11 +543,27 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy {
// check race condition
return;
}
const pathLayer = this.pathLayersConfigOrdered.find((pl) => {
return pl.matchers === null || // null matchers match everything
(parsedGPX.name &&
pl.matchers.findIndex(m => m.test(parsedGPX.name)) !== -1);
}) || this.pathLayersConfigOrdered[0];
let pathLayer: { layer: LayerGroup, icon?: DivIcon, theme?: { color?: string, dashArray?: string } };
for (const pl of this.pathLayersConfigOrdered) {
pathLayer = {layer: pl.layer, icon: MarkerFactory.defIcon};
if (!pl.themes || pl.themes.length === 0) {
break;
}
const th = pl.themes.find((th) => {
return !th.matchers || th.matchers.length == 0 || // null/empty matchers match everything
(parsedGPX.name &&
th.matchers.findIndex(m => m.test(parsedGPX.name)) !== -1);
});
if (th) {
pathLayer.theme = th.theme;
pathLayer.icon = th.icon || pathLayer.icon;
break;
}
}
if (!pathLayer) {
pathLayer = {layer: this.pathLayersConfigOrdered[0].layer, icon: MarkerFactory.defIcon};
}
if (parsedGPX.path.length !== 0) {
// render the beginning of the path with a marker
@ -537,7 +572,7 @@ export class GalleryMapLightboxComponent implements OnChanges, OnDestroy {
mkr.setIcon(pathLayer.icon);
// Setting popup photo
// Setting popup info
mkr.bindPopup(file.name + ': ' + parsedGPX.name);
pathLayer.layer.addLayer(

View File

@ -176,7 +176,7 @@ export class TemplateComponent implements OnInit, OnChanges, OnDestroy, ISetting
// if all sub elements are hidden, hide the parent too.
if (state.isConfigType) {
if (state.value.__state &&
if (state.value && state.value.__state &&
Object.keys(state.value.__state).findIndex(k => !st.value.__state[k].shouldHide()) === -1) {
return true;
}