You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
4.3 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. export class Display {
  2. constructor(baseUrl, dispatch, target) {
  3. this.baseUrl = baseUrl
  4. this.target = target
  5. const findA = target => {
  6. while (target.nodeName !== 'A') {
  7. target = target.parentNode
  8. if (!target) return
  9. }
  10. return target
  11. }
  12. target.addEventListener('click', e => {
  13. let target = findA(e.target)
  14. if (!target) return
  15. window.history.pushState(null, "", target.href)
  16. dispatch(target.getAttribute('href'))
  17. e.preventDefault()
  18. })
  19. target.addEventListener('dragstart', e => {
  20. let target = findA(e.target)
  21. if (!target || !target.draggable) return
  22. e.dataTransfer.setData('application/prs.x', target.dataset['id'])
  23. e.dataTransfer.effectAllowed = 'link'
  24. })
  25. target.addEventListener('dragenter', e => {
  26. let target = findA(e.target)
  27. if (!target) return
  28. e.preventDefault()
  29. })
  30. target.addEventListener('dragover', e => {
  31. let target = findA(e.target)
  32. if (!target) return
  33. e.preventDefault()
  34. })
  35. target.addEventListener('drop', e => {
  36. let target = findA(e.target)
  37. if (!target) return
  38. e.preventDefault()
  39. dispatch({ action: 'link', from: e.dataTransfer.getData("application/prs.x"), to: target.dataset['id']})
  40. })
  41. this.graph = new Springy.Graph()
  42. this.layout = new Springy.Layout.ForceDirected(
  43. this.graph,
  44. 400.0, // Spring stiffness
  45. 400.0, // Node repulsion
  46. 0.5 // Damping
  47. )
  48. }
  49. render(state) {
  50. const target = document.createElement('div')
  51. target.className = 'wrapper'
  52. const field = document.createElement('ul')
  53. field.className = 'items'
  54. const graph = this.graph
  55. for (const item of state.items) {
  56. graph.addNode(new Springy.Node(item.id, item))
  57. }
  58. for (const item of state.links) {
  59. graph.addEdge(new Springy.Edge(item.id, graph.nodeSet[item.from], graph.nodeSet[item.to], {}))
  60. }
  61. let currentBB = this.layout.getBoundingBox()
  62. let width = this.target.scrollWidth || 100
  63. let height = this.target.scrollHeight || 100
  64. var toScreen = function(p) {
  65. var size = currentBB.topright.subtract(currentBB.bottomleft);
  66. var sx = p.subtract(currentBB.bottomleft).divide(size.x).x * (width - 100);
  67. var sy = p.subtract(currentBB.bottomleft).divide(size.y).y * (height - 100);
  68. return new Springy.Vector(sx, sy);
  69. };
  70. var fromScreen = function(s) {
  71. var size = currentBB.topright.subtract(currentBB.bottomleft);
  72. var px = (s.x / canvas.width) * size.x + currentBB.bottomleft.x;
  73. var py = (s.y / canvas.height) * size.y + currentBB.bottomleft.y;
  74. return new Springy.Vector(px, py);
  75. };
  76. var renderer = new Springy.Renderer(
  77. this.layout,
  78. () => {
  79. currentBB = this.layout.getBoundingBox()
  80. width = this.target.scrollWidth
  81. height = this.target.scrollHeight
  82. field.innerHTML = ''
  83. },
  84. function drawEdge(edge, p1, p2) {
  85. // draw an edge
  86. },
  87. function drawNode(item, p) {
  88. const target = toScreen(p)
  89. const dom = document.createElement('li')
  90. const a = document.createElement('a')
  91. const action = item.data.state == 'face-down' ? 'flip' : 'show'
  92. a.href = `/${item.id}/${action}`
  93. a.draggable = false
  94. if (item.data.state !== 'face-down') {
  95. a.style.backgroundImage = `url(/img/${item.data.img})`
  96. a.dataset['id'] = item.id
  97. a.draggable = true
  98. }
  99. dom.className = item.data.state
  100. dom.style.position = 'absolute'
  101. dom.style.left = target.x + 'px'
  102. dom.style.top = target.y + 'px'
  103. dom.appendChild(a)
  104. field.appendChild(dom)
  105. }, undefined, undefined,
  106. () => {
  107. const dd = new diffDOM.DiffDOM()
  108. const diff = dd.diff(this.target.children[0], field)
  109. dd.apply(this.target.children[0], diff)
  110. }
  111. );
  112. target.appendChild(field)
  113. if (state.show !== null) {
  114. const wrapper = document.createElement('a')
  115. wrapper.href = '/'
  116. const fullview = document.createElement('div')
  117. wrapper.className = 'fullview'
  118. wrapper.appendChild(fullview)
  119. target.appendChild(wrapper)
  120. }
  121. const dd = new diffDOM.DiffDOM()
  122. const diff = dd.diff(this.target, target)
  123. dd.apply(this.target, diff)
  124. renderer.start();
  125. }
  126. }