76 lines
1.7 KiB
Vue
76 lines
1.7 KiB
Vue
<template>
|
|
<b-overlay :show="nodes === undefined" class="h-100">
|
|
<map-zoom id="library-map" :min-zoom="0.2" :max-zoom="2">
|
|
<foreignObject
|
|
v-for="(node, i) in nodes" :key="i"
|
|
:style="`--x: ${node.x}px; --y: ${node.y}px; --r: ${node.rotate}deg;`"
|
|
>
|
|
<node-view
|
|
:node="node.data"
|
|
mode="card"
|
|
@open-node="onOpen(node.data)"
|
|
/>
|
|
</foreignObject>
|
|
</map-zoom>
|
|
</b-overlay>
|
|
</template>
|
|
|
|
<script>
|
|
import { randomUniform } from 'd3'
|
|
import { forceSimulation, forceCollide, forceManyBody } from 'd3-force'
|
|
|
|
import { MapZoom } from '@/components/layouts'
|
|
import { NodeView } from '@/components/nodes'
|
|
|
|
|
|
export default {
|
|
name: 'LibraryMap',
|
|
|
|
components: {
|
|
MapZoom,
|
|
NodeView
|
|
},
|
|
|
|
data () {
|
|
return {
|
|
simulation: forceSimulation(),
|
|
nodes: undefined
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
onOpen (node) {
|
|
// FIXME ALSO CHECK IF PARENT
|
|
this.$emit('open-node', node.id)
|
|
}
|
|
},
|
|
|
|
created () {
|
|
this.$store.dispatch('INIT_LIBRARY_MAP').then(nodes => {
|
|
this.nodes = nodes.map((node, i) => {
|
|
return { x: i, rotate: randomUniform(-25, 25)(), data: node }
|
|
})
|
|
this.simulation.nodes(this.nodes)
|
|
.force('attract', forceManyBody().strength(10))
|
|
.force('collision', forceCollide().radius(650 / 2))
|
|
})
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
foreignObject {
|
|
width: $node-card-width;
|
|
height: $node-card-height;
|
|
x: var(--x);
|
|
y: var(--y);
|
|
transform-origin: var(--x) var(--y);
|
|
transform: rotate(var(--r)) translate(-#{$node-card-width / 2}, -#{$node-card-height / 2});
|
|
overflow: visible;
|
|
|
|
.node-view {
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
</style>
|