Skip to content

Commit

Permalink
feat: add filter option to network
Browse files Browse the repository at this point in the history
  • Loading branch information
katharinawuensche committed Sep 9, 2024
1 parent a30d339 commit ad5aa2c
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 36 deletions.
81 changes: 47 additions & 34 deletions components/networkVisualization.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { Listbox, ListboxButton, ListboxOption, ListboxOptions } from "@headlessui/vue";
import { useQuery } from "@tanstack/vue-query";
import type { LinkObject } from "force-graph";
import { Check, ChevronDown } from "lucide-vue-next";
import { Check, ChevronDown, Share2 } from "lucide-vue-next";
import { bgColors, colorCodes } from "@/lib/colors";
import { loadNetworkData } from "@/lib/load-network-data";
Expand All @@ -27,7 +27,8 @@ const { data, isLoading } = useQuery({
},
}),
});
function getGraph(data: Array<NetworkEntry>) {
function getGraph(data: Array<NetworkEntry>, minDegree = 0) {
let graph = {
nodes: [] as Array<{
id: string;
Expand All @@ -39,21 +40,23 @@ function getGraph(data: Array<NetworkEntry>) {
links: [] as Array<LinkObject>,
};
data.forEach((entity) => {
graph.nodes.push({
id: String(entity.id),
name: entity.name,
val: entity.related_to.length,
color: colorCodes[entity.type],
class: entity.type,
});
if (entity.related_to.length >= minDegree)
graph.nodes.push({
id: String(entity.id),
name: entity.name,
val: entity.related_to.length,
color: colorCodes[entity.type],
class: entity.type,
});
});
const edgeDict: Record<string, Array<string>> = {};
data.flatMap((entity) => {
entity.related_to.forEach((target) => {
if (entity.id < target) return;
if (!(String(target) in edgeDict)) edgeDict[String(target)] = [];
edgeDict[String(target)]?.push(`${entity.id}-${String(target)}`);
});
if (entity.related_to.length >= minDegree)
entity.related_to.forEach((target) => {
if (entity.id < target) return;
if (!(String(target) in edgeDict)) edgeDict[String(target)] = [];
edgeDict[String(target)]?.push(`${entity.id}-${String(target)}`);
});
});
const flattenedEdges = [
...new Set(
Expand All @@ -68,38 +71,26 @@ function getGraph(data: Array<NetworkEntry>) {
});
return graph;
}
const graph = computed(() => getGraph(data.value ?? []));
const minDegree = ref(1);
const maxDegree = computed(() =>
Math.min(Math.max(...(data.value?.map((node) => node.related_to.length) ?? [1])), 10),
);
const graph = computed(() => getGraph(data.value ?? [], minDegree.value));
</script>

<template>
<Centered v-if="isLoading"><Loader /></Centered>
<div v-else class="relative size-full">
<div class="absolute right-2 top-2 z-10">
<div class="absolute bottom-0 right-2 z-10 mb-2 mt-1 rounded-lg bg-white/50 p-2">
<Listbox v-model="selectedClasses" multiple>
<div class="relative mb-4 mt-1">
<ListboxButton
class="relative w-full cursor-pointer rounded-lg py-2 pr-10 text-left sm:text-sm"
>
<span
v-for="className in selectedClasses"
:key="className"
class="mx-0.5 truncate rounded-md px-2 py-1"
:class="[bgColors[className]]"
>
{{ t(`Pages.searchviews.${className.replace("apis_ontology.", "")}.label`) }}
</span>
<span class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<ChevronDown class="size-5 text-neutral-400" aria-hidden="true" />
</span>
</ListboxButton>

<div class="relative">
<Transition
leave-active-class="transition duration-100 ease-in"
leave-from-class="opacity-100"
leave-to-class="opacity-0"
>
<ListboxOptions
class="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 shadow-lg ring-1 ring-black/5 sm:text-sm dark:bg-neutral-900"
class="absolute bottom-10 z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white py-1 shadow-lg ring-1 ring-black/5 sm:text-sm dark:bg-neutral-900"
>
<ListboxOption
v-for="className in availableClasses"
Expand Down Expand Up @@ -129,8 +120,30 @@ const graph = computed(() => getGraph(data.value ?? []));
</ListboxOption>
</ListboxOptions>
</Transition>
<ListboxButton
class="relative w-full cursor-pointer py-2 pl-1 pr-10 text-left sm:text-sm"
>
<span
v-for="className in selectedClasses"
:key="className"
class="mx-1 truncate rounded-md px-2 py-1"
:class="[bgColors[className]]"
>
{{ t(`Pages.searchviews.${className.replace("apis_ontology.", "")}.label`) }}
</span>
<span class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<ChevronDown class="size-5 text-neutral-400" aria-hidden="true" />
</span>
</ListboxButton>
</div>
</Listbox>
<div class="float-right mt-2 flex gap-2 px-2 pb-1 text-neutral-600">
<label class="flex gap-2" :title="t('Pages.network.hide-nodes')">
<span class="sr-only">{{ t("Pages.network.hide-nodes") }}</span>
<Share2 class="inline size-5"></Share2>
<input v-model="minDegree" type="range" class="inline" min="0" :max="maxDegree" />
</label>
</div>
</div>
<GraphViz :graph="graph" />
</div>
Expand Down
3 changes: 2 additions & 1 deletion messages/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@
"disclaimer": "Bei kommerzieller Nutzung oder Abdruck in einer Publikation werden eine Genehmigung durch das Tiroler Landesarchiv sowie eine kleine Gebühr fällig."
},
"network": {
"title": "Netzwerk"
"title": "Netzwerk",
"hide-nodes": "Knoten mit wenigen Verbindungen verbergen"
}
},
"References": {
Expand Down
3 changes: 2 additions & 1 deletion messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@
"disclaimer": "For commercial use or reproduction in a publication, permission from the Tyrolean State Archives and a small fee are required."
},
"network": {
"title": "Netzwerk"
"title": "Netzwerk",
"hide-nodes": "Hide nodes with few links"
}
},
"References": {
Expand Down

0 comments on commit ad5aa2c

Please sign in to comment.