CardMap.vue 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. <template>
  2. <b-overlay :show="texts === undefined" class="h-100">
  3. <svg
  4. width="100%" height="100%"
  5. ref="svg" id="vis"
  6. :view-box.camel="viewBox"
  7. >
  8. <g id="cards">
  9. <foreignObject
  10. v-for="(node, i) in nodes" :key="i"
  11. width="500" height="300"
  12. :x="node.x" :y="node.y"
  13. :transform="`rotate(${node.rotate})`"
  14. >
  15. <node-view
  16. :node="texts[i]"
  17. mode="card"
  18. />
  19. </foreignObject>
  20. </g>
  21. </svg>
  22. </b-overlay>
  23. </template>
  24. <script>
  25. import { mapGetters } from 'vuex'
  26. import { select, randomUniform, zoom } from 'd3'
  27. import {
  28. forceSimulation, forceCenter, forceCollide
  29. } from 'd3-force'
  30. import { NodeView } from '@/components/nodes'
  31. export default {
  32. name: 'CardMap',
  33. components: {
  34. NodeView
  35. },
  36. data () {
  37. return {
  38. width: 100,
  39. height: 100,
  40. nodes: undefined,
  41. simulation: forceSimulation(),
  42. viewBox: null,
  43. texts: undefined
  44. }
  45. },
  46. computed: {
  47. ...mapGetters(['textsDepart'])
  48. },
  49. methods: {
  50. updateSize () {
  51. const { width, height } = this.$refs.svg.getBoundingClientRect()
  52. Object.assign(this.$data, { width, height })
  53. }
  54. },
  55. created () {
  56. this.$store.dispatch('INIT_LIBRARY_MAP').then(data => {
  57. this.texts = data
  58. this.nodes = data.map((node, i) => {
  59. return { x: i, rotate: randomUniform(-25, 25)() }
  60. })
  61. this.$nextTick(() => {
  62. this.updateSize()
  63. this.viewBox = `0 0 ${this.width} ${this.height}`
  64. const svg = select('#vis')
  65. const g = select('#cards')
  66. svg.call(zoom()
  67. .extent([[0, 0], [this.width, this.height]])
  68. .scaleExtent([-5, 8])
  69. .on('zoom', zoomed))
  70. function zoomed ({ transform }) {
  71. g.attr('transform', transform)
  72. }
  73. this.simulation
  74. .nodes(this.nodes)
  75. .force('collide', forceCollide(d => randomUniform(250, 350)()))
  76. .force('center', forceCenter(this.width * 0.5, this.height * 0.5))
  77. .alphaDecay([0.02])
  78. })
  79. })
  80. }
  81. }
  82. </script>
  83. <style lang="scss" scoped>
  84. foreignObject {
  85. transform-origin: 250, 150;
  86. }
  87. </style>