Files: fc704a02d1ed48331ea440f2de8a5ec2def88696 / index.js
3463 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 | ${moons({ moonRadius: 0.1, centerRadius: 0.7 })} |
11 | ${gears({ centerRadius: 0.15, toothLength: 0.3, toothWidth: 0.2 })} |
12 | </svg> |
13 | ` |
14 | } |
15 | |
16 | function gears ({ centerRadius, toothLength, toothWidth }) { |
17 | return ` |
18 | <style type="text/css"> |
19 | .gear { |
20 | stroke: black; |
21 | stroke-width: ${toothLength / 20}; |
22 | } |
23 | .gear-tooth { |
24 | fill: purple; |
25 | } |
26 | </style> |
27 | <g class="gear"> |
28 | ${range({ start: 0, stop: 1, step: 1/8 }) |
29 | .map(index => gearTooth({ |
30 | angle: (1/16 + index) * 2 * Math.PI, |
31 | offset: centerRadius, |
32 | length: toothLength, |
33 | width: toothWidth |
34 | })) |
35 | .join('\n') |
36 | } |
37 | </g> |
38 | ` |
39 | } |
40 | |
41 | function gearTooth ({ angle, offset, length, width }) { |
42 | return ` |
43 | <g |
44 | class="gear-tooth" |
45 | transform="rotate(${angle * 180 / Math.PI})" |
46 | > |
47 | <rect x="${-width / 2}" y="${offset}" height="${length}" width="${width}" /> |
48 | </g> |
49 | ` |
50 | } |
51 | |
52 | function moons ({ moonRadius, centerRadius }) { |
53 | return ` |
54 | <style type="text/css"> |
55 | .moon { |
56 | stroke: black; |
57 | stroke-width: ${moonRadius / 20}; |
58 | } |
59 | .moon-front { |
60 | fill: white; |
61 | } |
62 | .moon-back { |
63 | fill: purple; |
64 | } |
65 | </style> |
66 | ${range({ start: 0, stop: 1, step: 1/8 }) |
67 | .map(index => moon({ |
68 | radius: moonRadius, |
69 | center: rotate({ angle: index * 2 * Math.PI, point: { x: 0, y: centerRadius } }), |
70 | phase: index |
71 | })) |
72 | .join('\n') |
73 | } |
74 | ` |
75 | } |
76 | |
77 | // inspired by https://github.com/tingletech/moon-phase |
78 | function moon ({ radius, center, phase }) { |
79 | var sweep = [] |
80 | var mag |
81 | |
82 | // the "sweep-flag" and the direction of movement change every quarter moon |
83 | // zero and one are both new moon; 0.50 is full moon |
84 | if (phase <= 0.25) { |
85 | sweep = [ 1, 0 ] |
86 | mag = 1 - phase * 4 |
87 | } else if (phase <= 0.50) { |
88 | sweep = [ 0, 0 ] |
89 | mag = (phase - 0.25) * 4 |
90 | } else if (phase <= 0.75) { |
91 | sweep = [ 1, 1 ] |
92 | mag = 1 - (phase - 0.50) * 4 |
93 | } else if (phase <= 1) { |
94 | sweep = [ 0, 1 ] |
95 | mag = (phase - 0.75) * 4 |
96 | } else { |
97 | throw new Error(`unexpected moon phase: ${phase}`) |
98 | } |
99 | |
100 | // http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands |
101 | // http://www.i-programmer.info/programming/graphics-and-imaging/3254-svg-javascript-and-the-dom.html |
102 | |
103 | var r = radius / 5 |
104 | |
105 | return ` |
106 | <g class="moon"> |
107 | <path |
108 | class="moon-back" |
109 | d="M ${center.x},${center.y - radius / 2} |
110 | a ${r},${r} 0 1,1 0,${radius} |
111 | a ${r},${r} 0 1,1 0,-${radius}" |
112 | /> |
113 | <path |
114 | class="moon-front" |
115 | d="M ${center.x},${center.y - radius / 2} |
116 | a ${mag * r},${r} 0 1,${sweep[0]} 0,${radius} |
117 | a ${r},${r} 0 1,${sweep[1]} 0,-${radius}" |
118 | /> |
119 | </g> |
120 | ` |
121 | } |
122 | |
123 | function rotate ({ center = { x: 0, y: 0}, angle, point }) { |
124 | const a = Math.atan2(point.y - center.y, point.x - center.x) |
125 | const r = Math.sqrt(Math.pow(point.x - center.x, 2) + Math.pow(point.y - center.y, 2)) |
126 | return { |
127 | x: r * Math.cos(a + angle), |
128 | y: r * Math.sin(a + angle) |
129 | } |
130 | } |
131 | |
132 | |
133 | // https://stackoverflow.com/a/44957114 |
134 | function range ({ start = 0, stop, step = 1 }) { |
135 | return Array(Math.ceil((stop - start) / step)) |
136 | .fill(start).map((x, y) => x + y * step) |
137 | } |
138 |
Built with git-ssb-web