diff --git a/components/data-graph.vue b/components/data-graph.vue
index b07a35b3..7681e291 100644
--- a/components/data-graph.vue
+++ b/components/data-graph.vue
@@ -8,6 +8,7 @@ import { colors } from "../project.config.json";
const props = defineProps<{
networkData: NetworkEntity;
searchNode: string;
+ detailNode?: string;
}>();
const graph = new Graph();
@@ -62,5 +63,10 @@ function getNodeColor(nodeClass: string) {
-
+
diff --git a/components/data-map-view.vue b/components/data-map-view.vue
index 2cab6c7e..8bd21b68 100644
--- a/components/data-map-view.vue
+++ b/components/data-map-view.vue
@@ -16,12 +16,17 @@ const route = useRoute();
const t = useTranslations();
const currentView = useGetCurrentView();
+const { getUnprefixedId } = useIdPrefix();
const searchFiltersSchema = v.object({
category: v.fallback(v.picklist(categories), "entityName"),
search: v.fallback(v.string(), ""),
});
+const detailEntityId = computed(() => {
+ return route.params.id as string;
+});
+
const searchFilters = computed(() => {
return v.parse(searchFiltersSchema, route.query);
});
@@ -48,7 +53,7 @@ const { data, isPending, isPlaceholderData } = useGetSearchResults(
: [],
show: ["geometry", "when"],
centroid: true,
- system_classes: ["place", "object_location"],
+ system_classes: ["place"],
limit: 0,
};
}),
@@ -141,6 +146,34 @@ watch(data, () => {
*/
popover.value = null;
});
+
+watchEffect(() => {
+ const entity = entities.value.find((feature) => {
+ const id = getUnprefixedId(feature["@id"]);
+ return id === detailEntityId.value;
+ });
+
+ if (entity) {
+ let coordinates = null;
+
+ if (entity.geometry.type === "GeometryCollection") {
+ coordinates = entity.geometry.geometries.find((g) => {
+ return g.type === "Point";
+ })?.coordinates as [number, number] | undefined;
+ }
+
+ if (entity.geometry.type === "Point") {
+ coordinates = entity.geometry.coordinates as unknown as [number, number];
+ }
+
+ popover.value = {
+ coordinates:
+ coordinates ??
+ (turf.center(createFeatureCollection([entity])).geometry.coordinates as [number, number]),
+ entities: [entity],
+ };
+ }
+});
diff --git a/components/data-network-view.vue b/components/data-network-view.vue
index 27a3194c..a61386a8 100644
--- a/components/data-network-view.vue
+++ b/components/data-network-view.vue
@@ -9,6 +9,10 @@ import { project } from "../config/project.config";
const router = useRouter();
const route = useRoute();
+const detailEntityId = computed(() => {
+ return route.params.id as string;
+});
+
const searchFiltersSchema = z.object({
search: z.string().catch(""),
});
@@ -104,7 +108,11 @@ const systemClasses = computed(() => {
:system-classes="systemClasses"
@submit="onChangeCategory"
/>
-
+
diff --git a/components/geo-map-popup.client.vue b/components/geo-map-popup.client.vue
index fee65fdb..4010b71f 100644
--- a/components/geo-map-popup.client.vue
+++ b/components/geo-map-popup.client.vue
@@ -10,7 +10,7 @@ const emit = defineEmits<{
(event: "close"): void;
}>();
-const { map } = useGeoMap();
+const geoMapContext = useGeoMap();
const elementRef = ref(null);
@@ -24,6 +24,7 @@ const context: Context = {
onMounted(async () => {
await nextTick();
+ const { map } = geoMapContext;
assert(elementRef.value != null);
assert(map != null);
diff --git a/components/network.client.vue b/components/network.client.vue
index 93542741..b14032d4 100644
--- a/components/network.client.vue
+++ b/components/network.client.vue
@@ -23,6 +23,7 @@ interface State {
const props = defineProps<{
graph: Graph;
searchNode?: string;
+ detailNode?: string;
}>();
interface NetworkContext {
@@ -41,6 +42,7 @@ circular.assign(context.graph);
const locale = useLocale();
const router = useRouter();
+
let hoverTimeOut: ReturnType;
const state = ref({});
@@ -91,6 +93,48 @@ watch(
{ immediate: true },
);
+watch(
+ () => {
+ return props.detailNode;
+ },
+ (detailNode) => {
+ context.graph.nodes().forEach((el) => {
+ context.graph.removeNodeAttribute(el, "highlighted");
+ });
+
+ if (detailNode) {
+ const results = context.graph
+ .nodes()
+ .map((n) => {
+ return { id: n, label: context.graph.getNodeAttribute(n, "id") as string };
+ })
+ .filter(({ id }) => {
+ return id === detailNode;
+ });
+
+ if (results.length === 1) {
+ state.value.selectedNodes = results;
+ state.value.selectedNodes.forEach((el) => {
+ context.graph.setNodeAttribute(el.id, "highlighted", true);
+ });
+ }
+ }
+ // If the query is empty, then we reset the selectedNode
+ else {
+ state.value.selectedNodes = undefined;
+ }
+
+ // Refresh rendering
+ // You can directly call `renderer.refresh()`, but if you need performances
+ // you can provide some options to the refresh method.
+ // In this case, we don't touch the graph data so we can skip its reindexation
+ context.renderer?.refresh({
+ skipIndexation: true,
+ });
+ },
+ { immediate: true },
+);
+
const currentView = useGetCurrentView();
onMounted(async () => {
diff --git a/layouts/visualization.vue b/layouts/visualization.vue
index 5b027ecf..f2f35cfd 100644
--- a/layouts/visualization.vue
+++ b/layouts/visualization.vue
@@ -51,7 +51,7 @@ const currentView = useGetCurrentView();
-
+