Skip to content

Commit

Permalink
feat(controls): add rotation indicator and reset to minimaps
Browse files Browse the repository at this point in the history
  • Loading branch information
JMaio committed Feb 25, 2021
1 parent 11c0d7c commit 098d24f
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 48 deletions.
11 changes: 10 additions & 1 deletion src/common/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { OpaqueInterpolation } from 'react-spring';
import {
MandelbrotMapsWebGLUniforms,
precisionSpecifier,
ThetaType,
ViewerControlSprings,
XYType,
} from './types';
Expand Down Expand Up @@ -55,9 +56,12 @@ export interface JuliaRendererProps extends RendererProps {

export interface MinimapViewerProps extends WebGLCanvasProps {
canvasRef: React.RefObject<HTMLCanvasElement>;
onClick: () => void;
show: boolean;
id?: string;

controls: ViewerControlSprings;
// zoomOnClick: () => void;
// thetaOnClick: () => void;
// dpr: number;
// u: MandelbrotMapsWebGLUniforms;

Expand All @@ -71,3 +75,8 @@ export interface ViewChangerProps {
/** use this toggle to make the component display nicely for showcase purposes */
displayOnly?: boolean;
}

export interface RotationCompassProps {
theta: OpaqueInterpolation<ThetaType>;
onClick: () => void;
}
8 changes: 4 additions & 4 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
ViewerControlSprings,
ViewerLocation,
} from './types';
import { springsConfigs } from './values';
import { defaultPrecision, springsConfigs } from './values';

// https://usehooks.com/useWindowSize/
export function useWindowSize(): { w: number; h: number } {
Expand Down Expand Up @@ -71,12 +71,12 @@ export interface GenericTouchBindReturn {
// --------------------------------------------------------------------------
// https://gist.github.com/evdokimovm/0e7163faf7c8fe24e41e6b68461e4feb
// Convert from degrees to radians.
const degToRad = (deg: number): number => (deg * Math.PI) / 180;
export const degToRad = (deg: number): number => (deg * Math.PI) / 180;
// Math.radians(90); // 1.5707963267948966

// Convert from radians to degrees.
// eslint-disable-next-line
const radToDeg = (rad: number): number => (rad * 180) / Math.PI;
export const radToDeg = (rad: number): number => (rad * 180) / Math.PI;
// Math.degrees(3.141592653589793); // 180
// --------------------------------------------------------------------------

Expand Down Expand Up @@ -360,7 +360,7 @@ export const warpToPoint = (
{ xyCtrl: [, setXY], zoomCtrl: [, setZ], rotCtrl: [, setR] }: ViewerControlSprings,
// warp destination
{ xy, z, theta }: Partial<ViewerLocation>,
precision: precisionSpecifier,
precision: precisionSpecifier = defaultPrecision,
immediate = false,
): void => {
const conf = springsConfigs(precision);
Expand Down
4 changes: 2 additions & 2 deletions src/components/render/JuliaRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default function JuliaRenderer({
const miniCanvasRef = useRef<HTMLCanvasElement>(null);

const [{ xy }] = props.controls.xyCtrl;
const [{ z }, setControlZoom] = props.controls.zoomCtrl;
const [{ z }] = props.controls.zoomCtrl;
const [{ theta }] = props.controls.rotCtrl;
const maxI = props.maxI; // -> global
const AA = props.useAA ? 2 : 1;
Expand Down Expand Up @@ -76,8 +76,8 @@ export default function JuliaRenderer({
DPR={props.DPR}
u={u}
canvasRef={miniCanvasRef}
onClick={() => setControlZoom({ z: 1 })}
show={settings.showMinimap}
controls={props.controls}
/>
</div>
)}
Expand Down
4 changes: 2 additions & 2 deletions src/components/render/MandelbrotRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export default function MandelbrotRenderer({
// read incoming props
const [{ xy }] = props.controls.xyCtrl;
// const [{ theta, last_pointer_angle }, setControlRot] = props.controls.rot;
const [{ z }, setControlZoom] = props.controls.zoomCtrl;
const [{ z }] = props.controls.zoomCtrl;
const [{ theta }] = props.controls.rotCtrl;
const maxI = props.maxI; // -> global
const AA = props.useAA ? 2 : 1; // -> global
Expand Down Expand Up @@ -119,7 +119,7 @@ export default function MandelbrotRenderer({
canvasRef={miniCanvasRef}
// glRef={miniGl}
show={settings.showMinimap}
onClick={() => setControlZoom({ z: 1 })}
controls={props.controls}
/>
</div>
)}
Expand Down
4 changes: 2 additions & 2 deletions src/components/render/MandelbrotRendererDeep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default function MandelbrotRendererDeep({
// read incoming props
const [{ xy }] = controls.xyCtrl;
// const [{ theta, last_pointer_angle }, setControlRot] = props.controls.rot;
const [{ z }, setControlZoom] = controls.zoomCtrl;
const [{ z }] = controls.zoomCtrl;
const [{ theta }] = controls.rotCtrl;
// const maxI = props.maxI; // -> global
const AA = useAA ? 2 : 1; // -> global
Expand Down Expand Up @@ -136,7 +136,7 @@ export default function MandelbrotRendererDeep({
canvasRef={miniCanvasRef}
// glRef={miniGl}
show={settings.showMinimap}
onClick={() => setControlZoom({ z: 1 })}
controls={controls}
/>
</div>
)}
Expand Down
68 changes: 42 additions & 26 deletions src/components/render/MinimapViewer.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ButtonBase, Grow, makeStyles } from '@material-ui/core';
import { Box, ButtonBase, Grow, makeStyles } from '@material-ui/core';
import React from 'react';
import { MinimapViewerProps } from '../../common/render';
import { simpleBoxShadow } from '../../theme/theme';
import RotationCompass from './RotationCompass';
import WebGLCanvas from './WebGLCanvas';

const miniSize = 100;
Expand All @@ -11,47 +12,62 @@ const useStyles = makeStyles((theme) => ({
},
}));

const MinimapViewer = (props: MinimapViewerProps): JSX.Element => {
const { canvasRef, onClick, show, ...rest } = props;
const MinimapViewer = ({
canvasRef,
show,
controls,
...props
}: MinimapViewerProps): JSX.Element => {
const classes = useStyles();
const {
zoomCtrl: [, setZoom],
rotCtrl: [theta, setTheta],
} = controls;

return (
<Grow in={show}>
<ButtonBase
<Box
style={{
position: 'absolute',
// make minimap stick out through backdrop
zIndex: 1300,
margin: '0.5rem',
left: 0,
bottom: 0,
// cursor: 'pointer',
height: miniSize,
width: miniSize,
// borderRadius: borderRadius,
// border: "1px solid #000",
boxShadow: simpleBoxShadow,
overflow: 'hidden',
// opacity: zoom.interpolate((z) => _.clamp(z - 1, 0, 1)),
// display: zoom.interpolate((z) => (_.clamp(z - 1, 0, 1) === 0 ? 'none' : 'block')),
display: 'flex',
}}
onClick={onClick}
className={classes.root}
>
<WebGLCanvas
id={props.id}
mini={true}
ref={canvasRef}
{...rest}
// setting border radius here stops the canvas clickable area from overflowing
// outside the div circle, which would make the clickable area a rectangle
<RotationCompass theta={theta.theta} onClick={() => setTheta({ theta: 0 })} />
<ButtonBase
style={{
position: 'relative',
// cursor: 'pointer',
height: miniSize,
width: miniSize,
// borderRadius: borderRadius,
// cursor should be "pointer" (looks clickable) if this is a minimap,
cursor: 'pointer',
// border: "1px solid #000",
boxShadow: simpleBoxShadow,
overflow: 'hidden',
// opacity: zoom.interpolate((z) => _.clamp(z - 1, 0, 1)),
// display: zoom.interpolate((z) => (_.clamp(z - 1, 0, 1) === 0 ? 'none' : 'block')),
}}
/>
</ButtonBase>
onClick={() => setZoom({ z: 1 })}
className={classes.root}
>
<WebGLCanvas
mini={true}
ref={canvasRef}
{...props}
// setting border radius here stops the canvas clickable area from overflowing
// outside the div circle, which would make the clickable area a rectangle
style={{
// borderRadius: borderRadius,
// cursor should be "pointer" (looks clickable) if this is a minimap,
cursor: 'pointer',
}}
/>
</ButtonBase>
</Box>
</Grow>
);
};
Expand Down
76 changes: 76 additions & 0 deletions src/components/render/RotationCompass.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { ButtonBase, makeStyles, useTheme } from '@material-ui/core';
import React from 'react';
import { animated } from 'react-spring';
import { RotationCompassProps } from '../../common/render';
import { radToDeg } from '../../common/utils';

const useStyles = makeStyles((theme) => ({
root: {
borderRadius: theme.shape.borderRadius,
},
// awesome compass css @ Taylor Liesnham, from https://codepen.io/Chub/pen/eiHna
arrowUp: {
width: 0,
height: 0,
borderLeft: '4px solid transparent',
borderRight: '4px solid transparent',
borderBottom: `12px solid ${theme.palette.secondary.main}`,
position: 'relative',
},

arrowDown: {
width: 0,
height: 0,
transform: 'rotate(180deg)',
borderLeft: '4px solid transparent',
borderRight: '4px solid transparent',
// borderBottom: '14px solid #F3F3F3',
// borderBottom: '14px solid #3D3D3D',
borderBottom: `12px solid ${theme.palette.grey[100]}`,
position: 'relative',
},
}));

// odd-numbered width/heigh gives it a fixed central point to rotate upon;
// also makes it look far sharper
const compassDiameter = 29;

const RotationCompass = ({ theta, onClick }: RotationCompassProps): JSX.Element => {
const classes = useStyles();
const theme = useTheme();

return (
<ButtonBase
style={{
position: 'absolute',
// right: '50%',
right: 0,
transform: 'translate(25%, -25%)',
height: compassDiameter,
width: compassDiameter,
zIndex: 1301,
borderRadius: compassDiameter,
// cursor: 'pointer',
// border: "1px solid #000",
// boxShadow: simpleBoxShadow,
// overflow: 'hidden',
// opacity: zoom.interpolate((z) => _.clamp(z - 1, 0, 1)),
// display: zoom.interpolate((z) => (_.clamp(z - 1, 0, 1) === 0 ? 'none' : 'block')),
backgroundColor: theme.palette.grey[800],
// backgroundColor: '#3D3D3D',
}}
onClick={onClick}
>
<animated.div
style={{
position: 'relative',
transform: theta.interpolate((t) => `rotate(${radToDeg(t)}deg)`),
}}
>
<div className={classes.arrowUp} />
<div className={classes.arrowDown} />
</animated.div>
</ButtonBase>
);
};
export default RotationCompass;
16 changes: 5 additions & 11 deletions src/components/render/WebGLCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { fullscreenVertexArray, fullVertexShader } from '../../shaders/fullVerte
// https://mariusschulz.com/blog/typing-destructured-object-parameters-in-typescript
// https://stackoverflow.com/a/50294843/9184658
const WebGLCanvas = React.forwardRef<HTMLCanvasElement, WebGLCanvasProps>(
(props: WebGLCanvasProps, refAny) => {
({ u, setFPS, mini, ...props }: WebGLCanvasProps, refAny) => {
// const { mini = false, ...rest } = props;
// props:
// id
Expand All @@ -26,15 +26,9 @@ const WebGLCanvas = React.forwardRef<HTMLCanvasElement, WebGLCanvasProps>(
const bufferInfo = useRef<twgl.BufferInfo>();
const programInfo = useRef<twgl.ProgramInfo>();

const u = props.u;
const setFps = props.setFPS;

// have a zoom callback
// keeps minimaps at a fixed zoom level
const zoom = useCallback(() => (props.mini ? 0.95 : props.u.zoom.getValue()), [
props.mini,
props.u.zoom,
]);
const zoom = useCallback(() => (mini ? 0.95 : u.zoom.getValue()), [mini, u.zoom]);

// const DPR = props.useDPR ? props.DPR : 1;

Expand Down Expand Up @@ -116,15 +110,15 @@ const WebGLCanvas = React.forwardRef<HTMLCanvasElement, WebGLCanvasProps>(
twgl.drawBufferInfo(ctx, buff);

// calculate fps
if (setFps !== undefined) {
if (setFPS !== undefined) {
frames.current++;
elapsedTime.current += time - then.current;
then.current = time;

// console.log(elapsedTime.current);
if (elapsedTime.current >= interval) {
//multiply with (1000 / elapsed) for accuracy
setFps((frames.current * (interval / elapsedTime.current)).toFixed(1));
setFPS((frames.current * (interval / elapsedTime.current)).toFixed(1));
frames.current = 0;
elapsedTime.current -= interval;

Expand All @@ -135,7 +129,7 @@ const WebGLCanvas = React.forwardRef<HTMLCanvasElement, WebGLCanvasProps>(
// The 'state' will always be the initial value here
renderRequestRef.current = requestAnimationFrame(render);
},
[gl, u, zoom, props.DPR, setFps, interval, canvasRef],
[gl, u, zoom, props.DPR, setFPS, interval, canvasRef],
);

useEffect(() => {
Expand Down

0 comments on commit 098d24f

Please sign in to comment.