]> git.ardis.lu - utf-8-visualizer/commitdiff
Show the point binary aligning with encoded value
authorArdis Lu <ardisglu@gmail.com>
Sat, 7 Jan 2023 05:38:58 +0000 (21:38 -0800)
committerArdis Lu <ardisglu@gmail.com>
Sat, 7 Jan 2023 05:38:58 +0000 (21:38 -0800)
script.js
style.css

index 76329b6504b2bbef34800725dc310d709a986668..b9c704495758c0c3a44898717aa090e7a4b9ed39 100644 (file)
--- a/script.js
+++ b/script.js
@@ -25,12 +25,10 @@ function calculateOutput(input) {
   for (const char of input) {
     const point = char.codePointAt(0);
     const pointHex = point.toString(16);
-    const pointBinary = point.toString(2);
 
     output.push({
       char: invisibleCharacters.includes(point) ? '◌' : char, // Visual representation of the code point, replacing whitespace with ◌
       point: `U+${pointHex.toUpperCase()}`, // Unicode code point, in hex
-      pointBinary: pointBinary.padStart(8 * Math.ceil(pointBinary.length / 8), '0'), // Unicode code point, in binary
       bytes: [...encoder.encode(char)].map(c => c.toString(2).padStart(8, '0')) // UTF-8 encoding of the code point, in binary
     });
   }
@@ -42,7 +40,7 @@ function parseBytes(bytes) {
   // A UTF-8 encoded code point with a byte length of 1 is always encoded with this pattern: 0xxxxxxx
   // Do not mark first bit insignificant because the UTF-8 encoding is exactly equal to the code point binary
   if (bytes.length === 1) {
-    return `<span class="significant">${bytes[0]}</span>`;
+    return [bytes[0], bytes[0]];
   }
 
   // All other UTF-8 byte lengths follow the same pattern
@@ -51,21 +49,24 @@ function parseBytes(bytes) {
   // Length = 4 bytes: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
   // Length = 5 bytes: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
   else {
-    let template = '';
+    let pointBinaryTemplate = '';
+    let bytesTemplate = '';
 
     // The number of insignificant bits in the first byte is always the length of the array plus one
     const initialLength = bytes.length;
     const firstByte = bytes.shift();
-    template += `<span class="insignificant">${firstByte.substring(0, initialLength + 1)}</span>`;
-    template += `<span class="significant">${firstByte.substring(initialLength + 1)}</span>`;
+    const i = firstByte.substring(0, initialLength + 1);
+    const s = firstByte.substring(initialLength + 1);
+    pointBinaryTemplate += `<span class="shrink w-${i.length}"></span>${s}`;
+    bytesTemplate += `<span class="insignificant">${i}</span>${s}`;
 
     // Remaining bytes always have 2 insignificant bits
     for (const byte of bytes) {
-      template += `<span class="insignificant">10</span>`;
-      template += `<span class="significant">${byte.substring(2)}</span>`;
+      pointBinaryTemplate += `<span class="shrink w-2"></span>${byte.substring(2)}`;
+      bytesTemplate += `<span class="insignificant">10</span>${byte.substring(2)}`;
     }
 
-    return template;
+    return [pointBinaryTemplate, bytesTemplate];
   }
 }
 
@@ -77,8 +78,10 @@ function render(output) {
     const viz = document.createElement('al-point-visualization');
     viz.insertAdjacentHTML('beforeend', `<span slot="char">${item.char}</slot>`);
     viz.insertAdjacentHTML('beforeend', `<span slot="point">${item.point}</slot>`);
-    viz.insertAdjacentHTML('beforeend', `<span slot="point-binary">${item.pointBinary}</slot>`);
-    viz.insertAdjacentHTML('beforeend', `<span slot="bytes">${parseBytes(item.bytes)}</slot>`);
+
+    const [pointBinary, bytes] = parseBytes(item.bytes);
+    viz.insertAdjacentHTML('beforeend', `<span slot="point-binary">${pointBinary}</slot>`);
+    viz.insertAdjacentHTML('beforeend', `<span slot="bytes">${bytes}</slot>`);
 
     vizContainer.insertAdjacentElement('beforeend', viz);
   }
index 85bfdabfc544adc04c814765eb18316854269f47..54cf89ca05f5acd9f54a74ced5e43b367add100a 100644 (file)
--- a/style.css
+++ b/style.css
@@ -77,6 +77,41 @@ a>svg {
   transition: transform 200ms;
 }
 
+/* For the point binary */
+.shrink {
+  display: inline-block;
+  inline-size: 0;
+  line-height: 0;
+  overflow: hidden;
+  visibility: hidden;
+  transition: inline-size 600ms;
+}
+
+:is(al-point-visualization:hover, al-point-visualization:focus-within) .shrink {
+  transition: inline-size 200ms;
+}
+
+/* Can't use inline-size: fit-content or inline-size: auto, must hardcode a concrete size for transition to work. */
+:is(al-point-visualization:hover, al-point-visualization:focus-within) .shrink.w-2 {
+  inline-size: 2ch;
+}
+
+:is(al-point-visualization:hover, al-point-visualization:focus-within) .shrink.w-3 {
+  inline-size: 3ch;
+}
+
+:is(al-point-visualization:hover, al-point-visualization:focus-within) .shrink.w-4 {
+  inline-size: 4ch;
+}
+
+:is(al-point-visualization:hover, al-point-visualization:focus-within) .shrink.w-5 {
+  inline-size: 5ch;
+}
+
+:is(al-point-visualization:hover, al-point-visualization:focus-within) .shrink.w-6 {
+  inline-size: 6ch;
+}
+
 /* For the raw UTF-8 bytes */
 .insignificant {
   transition: opacity 600ms;
This page took 0.045445 seconds and 4 git commands to generate.