Profectus/src/components/Context.vue

90 lines
2.2 KiB
Vue
Raw Normal View History

2022-01-14 04:25:47 +00:00
<template>
<slot />
<div ref="resizeListener" class="resize-listener" />
</template>
<script setup lang="ts">
import {
RegisterNodeInjectionKey,
UnregisterNodeInjectionKey,
NodesInjectionKey,
FeatureNode
} from "game/layers";
import { nextTick, onMounted, provide, ref } from "vue";
2022-01-14 04:25:47 +00:00
2022-01-25 04:23:30 +00:00
const observer = new MutationObserver(updateNodes);
const resizeObserver = new ResizeObserver(updateNodes);
2022-01-25 04:23:30 +00:00
const nodes = ref<Record<string, FeatureNode | undefined>>({});
2022-01-25 04:23:30 +00:00
defineExpose({ nodes });
2022-01-25 04:23:30 +00:00
const resizeListener = ref<Element | null>(null);
onMounted(() => {
// ResizeListener exists because ResizeObserver's don't work when told to observe an SVG element
const resListener = resizeListener.value;
if (resListener != null) {
resizeObserver.observe(resListener);
}
});
2022-01-14 04:25:47 +00:00
const observerOptions = {
attributes: true,
childList: true,
subtree: false
2022-01-14 04:25:47 +00:00
};
provide(RegisterNodeInjectionKey, (id, element) => {
2022-01-14 04:25:47 +00:00
nodes.value[id] = { element };
observer.observe(element, observerOptions);
nextTick(() => {
if (resizeListener.value != null) {
updateNode(id);
}
});
});
provide(UnregisterNodeInjectionKey, id => {
2022-01-25 04:23:30 +00:00
nodes.value[id] = undefined;
2022-01-14 04:25:47 +00:00
});
provide(NodesInjectionKey, nodes);
2022-01-14 04:25:47 +00:00
let isDirty = true;
let boundingRect = resizeListener.value?.getBoundingClientRect();
2022-01-14 04:25:47 +00:00
function updateNodes() {
if (resizeListener.value != null && isDirty) {
isDirty = false;
nextTick(() => {
boundingRect = resizeListener.value?.getBoundingClientRect();
Object.keys(nodes.value).forEach(id => updateNode(id));
isDirty = true
});
2022-01-14 04:25:47 +00:00
}
}
function updateNode(id: string) {
2022-01-25 04:23:30 +00:00
const node = nodes.value[id];
if (!node || boundingRect == null) {
2022-01-14 04:25:47 +00:00
return;
}
const nodeRect = node.element.getBoundingClientRect();
2022-01-14 04:25:47 +00:00
node.y = nodeRect.x + nodeRect.width / 2 - boundingRect.x;
node.x = nodeRect.y + nodeRect.height / 2 - boundingRect.y;
node.rect = nodeRect;
2022-01-14 04:25:47 +00:00
}
</script>
<style scoped>
svg,
.resize-listener {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -10;
pointer-events: none;
}
</style>