update LibraryMap with MapZoom

This commit is contained in:
axolotle
2021-06-11 15:00:05 +02:00
parent 88f866afe3
commit 56e1c81aef
+36 -69
View File
@@ -1,68 +1,44 @@
<template> <template>
<b-overlay :show="texts === undefined" class="h-100"> <b-overlay :show="nodes === undefined" class="h-100">
<svg <map-zoom id="library-map" :min-zoom="0.2" :max-zoom="2">
width="100%" height="100%" <foreignObject
ref="svg" id="vis" v-for="(node, i) in nodes" :key="i"
:view-box.camel="viewBox" :style="`--x: ${node.x}px; --y: ${node.y}px; --r: ${node.rotate}deg;`"
> >
<g id="cards"> <node-view
<foreignObject :node="node.data"
v-for="(node, i) in nodes" :key="i" mode="card"
width="500" height="300" @open-node="onOpen(node.data)"
:x="node.x" :y="node.y" />
:transform="`rotate(${node.rotate})`" </foreignObject>
> </map-zoom>
<node-view
:node="texts[i]"
mode="card"
@open-node="onOpen(texts[i])"
/>
</foreignObject>
</g>
</svg>
</b-overlay> </b-overlay>
</template> </template>
<script> <script>
import { mapGetters } from 'vuex' import { randomUniform } from 'd3'
import { forceSimulation, forceCollide, forceManyBody } from 'd3-force'
import { select, randomUniform, zoom } from 'd3'
import {
forceSimulation, forceCenter, forceCollide
} from 'd3-force'
import { MapZoom } from '@/components/layouts'
import { NodeView } from '@/components/nodes' import { NodeView } from '@/components/nodes'
export default { export default {
name: 'CardMap', name: 'LibraryMap',
components: { components: {
MapZoom,
NodeView NodeView
}, },
data () { data () {
return { return {
width: 100,
height: 100,
nodes: undefined,
simulation: forceSimulation(), simulation: forceSimulation(),
viewBox: null, nodes: undefined
texts: undefined
} }
}, },
computed: {
...mapGetters(['textsDepart'])
},
methods: { methods: {
updateSize () {
const { width, height } = this.$refs.svg.getBoundingClientRect()
Object.assign(this.$data, { width, height })
},
onOpen (node) { onOpen (node) {
// FIXME ALSO CHECK IF PARENT // FIXME ALSO CHECK IF PARENT
this.$emit('open-node', node.id) this.$emit('open-node', node.id)
@@ -70,32 +46,13 @@ export default {
}, },
created () { created () {
this.$store.dispatch('INIT_LIBRARY_MAP').then(data => { this.$store.dispatch('INIT_LIBRARY_MAP').then(nodes => {
this.texts = data this.nodes = nodes.map((node, i) => {
this.nodes = data.map((node, i) => { return { x: i, rotate: randomUniform(-25, 25)(), data: node }
return { x: i, rotate: randomUniform(-25, 25)() }
})
this.$nextTick(() => {
this.updateSize()
this.viewBox = `0 0 ${this.width} ${this.height}`
const svg = select('#vis')
const g = select('#cards')
svg.call(zoom()
.extent([[0, 0], [this.width, this.height]])
.scaleExtent([-5, 8])
.on('zoom', zoomed))
function zoomed ({ transform }) {
g.attr('transform', transform)
}
this.simulation
.nodes(this.nodes)
.force('collide', forceCollide(d => randomUniform(250, 350)()))
.force('center', forceCenter(this.width * 0.5, this.height * 0.5))
.alphaDecay([0.02])
}) })
this.simulation.nodes(this.nodes)
.force('attract', forceManyBody().strength(10))
.force('collision', forceCollide().radius(650 / 2))
}) })
} }
} }
@@ -103,6 +60,16 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
foreignObject { foreignObject {
transform-origin: 250, 150; 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> </style>