export class Display { constructor(baseUrl, dispatch, target) { this.baseUrl = baseUrl this.target = target const findA = target => { while (target.nodeName !== 'A') { target = target.parentNode if (!target) return } return target } target.addEventListener('click', e => { let target = findA(e.target) if (!target) return window.history.pushState(null, "", target.href) dispatch(target.getAttribute('href')) e.preventDefault() }) target.addEventListener('dragstart', e => { let target = findA(e.target) if (!target || !target.draggable) return e.dataTransfer.setData('application/prs.x', target.dataset['id']) e.dataTransfer.effectAllowed = 'link' }) target.addEventListener('dragenter', e => { let target = findA(e.target) if (!target) return e.preventDefault() }) target.addEventListener('dragover', e => { let target = findA(e.target) if (!target) return e.preventDefault() }) target.addEventListener('drop', e => { let target = findA(e.target) if (!target || !target.draggable) return dispatch({ action: 'link', from: e.dataTransfer.getData("application/prs.x"), to: target.dataset['id']}) && e.preventDefault() }) this.graph = new Springy.Graph() this.layout = new Springy.Layout.ForceDirected( this.graph, 15, 1000.0, // Node repulsion 0.5 // Damping ) } render(state) { const target = document.createElement('div') target.className = 'wrapper' const field = document.createElement('ul') field.className = 'items' const graph = this.graph for (const item of state.items) { graph.addNode(new Springy.Node(item.id, item)) } for (const item of state.links) { graph.addEdge(new Springy.Edge(item.id, graph.nodeSet[item.from], graph.nodeSet[item.to], { text: state.items[item.from].linkable.filter(i => state.items[item.to].linkable.includes(i)).join(', ') })) } let currentBB = this.layout.getBoundingBox() let width = this.target.scrollWidth || 100 let height = this.target.scrollHeight || 100 var toScreen = function(p) { var size = currentBB.topright.subtract(currentBB.bottomleft); var sx = p.subtract(currentBB.bottomleft).divide(size.x).x * (width - 60) + 30; var sy = p.subtract(currentBB.bottomleft).divide(size.y).y * (height - 60) + 30; return new Springy.Vector(sx, sy); }; var renderer = new Springy.Renderer( this.layout, () => { currentBB = this.layout.getBoundingBox() width = this.target.scrollWidth height = this.target.scrollHeight field.innerHTML = '' }, function drawEdge(edge, p1, p2) { const dom = document.createElement('span') dom.innerText = edge.data.text p1 = toScreen(p1) p2 = toScreen(p2) if (p1.y > p2.y) [p1, p2] = [p2, p1] const a = p2.x - p1.x const b = p2.y - p1.y const negative = (a < 0) != (b < 0) let rad = Math.atan(b / a) if (negative) rad = rad + Math.PI if (rad > Math.PI / 2) { rad += Math.PI ;[p2, p1] = [p1, p2] } dom.className = 'line' dom.style.transform = 'rotate(' + rad + 'rad) translateY(-1em)' dom.style.left = p1.x + 'px' dom.style.top = p1.y + 'px' dom.style.right = p2.x + 'px' dom.style.bottom = p2.y + 'px' dom.style.width = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2)) + 'px' // FIXME eigentlich falsches parent field.appendChild(dom) }, function drawNode(item, p) { const target = toScreen(p) const dom = document.createElement('li') const a = document.createElement('a') const action = item.data.state == 'face-down' ? 'flip' : 'show' a.href = `/${item.id}/${action}` a.draggable = false if (item.data.state !== 'face-down') { a.style.backgroundImage = `url(/img/${item.data.img})` a.dataset['id'] = item.id a.draggable = true } dom.className = item.data.state dom.style.position = 'absolute' dom.style.left = (target.x - 60) + 'px' dom.style.top = (target.y - 60) + 'px' dom.appendChild(a) field.appendChild(dom) }, undefined, undefined, () => { const dd = new diffDOM.DiffDOM() const diff = dd.diff(this.target.children[0], field) dd.apply(this.target.children[0], diff) } ); target.appendChild(field) if (state.show !== null) { const wrapper = document.createElement('a') wrapper.href = '/' wrapper.className = 'fullview' const fullview = document.createElement('div') const name = 'Gretchen' const desc = 'Näherin, 20' const img = '/img/gretchen.jpg' const text = '

Text

More text text text

' fullview.innerHTML = `

${name}

${desc}

${text}
` wrapper.appendChild(fullview) target.appendChild(wrapper) } const dd = new diffDOM.DiffDOM() const diff = dd.diff(this.target, target) dd.apply(this.target, diff) renderer.start(); } }