Skip to content

Commit a14710f

Browse files
authored
Merge pull request #43 from dapi-labs/seed
seed generation
2 parents c1db8e8 + 0e5d96b commit a14710f

File tree

7 files changed

+116
-43
lines changed

7 files changed

+116
-43
lines changed

README.md

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,22 @@ yarn add react-nice-avatar
4242
```js
4343
import Avatar, { genConfig } from 'react-nice-avatar'
4444
```
45-
2. Generate a random configuration, save it so that you can always rendering a same avatar with the configuration.
45+
2. Generate a configuration
46+
47+
Config can be generated with a seed, seed is a string of name, email or anything you like
4648
```js
47-
const config = genConfig(AvatarConfig?)
49+
const config = genConfig("[email protected]")
4850
```
4951

50-
`tip`: AvatarConfig is an Object, plz check the **Options** below for what attributes can be passed in
52+
or it can be generate with customized object, plz check the Options below for what attributes can be passed in
53+
```js
54+
const config = genConfig({ sex: "man", hairStyle: "mohawk" })
55+
```
56+
57+
or generate a random config by passing nothing to the function genConfig
58+
```js
59+
const config = genConfig()
60+
```
5161

5262
3. Render the component with specific width / height and configuration.
5363
```jsx
@@ -126,15 +136,3 @@ The options can be passed into genConfig or as React props
126136
## License
127137

128138
Released under [MIT](/LICENSE) by [@dapi-labs](https://github.com/dapi-labs).
129-
130-
---
131-
132-
<br />
133-
134-
<div align="center">
135-
<a href="https://dapiok.com">
136-
<img src="https://user-images.githubusercontent.com/5305874/131276202-ee5f6941-531c-4c01-bbc4-3ff8aca0e629.png" width="260" alt="dapi">
137-
</a>
138-
</div>
139-
140-
<br />

demo/src/App/index.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@
44
background: #000;
55
color: #fff;
66
}
7+
8+
.inputField {
9+
background: rgba(255, 255, 255, 0.1);
10+
}

demo/src/App/index.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ class App extends Component {
5454
}
5555
}
5656

57+
onInputKeyUp (e) {
58+
this.setState({
59+
config: genConfig(e.target.value)
60+
})
61+
}
62+
5763
render() {
5864
const { config, shape } = this.state
5965
return (
@@ -74,6 +80,10 @@ class App extends Component {
7480
updateConfig={this.updateConfig.bind(this)}
7581
updateShape={this.updateShape.bind(this)}
7682
download={this.download.bind(this)} />
83+
<input
84+
className="w-64 h-10 p-2 rounded mt-10 inputField text-center outline-none"
85+
placeholder="input name or email ..."
86+
onKeyUp={this.onInputKeyUp.bind(this)} />
7787
</main>
7888

7989
{/* Avatar list */}

demo/tsconfig.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88
"target": "es5", // specify ECMAScript target version
99
"allowJs": true, // allow a partial TypeScript and JavaScript codebase
1010
"allowSyntheticDefaultImports": true, // import default
11-
"baseUrl": "."
11+
"baseUrl": ".",
12+
"path": {
13+
"react-nice-avatar/*": "../src/*"
14+
}
1215
},
1316
"include": [
1417
"./src",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-nice-avatar",
3-
"version": "1.2.4",
3+
"version": "1.3.0",
44
"description": "react library for generating avatar",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export interface NiceAvatarProps extends AvatarConfig {
4747
shape?: "circle" | "rounded" | "square"
4848
}
4949

50-
export type GenConfigFunc = (config?: AvatarFullConfig) => Required<AvatarFullConfig>
50+
export type GenConfigFunc = (config?: AvatarFullConfig | string) => Required<AvatarFullConfig>
5151

5252
export declare const genConfig: GenConfigFunc
5353

src/utils.ts

Lines changed: 83 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ interface PickRandomOpt<T> {
2121
avoidList?: T[],
2222
usually?: T[]
2323
}
24+
2425
type PickRandomFromList = <T>(data: T[], opt?: PickRandomOpt<T | undefined>) => T;
26+
2527
export const pickRandomFromList: PickRandomFromList = (data, { avoidList = [], usually = [] } = {}) => {
2628
// Filter out avoid options
2729
const avoidSet = new Set(
@@ -66,6 +68,7 @@ interface DefaultOptions {
6668
bgColor: string[],
6769
gradientBgColor: string[]
6870
}
71+
6972
export const defaultOptions: DefaultOptions = {
7073
sex: ["man", "woman"],
7174
faceColor: ["#F9C9B6", "#AC6651"],
@@ -93,21 +96,61 @@ export const defaultOptions: DefaultOptions = {
9396
"linear-gradient(45deg, #56b5f0 0%, #45ccb5 100%)"
9497
]
9598
};
99+
100+
const stringToHashCode = (str: string) : number => {
101+
if (str.length === 0) return 0
102+
let hash = 0
103+
let char
104+
for (let i = 0; i < str.length; i++) {
105+
char = str.charCodeAt(i);
106+
hash = ((hash << 5) - hash) + char;
107+
hash |= 0; // Convert to 32bit integer
108+
}
109+
return Math.abs(hash);
110+
}
111+
112+
type PickByHashCodeOpts = {
113+
avoidList?: string[],
114+
usually?: string[]
115+
}
116+
const pickByHashCode = (code: number, type: keyof DefaultOptions, opts?: PickByHashCodeOpts): string => {
117+
const avoidList = opts && opts.avoidList || []
118+
const usually = opts && opts.usually || []
119+
120+
// Filter out avoid options
121+
const avoidSet = new Set<string>(avoidList)
122+
let myDefaultOptions = defaultOptions[type].filter(item => !avoidSet.has(item))
123+
124+
// Increase selecting possibility of usually options
125+
myDefaultOptions = usually
126+
.filter(Boolean)
127+
.reduce(
128+
(acc, cur) => acc.concat(new Array(15).fill(cur)),
129+
[] as string[]
130+
)
131+
.concat(myDefaultOptions)
132+
133+
const index = code % myDefaultOptions.length
134+
return myDefaultOptions[index]
135+
}
136+
96137
export const genConfig: GenConfigFunc = (userConfig = {}) => {
138+
const isSeedConfig = typeof userConfig === 'string';
139+
const hashCode = isSeedConfig && stringToHashCode(userConfig) || 0
97140
const response = {} as Required<AvatarFullConfig>;
98-
response.sex = userConfig.sex || pickRandomFromList(defaultOptions.sex);
99-
response.faceColor = userConfig.faceColor || pickRandomFromList(defaultOptions.faceColor);
100-
response.earSize = userConfig.earSize || pickRandomFromList(defaultOptions.earSize);
101-
response.eyeStyle = userConfig.eyeStyle || pickRandomFromList(defaultOptions.eyeStyle);
102-
response.noseStyle = userConfig.noseStyle || pickRandomFromList(defaultOptions.noseStyle);
103-
response.mouthStyle = userConfig.mouthStyle || pickRandomFromList(defaultOptions.mouthStyle);
104-
response.shirtStyle = userConfig.shirtStyle || pickRandomFromList(defaultOptions.shirtStyle);
105-
response.glassesStyle = userConfig.glassesStyle || pickRandomFromList(defaultOptions.glassesStyle, { usually: ["none"] });
141+
response.sex = isSeedConfig ? pickByHashCode(hashCode, 'sex') as Sex : (userConfig.sex || pickRandomFromList(defaultOptions.sex));
142+
response.faceColor = isSeedConfig ? pickByHashCode(hashCode, 'faceColor') : (userConfig.faceColor || pickRandomFromList(defaultOptions.faceColor));
143+
response.earSize = isSeedConfig ? pickByHashCode(hashCode, 'earSize') as EarSize : (userConfig.earSize || pickRandomFromList(defaultOptions.earSize));
144+
response.eyeStyle = isSeedConfig ? pickByHashCode(hashCode, 'eyeStyle') as EyeStyle : (userConfig.eyeStyle || pickRandomFromList(defaultOptions.eyeStyle));
145+
response.noseStyle = isSeedConfig ? pickByHashCode(hashCode, 'noseStyle') as NoseStyle : (userConfig.noseStyle || pickRandomFromList(defaultOptions.noseStyle));
146+
response.mouthStyle = isSeedConfig ? pickByHashCode(hashCode, 'mouthStyle') as MouthStyle : (userConfig.mouthStyle || pickRandomFromList(defaultOptions.mouthStyle));
147+
response.shirtStyle = isSeedConfig ? pickByHashCode(hashCode, 'shirtStyle') as ShirtStyle : (userConfig.shirtStyle || pickRandomFromList(defaultOptions.shirtStyle));
148+
response.glassesStyle = isSeedConfig ? pickByHashCode(hashCode, 'glassesStyle', { usually: ["none"] }) as GlassesStyle : (userConfig.glassesStyle || pickRandomFromList(defaultOptions.glassesStyle, { usually: ["none"] }));
106149

107150
// Hair
108151
let hairColorAvoidList: string[] = [];
109152
let hairColorUsually: string[] = [];
110-
if (!userConfig.hairColor) {
153+
if (isSeedConfig || !userConfig.hairColor) {
111154
switch (response.sex) {
112155
case "woman": {
113156
hairColorAvoidList = response.faceColor === defaultOptions.faceColor[1] && ["#77311D"] || [];
@@ -118,48 +161,63 @@ export const genConfig: GenConfigFunc = (userConfig = {}) => {
118161
}
119162
}
120163
}
121-
response.hairColor = userConfig.hairColor || pickRandomFromList(defaultOptions.hairColor, {
122-
avoidList: hairColorAvoidList,
123-
usually: hairColorUsually
124-
});
164+
response.hairColor = isSeedConfig
165+
? pickByHashCode(hashCode, 'hairColor', {
166+
avoidList: hairColorAvoidList,
167+
usually: hairColorUsually
168+
})
169+
: (userConfig.hairColor || pickRandomFromList(defaultOptions.hairColor, {
170+
avoidList: hairColorAvoidList,
171+
usually: hairColorUsually
172+
}));
125173

126-
let myHairStyle = userConfig.hairStyle;
127-
if (!myHairStyle) {
174+
if (isSeedConfig || !userConfig.hairStyle) {
128175
switch (response.sex) {
129176
case "man": {
130-
myHairStyle = pickRandomFromList(defaultOptions.hairStyleMan, { usually: ["normal", "thick"] });
177+
response.hairStyle = isSeedConfig
178+
? pickByHashCode(hashCode, 'hairStyleMan', { usually: ["normal", "thick"] }) as HairStyleMan
179+
: pickRandomFromList(defaultOptions.hairStyleMan, { usually: ["normal", "thick"] });
131180
break;
132181
}
133182
case "woman": {
134-
myHairStyle = pickRandomFromList(defaultOptions.hairStyleWoman);
183+
response.hairStyle = isSeedConfig
184+
? pickByHashCode(hashCode, 'hairStyleWoman') as HairStyleWoman
185+
: pickRandomFromList(defaultOptions.hairStyleWoman);
135186
break;
136187
}
137188
}
138189
}
139-
response.hairStyle = myHairStyle;
140190

141191
// Hat
142-
response.hatStyle = userConfig.hatStyle || pickRandomFromList(defaultOptions.hatStyle, { usually: ["none"] });
143-
response.hatColor = userConfig.hatColor || pickRandomFromList(defaultOptions.hatColor);
192+
response.hatStyle = isSeedConfig
193+
? pickByHashCode(hashCode, 'hatStyle', { usually: ["none"] }) as HatStyle
194+
: (userConfig.hatStyle || pickRandomFromList(defaultOptions.hatStyle, { usually: ["none"] }));
195+
response.hatColor = isSeedConfig ? pickByHashCode(hashCode, 'hatColor') : (userConfig.hatColor || pickRandomFromList(defaultOptions.hatColor));
144196
const _hairOrHatColor = response.hatStyle === "none" && response.hairColor || response.hatColor;
145197

146198
// Eyebrow
147-
if (userConfig.eyeBrowStyle) {
199+
if (!isSeedConfig && userConfig.eyeBrowStyle) {
148200
response.eyeBrowStyle = userConfig.eyeBrowStyle
149201
} else {
150202
response.eyeBrowStyle = response.sex === "woman"
151-
? pickRandomFromList(defaultOptions.eyeBrowWoman)
203+
? isSeedConfig
204+
? pickByHashCode(hashCode, 'eyeBrowWoman') as EyeBrowStyle
205+
: pickRandomFromList(defaultOptions.eyeBrowWoman)
152206
: "up"
153207
}
154208

155209
// Shirt color
156-
response.shirtColor = userConfig.shirtColor || pickRandomFromList(defaultOptions.shirtColor, { avoidList: [_hairOrHatColor] });
210+
response.shirtColor = isSeedConfig
211+
? pickByHashCode(hashCode, 'shirtColor', { avoidList: [_hairOrHatColor] })
212+
: userConfig.shirtColor || pickRandomFromList(defaultOptions.shirtColor, { avoidList: [_hairOrHatColor] });
157213

158214
// Background color
159-
if (userConfig.isGradient) {
215+
if (!isSeedConfig && userConfig.isGradient) {
160216
response.bgColor = userConfig.bgColor || pickRandomFromList(defaultOptions.gradientBgColor);
161217
} else {
162-
response.bgColor = userConfig.bgColor || pickRandomFromList(defaultOptions.bgColor, { avoidList: [_hairOrHatColor, response.shirtColor] });
218+
response.bgColor = isSeedConfig
219+
? pickByHashCode(hashCode, 'bgColor', { avoidList: [_hairOrHatColor, response.shirtColor] })
220+
: userConfig.bgColor || pickRandomFromList(defaultOptions.bgColor, { avoidList: [_hairOrHatColor, response.shirtColor] });
163221
}
164222

165223
return response;

0 commit comments

Comments
 (0)