|
|
|
@ -6,7 +6,7 @@ import '@fontsource/roboto/300.css';
|
|
|
|
|
import '@fontsource/roboto/400.css';
|
|
|
|
|
import '@fontsource/roboto/500.css';
|
|
|
|
|
import '@fontsource/roboto/700.css';
|
|
|
|
|
import cytoscape from 'cytoscape'
|
|
|
|
|
import cytoscape, { LayoutOptions } from 'cytoscape'
|
|
|
|
|
import klay from 'cytoscape-klay';
|
|
|
|
|
import { Link as RouterLink, useNavigate } from 'react-router-dom';
|
|
|
|
|
|
|
|
|
@ -15,70 +15,22 @@ cytoscape.use( klay );
|
|
|
|
|
|
|
|
|
|
import { Box, Typography, Button, CircularProgress, Grid } from '@mui/material';
|
|
|
|
|
import { useGetGameInfoQuery } from '../game/api';
|
|
|
|
|
import { Link } from 'react-router-dom';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function Welcome() {
|
|
|
|
|
const navigate = useNavigate();
|
|
|
|
|
|
|
|
|
|
const worldsRef = useRef<HTMLDivElement>(null)
|
|
|
|
|
|
|
|
|
|
const drawWorlds = (worlds) => {
|
|
|
|
|
let elements = []
|
|
|
|
|
for (let node of worlds.nodes) {
|
|
|
|
|
elements.push({ data: { id: node } })
|
|
|
|
|
}
|
|
|
|
|
for (let edge of worlds.edges) {
|
|
|
|
|
elements.push({
|
|
|
|
|
data: {
|
|
|
|
|
id: edge[0] + " --edge-to--> " + edge[1],
|
|
|
|
|
source: edge[0],
|
|
|
|
|
target: edge[1]
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
const layout : any = {name: "klay", klay: {direction: "DOWN"}}
|
|
|
|
|
const cy = cytoscape({ container: worldsRef.current!, elements, layout,
|
|
|
|
|
style: [ // the stylesheet for the graph
|
|
|
|
|
{
|
|
|
|
|
selector: 'node',
|
|
|
|
|
style: {
|
|
|
|
|
'background-color': '#666',
|
|
|
|
|
'label': 'data(id)'
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
selector: 'edge',
|
|
|
|
|
style: {
|
|
|
|
|
'width': 3,
|
|
|
|
|
'line-color': '#ccc',
|
|
|
|
|
'target-arrow-color': '#ccc',
|
|
|
|
|
'target-arrow-shape': 'triangle',
|
|
|
|
|
'curve-style': 'bezier'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
userPanningEnabled: false,
|
|
|
|
|
userZoomingEnabled: false,
|
|
|
|
|
autoungrabify: true,
|
|
|
|
|
autounselectify: true,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
cy.on('click', 'node', function(evt){
|
|
|
|
|
navigate(`/world/${this.id()}/level/1`);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const gameInfo = useGetGameInfoQuery()
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (gameInfo.data?.worlds) { drawWorlds(gameInfo.data.worlds); }
|
|
|
|
|
}, [gameInfo.data?.worlds])
|
|
|
|
|
const { nodes, bounds }: any = gameInfo.data ? computeWorldLayout(gameInfo.data?.worlds) : {nodes: []}
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (gameInfo.data?.title) window.document.title = gameInfo.data.title
|
|
|
|
|
}, [gameInfo.data?.title])
|
|
|
|
|
|
|
|
|
|
const padding = 10
|
|
|
|
|
|
|
|
|
|
return <div>
|
|
|
|
|
{ gameInfo.isLoading?
|
|
|
|
|
<Box display="flex" alignItems="center" justifyContent="center" sx={{ height: "calc(100vh - 64px)" }}><CircularProgress /></Box>
|
|
|
|
@ -94,7 +46,18 @@ function Welcome() {
|
|
|
|
|
<Box textAlign='center' sx={{ m: 5 }}>
|
|
|
|
|
<Button component={RouterLink} to="/world/Logic/level/1" variant="contained">Start rescue mission</Button>
|
|
|
|
|
</Box>
|
|
|
|
|
<div ref={worldsRef} style={{"width": "100%","height": "50em"}} />
|
|
|
|
|
<Box textAlign='center' sx={{ m: 5 }}>
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" width="30%"
|
|
|
|
|
viewBox={bounds ? `${bounds.x1 - padding} ${bounds.y1 - padding} ${bounds.x2 - bounds.x1 + 2 * padding} ${bounds.y2 - bounds.y1 + 2 * padding}` : ''}>
|
|
|
|
|
{gameInfo.data ? gameInfo.data.worlds.edges.map((edge) =>
|
|
|
|
|
<line x1={nodes[edge[0]].x} y1={nodes[edge[0]].y} x2={nodes[edge[1]].x} y2={nodes[edge[1]].y} stroke="#1976d2" stroke-width="1"/>) : null}
|
|
|
|
|
{Object.entries(nodes).map(([id, position]) =>
|
|
|
|
|
<Link to={`/world/${id}/level/1`}>
|
|
|
|
|
<circle fill="#61DAFB" cx={(position as cytoscape.Position).x} cy={(position as cytoscape.Position).y} r="8" />
|
|
|
|
|
<text style={{font: "italic 2px sans-serif", "text-anchor": "middle", "dominant-baseline": "middle"} as any} x={(position as cytoscape.Position).x} y={(position as cytoscape.Position).y}>{id}</text>
|
|
|
|
|
</Link>)}
|
|
|
|
|
</svg>
|
|
|
|
|
</Box>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -102,3 +65,37 @@ function Welcome() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default Welcome
|
|
|
|
|
|
|
|
|
|
function computeWorldLayout(worlds) {
|
|
|
|
|
|
|
|
|
|
let elements = []
|
|
|
|
|
for (let node of worlds.nodes) {
|
|
|
|
|
elements.push({ data: { id: node } })
|
|
|
|
|
}
|
|
|
|
|
for (let edge of worlds.edges) {
|
|
|
|
|
elements.push({
|
|
|
|
|
data: {
|
|
|
|
|
id: edge[0] + " --edge-to--> " + edge[1],
|
|
|
|
|
source: edge[0],
|
|
|
|
|
target: edge[1]
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const cy = cytoscape({
|
|
|
|
|
container: null,
|
|
|
|
|
elements,
|
|
|
|
|
headless: true,
|
|
|
|
|
styleEnabled: false
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const layout = cy.layout({name: "klay", klay: {direction: "DOWN"}} as LayoutOptions).run()
|
|
|
|
|
let nodes = {}
|
|
|
|
|
cy.nodes().forEach((node, id) => {
|
|
|
|
|
nodes[node.id()] = node.position()
|
|
|
|
|
console.log(node.position())
|
|
|
|
|
})
|
|
|
|
|
const bounds = cy.nodes().boundingBox()
|
|
|
|
|
console.log(bounds)
|
|
|
|
|
return { nodes, bounds }
|
|
|
|
|
}
|
|
|
|
|