Browse Source

feature(network map): loading screen for network map

renovate/lint-staged-8.x
Jack Mallers 7 years ago
parent
commit
a51b14f080
  1. 22
      app/components/Network/CanvasNetworkGraph.css
  2. 58
      app/components/Network/CanvasNetworkGraph.js
  3. 156
      app/components/Network/CanvasNetworkGraph.scss
  4. 18
      app/reducers/network.js
  5. 6
      app/routes/network/components/Network.js
  6. 11
      app/routes/network/containers/NetworkContainer.js

22
app/components/Network/CanvasNetworkGraph.css

@ -1,22 +0,0 @@
.network {
width: 100%;
height: 100vh;
animation: fadein 0.5s;
animation-timing-function:linear;
animation-fill-mode: forwards;
animation-iteration-count: 1;
}
.links line {
stroke: #999;
stroke-opacity: 0.6;
}
.nodes circle {
stroke: black ;
stroke-width: 0px;
}
.active-peer {
fill: pink;
}

58
app/components/Network/CanvasNetworkGraph.js

@ -2,7 +2,7 @@ import { findDOMNode } from 'react-dom'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import * as d3 from 'd3'
// import './CanvasNetworkGraph.css'
import styles from './CanvasNetworkGraph.scss'
function generateSimulationData(nodes, edges) {
const resNodes = nodes.map(node => Object.assign(node, { id: node.pub_key }))
@ -26,7 +26,9 @@ class CanvasNetworkGraph extends Component {
simulationData: {
nodes: [],
links: []
}
},
svgLoaded: false
}
this._startSimulation = this._startSimulation.bind(this)
@ -35,10 +37,31 @@ class CanvasNetworkGraph extends Component {
this._restart = this._restart.bind(this)
}
componentWillReceiveProps(nextProps) {
const { network } = nextProps
const { simulationData: { nodes, links } } = this.state
const simulationDataEmpty = !nodes.length && !links.length
const networkDataLoaded = network.nodes.length || network.edges.length
// if the simulationData is empty and we have data
if (simulationDataEmpty && networkDataLoaded) {
this.setState({
simulationData: generateSimulationData(network.nodes, network.edges)
})
}
}
componentDidMount() {
// wait for the svg to me in the DOM before we start the simulation
const svgInterval = setInterval(() => {
if (document.getElementById('map')) {
if (document.getElementById('mapContainer')) {
d3.select('#mapContainer')
.append('svg')
.attr('id', 'map')
.attr('width', 800)
.attr('height', 800)
this._startSimulation()
clearInterval(svgInterval)
@ -79,7 +102,6 @@ class CanvasNetworkGraph extends Component {
componentWillUnmount() {
d3.select('#map')
.selectAll('*')
.remove()
}
@ -177,6 +199,10 @@ class CanvasNetworkGraph extends Component {
.force('link', d3.forceLink(links).id(d => d.pub_key).distance(500))
.force('collide', d3.forceCollide(300))
.on('tick', this._ticked)
.on('end', () => {
this.setState({ svgLoaded: true })
})
// zoom
const zoom_handler = d3.zoom().on('zoom', this._zoomActions)
@ -235,18 +261,22 @@ class CanvasNetworkGraph extends Component {
}
render() {
const { simulationData } = this.state
const {
network: { nodes, edges, selectedChannel, networkLoading },
selectedPeerPubkeys,
selectedChannelIds,
currentRouteChanIds,
identity_pubkey
} = this.props
const { svgLoaded } = this.state
return (
<div id='mapContainer' style={{ display: 'inline' }}>
<svg width='800' height='800' id='map'></svg>
<div className={styles.mapContainer} id='mapContainer'>
{
!svgLoaded &&
<div className={styles.loadingContainer}>
<div className={styles.loadingWrap}>
<div className={styles.loader}></div>
<div className={styles.loaderbefore}></div>
<div className={styles.circular}></div>
<div className={`${styles.circular} ${styles.another}`}></div>
<div className={styles.text}>loading</div>
</div>
</div>
}
</div>
)
}

156
app/components/Network/CanvasNetworkGraph.scss

@ -0,0 +1,156 @@
@import '../../variables.scss';
@keyframes fadein {
0% { background: $white; }
50% { background: lighten($secondary, 50%); }
100% { background: $secondary; animation-fill-mode:forwards; }
}
.mapContainer {
position: relative;
display: inline-block;
width: 70%;
height: 100%;
}
.loadingContainer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: $secondary;
}
.loadingWrap {
position: relative;
top: calc(50% - 150px);
width: 150px;
margin: 0 auto;
}
.loader {
position: absolute;
top: 0;
z-index: 10;
width: 50px;
height: 50px;
border: 15px solid;
border-radius: 50%;
border-top-color: rgba(44,44,44,0);
border-right-color: rgba(55,55,55,0);
border-bottom-color: rgba(66,66,66,0);
border-left-color: rgba(33,33,33,0);
animation: loadEr 3s infinite;
}
@keyframes loadEr {
0% {
border-top-color: rgba(44,44,44,0);
border-right-color: rgba(55,55,55,0);
border-bottom-color: rgba(66,66,66,0);
border-left-color: rgba(33,33,33,0);
}
10.4% {
border-top-color: rgba(44,44,44,0.5);
border-right-color: rgba(55,55,55,0);
border-bottom-color: rgba(66,66,66,0);
border-left-color: rgba(33,33,33,0);
}
20.8% {
border-top-color: rgba(44,44,44,0);
border-right-color: rgba(55,55,55,0);
border-bottom-color: rgba(66,66,66,0);
border-left-color: rgba(33,33,33,0);
}
31.2% {
border-top-color: rgba(44,44,44,0);
border-right-color: rgba(55,55,55,0.5);
border-bottom-color: rgba(66,66,66,0);
border-left-color: rgba(33,33,33,0);
}
41.6% {
border-top-color: rgba(44,44,44,0);
border-right-color: rgba(55,55,55,0);
border-bottom-color: rgba(66,66,66,0);
border-left-color: rgba(33,33,33,0);
transform: rotate(40deg);
}
52% {
border-top-color: rgba(44,44,44,0);
border-right-color: rgba(55,55,55,0);
border-bottom-color: rgba(66,66,66,0.5);
border-left-color: rgba(33,33,33,0);
}
62.4% {
border-top-color: rgba(44,44,44,0);
border-right-color: rgba(55,55,55,0);
border-bottom-color: rgba(66,66,66,0);
border-left-color: rgba(33,33,33,0);
}
72.8% {
border-top-color: rgba(44,44,44,0);
border-right-color: rgba(55,55,55,0);
border-bottom-color: rgba(66,66,66,0);
border-left-color: rgba(33,33,33,0.5);
}
}
.loaderbefore {
width: 50px;
height:50px;
border: 15px solid #ddd;
border-radius: 50%;
position: absolute;
top: 0;
z-index: 9;
}
.circular {
position: absolute;
top: -15px;
left: -15px;
width: 70px;
height: 70px;
border: 20px solid;
border-radius: 50%;
border-top-color: #333;
border-left-color: #fff;
border-bottom-color: #333;
border-right-color: #fff;
opacity: 0.2;
animation: poof 5s infinite;
}
@keyframes poof {
0% {transform: scale(1,1) rotate(0deg); opacity: 0.2;}
50% {transform: scale(4,4) rotate(360deg); opacity: 0;}
}
.another {
opacity: 0.1;
transform: rotate(90deg);
animation: poofity 5s infinite;
animation-delay: 1s;
}
@keyframes poofity {
0% {transform: scale(1,1) rotate(90deg); opacity: 0.1;}
50% {transform: scale(4,4) rotate(-360deg); opacity: 0;}
}
.text {
position: absolute;
top: 95px;
left: 8px;
font-family: Arial;
text-transform: uppercase;
color: #888;
animation: opaa 10s infinite;
}
@keyframes opaa {
0% {opacity: 1;}
10% {opacity: 0.5}
15% {opacity: 1;}
30% {opacity: 1;}
65% {opacity: 0.3;}
90% {opacity: 0.8;}
}

18
app/reducers/network.js

@ -23,8 +23,10 @@ export const UPDATE_PAY_REQ = 'UPDATE_PAY_REQ'
export const RESET_PAY_REQ = 'RESET_PAY_REQ'
export const UPDATE_SELECTED_PEERS = 'UPDATE_SELECTED_PEERS'
export const CLEAR_SELECTED_PEERS = 'CLEAR_SELECTED_PEERS'
export const UPDATE_SELECTED_CHANNELS = 'UPDATE_SELECTED_CHANNELS'
export const CLEAR_SELECTED_CHANNELS = 'CLEAR_SELECTED_CHANNELS'
export const GET_INFO_AND_QUERY_ROUTES = 'GET_INFO_AND_QUERY_ROUTES'
export const RECEIVE_INFO_AND_QUERY_ROUTES = 'RECEIVE_INFO_AND_QUERY_ROUTES'
@ -113,6 +115,18 @@ export function clearQueryRoutes() {
}
}
export function clearSelectedPeers() {
return {
type: CLEAR_SELECTED_PEERS
}
}
export function clearSelectedChannels() {
return {
type: CLEAR_SELECTED_CHANNELS
}
}
// Send IPC event for describeNetwork
export const fetchDescribeNetwork = () => (dispatch) => {
dispatch(getDescribeNetwork())
@ -185,6 +199,7 @@ const ACTION_HANDLERS = {
...state, selectedPeers
}
},
[CLEAR_SELECTED_PEERS]: state => ({ ...state, selectedPeers: [] }),
[UPDATE_SELECTED_CHANNELS]: (state, { channel }) => {
let selectedChannels
@ -200,7 +215,8 @@ const ACTION_HANDLERS = {
return {
...state, selectedChannels
}
}
},
[CLEAR_SELECTED_CHANNELS]: state => ({ ...state, selectedChannels: [] }),
}
// ------------------------------------

6
app/routes/network/components/Network.js

@ -34,10 +34,12 @@ class Network extends Component {
}
componentWillUnmount() {
const { clearQueryRoutes, resetPayReq } = this.props
const { clearQueryRoutes, resetPayReq, clearSelectedChannels, clearSelectedPeers } = this.props
clearQueryRoutes()
resetPayReq()
resetPayReq()
clearSelectedChannels()
clearSelectedPeers()
}
render() {

11
app/routes/network/containers/NetworkContainer.js

@ -5,8 +5,13 @@ import {
fetchDescribeNetwork,
setCurrentTab,
updateSelectedPeers,
clearSelectedPeers,
updateSelectedChannels,
clearSelectedChannels,
setCurrentRoute,
updatePayReq,
@ -25,7 +30,10 @@ import Network from '../components/Network'
const mapDispatchToProps = {
fetchDescribeNetwork,
setCurrentTab,
updateSelectedPeers,
clearSelectedPeers,
updatePayReq,
fetchInvoiceAndQueryRoutes,
setCurrentRoute,
@ -35,7 +43,8 @@ const mapDispatchToProps = {
fetchPeers,
fetchChannels,
updateSelectedChannels
updateSelectedChannels,
clearSelectedChannels
}
const mapStateToProps = state => ({

Loading…
Cancel
Save