Skip to content

Instantly share code, notes, and snippets.

@Youngestdev
Created February 17, 2019 04:04
Show Gist options
  • Select an option

  • Save Youngestdev/cc5e487fc7f10b1f25957ab54990a922 to your computer and use it in GitHub Desktop.

Select an option

Save Youngestdev/cc5e487fc7f10b1f25957ab54990a922 to your computer and use it in GitHub Desktop.
Converting from class to functional.
import React, {useEffect, useRef } from 'react';
import Rough from 'roughjs/dist/rough.umd';
import useForceUpdate from 'use-force-update';
const RoughContext = React.createContext();
const __VALID_KEYS__ = [
'bowing',
'fill',
'fillStyle',
'fillWeight',
'hachureAngle',
'hachureGap',
'height',
'width',
'roughness',
'stroke',
'strokeWidth'
];
export const NodeMounter = props => {
const ref = useRef('');
const { node } = props;
ref.appendChild(node);
useEffect(() => {
//Perhaps there's something fishy here ?
ref.current.removeChild(node);
ref.current.appendChild(node);
return () => {
const { node } = props;
ref.current.removeChild(node);
}
}, []);
return <g ref={ref} />;
};
const RoughConsumer = ({ type, dataString, points, ...data }) => (
<RoughContext.Consumer>
{contextValue => {
if (typeof contextValue === 'undefined') {
throw new Error('ReactRough Component not found!');
}
const dataArray = Object.keys(data);
for (let i = 0, len = dataArray.length; i < len; i++) {
if (!__VALID_KEYS__.includes(dataArray[i])) {
throw new Error(
`Invalid key "${dataArray[i]}" assigned to "${type} component"`
);
}
}
let node = null;
if (contextValue.rc) {
if (type === 'path') {
if (typeof points !== 'undefined') {
throw new Error(
'You need a dataString property for path, not points'
);
}
node = contextValue.rc[type](dataString, data);
} else {
node = contextValue.rc[type](...points, data);
}
return contextValue.renderer === 'svg' ? (
<NodeMounter node={node} />
) : null;
}
return null;
}}
</RoughContext.Consumer>
);
export const Arc = props => <RoughConsumer type="arc" {...props} />;
export const Circle = props => <RoughConsumer type="circle" {...props} />;
export const Curve = props => <RoughConsumer type="curve" {...props} />;
export const Ellipse = props => <RoughConsumer type="ellipse" {...props} />;
export const Line = props => <RoughConsumer type="line" {...props} />;
export const Path = props => <RoughConsumer type="path" {...props} />;
export const LinearPath = props => (
<RoughConsumer type="linearPath" {...props} />
);
export const Polygon = props => <RoughConsumer type="polygon" {...props} />;
export const Rectangle = props => <RoughConsumer type="rectangle" {...props} />;
const ReactRough = props => {
const { renderer, width, height, backgroundColor } = props;
const forceUpdate = useForceUpdate();
let ctx, rc;
let rendererRef = useRef('');
useEffect(() => {
const { renderer } = props;
ctx =
renderer === 'canvas' && rendererRef.current.getContext('2d');
rc = Rough[renderer](rendererRef.current);
// TODO: this.forceUpdate();
forceUpdate();
}, []);
const clearCanvas = () => {
const { backgroundColor, width, height } = props;
// If this is the first render the ctx will be null
// It will be cleared later in the useEffect arc
if ( !ctx ) {
return;
}
if ( backgroundColor ) {
ctx.save();
ctx.fillstyle = backgroundColor;
ctx.fillRect(0, 0, width, height);
ctx.restore();
} else {
ctx.clearRect(0, 0, width, height);
}
};
const redraw = () => forceUpdate();
let children = props.children;
const rendererOptions = {
width,
height
};
// First clear the canvas in case of a new render.
if ( renderer === 'canvas') {
clearCanvas();
} else {
rendererOptions.style = { backgroundColor };
}
const Renderer = renderer;
return(
<RoughContext.Provider value={{ rc: rc, renderer }}>
<Renderer {...rendererOptions} ref={rendererRef}>
{children}
</Renderer>
</RoughContext.Provider>
);
};
ReactRough.defaultProps = {
width: 500,
height: 500,
renderer: 'canvas'
};
export default ReactRough;
@Youngestdev
Copy link
Copy Markdown
Author

SO 17 tests passed. The remaining four failed - 3 of them were issues with .prototype. They should be pretty easy to fix by an expert, I'm not stressing my brain. Perhaps, take a look @ooade ?

@ooade
Copy link
Copy Markdown

ooade commented Feb 17, 2019

I'll be going to church now. Perhaps, later

@Youngestdev
Copy link
Copy Markdown
Author

Oh ok.

@ooade
Copy link
Copy Markdown

ooade commented Feb 17, 2019

I still don't have access to my laptop but I'm my phone anyways. I'm not sure we need use force-update. Did you see my chat with Dan and Kent yesterday?

@ooade
Copy link
Copy Markdown

ooade commented Feb 17, 2019

I'll just paste what I wanted. One could force update like this.
We'll just make use of useState to achieve that. No need for an extra dependency

@Youngestdev
Copy link
Copy Markdown
Author

Oh ok pretty nice. I'll remove the extra dependency. I actually thought of that aporocahc but was also thinking, create a state object we won't use ?. I think the useState approach is >>> tho if we look at build size etc

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