-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathindex.html
157 lines (134 loc) Β· 4.89 KB
/
index.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
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<script>
const t0 = performance.now();
</script>
<script src="font-kit.js"></script>
<style id="emoji_style"></style>
<style>
#emoji_picker > * {
font-size: 4em;
}
#emoji {
font-family: "Noto Color Emoji";
font-size: 16em;
font-palette: --palette;
display: inline-block;
}
#canvas {
font-family: "Noto Color Emoji";
display: inline-block;
}
</style>
<style id="palette_overrides"></style>
</head>
<body>
<!--
https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas#a_color_picker
https://github.com/opentypejs/opentype.js/issues/374 suggests no support for COLRv1
https://github.com/opentypejs/opentype.js/pull/490 adds COLRv0 and CPAL
Won't even load CPAL because it doesn't speak COLRv1 :( Hacked a local opentypejs for now.
-->
<div id="emoji_picker">
<span onclick="updateEmojiSelection('π¦');">π¦</span>
<span onclick="updateEmojiSelection('π« ');">π« </span>
<span onclick="updateEmojiSelection('π');">π</span>
<span onclick="updateEmojiSelection('π₯·');">π₯·</span>
</div>
<div style="display: flex;">
<div id="emoji">π¦</div>
<canvas id="canvas"></canvas>
</div>
<div id="pickers"></div>
<br>
<pre>NOTE: color changing only works in Chrome 101.0.4950.2+, as of 4/12/2022 you probably want Canary</pre>
<script>
var originalPalette = [];
var palette = [];
function colorEqual(c1, c2) {
return c1.every((c, i) => c == c2[i]);
}
function computeOverrides() {
return palette
.map((c, i) => `${i} rgba(${c[0]}, ${c[1]}, ${c[2]}, ${c[3]})`)
.filter((s, i) => !colorEqual(palette[i], originalPalette[i]))
.join(", ");
}
function updatePalette(overrideColors) {
const style = document.getElementById("palette_overrides");
style.innerHTML = `
@font-palette-values --palette {
font-family: "Noto Color Emoji";
base-palette: 0;
override-colors: ${overrideColors};
}
`;
window.location.hash = encodeURIComponent(overrideColors);
}
function updatePaletteEntry(paletteIndex, rgb_color) {
[0, 1, 2].forEach(i => {
palette[paletteIndex][i] = parseInt(rgb_color.substring(i * 2, i * 2 + 2), 16);
});
updatePalette(computeOverrides());
}
async function updateEmojiSelection(emoji) {
// my kingdom for predictable font urls?
const css_response = await fetch('https://fonts.googleapis.com/css2?family=Noto+Color+Emoji&text=' + encodeURIComponent(emoji));
const css_text = await css_response.text();
document.getElementById('emoji_style').innerHTML = css_text;
document.getElementById('emoji').innerHTML = emoji;
const font_url = css_text.split("\n").filter(e => e.indexOf("src:") != -1)[0].match(/src:\s+url\(([^)]+)\)/)[1];
const font_binary = await (await fetch(font_url)).arrayBuffer();
const font = fontkit.create(new Buffer(font_binary));
// update globals with palette, for now always the first palette
originalPalette = font.CPAL.colorRecords.slice(
font.CPAL.colorRecordIndices[0],
font.CPAL.colorRecordIndices[0] + font.CPAL.numPaletteEntries
).map(e => [e.red, e.green, e.blue, e.alpha]);
palette = [];
for (color of originalPalette) {
palette.push([...color]); // copy so we can modify freely
}
updatePalette(window.location.hash.substring(1));
pickers = document.getElementById("pickers");
while (pickers.firstChild) {
pickers.removeChild(pickers.firstChild);
}
palette.forEach((color, i) => {
picker = document.createElement("input");
picker.type = "color";
// slice away alpha, color picker does not support
picker.value = "#" + color.slice(0, 3).map(e => e.toString(16)).map(e => e.length == 1 ? "0" + e : e).join("");
pickers.appendChild(picker);
picker.addEventListener('input', function(e) { updatePaletteEntry(i, e.target.value.substring(1)); })
});
const t0 = performance.now();
load_promises = []
for (var fontFace of document.fonts.values()) {
load_promises.push(fontFace.load());
}
await Promise.all(load_promises);
console.log("Fonts ready.", performance.now() - t0, "ms");
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
emWidth = 8;
ctx.font = `${emWidth}em 'Noto Color Emoji'`;
ctx.textAlign = "center";
textMetrics = ctx.measureText(emoji);
emWidth = Math.min(canvas.width, canvas.height) / textMetrics.width * emWidth;
ctx.font = `${emWidth}em 'Noto Color Emoji'`;
ctx.textBaseline = 'middle';
ctx.textAlign = 'center';
ctx.fillText(emoji, canvas.width / 2, canvas.height / 2);
}
canvas.width = document.getElementById('emoji').offsetWidth;
canvas.height = document.getElementById('emoji').offsetHeight;
updateEmojiSelection("π¦");
</script>
</body>
</html>