-
Notifications
You must be signed in to change notification settings - Fork 2
/
final.html
234 lines (168 loc) · 10.4 KB
/
final.html
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
<meta charset=utf-8>
<body id=b>
<center>
<canvas id=a width=1090 height=700>
<script>
c=a.getContext("2d");
a.style.maxWidth="99%";
/*** entry ***/
// ================= //
// JS1k'16 //
// //
// PERIOD1K TABLE //
// //
// by //
// Maxime Euzière //
// Tommy Hodgins //
// Anton Khlynovskiy //
// ================= //
// Updated in june 2016 with the four new elements names
// --------------
// Introduction
// --------------
// This demo draws a periodic table of chemical elements on a 1090*700 px canvas, including as much useful information as possible, in 1kb.
// It is drawn from top-left to bottom-right using a single loop and two variables:
// i represents the current atomic number (values: 1-56,71-88,103-118-57-70,89-102).
// j represents the current cell of the periodic table (including "gaps", values: 0-178).
// The cells measure 58*58px and are separated by 2px gutters.
// The page's background is colored in black using the ancestral hack "b.bgColor=0" (b is the page's <body>).
// The coordinates of an element are computed from j: horizontally "j%18*60", vertically "~~(j/18)*60".
// These coordinates are repeated many times in the source code, instead of being set in variables like x and y, to optimize RegPack compression.
for(i=j=b.bgColor=0;j<178;){
// --------------------
// 1: Element's group
// --------------------
// The periodic table represents the element groups as a background color for each element.
// According to https://en.wikipedia.org/wiki/Names_for_sets_of_chemical_elements ,
// There are a ton of different and overlapping element groups, and all periodic tables are a little different because of that.
// Here's our classification:
// 0: Alkali metals – Li, Na, K, Rb, Cs, Fr.
// 1: Alkaline earth metals – Be, Mg, Ca, Sr, Ba, Ra.
// 2: Halogens – F, Cl, Br, I, At.
// 3: Noble gases – He, Ne, Ar, Kr, Xe, Rn.
// 4: Lanthanoids – La, Ce, Pr, Nd, Pm, Sm, Eu, Gd, Tb, Dy, Ho, Er, Tm, Yb, Lu.
// 5: Actinoids – Ac, Th, Pa, U, Np, Pu, Am, Cm, Bk, Cf, Es, Fm, Md, No, Lr.
// 6: Transition metals – Elements in groups 3 to 12.
// 7: poor metals: Al, Ga, In, Sn, Tl, Pb, Bi, Po.
// 8: Metalloids – B, Si, Ge, As, Sb, Te, At (too).
// 9: non-metals: H, C, N, O, P, S, Se.
// These sets are numbered from 0 to 9 and placed in a 118-char string (1 char per element).
// Each element's char is multiplied by 35 (thanks to duck-typing) to define the hue of the hsl background color.
// Then the rectangle is drawn
c.fillStyle="hsl("+"9301899923017899230166666666667889230166666666667788230144444444444444466666666677772301555555555555555666666666777723"[i]*35+",48%,48%)";
c.fillRect(j%18*60,~~(j/18)*60+30,58,58);
// -------------------
// 2. Element's name
// -------------------
// The 118 elements' abbreviated names are drawn in the middle of each cell with a little shadow effect.
// These names were concatenated in a long string like that:
//
// ["H","He","Li","Be","B","C","N","O","F","Ne","Na","Mg","Al","Si","P","S","Cl","Ar","K","Ca","Sc","Ti",
// "V","Cr","Mn","Fe","Co","Ni","Cu","Zn","Ga","Ge","As","Se","Br","Kr","Rb","Sr","Y","Zr","Nb","Mo","Tc",
// "Ru","Rh","Pd","Ag","Cd","In","Sn","Sb","Te","I","Xe","Cs","Ba","La","Ce","Pr","Nd","Pm","Sm","Eu","Gd",
// "Tb","Dy","Ho","Er","Tm","Yb","Lu","Hf","Ta","W","Re","Os","Ir","Pt","Au","Hg","Tl","Pb","Bi","Po","At",
// "Rn","Fr","Ra","Ac","Th","Pa","U","Np","Pu","Am","Cm","Bk","Cf","Es","Fm","Md","No","Lr","Rf","Db","Sg",
// "Bh","Hs","Mt","Ds","Rg","Cn","Nh","Fl","Mc","Lv","Ts","Og].join();
//
// The resulting string, used in the code below, is split before each uppercase letter to retrieve the array above.
// The name is drawn two times (in gray and in white) with a small offset to make a text-shadow effect.
// The two long fillText() statements are repeated on purpose, to optimize RegPack compression.
// Set font size, centering, shadow color
c.font="bold 15pt arial";
c.textAlign="center";
c.fillStyle="#444";
// Draw text shadow
c.fillText("HHeLiBeBCNOFNeNaMgAlSiPSClArKCaScTiVCrMnFeCoNiCuZnGaGeAsSeBrKrRbSrYZrNbMoTcRuRhPdAgCdInSnSbTeIXeCsBaLaCePrNdPmSmEuGdTbDyHoErTmYbLuHfTaWReOsIrPtAuHgTlPbBiPoAtRnFrRaAcThPaUNpPuAmCmBkCfEsFmMdNoLrRfDbSgBhHsMtDsRgCnNhFlMcLvTsOg".split(/(?=[A-Z])/)[i],j%18*60+32,~~(j/18)*60+68);
// Set text color
c.fillStyle="#fff";
// Draw text
c.fillText("HHeLiBeBCNOFNeNaMgAlSiPSClArKCaScTiVCrMnFeCoNiCuZnGaGeAsSeBrKrRbSrYZrNbMoTcRuRhPdAgCdInSnSbTeIXeCsBaLaCePrNdPmSmEuGdTbDyHoErTmYbLuHfTaWReOsIrPtAuHgTlPbBiPoAtRnFrRaAcThPaUNpPuAmCmBkCfEsFmMdNoLrRfDbSgBhHsMtDsRgCnNhFlMcLvTsOg".split(/(?=[A-Z])/)[i],j%18*60+30,~~(j/18)*60+66);
// Set a smaller font size for the other texts
c.font="9pt arial";
// -------------------------------------------------
// 3. Element's relative atomic mass and stability
// -------------------------------------------------
// The relative atomic mass of an element is the average weight of the element and its isotopes,
// pondered by their abundance, and compared to 1/12th of the mass of a carbon-12 element.
// More information here: https://en.wikipedia.org/wiki/Relative_atomic_mass
// Atomic masses are rounded to 2 decimals.
// Each atomic mass is multiplied by 100 to get rid of the decimal part, and placed in this array:
// m=[100,400,694,901,1081,1201,1401,1600,1900,2018,2299,2431,2698,2809,3097,3206,3545,3995,3910,4008,
// 4496,4787,5094,5200,5494,5585,5893,5869,6355,6538,6972,7263,7492,7897,7990,8380,8547,8762,8891,9122,
// 9291,9595,9791,10107,10291,10642,10787,11241,11482,11871,12176,12760,12690,13129,13291,13733,13891,
// 14012,14091,14424,14491,15036,15196,15725,15893,16250,16493,16726,16893,17305,17497,17849,18095,
// 18384,18621,19023,19222,19508,19697,20059,20438,20720,20898,20898,20999,22202,22302,22603,22703,
// 23204,23104,23803,23705,24406,24306,24707,24707,25108,25208,25710,25810,25910,26612,26712,26813,
// 27113,27013,27715,27816,28117,28217,28518,28619,28919,28919,29320,29421,29421];
// Each number of the array is converted into 2 ASCII chars using this JS (ES6) code:
// m=m.map((v,i)=>v-i*256+(i>68?570:1100)).map(v=>v.toString(36)).join('');
// Which leads to:
// m="xcykzmy9w5sdqtp8qgmmnbjvk6g5h1cyf9knb66sd8e7fmbgci7x9d1l7z5yawbvb4f9aqegbzau7b6m475j3v5j3j66338l86bvd\
// 8mcdaidfrkxi7eg9jbo6fegbsjdgxjqjdiqg95v436r6h7e6vax9ca68bb9eofed8641ts4nsp1kprihmtxk3wgmkqljhnij6q0lo\
// hctqpel3mbcfotkilrhfioedfl8hci8713"
// The decoding looks like this, for the i-th element:
// mass=parseInt(m.substr(i*2,2),36)+i*256-(i>68?570:1100);
// The resulting mass is converted to a string and split two chars before the end to make an array separating entire part and decimal part:
// mass=(parseInt(m.substr(i*2,2),36)+i*256-(i>68?570:1100)+"").split(/(?=..$)/);
// This array (eg. ["294",21"]) will be coerted to a string (eg. "294,21") when fillText will try to draw it on the canvas.
// Uncoment the .join(".") snippets to have points instead of commas.
// This approach allows to keep all trailing zeroes in the relative atomic masses.
// If g was just a floating-point number, it would appear as "16" for Oxygen (element 8) instead of "16,00", or "126.9" for Iodine (element 53) instead of "126,90"
// The code below uses this techniques, with a lot of repetitions to optimize for RegPack.
// Stable elements are elements that have at least one stable isotope.
// "Unstable" elements have isotopes with half-lives between a few minutes and a few million years.
// Elements 43, 61 and higher than 85 are unstable.
// Their relative atomic masses are drawn between parenthesis.
// More information here: https://commons.wikimedia.org/wiki/File:Periodic_Table_Stability_%26_Radioactivity.png
// And here: https://en.wikipedia.org/wiki/Radioactive_decay
// Elements 1 to 4 also get an extra decimal (respectively 8, 3, 1 and 2), because their mass is lower than 10 and there was enough room for that.
c.fillText(
// Stable elements masses
(i!=42^i!=60^i<83)
?
(parseInt('xcykzmy9w5sdqtp8qgmmnbjvk6g5h1cyf9knb66sd8e7fmbgci7x9d1l7z5yawbvb4f9aqegbzau7b6m475j3v5j3j66338l86bvd8mcdaidfrkxi7eg9jbo6fegbsjdgxjqjdiqg95v436r6h7e6vax9ca68bb9eofed8641ts4nsp1kprihmtxk3wgmkqljhnij6q0lohctqpel3mbcfotkilrhfioedfl8hci8713'.substr(i*2,2),36)+i*256-(i>68?570:1100)+"").split(/(?=..$)/)/*.join(".")*/
// Extra decimal for elements 1, 2, 3, 4.
+["8312"[i]]
:
// Unstable elements masses between parenthesis
("("+(parseInt('xcykzmy9w5sdqtp8qgmmnbjvk6g5h1cyf9knb66sd8e7fmbgci7x9d1l7z5yawbvb4f9aqegbzau7b6m475j3v5j3j66338l86bvd8mcdaidfrkxi7eg9jbo6fegbsjdgxjqjdiqg95v436r6h7e6vax9ca68bb9eofed8641ts4nsp1kprihmtxk3wgmkqljhnij6q0lohctqpel3mbcfotkilrhfioedfl8hci8713'.substr(i*2,2),36)+i*256-(i>68?570:1100)+"").split(/(?=..$)/)/*.join(".")*/+")"),
j%18*60+30,
~~(j/18)*60+83
);
// ------------------
// 4. Atomic number
// ------------------
// The atomic number (written on top of each cell) represents the number of protons in the current element.
// More information: https://en.wikipedia.org/wiki/Atomic_number
c.fillText(i+1,j%18*60+30,~~(j/18)*60+45);
// ----------
// 5. next!
// ----------
// j offsets:
// This operation adds the "gaps" in the table.
// i.e. 17 gaps after element 0, 11 gaps after element 3, etc.
// If there's no gap, j is just incremented by 1.
j+={117:21,0:17,3:11,11:11,69:5}[i]|1;
// i offsets:
// This operation adds the "jumps" in the atomic numbers.
// i.e: 15 jumps after element 55, etc.
// If there's no jump, i is just incremented by 1.
i+={117:-61,87:15,69:18,55:15}[i]|1;
// The values are shuffled a little to optimize RegPack compression (note the repetition of "+={117:" and "5}[i]|1")
}
// -------
// Title
// -------
// Draw the title "PERIOD1K" on top of the canvas, to fill the remaining bytes.
c.font="bold 15pt arial";
c.fillText("PERIOD1K",545,50);
// --------------------------
// Minification and packing
// --------------------------
// - Pass this code through closure compiler, advanced mode (https://closure-compiler.appspot.com).
// - Remove the line breaks and the trailing semicolon generated by closure compiler.
// - Paste the result in RegPack (http://siorki.github.io/regPack.html). Pack with the following setup: 10 / 0 / 1 / "Longest string first"
// - Result: 1024b.
// - Yay!
/*** end of entry ***/
</script>