Files
buildpath/frontend/components/item/Tree.vue
Valentin Haudiquet 3fc52205f6
Some checks failed
pipeline / lint-and-format (push) Failing after 56s
pipeline / build-and-push-images (push) Has been skipped
Lint and format
2026-01-21 00:59:23 +01:00

129 lines
2.7 KiB
Vue

<script setup lang="ts">
import svgdomarrows from 'svg-dom-arrows'
defineProps<{
tree: ItemTree
parentCount?: number
}>()
const emit = defineEmits<{
mount: [end: Element]
refresh: []
}>()
const { data: items }: ItemResponse = await useFetch(
CDRAGON_BASE + 'plugins/rcp-be-lol-game-data/global/default/v1/items.json'
)
const itemMap = reactive(new Map())
for (const item of items.value) {
itemMap.set(item.id, item)
}
const start: Ref<Element | null> = useTemplateRef('start')
const arrows: Array<svgdomarrows.LinePath> = []
onMounted(() => {
refreshArrows()
emit('mount', start.value!)
})
onBeforeUpdate(() => {
for (const arrow of arrows) {
arrow.release()
}
arrows.splice(0, arrows.length)
})
onUpdated(() => {
refreshArrows()
emit('mount', start.value!)
})
onUnmounted(() => {
for (const arrow of arrows) {
arrow.release()
}
})
function drawArrow(start: Element, end: Element) {
// console.log("drawArrow(", start, ", ", end, ")")
if (start == null || end == null) return
const arrow = new svgdomarrows.LinePath({
start: {
element: start,
position: {
top: 0.5,
left: 1
}
},
end: {
element: end,
position: {
top: 0.5,
left: 0
}
},
style: 'stroke:var(--color-on-surface);stroke-width:3;fill:transparent;',
appendTo: document.body
})
arrows.push(arrow)
}
function refreshArrows() {
for (const arrow of arrows) {
arrow.redraw()
}
}
// Redraw arrows on window resize
addEventListener('resize', _ => {
refreshArrows()
})
addEventListener('scroll', _ => {
refreshArrows()
})
function handleSubtreeMount(end: Element) {
drawArrow(start.value!, end)
refreshArrows()
emit('refresh')
}
function handleRefresh() {
refreshArrows()
emit('refresh')
}
</script>
<template>
<div style="display: flex; align-items: center">
<div
v-if="tree.data != undefined && tree.data != null"
style="width: fit-content; height: fit-content"
>
<img
ref="start"
class="item-img"
width="64"
height="64"
:alt="tree.data.toString()"
:src="CDRAGON_BASE + mapPath(itemMap.get(tree.data).iconPath)"
>
<h3 style="width: fit-content; margin: auto; margin-bottom: 10px">
{{ ((tree.count / parentCount!!) * 100).toFixed(0) }}%
</h3>
</div>
<div style="margin-left: 30px">
<div v-for="child in tree.children" style="width: fit-content; height: fit-content">
<ItemTree
:tree="child"
:parent-count="tree.count"
@refresh="handleRefresh"
@mount="end => handleSubtreeMount(end)"
/>
</div>
</div>
</div>
</template>