133 lines
2.7 KiB
Vue
133 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"
|
|
:key="child.data"
|
|
style="width: fit-content; height: fit-content"
|
|
>
|
|
<ItemTree
|
|
:tree="child"
|
|
:parent-count="tree.count"
|
|
@refresh="handleRefresh"
|
|
@mount="end => handleSubtreeMount(end)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|