From 0651c91b4418380c247b0465ebf2fffefc037393 Mon Sep 17 00:00:00 2001 From: Determinant Date: Thu, 11 Apr 2019 00:14:46 -0400 Subject: add description; fix cursor bug --- src/About.tsx | 7 ++++++- src/Grid.css | 26 +++++++----------------- src/Grid.tsx | 65 ++++++++++++++++++++++++++++++++--------------------------- src/Snow.tsx | 39 +++++++++++++++++++++++++++-------- src/index.tsx | 7 +++---- 5 files changed, 82 insertions(+), 62 deletions(-) (limited to 'src') 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 (
+
The MIT License (MIT)

Copyright 2019 Maofan "Ted" Yin

@@ -60,6 +60,10 @@ function About(props: AboutProps) { 73d at tedyin dot com + GitHub: + + Determinant/snow-bft-demo + Buy me a cup of coffee: @@ -69,6 +73,7 @@ function About(props: AboutProps) { +
); } 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 { 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 ( -
- { - data.map((row, i) => ( -
+
{ + 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) => ( -
onClickNode(i, j)} - onMouseOver={event => { - if (event.buttons === 1 || event.buttons === 3) - onHoverNode(i, j); - }}> + onHoverNode(y, x); + } + }}> + {data.map((row, i) => ( +
+ {row.map((cell, j) => (
-
- )) - } + ))}
- )) - } -
- ); + ))} +
); } } -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 { 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 { 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 { onClickNode={(i: number, j: number) => this.flipNode(i, j)} onHoverNode={(i: number, j: number) => this.flipNode(i, j)} /> +
{ 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 { 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 + }}/> +
+ +

+ This demo shows the Snowball protocol used as the core of a peer-to-peer payment system, Avalanche, introduced in  + + this paper + +  . 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. +

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?

+
@@ -352,7 +375,7 @@ class Snow extends React.Component { error={this.state.kError} onChange={event => this.setState({k: event.target.value, kError: false})}/> {this.state.kError && - k must be in 1..n} + k must be in 1..(n-1)} @@ -421,7 +444,7 @@ class Snow extends React.Component {
- + - + - +