Created
December 13, 2019 22:13
-
-
Save Workshopshed/0dec02a0f5a59da2f3013d591ae925a9 to your computer and use it in GitHub Desktop.
Synchronising React components
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Demo page in action