Files: 769478285595bed29bf26168093589c868b286ee / index.js
4921 bytesRaw
1 | module.exports = solarpunkIcon |
2 | |
3 | function solarpunkIcon () { |
4 | return ` |
5 | <svg |
6 | xmlns="http://www.w3.org/2000/svg" |
7 | xmlns:xlink="http://www.w3.org/1999/xlink" |
8 | viewBox="-1 -1 2 2" |
9 | > |
10 | ${plants({ size: 0.25, offsetRadius: 0.2 })} |
11 | ${gear({ offsetRadius: 0.15, toothLength: 0.3, toothWidth: 0.2 })} |
12 | ${moons({ moonRadius: 0.2, offsetRadius: 0.7 })} |
13 | </svg> |
14 | ` |
15 | } |
16 | |
17 | function gear ({ offsetRadius, toothLength, toothWidth }) { |
18 | return ` |
19 | <style type="text/css"> |
20 | .gear { |
21 | stroke: black; |
22 | stroke-width: ${toothLength / 20}; |
23 | } |
24 | .gear-tooth { |
25 | fill: purple; |
26 | } |
27 | </style> |
28 | <g class="gear"> |
29 | ${range({ start: 0, stop: 1, step: 1 / 8 }) |
30 | .map(index => gearTooth({ |
31 | angle: (1 / 16 + index) * 2 * Math.PI, |
32 | offset: offsetRadius, |
33 | length: toothLength, |
34 | width: toothWidth |
35 | })) |
36 | .join('\n') |
37 | } |
38 | </g> |
39 | ` |
40 | } |
41 | |
42 | function gearTooth ({ angle, offset, length, width }) { |
43 | return ` |
44 | <g |
45 | class="gear-tooth" |
46 | transform="rotate(${angle * 180 / Math.PI})" |
47 | > |
48 | <rect x="${-width / 2}" y="${offset}" height="${length}" width="${width}" /> |
49 | </g> |
50 | ` |
51 | } |
52 | |
53 | function plants ({ size, offsetRadius }) { |
54 | return ` |
55 | <style type="text/css"> |
56 | .plant { |
57 | stroke: black; |
58 | stroke-width: ${size / 20}; |
59 | } |
60 | .plant-stem { |
61 | fill: none; |
62 | } |
63 | .plant-leaf { |
64 | fill: green; |
65 | } |
66 | </style> |
67 | ${range({ start: 0, stop: 1, step: 1 / 8 }) |
68 | .map(index => plant({ |
69 | size, |
70 | angle: index * 2 * Math.PI, |
71 | offsetRadius |
72 | })) |
73 | .join('\n') |
74 | } |
75 | ` |
76 | } |
77 | |
78 | function plant ({ size, angle, offsetRadius }) { |
79 | return ` |
80 | <g |
81 | class="plant" |
82 | transform=" |
83 | rotate(${angle * 180 / Math.PI}) |
84 | translate(0, ${offsetRadius}) |
85 | " |
86 | > |
87 | <path class="plant-stem" |
88 | d=" |
89 | M 0,0 |
90 | L 0,${size} |
91 | " |
92 | /> |
93 | ${plantStem({ size, direction: 1 })} |
94 | ${plantStem({ size, direction: -1 })} |
95 | ${plantLeaf({ size, direction: 1 })} |
96 | ${plantLeaf({ size, direction: -1 })} |
97 | </g> |
98 | ` |
99 | } |
100 | |
101 | function plantStem ({ size, direction }) { |
102 | return ` |
103 | <path class="plant-stem" |
104 | d=" |
105 | M 0,${size * 0.9} |
106 | C 0,${size * 0.8} 0,${size * 1.2} ${size * direction * 0.3},${size * 1.4} |
107 | " |
108 | /> |
109 | ` |
110 | } |
111 | |
112 | function plantLeaf ({ size, direction }) { |
113 | return ` |
114 | <path class="plant-leaf" |
115 | d=" |
116 | M ${size * direction * 0.3},${size * 1.4} |
117 | a ${size},${size} -45 0,0 ${size * direction * 0.8},${size * 0.6} |
118 | A ${size},${size} -45 0,0 ${size * direction * 0.3},${size * 1.4} |
119 | " |
120 | /> |
121 | ` |
122 | } |
123 | |
124 | function moons ({ moonRadius, offsetRadius }) { |
125 | return ` |
126 | <style type="text/css"> |
127 | .moon { |
128 | stroke: black; |
129 | stroke-width: ${moonRadius / 20}; |
130 | } |
131 | .moon-front { |
132 | fill: white; |
133 | } |
134 | .moon-back { |
135 | fill: purple; |
136 | } |
137 | </style> |
138 | ${range({ start: 0, stop: 1, step: 1 / 8 }) |
139 | .map(index => moon({ |
140 | radius: moonRadius, |
141 | center: rotate({ angle: index * 2 * Math.PI, point: { x: 0, y: offsetRadius } }), |
142 | phase: index |
143 | })) |
144 | .join('\n') |
145 | } |
146 | ` |
147 | } |
148 | |
149 | // inspired by https://github.com/tingletech/moon-phase |
150 | function moon ({ radius, center, phase }) { |
151 | var sweep = [] |
152 | var mag |
153 | |
154 | // the "sweep-flag" and the direction of movement change every quarter moon |
155 | // zero and one are both new moon; 0.50 is full moon |
156 | if (phase <= 0.25) { |
157 | sweep = [ 1, 0 ] |
158 | mag = 1 - phase * 4 |
159 | } else if (phase <= 0.50) { |
160 | sweep = [ 0, 0 ] |
161 | mag = (phase - 0.25) * 4 |
162 | } else if (phase <= 0.75) { |
163 | sweep = [ 1, 1 ] |
164 | mag = 1 - (phase - 0.50) * 4 |
165 | } else if (phase <= 1) { |
166 | sweep = [ 0, 1 ] |
167 | mag = (phase - 0.75) * 4 |
168 | } else { |
169 | throw new Error(`unexpected moon phase: ${phase}`) |
170 | } |
171 | |
172 | // http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands |
173 | // http://www.i-programmer.info/programming/graphics-and-imaging/3254-svg-javascript-and-the-dom.html |
174 | |
175 | var r = radius / 5 |
176 | |
177 | return ` |
178 | <g class="moon"> |
179 | <path |
180 | class="moon-back" |
181 | d="M ${center.x},${center.y - radius / 2} |
182 | a ${r},${r} 0 1,1 0,${radius} |
183 | a ${r},${r} 0 1,1 0,-${radius}" |
184 | /> |
185 | <path |
186 | class="moon-front" |
187 | d="M ${center.x},${center.y - radius / 2} |
188 | a ${mag * r},${r} 0 1,${sweep[0]} 0,${radius} |
189 | a ${r},${r} 0 1,${sweep[1]} 0,-${radius}" |
190 | /> |
191 | </g> |
192 | ` |
193 | } |
194 | |
195 | function rotate ({ center = { x: 0, y: 0 }, angle, point }) { |
196 | const a = Math.atan2(point.y - center.y, point.x - center.x) |
197 | const r = Math.sqrt(Math.pow(point.x - center.x, 2) + Math.pow(point.y - center.y, 2)) |
198 | return { |
199 | x: r * Math.cos(a + angle), |
200 | y: r * Math.sin(a + angle) |
201 | } |
202 | } |
203 | |
204 | // https://stackoverflow.com/a/44957114 |
205 | function range ({ start = 0, stop, step = 1 }) { |
206 | return Array(Math.ceil((stop - start) / step)) |
207 | .fill(start).map((x, y) => x + y * step) |
208 | } |
209 |
Built with git-ssb-web