facilmap/frontend/src/lib/components/legend/legend-utils.ts

177 wiersze
4.8 KiB
TypeScript
Czysty Zwykły widok Historia

2023-11-02 14:14:05 +00:00
import type { ID, Shape, Symbol, Type } from "facilmap-types";
2021-03-11 17:01:40 +00:00
import { symbolList } from "facilmap-leaflet";
import { getBrightness } from "facilmap-utils";
2023-11-06 02:22:33 +00:00
import type { FacilMapContext } from "../facil-map-context-provider/facil-map-context";
import { requireClientContext, requireMapContext } from "../facil-map-context-provider/facil-map-context-provider.vue";
2021-03-11 17:01:40 +00:00
export interface LegendType {
2023-10-30 00:14:54 +00:00
key: string;
2021-03-11 17:01:40 +00:00
type: Type['type'];
typeId: ID;
name: string;
items: LegendItem[];
filtered: boolean;
2021-03-27 17:17:28 +00:00
defaultColour?: string;
2021-03-11 17:01:40 +00:00
defaultShape?: Shape;
}
export interface LegendItem {
2023-10-30 00:14:54 +00:00
key: string;
2021-03-11 17:01:40 +00:00
value: string;
label?: string;
field?: string;
filtered?: boolean;
first?: boolean;
strikethrough?: boolean;
2021-03-27 17:17:28 +00:00
colour?: string;
2021-03-11 17:01:40 +00:00
symbol?: Symbol;
shape?: Shape;
width?: number;
bright?: boolean;
}
2023-11-06 02:22:33 +00:00
export function getLegendItems(context: FacilMapContext): LegendType[] {
const client = requireClientContext(context).value;
const mapContext = requireMapContext(context).value;
2021-03-11 17:01:40 +00:00
const legendItems: LegendType[] = [ ];
for (const i in client.types) {
const type = client.types[i];
if(!type.showInLegend)
continue;
const items: LegendItem[] = [ ];
2021-04-04 22:24:05 +00:00
const fields: Record<string, string[]> = Object.create(null);
2021-03-11 17:01:40 +00:00
if (type.colourFixed || (type.type == "marker" && type.symbolFixed && type.defaultSymbol && (symbolList.includes(type.defaultSymbol) || type.defaultSymbol.length == 1)) || (type.type == "marker" && type.shapeFixed) || (type.type == "line" && type.widthFixed)) {
2023-10-30 00:14:54 +00:00
const item: LegendItem = {
key: `legend-item-${type.id}`,
value: type.name,
label: type.name,
filtered: true
};
2021-03-11 17:01:40 +00:00
if(type.colourFixed)
2021-03-27 17:17:28 +00:00
item.colour = type.defaultColour ? `#${type.defaultColour}` : undefined;
2021-03-11 17:01:40 +00:00
if(type.type == "marker" && type.symbolFixed && type.defaultSymbol && (symbolList.includes(type.defaultSymbol) || type.defaultSymbol.length == 1))
item.symbol = type.defaultSymbol;
if(type.type == "marker" && type.shapeFixed)
2021-04-09 22:30:22 +00:00
item.shape = type.defaultShape ?? "";
2021-03-11 17:01:40 +00:00
if(type.type == "line" && type.widthFixed)
item.width = type.defaultWidth ?? undefined;
2021-05-07 03:41:25 +00:00
2021-03-11 17:01:40 +00:00
if (item.colour)
item.bright = getBrightness(item.colour) > 0.7;
items.push(item);
}
for (const field of type.fields) {
if ((field.type != "dropdown" && field.type != "checkbox") || (!field.controlColour && (type.type != "marker" || !field.controlSymbol) && (type.type != "marker" || !field.controlShape) && (type.type != "line" || !field.controlWidth)))
continue;
fields[field.name] = [ ];
(field.options || [ ]).forEach((option, idx) => {
2023-10-30 00:14:54 +00:00
const item: LegendItem = {
key: `legend-item-${type.id}-${field.name}`,
value: option.value,
label: option.value,
field: field.name,
filtered: true,
first: idx == 0
};
2021-03-11 17:01:40 +00:00
if(field.type == "checkbox") {
item.value = idx == 0 ? "0" : "1";
if(!item.label || /* Legacy format */ item.label == '0' || item.label == '1') {
item.label = field.name;
if(idx == 0)
item.strikethrough = true;
}
}
if(field.controlColour)
2021-03-27 17:17:28 +00:00
item.colour = `#${option.colour}`;
2021-03-11 17:01:40 +00:00
if(type.type == "marker" && field.controlSymbol)
item.symbol = option.symbol;
if(type.type == "marker" && field.controlShape)
item.shape = option.shape;
if(type.type == "line" && field.controlWidth)
item.width = option.width;
if (item.colour)
item.bright = getBrightness(item.colour) > 0.7;
items.push(item);
fields[field.name].push(item.value);
});
}
if(items.length == 0) {
const item: LegendItem = {
2023-10-30 00:14:54 +00:00
key: `legend-item-${type.id}`,
2021-03-11 17:01:40 +00:00
value: type.name,
label: type.name,
filtered: true
};
if(type.type == "marker")
item.shape = "drop";
items.push(item);
}
2023-10-30 00:14:54 +00:00
const legendType: LegendType = {
key: `legend-type-${type.id}`,
type: type.type,
typeId: type.id,
name: type.name,
items,
filtered: true,
defaultColour: type.defaultColour ?? undefined,
defaultShape: type.defaultShape ?? undefined
};
2021-03-11 17:01:40 +00:00
// Check which fields are filtered
allCombinations(fields, (data) => {
2021-04-04 22:24:05 +00:00
if(mapContext.filterFunc({ typeId: legendType.typeId, data } as any, type)) {
2021-03-11 17:01:40 +00:00
legendType.filtered = false;
for (const item of items) {
if (!item.field)
item.filtered = false;
}
for(const i in data) {
items.forEach(function(it) {
if(it.field == i && it.value == data[i])
it.filtered = false;
});
}
}
});
legendItems.push(legendType);
}
return legendItems;
}
function allCombinations(fields: Record<string, string[]>, callback: (data: Record<string, string>) => void): void {
const fieldKeys = Object.keys(fields);
function rec(i: number, vals: Record<string, string>) {
if(i == fieldKeys.length)
return callback(vals);
for (const f of fields[fieldKeys[i]]) {
vals[fieldKeys[i]] = f;
rec(i+1, vals);
}
}
2021-04-04 22:24:05 +00:00
rec(0, Object.create(null));
2021-03-11 17:01:40 +00:00
}