You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
3.9 KiB
TypeScript
167 lines
3.9 KiB
TypeScript
// Modified from https://github.com/redlanta/react-jazzicon
|
|
|
|
import React from 'react';
|
|
import Color from 'color';
|
|
import { Paper } from './Paper';
|
|
import { RNG } from './RNG';
|
|
|
|
const defaultColors = [
|
|
'#01888c', // teal
|
|
'#fc7500', // bright orange
|
|
'#034f5d', // dark teal
|
|
'#E784BA', // light pink
|
|
'#81C8B6', // bright green
|
|
'#c7144c', // raspberry
|
|
'#f3c100', // goldenrod
|
|
'#1598f2', // lightning blue
|
|
'#2465e1', // sail blue
|
|
'#f19e02', // gold
|
|
];
|
|
|
|
const isColor = (str: string) => /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(str);
|
|
const isColors = (arr: Array<string>) => {
|
|
if (!Array.isArray(arr)) {
|
|
return false;
|
|
}
|
|
|
|
if (arr.every(value => typeof value === 'string' && isColor(value))) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
interface Props {
|
|
diameter: number;
|
|
seed: number;
|
|
paperStyles?: Object;
|
|
svgStyles?: Object;
|
|
shapeCount?: number;
|
|
wobble?: number;
|
|
colors?: Array<string>;
|
|
}
|
|
|
|
// tslint:disable-next-line no-http-string
|
|
const svgns = 'http://www.w3.org/2000/svg';
|
|
const shapeCount = 4;
|
|
const wobble = 30;
|
|
|
|
export class JazzIcon extends React.PureComponent<Props> {
|
|
public render() {
|
|
const {
|
|
colors: customColors,
|
|
diameter,
|
|
paperStyles,
|
|
seed,
|
|
svgStyles,
|
|
} = this.props;
|
|
|
|
const generator = new RNG(seed);
|
|
|
|
const colors = customColors || defaultColors;
|
|
|
|
const newColours = this.hueShift(
|
|
this.colorsForIcon(colors).slice(),
|
|
generator
|
|
);
|
|
const shapesArr = Array(shapeCount).fill(null);
|
|
const shuffledColours = this.shuffleArray(newColours, generator);
|
|
|
|
return (
|
|
<Paper color={shuffledColours[0]} diameter={diameter} style={paperStyles}>
|
|
<svg
|
|
xmlns={svgns}
|
|
x="0"
|
|
y="0"
|
|
height={diameter}
|
|
width={diameter}
|
|
style={svgStyles}
|
|
>
|
|
{shapesArr.map((_, i) =>
|
|
this.genShape(
|
|
shuffledColours[i + 1],
|
|
diameter,
|
|
i,
|
|
shapeCount - 1,
|
|
generator
|
|
)
|
|
)}
|
|
</svg>
|
|
</Paper>
|
|
);
|
|
}
|
|
|
|
private hueShift(colors: Array<string>, generator: RNG) {
|
|
const amount = generator.random() * 30 - wobble / 2;
|
|
|
|
return colors.map(hex =>
|
|
Color(hex)
|
|
.rotate(amount)
|
|
.hex()
|
|
);
|
|
}
|
|
|
|
private genShape(
|
|
colour: string,
|
|
diameter: number,
|
|
i: number,
|
|
total: number,
|
|
generator: RNG
|
|
) {
|
|
const center = diameter / 2;
|
|
const firstRot = generator.random();
|
|
const angle = Math.PI * 2 * firstRot;
|
|
const velocity =
|
|
diameter / total * generator.random() + i * diameter / total;
|
|
const tx = Math.cos(angle) * velocity;
|
|
const ty = Math.sin(angle) * velocity;
|
|
const translate = `translate(${tx} ${ty})`;
|
|
|
|
// Third random is a shape rotation on top of all of that.
|
|
const secondRot = generator.random();
|
|
const rot = firstRot * 360 + secondRot * 180;
|
|
const rotate = `rotate(${rot.toFixed(1)} ${center} ${center})`;
|
|
const transform = `${translate} ${rotate}`;
|
|
|
|
return (
|
|
<rect
|
|
key={i}
|
|
x="0"
|
|
y="0"
|
|
rx="0"
|
|
ry="0"
|
|
height={diameter}
|
|
width={diameter}
|
|
transform={transform}
|
|
fill={colour}
|
|
/>
|
|
);
|
|
}
|
|
|
|
private colorsForIcon(arr: Array<string>) {
|
|
if (isColors(arr)) {
|
|
return arr;
|
|
}
|
|
|
|
return defaultColors;
|
|
}
|
|
|
|
private shuffleArray<T>(array: Array<T>, generator: RNG) {
|
|
let currentIndex = array.length;
|
|
const newArray = [...array];
|
|
|
|
// While there remain elements to shuffle...
|
|
while (currentIndex > 0) {
|
|
// Pick a remaining element...
|
|
const randomIndex = generator.next() % currentIndex;
|
|
currentIndex -= 1;
|
|
// And swap it with the current element.
|
|
const temporaryValue = newArray[currentIndex];
|
|
newArray[currentIndex] = newArray[randomIndex];
|
|
newArray[randomIndex] = temporaryValue;
|
|
}
|
|
|
|
return newArray;
|
|
}
|
|
}
|