-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
103 lines (87 loc) · 2.68 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
const styles = {
enanomapper: [
{ color: '#cf2323', textColor: 'white', radius: 40, text: [0, 0] },
{ color: '#555', textColor: '#555', radius: 70, text: [130, 50] },
{ color: 'grey', textColor: 'grey', radius: 100, text: [130, -80] }
],
nanomaterialRegistry: {
extends: 'enanomapper',
parts: [
{ color: 'orange', textColor: 'white' },
{ color: 'lightblue', textColor: 'lightblue' },
{ color: 'lightgrey', textColor: 'lightgrey', striped: true }
]
}
}
function makeStyle (style = 'enanomapper') {
if (typeof style === 'string') {
return makeStyle(styles[style])
} else if (Array.isArray(style)) {
return style
} else if (!style.extends) {
return style.parts
} else {
const parent = makeStyle(style.extends)
return style.parts.map((part, i) => Object.assign({}, parent[i], part))
}
}
function makePattern (pattern, id, color) {
switch (pattern) {
case 'striped':
return `<pattern id="${id}" width="10%" height="10%" viewbox="0,0,4,4" patternTransform="rotate(45)">
<path stroke="${color}" d="M0,0 V4 M2,0 V4 M4,0 V4"></path>
</pattern>`
case 'dotted':
return `<pattern id="${id}" width="10%" height="10%" viewbox="0,0,3,3">
<circle fill="${color}" r="1" cx="1" cy="1"></circle>
</pattern>`
}
}
function makePart (part, style, defs) {
let fill
if (style.striped && !style.pattern) {
style.pattern = 'striped'
}
if (style.pattern) {
const id = `${style.pattern}-${part.label}`
defs.push(makePattern(style.pattern, id, style.color))
fill = `url(#${id})`
} else {
fill = style.color
}
let textAnchor
let lineEnd
if (style.text[0] > 0) {
textAnchor = 'start'
lineEnd = Math.max(style.text[0] - 5, 0)
} else if (style.text[0] < 0) {
textAnchor = 'end'
lineEnd = Math.min(style.text[0] + 5, 0)
} else {
textAnchor = 'middle'
lineEnd = 0
}
return `<circle fill="${fill}" r="${style.radius}" />
<line stroke="${style.color}" stroke-width="3" x1="0" y1="${style.text[1]}" x2="${lineEnd}" y2="${style.text[1]}" />
<text fill="${style.textColor}" x="${style.text[0]}" y="${style.text[1]}"
alignment-baseline="middle" text-anchor="${textAnchor}">
${part.label}
</text>`
}
module.exports.nanoMaterial = function nanoMaterial (parts, style) {
style = makeStyle(style)
const svg = [
'<svg width="300" height="200" viewBox="-100 -100 300 200" font-weight="bold" xmlns="http://www.w3.org/2000/svg">'
]
const defs = []
const graphics = parts.map((part, i) => part ? makePart(part, style[i], defs) : '').reverse()
svg.push(`
<defs>
${defs.join('\n')}
</defs>
`)
svg.push(graphics.join('\n'))
svg.push(`
</svg>`)
return svg.join('')
}