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;
 | 
						|
  }
 | 
						|
}
 |