aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDeterminant <[email protected]>2019-04-11 00:14:46 -0400
committerDeterminant <[email protected]>2019-04-11 00:14:46 -0400
commit0651c91b4418380c247b0465ebf2fffefc037393 (patch)
tree81d024d94690620e1e1d227ad1202c1250b85031 /src
parent306eb3cdf3015dbaa52aab3377de396c5277ea06 (diff)
add description; fix cursor bug
Diffstat (limited to 'src')
-rw-r--r--src/About.tsx7
-rw-r--r--src/Grid.css26
-rw-r--r--src/Grid.tsx65
-rw-r--r--src/Snow.tsx39
-rw-r--r--src/index.tsx7
5 files changed, 82 insertions, 62 deletions
diff --git a/src/About.tsx b/src/About.tsx
index 118b961..6966d6f 100644
--- a/src/About.tsx
+++ b/src/About.tsx
@@ -13,7 +13,6 @@ const styles = (theme: Theme): StyleRules => ({
body: {
margin: '0 auto',
width: 800,
- fontSize: 16
},
pre: {
fontFamily: "Monospace"
@@ -32,6 +31,7 @@ function About(props: AboutProps) {
const { classes } = props;
return (
<div className={classes.body}>
+ <Typography variant="body1">
<article>
The MIT License (MIT)
<p>Copyright 2019 Maofan "Ted" Yin</p>
@@ -60,6 +60,10 @@ function About(props: AboutProps) {
73d at tedyin dot com
</ListItem>
<ListItem>
+ <span className={classes.infoField}>GitHub:</span>
+ <Link href="https://github.com/Determinant/snow-bft-demo" target="_blank" rel="noopener">
+ Determinant/snow-bft-demo
+ </Link>
</ListItem>
<ListItem>
<span className={classes.infoField}>Buy me a cup of coffee:</span>
@@ -69,6 +73,7 @@ function About(props: AboutProps) {
</List>
</ListItem>
</List>
+ </Typography>
</div>
);
}
diff --git a/src/Grid.css b/src/Grid.css
index 620d114..33c2725 100644
--- a/src/Grid.css
+++ b/src/Grid.css
@@ -2,39 +2,27 @@ div.grid {
display: inline-block;
}
-
.grid div {
- -webkit-transition: background-color 0.1s ease-out;
- -moz-transition: background-color 0.1s ease-out;
- -o-transition: background-color 0.1s ease-out;
- transition: background-color 0.1s ease-out;
+ -webkit-transition: background-color 0.3s ease-out;
+ -moz-transition: background-color 0.3s ease-out;
+ -o-transition: background-color 0.3s ease-out;
+ transition: background-color 0.3s ease-out;
+ user-select: none;
}
-.gridCell div div div {
+.gridCell div div {
height: 20px;
width: 20px;
margin: 2px;
display: inline-block;
-}
-
-.gridCell div div {
- height: 24px;
- width: 24px;
- display: inline-block;
cursor: pointer;
}
-.smallGridCell div div div {
+.smallGridCell div div {
height: 15px;
width: 15px;
margin: 1px;
display: inline-block;
-}
-
-.smallGridCell div div {
- height: 17px;
- width: 17px;
- display: inline-block;
cursor: pointer;
}
diff --git a/src/Grid.tsx b/src/Grid.tsx
index 1bfcaee..d1fc973 100644
--- a/src/Grid.tsx
+++ b/src/Grid.tsx
@@ -3,17 +3,10 @@ import 'typeface-roboto';
import MGrid from '@material-ui/core/Grid';
import orange from '@material-ui/core/colors/orange';
import blue from '@material-ui/core/colors/blue';
-import { Theme, withStyles, StyleRules } from '@material-ui/core/styles';
import Color from 'color';
-import { TransitionGroup, CSSTransition } from "react-transition-group";
import './Grid.css';
-const styles = (theme: Theme): StyleRules => ({
-});
-
interface GridProps {
- classes: {
- },
onClickNode: (i: number, j: number) => void
onHoverNode: (i: number, j: number) => void
data: {d: number[], col: number}[][]
@@ -30,36 +23,48 @@ class Grid extends React.Component<GridProps> {
static getColor(s: {d: number[], col: number}) {
return getNodeColor(s.d[s.col], s.col);
}
+ mouseDown = false;
+ mousePos = {x: -1, y: -1};
render() {
- const { classes, data, onClickNode, onHoverNode } = this.props;
- const { gr, gc } = data.length <= 20 ?
- { gr: 'gridRow', gc: 'gridCell' } :
- { gr: 'smallGridRow', gc: 'smallGridCell' };
+ const { data, onClickNode, onHoverNode } = this.props;
+ const { gr, gc, l } = data.length <= 20 ?
+ { gr: 'gridRow', gc: 'gridCell', l: 24 } :
+ { gr: 'smallGridRow', gc: 'smallGridCell', l: 15 };
return (
- <div className={`grid ${gr} ${gc}`}>
- {
- data.map((row, i) => (
- <div key={i}>
+ <div className={`grid ${gr} ${gc}`}
+ onMouseDown={event => {
+ event.preventDefault();
+ this.mouseDown = true;
+ onClickNode(this.mousePos.y, this.mousePos.x);
+ }}
+ onMouseUp={event => {
+ event.preventDefault();
+ this.mouseDown = false;
+ }}
+ onMouseOver={event => {
+ const bounds = (event.currentTarget as Element).getBoundingClientRect();
+ const x = Math.floor((event.clientX - bounds.left) / l);
+ const y = Math.floor((event.clientY - bounds.top) / l);
+ console.log(y, x, this.mouseDown);
+ const t = this.mousePos;
+ this.mousePos = {x, y};
+ if (!this.mouseDown) return;
+ if (t.x !== x || t.y !== y)
{
- row.map((cell, j) => (
- <div
- onClick={event => onClickNode(i, j)}
- onMouseOver={event => {
- if (event.buttons === 1 || event.buttons === 3)
- onHoverNode(i, j);
- }}>
+ onHoverNode(y, x);
+ }
+ }}>
+ {data.map((row, i) => (
+ <div key={i}>
+ {row.map((cell, j) => (
<div key={j}
style={{backgroundColor: Grid.getColor(cell)}}>
</div>
- </div>
- ))
- }
+ ))}
</div>
- ))
- }
- </div>
- );
+ ))}
+ </div>);
}
}
-export default withStyles(styles)(Grid);
+export default Grid;
diff --git a/src/Snow.tsx b/src/Snow.tsx
index 4bba422..7b296e6 100644
--- a/src/Snow.tsx
+++ b/src/Snow.tsx
@@ -9,9 +9,11 @@ import TableCell from '@material-ui/core/TableCell';
import Button from '@material-ui/core/Button';
import Slider from '@material-ui/lab/Slider';
import FormGroup from '@material-ui/core/FormGroup';
-import Grid, {getNodeColor} from './Grid';
+import Typography from '@material-ui/core/Typography';
+import Link from '@material-ui/core/Link';
import { Line } from 'react-chartjs-2';
import Color from 'color';
+import Grid, {getNodeColor} from './Grid';
const styles = (theme: Theme): StyleRules => ({
inputLabel: {
@@ -154,7 +156,7 @@ class Snow extends React.Component<SnowProps> {
let s = this.getNodeState(n, u);
for (let c = 0; c < 2; c++)
{
- if (cnt[c] > this.config.alpha)
+ if (cnt[c] >= this.config.alpha)
{
s.d[c]++;
if (s.d[c] > s.d[s.col])
@@ -210,7 +212,7 @@ class Snow extends React.Component<SnowProps> {
this.setState({ nError: true });
return;
}
- if (!Number.isInteger(k) || k < 1 || k > N)
+ if (!Number.isInteger(k) || k < 1 || k >= N)
{
this.setState({ kError: true });
return;
@@ -296,6 +298,7 @@ class Snow extends React.Component<SnowProps> {
onClickNode={(i: number, j: number) => this.flipNode(i, j)}
onHoverNode={(i: number, j: number) => this.flipNode(i, j)}
/>
+ <div style={{position: 'relative', height: '40vh'}}>
<Line data={() => {
let datasets = this.state.dcnts.map((dd, c) => dd.map((line, i) => {
const base = getNodeColor(watchedD[i], c);
@@ -312,14 +315,34 @@ class Snow extends React.Component<SnowProps> {
labels: this.state.ticks
}
}}
- options={{ scales: { yAxes: [{ ticks: {min: -this.state.N, max: this.state.N}}]}}}/>
+ options={{
+ scales: { yAxes: [{ ticks: {min: -this.state.N, max: this.state.N}}]},
+ maintainAspectRatio: false
+ }}/>
+ </div>
</MGrid>
<MGrid item lg={4} xs={12}>
+ <Typography variant="body1">
+ <p>
+ This demo shows the Snowball protocol used as the core of a peer-to-peer payment system, Avalanche, introduced in&nbsp;
+ <Link href="https://avalanchelabs.org/QmT1ry38PAmnhparPUmsUNHDEGHQusBLD6T5XJh4mUUn3v.pdf" target="_blank" rel="noopener">
+ this paper
+ </Link>
+ &nbsp;. It visualizes the process of a binary,
+ single-decree, probabilistic Snowball consensus that harnesses
+ metastability to guarantee safety.
+ Little squares represent different nodes, wherein
+ the color of each square represents its current
+ proposal. Darkness of the color shows the node's
+ conviction in that proposal. Expectedly, all nodes
+ will collapse to the same color in the end.
+ </p>
<p>
Try to click or move the mouse when clicked to flip the
color of squares. Are you able to prevent them from
going to a single color?
</p>
+ </Typography>
<Table>
<TableBody>
<TableRow>
@@ -352,7 +375,7 @@ class Snow extends React.Component<SnowProps> {
error={this.state.kError}
onChange={event => this.setState({k: event.target.value, kError: false})}/>
{this.state.kError &&
- <span className={classes.errorHint}>k must be in 1..n</span>}
+ <span className={classes.errorHint}>k must be in 1..(n-1)</span>}
</TableCell>
</TableRow>
<TableRow>
@@ -421,7 +444,7 @@ class Snow extends React.Component<SnowProps> {
<div className={classes.buttonSpacer} />
<div className={classes.bottomButtons}>
<MGrid container item spacing={16}>
- <MGrid item lg={4} xs={12}>
+ <MGrid item md={4} xs={12}>
<FormGroup>
<Button
variant="contained" color="primary"
@@ -429,7 +452,7 @@ class Snow extends React.Component<SnowProps> {
disabled={this.state.ticking}>Run</Button>
</FormGroup>
</MGrid>
- <MGrid item lg={4} xs={12}>
+ <MGrid item md={4} xs={12}>
<FormGroup>
<Button
variant="contained" color="primary"
@@ -437,7 +460,7 @@ class Snow extends React.Component<SnowProps> {
disabled={!this.state.ticking}>Stop</Button>
</FormGroup>
</MGrid>
- <MGrid item lg={4} xs={12}>
+ <MGrid item md={4} xs={12}>
<FormGroup>
<Button
variant="contained" color="primary"
diff --git a/src/index.tsx b/src/index.tsx
index baa46f5..36bb16c 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -96,15 +96,15 @@ class MainTabs extends React.Component<MainTabsProps> {
position="absolute"
className={classes.appBar}>
<Toolbar className={classes.toolbar}>
- <Typography component="h1" variant="h6" color="inherit" noWrap className={classes.title}>
- <Logo style={{width: '5em', verticalAlign: 'bottom', marginRight: '0.5em'}}/>
+ <Typography color="inherit" noWrap className={classes.title} style={{fontSize: 28, fontWeight: 300}}>
+ <Logo style={{height: 42, verticalAlign: 'bottom', marginRight: '0.5em'}}/>
Snow BFT Demo
</Typography>
<Tabs
classes={{ indicator: classes.indicator }}
value={this.props.history.location.pathname}
onChange={this.handleChangeTab}>
- <Tab label="Snow" {...{component: Link, to: "/snow"} as any} value="/snow" />
+ <Tab label="Demo" {...{component: Link, to: "/snow"} as any} value="/snow" />
<Tab label="About" {...{component: Link, to: "/about"} as any} value="/about" />
</Tabs>
</Toolbar>
@@ -124,7 +124,6 @@ class MainTabs extends React.Component<MainTabsProps> {
}}>
<div className={classes.content}>
<Switch location={location}>
- {console.log(location)}
<Route exact path="/snow" component={Snow} />
<Route exact path="/about" component={About} />
<Route exact path="/" render={() => <Redirect to="/snow" />}/>