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.
186 lines
6.2 KiB
186 lines
6.2 KiB
export const modal = content => {
|
|
const wrapper = document.createElement('a')
|
|
wrapper.href = '/'
|
|
wrapper.className = 'fullview'
|
|
const fullview = document.createElement('div')
|
|
fullview.innerHTML = content
|
|
wrapper.appendChild(fullview)
|
|
return wrapper
|
|
}
|
|
|
|
export class Display {
|
|
constructor(dispatch, target) {
|
|
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
|
|
// https://github.com/Bernardo-Castilho/dragdroptouch/pull/37
|
|
// e.dataTransfer.clearData()
|
|
for (const x of e.dataTransfer.types) { e.dataTransfer.clearData(x) }
|
|
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
|
|
)
|
|
}
|
|
renderIntro(intro) {
|
|
this.target.appendChild(modal(intro))
|
|
}
|
|
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
|
|
const ballRadius = Math.min(document.body.clientWidth, document.body.clientHeight) * 0.06
|
|
var toScreen = function(p) {
|
|
var size = currentBB.topright.subtract(currentBB.bottomleft);
|
|
var sx = p.subtract(currentBB.bottomleft).divide(size.x).x * (width - ballRadius * 2) + ballRadius;
|
|
var sy = p.subtract(currentBB.bottomleft).divide(size.y).y * (height - ballRadius * 2) + ballRadius;
|
|
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.icon}")`
|
|
a.dataset['id'] = item.id
|
|
a.draggable = true
|
|
}
|
|
dom.className = item.data.state
|
|
dom.style.position = 'absolute'
|
|
dom.style.left = (target.x - ballRadius) + 'px'
|
|
dom.style.top = (target.y - ballRadius) + '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.items.filter(i => i.state != 'face-up').length == 0) {
|
|
const a = document.createElement('a')
|
|
a.className = 'continue'
|
|
a.innerText = 'fertig'
|
|
a.href = '/end'
|
|
target.appendChild(a)
|
|
}
|
|
if (state.show !== null) {
|
|
const data = state.items[state.show]
|
|
const name = data.name
|
|
const desc = data.desc
|
|
const img = '/img/' + data.img
|
|
const text = (data.text || []).map(v => '<p>' + v + '</p>').join('')
|
|
const wrapper = modal(`
|
|
<header>
|
|
<img src=${img} />
|
|
<h1>${name}</h1>
|
|
<p class=desc>${desc}</p>
|
|
</header>
|
|
<div class=fulltext-wrapper><div class=fulltext>${text}
|
|
<blockquote>${data.quote || ''}</blockquote></div></div>
|
|
`)
|
|
target.appendChild(wrapper)
|
|
}
|
|
if (state.special) {
|
|
target.appendChild(modal(state.special))
|
|
}
|
|
|
|
const dd = new diffDOM.DiffDOM()
|
|
const diff = dd.diff(this.target, target)
|
|
dd.apply(this.target, diff)
|
|
|
|
renderer.start();
|
|
}
|
|
}
|