Skip to content

Instantly share code, notes, and snippets.

@Workshopshed
Created December 13, 2019 22:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Workshopshed/0dec02a0f5a59da2f3013d591ae925a9 to your computer and use it in GitHub Desktop.
Save Workshopshed/0dec02a0f5a59da2f3013d591ae925a9 to your computer and use it in GitHub Desktop.
Synchronising React components
const e = React.createElement;
const rangestyle = {
width: '100%'
};
class Compass extends React.Component {
constructor(props) {
super(props);
this.state = { value: 180 }
// To use the 'this' keyword, we need to bind it to our function
this.handleChange = this.handleChange.bind(this);
}
// A custom function to change the name in our state to match the user input
handleChange(val) {
this.setState({
value: val
})
}
render() {
const degrees = this.state.value;
return (
<div className="row">
<CompassInput value={degrees} onDegreesChange={this.handleChange} />
<CompassOutput value={degrees} />
</div>
)
}
}
class CompassOutput extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
this.updateCanvas();
}
componentDidUpdate() {
this.updateCanvas();
}
updateCanvas() {
var canvas = this.refs.compassCanvas;
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
var radius = canvas.height / 2;
ctx.translate(radius, radius);
radius = radius * 0.90
this.drawCompass(ctx,radius);
ctx.setTransform(1, 0, 0, 1, 0, 0);
}
drawCompass(ctx,radius) {
const degrees = this.props.value;
this.drawFace(ctx, radius);
this.drawLetters(ctx, radius);
this.drawPointer(ctx, degrees, radius*0.9, radius*0.02);
}
drawFace(ctx, radius) {
var grad;
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
ctx.fillStyle = 'blue';
ctx.fill();
grad = ctx.createRadialGradient(0, 0 ,radius * 0.95, 0, 0, radius * 1.05);
grad.addColorStop(0, '#333');
grad.addColorStop(0.5, 'blue');
grad.addColorStop(1, '#333');
ctx.strokeStyle = grad;
ctx.lineWidth = radius*0.1;
ctx.stroke();
ctx.beginPath();
ctx.arc(0, 0, radius * 0.1, 0, 2 * Math.PI);
ctx.fillStyle = '#333';
ctx.fill();
}
drawPointer(ctx, pos, length, width) {
ctx.beginPath();
ctx.lineWidth = width;
ctx.lineCap = "round";
ctx.moveTo(0,0);
ctx.rotate(pos * Math.PI / 180);
ctx.lineTo(0, -length);
ctx.stroke();
ctx.rotate(-pos * Math.PI / 180);
}
drawLetters(ctx, radius) {
var ang;
var num;
ctx.font = radius * 0.15 + "px arial";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
var directions = ["N","E","S","W"]
for(num = 0; num < 4; num++){
ang = num * Math.PI / 2;
ctx.rotate(ang);
ctx.translate(0, -radius * 0.85);
ctx.rotate(-ang);
ctx.fillText(directions[num], 0, 0);
ctx.rotate(ang);
ctx.translate(0, radius * 0.85);
ctx.rotate(-ang);
}
}
render() {
const degrees = this.props.value;
return (
<div className="col">
<div className="card">
<div className="card-header">Output Direction</div>
<div className="card-body">
<h5 className="card-title">Direction Displayed here</h5>
<p className="card-text">{degrees}</p>
<canvas ref="compassCanvas" width={300} height={300}/>
</div>
</div>
</div>
)
}
}
class CompassInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleReset = this.handleReset.bind(this);
}
handleChange(e) {
this.props.onDegreesChange(e.target.value);
}
handleReset(e) {
this.props.onDegreesChange(180);
}
render() {
const degrees = this.props.value;
return (
<div className="col">
<div className="card">
<div className="card-header">Input Direction</div>
<div className="card-body">
<h5 className="card-title">Enter the direction of the compass</h5>
<div className="card-text">
<form>
<div className="form-group">
<label htmlFor="formControlRange">Heading</label>
<p>
<span>0</span>
<span className="float-right">360</span>
</p>
<input type="range" className="form-control-range" id="formControlRange" min="0" max="360" style={rangestyle} value={degrees} onChange={this.handleChange}>
</input>
</div>
</form>
<a href="#" className="btn btn-primary" onClick={this.handleReset}>Reset</a>
</div>
</div>
</div>
</div>
)
}
}
const domElement = document.querySelector('#compass');
ReactDOM.render(e(Compass), domElement);
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!--Bootstrap-->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<title>Compass Demo!</title>
</head>
<body>
<!-- Load React. -->
<!-- Note: when deploying, replace "development.js" with "production.min.js". -->
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<div class="container">
<div class="jumbotron">
<h1 class="display-4">Demo page</h1>
<p class="lead">An example to showcase a compass control.</p>
<hr class="my-4">
<p>It uses bootstrap and react. Components are rendered as a parent compass with a input and output child components. Data is passed back up to the parent via a callback function passed to the child via the props. See <a href="https://reactjs.org/docs/lifting-state-up.html">Lifting State Up</a> in the React docs. The rendering of the compass was based on the <a href="https://www.w3schools.com/graphics/canvas_clock.asp">w3schools clock</a></p>
</div>
<div id="compass"></div>
</div>
<!--Our components-->
<script type="text/babel" src="./compass.js" ></script>
</body>
</html>
@Workshopshed
Copy link
Author

Demo page in action

ReactComponentDemo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment