Skip to content

Instantly share code, notes, and snippets.

@vthibault
Last active June 4, 2020 12:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vthibault/b129cf2481aa9855407c37386e345d02 to your computer and use it in GitHub Desktop.
Save vthibault/b129cf2481aa9855407c37386e345d02 to your computer and use it in GitHub Desktop.
Detect emoji v2
// https://unicode.org/emoji/charts/full-emoji-list.html
// var list = Array.from(document.querySelectorAll('.chars')).map(t => t.textContent);
const ctx = document.createElement('canvas').getContext('2d');
const CANVAS_HEIGHT = 25;
const CANVAS_WIDTH = 30;
/**
* @var {Object} cache
*/
let cache = new Map();
// Initialize convas context
ctx.font = '24px Arial, Sans-Serif';
ctx.textBaseline = 'Top';
ctx.canvas.width = CANVAS_WIDTH * 2;
ctx.canvas.height = CANVAS_HEIGHT;
/**
* Check if the two pixels parts are perfectly the sames
*
* @params {string} unicode
* @returns {boolean}
*/
function isEmojiSupported(unicode) {
ctx.clearRect(0, 0, CANVAS_WIDTH * 2, CANVAS_HEIGHT);
// Draw in red on the left
ctx.fillStyle = '#FF0000';
ctx.fillText(unicode, 0, 22);
// Draw in blue on right
ctx.fillStyle = '#0000FF';
ctx.fillText(unicode, CANVAS_WIDTH, 22);
const a = ctx.getImageData(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT).data;
const count = a.length;
let i = 0;
// Search the first visible pixel
for (; i < count && !a[i + 3]; i += 4);
// No visible pixel
if (i >= count) {
return false;
}
// Emoji has immutable color, so we check the color of the emoji in two different colors
// the result show be the same.
const x = CANVAS_WIDTH + i / 4 % CANVAS_WIDTH;
const y = Math.floor(i / 4 / CANVAS_WIDTH);
const b = ctx.getImageData(x, y, 1, 1).data;
if (a[i] !== b[0] || a[i + 2] !== b[2]) {
return false;
}
// Some emojis are a contraction of different ones, so if it's not
// supported, it will show multiple characters
if (ctx.measureText(unicode).width >= CANVAS_WIDTH) {
return false;
}
return true;
}
/**
* Check if emoji is supported with cache
*
* @params {string} unicode
* @returns {boolean}
*/
export function isSupported(unicode) {
if (cache.has(unicode)) {
return cache.get(unicode);
}
const supported = isEmojiSupported(unicode);
cache.set(unicode, supported);
return supported;
}
/**
* Request to handle cache directly
*
* @params {Map} store
*/
export function setStore (store) {
cache = store;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment