Sine + Cosine: http://codepen.io/HunorMarton/pen/BpvBeM
Tangent: http://codepen.io/HunorMarton/pen/mRZemO
Tangent + Cotangent: http://codepen.io/HunorMarton/pen/QdXyMR
A Pen by HARUN PEHLİVAN on CodePen.
| <div id="app" /> |
| const Sine = () => { | |
| const [degree, setDegree] = React.useState(0) | |
| // A reference is basically a state that you can change directly | |
| // and that won't trigger rerendering of the component | |
| const lastTimeRef = React.useRef(null); | |
| const frameRef = React.useRef(); | |
| const animate = time => { | |
| if (lastTimeRef.current != null) { | |
| const delta = (time - lastTimeRef.current) * 0.03; | |
| // Because of the unfortunate side effect of the effect's | |
| // second parameter we cannot refer to degree as simple | |
| // as you might would in an other situation. Luckily for | |
| // us though the setter function can accept a function if | |
| // the state is needed to calcualte the next value and | |
| // that function will always have the latest value of the state | |
| setDegree(previousDegree => (previousDegree + delta) % 360); | |
| } | |
| lastTimeRef.current = time; | |
| frameRef.current = requestAnimationFrame(animate); | |
| } | |
| // This effect will run only once because an empty array is passed on | |
| // as a second argument. That empty array has an unfortunate side-effect | |
| // though. If we pass on an empty array then the effect will assume that | |
| // everything is static and it's not worth being up to date with such | |
| // things as the state changes. This behaviour is true for the animate | |
| // function as well so if we are going to try to reference the value of | |
| // degree in there then it will always give back the initial value. | |
| React.useEffect(() => { | |
| frameRef.current = requestAnimationFrame(animate); | |
| return () => cancelAnimationFrame(frameRef.current); | |
| }, []); | |
| return <Draw degree={degree} />; | |
| } | |
| // Note: Math.sin and Math.cos accept a radian value and 360 degrees equal 2 * pi radians | |
| // The sin value is in minus because coordinates in SVGs increase from top to bottom | |
| const sin = value => -Math.sin(value/180*Math.PI) | |
| const cos = value => Math.cos(value/180*Math.PI) | |
| const Draw = ({ degree }) => ( | |
| <svg width='1020' height='240' viewBox='0 -120 1020 240'> | |
| <text x='100'> | |
| sin( | |
| </text> | |
| {/* This is the line that connects the two sides */} | |
| <line | |
| transform='translate(310 0)' | |
| className='thin' | |
| x1={cos(degree) * 100} | |
| y1={sin(degree) * 100} | |
| x2={degree + 250} | |
| y2={sin(degree) * 100} | |
| /> | |
| {/* This is the left side block with the circle*/} | |
| <g transform='translate(310 0)'> | |
| <circle className='thin' cx='0' cy='0' r='100' /> | |
| {/* This is the arc showing the progress (M: move to, A: arc to)*/} | |
| <path d={` | |
| M 30 0 | |
| A 30 30 0 ${degree <= 180 ? 0 : 1} 0 ${cos(degree) * 30} ${sin(degree) * 30} | |
| `} /> | |
| {/* These are the two sides of the angle */} | |
| <line | |
| className='thin' | |
| x1='0' | |
| y1='0' | |
| x2='100' | |
| y2='0' | |
| /> | |
| <line | |
| className='thin' | |
| x1='0' | |
| y1='0' | |
| x2={cos(degree) * 100} | |
| y2={sin(degree) * 100} | |
| /> | |
| {/* This is the degree of the angle */} | |
| <text | |
| x={cos(degree) * 100 + 10} | |
| y={sin(degree) * 100} | |
| > | |
| {Math.round(degree)}° | |
| </text> | |
| </g> | |
| <text x='470'> | |
| ) = | |
| </text> | |
| {/* This is the right side block with the sine wave */} | |
| <g transform='translate(560 0)'> | |
| {/* This is the baseline */} | |
| <line className='thin' x1='0' y1='0' x2='360' y2='0' /> | |
| {/* These are the full sine wave in the background and the in progress one*/} | |
| <polyline className='thin' | |
| points={Array.from( | |
| { length: 360 }, | |
| (v, d) => `${d} ${sin(d) * 100}` | |
| )} | |
| /> | |
| <polyline | |
| points={Array.from( | |
| { length: degree }, | |
| (v, d) => `${d} ${sin(d) * 100}` | |
| )} | |
| /> | |
| {/* This is the value of the sine */} | |
| <text x={degree + 10} y={sin(degree) * 100}> | |
| {parseFloat(Math.sin(degree/180*Math.PI)).toFixed(4)} | |
| </text> | |
| </g> | |
| </svg> | |
| ) | |
| ReactDOM.render(<Sine />, document.getElementById('app')); |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script> |
Sine + Cosine: http://codepen.io/HunorMarton/pen/BpvBeM
Tangent: http://codepen.io/HunorMarton/pen/mRZemO
Tangent + Cotangent: http://codepen.io/HunorMarton/pen/QdXyMR
A Pen by HARUN PEHLİVAN on CodePen.
| @import url('https://fonts.googleapis.com/css?family=Droid+Sans+Mono'); | |
| $font-color: #FF0050; | |
| $primary-color: #C1003D; | |
| $secondary-color: #60001E; | |
| $background-color: #440015; | |
| body { | |
| background-color: $background-color; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| html { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| width: 100%; | |
| height: 100%; | |
| } | |
| svg { | |
| stroke: $primary-color; | |
| fill: transparent; | |
| stroke-width: 8px; | |
| max-width: 100%; | |
| max-height: 100%; | |
| } | |
| .thin { | |
| stroke: $secondary-color; | |
| fill: transparent; | |
| stroke-width: 3px; | |
| } | |
| text { | |
| font-family: 'Droid Sans Mono', monospace; | |
| font-size: 20px; | |
| fill: $font-color; | |
| stroke: $font-color; | |
| stroke-width: 1px; | |
| } |