Improve styling
This commit is contained in:
parent
121f5c6e92
commit
c62106f2c1
@ -1,239 +1,316 @@
|
|||||||
import React, { useState ,useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { fetchRoads, fetchCities, getShortestPath } from './requests';
|
import { fetchRoads, fetchCities, getShortestPath } from './requests';
|
||||||
import { Select, Button, Icon } from 'antd';
|
import { Layout, Select, Button, Icon } from 'antd';
|
||||||
import Graph from 'react-graph-vis';
|
import Graph from 'react-graph-vis';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import 'antd/dist/antd.css';
|
import 'antd/dist/antd.css';
|
||||||
import arrow from '../assets/arrow-right.png';
|
import arrow from '../assets/arrow-right.png';
|
||||||
|
|
||||||
|
const { Header, Footer, Content } = Layout;
|
||||||
|
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
|
|
||||||
function HomeView() {
|
function HomeView() {
|
||||||
const [startingPoint, setStartingPoint] = useState(1);
|
const [startingPoint, setStartingPoint] = useState(1);
|
||||||
const [destination, setDestination] = useState(9);
|
const [destination, setDestination] = useState(9);
|
||||||
const [errorSelect, setError] = useState({ message: '', flag: false });
|
const [errorSelect, setError] = useState({ message: '', flag: false });
|
||||||
const [shortestPath, setShortestPath] = useState();
|
const [shortestPath, setShortestPath] = useState();
|
||||||
|
|
||||||
const [cities, setCities] = useState([]);
|
const [cities, setCities] = useState([]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchCities()
|
fetchCities()
|
||||||
.then(data => setCities(data))
|
.then((data) => setCities(data))
|
||||||
.catch(error => console.log(error))
|
.catch((error) => console.log(error));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const [roads, setRoads] = useState([]);
|
const [roads, setRoads] = useState([]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchRoads()
|
fetchRoads()
|
||||||
.then(data => setRoads(data))
|
.then((data) => setRoads(data))
|
||||||
.catch(error => console.log(error));
|
.catch((error) => console.log(error));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const [graph, setGraph] = useState({nodes: [], edges: []});
|
const [graph, setGraph] = useState({ nodes: [], edges: [] });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let nodes = cities.map(node => (
|
let nodes = cities.map((node) => ({
|
||||||
{ id: node.id, label: node.name, title: node.name}
|
id: node.id,
|
||||||
));
|
label: node.name,
|
||||||
|
title: node.name,
|
||||||
|
}));
|
||||||
|
|
||||||
let edges = roads.map(edge => (
|
let edges = roads.map((edge) => ({
|
||||||
{ from: edge.start_city_id, to: edge.end_city_id, length: edge.distance * 2 }
|
from: edge.start_city_id,
|
||||||
))
|
to: edge.end_city_id,
|
||||||
|
length: edge.distance * 2,
|
||||||
|
}));
|
||||||
|
|
||||||
setGraph({nodes, edges})
|
setGraph({ nodes, edges });
|
||||||
}, [cities, roads, shortestPath])
|
}, [cities, roads, shortestPath]);
|
||||||
|
|
||||||
function handleStart(city_id) {
|
function handleStart(city_id) {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
let [ startingPoint ] = cities.filter(city => city.id == city_id);
|
let [startingPoint] = cities.filter((city) => city.id == city_id);
|
||||||
setStartingPoint(startingPoint);
|
setStartingPoint(startingPoint);
|
||||||
// Check if start and destination are the same
|
// Check if start and destination are the same
|
||||||
if (startingPoint === destination) {
|
if (startingPoint === destination) {
|
||||||
setError({ message: 'The start and destination must be different.', flag: true });
|
setError({
|
||||||
return
|
message: 'The start and destination must be different.',
|
||||||
}
|
flag: true,
|
||||||
// Will reset the error message and shown path
|
});
|
||||||
setShortestPath();
|
return;
|
||||||
setError({ flag: false });
|
}
|
||||||
}
|
// Will reset the error message and shown path
|
||||||
|
setShortestPath();
|
||||||
|
setError({ flag: false });
|
||||||
|
}
|
||||||
|
|
||||||
function handleDestination(city_id) {
|
function handleDestination(city_id) {
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
let [ destination ] = cities.filter(city => city.id == city_id);
|
let [destination] = cities.filter((city) => city.id == city_id);
|
||||||
setDestination(destination);
|
setDestination(destination);
|
||||||
// Check if start and destination are the same
|
// Check if start and destination are the same
|
||||||
if (startingPoint === destination) {
|
if (startingPoint === destination) {
|
||||||
setError({ message: 'The start and destination must be different.', flag: true });
|
setError({
|
||||||
return
|
message: 'The start and destination must be different.',
|
||||||
}
|
flag: true,
|
||||||
// Will reset the error message and shown path
|
});
|
||||||
setShortestPath();
|
return;
|
||||||
setError({ flag: false });
|
}
|
||||||
}
|
// Will reset the error message and shown path
|
||||||
|
setShortestPath();
|
||||||
|
setError({ flag: false });
|
||||||
|
}
|
||||||
|
|
||||||
function handleSubmit() {
|
function handleSubmit() {
|
||||||
if (startingPoint === destination) {
|
if (startingPoint === destination) {
|
||||||
setError({ message: 'Please select a start and a destination', flag: true});
|
setError({
|
||||||
return
|
message: 'Please select a start and a destination',
|
||||||
} else
|
flag: true,
|
||||||
if (startingPoint && destination) {
|
});
|
||||||
getShortestPath(startingPoint.id, destination.id)
|
return;
|
||||||
.then(data => setShortestPath(data))
|
} else if (startingPoint && destination) {
|
||||||
.catch(error => console.log(error));
|
getShortestPath(startingPoint.id, destination.id)
|
||||||
setError({ flag: false });
|
.then((data) => setShortestPath(data))
|
||||||
} else {
|
.catch((error) => console.log(error));
|
||||||
setError({ message: 'Please select a start and a destination', flag: true});
|
setError({ flag: false });
|
||||||
}
|
} else {
|
||||||
}
|
setError({
|
||||||
|
message: 'Please select a start and a destination',
|
||||||
|
flag: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Graph visualization settings
|
// Graph visualization settings
|
||||||
const options = {
|
const options = {
|
||||||
layout: {
|
layout: {
|
||||||
hierarchical: false
|
hierarchical: false,
|
||||||
},
|
},
|
||||||
edges: {
|
edges: {
|
||||||
color: "#000000"
|
color: '#000000',
|
||||||
},
|
},
|
||||||
height: "500px"
|
height: '500px',
|
||||||
};
|
};
|
||||||
const events = {
|
const events = {
|
||||||
select: function(event) {
|
select: function (event) {
|
||||||
let { nodes, edges } = event;
|
let { nodes, edges } = event;
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
// TODO Find a solution to trigger a re-render of the map
|
// // TODO Find a solution to trigger a re-render of the map
|
||||||
// Add dashes to shortest path edges
|
// // Add dashes to shortest path edges
|
||||||
// let path = test.path;
|
// let path = test.path;
|
||||||
// let pairs = [];
|
// let pairs = [];
|
||||||
|
|
||||||
// for (let i = 0; path.length - 1 > i; i++) {
|
// for (let i = 0; path.length - 1 > i; i++) {
|
||||||
// let obj = { from: path[i], to: path[i+1]}
|
// let obj = { from: path[i], to: path[i+1]}
|
||||||
// pairs.push(obj);
|
// pairs.push(obj);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// let updatedEdges = graph.edges.map(edge => {
|
// let updatedEdges = graph.edges.map(edge => {
|
||||||
// if (pairs.includes(edge)){
|
// if (pairs.includes(edge)){
|
||||||
// edge['dashes'] = true;
|
// edge['dashes'] = true;
|
||||||
// }
|
// }
|
||||||
// return edge
|
// return edge
|
||||||
// })
|
// })
|
||||||
// console.log(updatedEdges)
|
// console.log(updatedEdges)
|
||||||
// setGraph({...graph, edges: updatedEdges});
|
// setGraph({...graph, edges: updatedEdges});
|
||||||
|
|
||||||
return(
|
return (
|
||||||
<Main>
|
<>
|
||||||
<h1>Dijkstra</h1>
|
<Header style={{ backgroundColor: '#ededed' }}>
|
||||||
<p>Find the shortest path between different cities in Belgium with Dijkstra algorithm.</p>
|
<div style={{ margin: '0 auto', maxWidth: '800px' }}>
|
||||||
<Section>
|
<InlineH1>Dijkstra | </InlineH1>
|
||||||
<h2>Starting Point</h2>
|
<InlineP>
|
||||||
<div>
|
Find the shortest path between different cities in
|
||||||
<StyledSelect defaultValue="Belgium" disabled>
|
Belgium with Dijkstra algorithm
|
||||||
</StyledSelect>
|
</InlineP>
|
||||||
<Select
|
</div>
|
||||||
defaultValue="Select a city"
|
</Header>
|
||||||
onChange={handleStart}
|
|
||||||
style={{ width: 139 }}
|
|
||||||
>
|
|
||||||
{cities.map(city => (
|
|
||||||
<Option key={city.id}>{city.name}</Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
</Section>
|
|
||||||
<Section>
|
|
||||||
<h2>Destination</h2>
|
|
||||||
<div>
|
|
||||||
<StyledSelect defaultValue="Belgium" disabled>
|
|
||||||
</StyledSelect>
|
|
||||||
<Select
|
|
||||||
defaultValue="Select a city"
|
|
||||||
onChange={handleDestination}
|
|
||||||
style={{ width: 139 }}
|
|
||||||
>
|
|
||||||
{cities.map(city => (
|
|
||||||
<Option key={city.id}>{city.name}</Option>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
</Section>
|
|
||||||
<Section>
|
|
||||||
<Button
|
|
||||||
type="primary"
|
|
||||||
onClick={handleSubmit}
|
|
||||||
>
|
|
||||||
Get shortest path between the cities
|
|
||||||
<Icon type="right" />
|
|
||||||
</Button>
|
|
||||||
{errorSelect.flag &&
|
|
||||||
<p>{errorSelect.message}</p>
|
|
||||||
}
|
|
||||||
</Section>
|
|
||||||
{
|
|
||||||
shortestPath &&
|
|
||||||
<Section>
|
|
||||||
<h2>Shortest path from {startingPoint.name} to {destination.name} ({shortestPath.distance}km)</h2>
|
|
||||||
<StyledP>{shortestPath.path.map(city => (
|
|
||||||
<StyledSpan key={city.id} class="cityPath">{city.name}</StyledSpan>
|
|
||||||
))}
|
|
||||||
</StyledP>
|
|
||||||
|
|
||||||
</Section>
|
<Content>
|
||||||
}
|
<Main
|
||||||
{ graph.nodes.length > 0 &&
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
flexFlow: 'row wrap',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{margin: '0 20px'}}>
|
||||||
|
<Section>
|
||||||
|
<h2>Starting Point</h2>
|
||||||
|
<div>
|
||||||
|
<StyledSelect
|
||||||
|
defaultValue='Belgium'
|
||||||
|
disabled
|
||||||
|
></StyledSelect>
|
||||||
|
<Select
|
||||||
|
defaultValue='Select a city'
|
||||||
|
onChange={handleStart}
|
||||||
|
style={{ width: 139 }}
|
||||||
|
>
|
||||||
|
{cities.map((city) => (
|
||||||
|
<Option key={city.id}>
|
||||||
|
{city.name}
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
<Section>
|
||||||
|
<h2>Destination</h2>
|
||||||
|
<div>
|
||||||
|
<StyledSelect
|
||||||
|
defaultValue='Belgium'
|
||||||
|
disabled
|
||||||
|
></StyledSelect>
|
||||||
|
<Select
|
||||||
|
defaultValue='Select a city'
|
||||||
|
onChange={handleDestination}
|
||||||
|
style={{ width: 139 }}
|
||||||
|
>
|
||||||
|
{cities.map((city) => (
|
||||||
|
<Option key={city.id}>
|
||||||
|
{city.name}
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
<Section>
|
||||||
|
<Button type='primary' onClick={handleSubmit}>
|
||||||
|
Get shortest path between the cities
|
||||||
|
<Icon type='right' />
|
||||||
|
</Button>
|
||||||
|
{errorSelect.flag && <p>{errorSelect.message}</p>}
|
||||||
|
</Section>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Graph
|
<div style={{ maxWidth: '660px', minWidth: '400px' }}>
|
||||||
graph={graph}
|
{graph.nodes.length > 0 && (
|
||||||
options={options}
|
<Graph
|
||||||
events={events}
|
graph={graph}
|
||||||
getNetwork={network => {
|
options={options}
|
||||||
// if you want access to vis.js network api you can set the state in a parent component using this property
|
events={events}
|
||||||
}}
|
getNetwork={(network) => {
|
||||||
/>
|
// if you want access to vis.js network api you can set the state in a parent component using this property
|
||||||
}
|
}}
|
||||||
<Section>
|
/>
|
||||||
<p>Git: <a href="https://git.armada.digital/rui/dijkstra-backend">backend</a> & <a href="https://git.armada.digital/rui/dijkstra-frontend">frontend</a> </p>
|
)}
|
||||||
</Section>
|
</div>
|
||||||
</Main>
|
|
||||||
);
|
<div>
|
||||||
|
{shortestPath && (
|
||||||
|
<Section>
|
||||||
|
<h2>
|
||||||
|
Shortest path from {startingPoint.name} to{' '}
|
||||||
|
{destination.name} ({shortestPath.distance}
|
||||||
|
km)
|
||||||
|
</h2>
|
||||||
|
<StyledP>
|
||||||
|
{shortestPath.path.map((city) => (
|
||||||
|
<StyledSpan
|
||||||
|
key={city.id}
|
||||||
|
class='cityPath'
|
||||||
|
>
|
||||||
|
{city.name}
|
||||||
|
</StyledSpan>
|
||||||
|
))}
|
||||||
|
</StyledP>
|
||||||
|
</Section>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Main>
|
||||||
|
</Content>
|
||||||
|
|
||||||
|
<Footer>
|
||||||
|
<div style={{ margin: '0 auto', maxWidth: '800px' }}>
|
||||||
|
<p>
|
||||||
|
Git |{' '}
|
||||||
|
<a href='https://git.armada.digital/rui/dijkstra-backend'>
|
||||||
|
backend
|
||||||
|
</a>{' '}
|
||||||
|
&{' '}
|
||||||
|
<a href='https://git.armada.digital/rui/dijkstra-frontend'>
|
||||||
|
frontend
|
||||||
|
</a>{' '}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Footer>
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HomeView
|
export default HomeView;
|
||||||
|
|
||||||
|
// STYLED COMPONENTS
|
||||||
|
|
||||||
|
const InlineP = styled.p`
|
||||||
|
display: inline;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const InlineH1 = styled.h1`
|
||||||
|
display: inline;
|
||||||
|
`;
|
||||||
|
|
||||||
const Main = styled.main`
|
const Main = styled.main`
|
||||||
padding-top: 20px;
|
padding-top: 20px;
|
||||||
max-width: 800px;
|
max-width: 1200px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
`
|
height: calc(100vh - 147px);
|
||||||
|
`;
|
||||||
|
|
||||||
const Section = styled.section`
|
const Section = styled.section`
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
`
|
`;
|
||||||
|
|
||||||
const StyledSelect = styled(Select)`
|
const StyledSelect = styled(Select)`
|
||||||
margin-right:10px;
|
margin-right: 10px;
|
||||||
`
|
`;
|
||||||
|
|
||||||
const StyledSpan = styled.span`
|
const StyledSpan = styled.span`
|
||||||
::after {
|
::after {
|
||||||
content: "";
|
content: '';
|
||||||
background-image: url(${arrow});
|
background-image: url(${arrow});
|
||||||
background-size: 13px 17px;
|
background-size: 13px 17px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 13px;
|
width: 13px;
|
||||||
height: 17px;
|
height: 17px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
bottom: -10px;
|
bottom: -10px;
|
||||||
}
|
}
|
||||||
font-size:1.5rem;
|
font-size: 1.5rem;
|
||||||
color: #40a9ff;
|
color: #40a9ff;
|
||||||
`
|
`;
|
||||||
|
|
||||||
const StyledP = styled.p`
|
const StyledP = styled.p`
|
||||||
span:last-child {
|
span:last-child {
|
||||||
::after {
|
::after {
|
||||||
background-image: none;
|
background-image: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`;
|
||||||
|
Loading…
Reference in New Issue
Block a user