|
@@ -1,12 +1,100 @@
|
|
<template>
|
|
<template>
|
|
- <component-debug :component="this" />
|
|
|
|
|
|
+ <b-overlay :show="loading" class="h-100">
|
|
|
|
+ <svg
|
|
|
|
+ width="100%" height="100%"
|
|
|
|
+ ref="svg" id="vis"
|
|
|
|
+ v-if="textsDepart"
|
|
|
|
+ :view-box.camel="viewBox"
|
|
|
|
+ >
|
|
|
|
+ <g id="cards">
|
|
|
|
+ <foreignObject
|
|
|
|
+ v-for="(node, i) in nodes" :key="i"
|
|
|
|
+ width="500" height="300"
|
|
|
|
+ :x="node.x" :y="node.y"
|
|
|
|
+ :transform="`rotate(${node.rotate})`"
|
|
|
|
+ >
|
|
|
|
+ <text-mini-card
|
|
|
|
+ :id="textsDepart[i].id"
|
|
|
|
+ :text-data="textsDepart[i]"
|
|
|
|
+ />
|
|
|
|
+ </foreignObject>
|
|
|
|
+ </g>
|
|
|
|
+ </svg>
|
|
|
|
+ </b-overlay>
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<script>
|
|
<script>
|
|
|
|
+import { mapGetters } from 'vuex'
|
|
|
|
+
|
|
|
|
+import { select, randomUniform, zoom } from 'd3'
|
|
|
|
+import {
|
|
|
|
+ forceSimulation, forceCenter, forceCollide
|
|
|
|
+} from 'd3-force'
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+import TextMiniCard from '@/components/text/TextMiniCard'
|
|
|
|
+
|
|
|
|
+
|
|
export default {
|
|
export default {
|
|
- name: 'CardMap'
|
|
|
|
|
|
+ name: 'CardMap',
|
|
|
|
+
|
|
|
|
+ components: {
|
|
|
|
+ TextMiniCard
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ data () {
|
|
|
|
+ return {
|
|
|
|
+ loading: true,
|
|
|
|
+ width: 100,
|
|
|
|
+ height: 100,
|
|
|
|
+ nodes: new Array(20).fill().map((_, i) => ({ x: i, rotate: randomUniform(-25, 25)() })),
|
|
|
|
+ simulation: forceSimulation(),
|
|
|
|
+ viewBox: null
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ computed: {
|
|
|
|
+ ...mapGetters(['textsDepart'])
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ methods: {
|
|
|
|
+ updateSize () {
|
|
|
|
+ const { width, height } = this.$refs.svg.getBoundingClientRect()
|
|
|
|
+ Object.assign(this.$data, { width, height })
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ created () {
|
|
|
|
+ this.$store.dispatch('GET_TEXTS_DEPART').then(() => {
|
|
|
|
+ this.loading = false
|
|
|
|
+
|
|
|
|
+ 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])
|
|
|
|
+ })
|
|
|
|
+ })
|
|
|
|
+ }
|
|
}
|
|
}
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
|
|
+foreignObject {
|
|
|
|
+ transform-origin: 250, 150;
|
|
|
|
+}
|
|
</style>
|
|
</style>
|