fitfont
Version:
This library allows you to easily display text with custom fonts.
208 lines (173 loc) • 5.14 kB
JavaScript
import document from 'document';
import { statSync, openSync, readSync, closeSync } from 'fs';
var fonts = {};
var CURRENT_VERSION = 1;
var INDEX_VERSION = 0;
var INDEX_DESCENT = 1;
var INDEX_ASCENT = 2;
var INDEX_CHARS = 3;
var BYTES_PER_CHAR = 2;
var INFO_PER_CHAR = 5;
var TOTAL_BYTES_PER_CHAR = BYTES_PER_CHAR + INFO_PER_CHAR;
var getCharIndex = function getCharIndex(info, c) {
var count = (info.length - INDEX_CHARS) / TOTAL_BYTES_PER_CHAR;
var min = 0;
var max = count - 1;
// Check if the character is in the list
var charMinOffset = INDEX_CHARS + BYTES_PER_CHAR * min;
var charMaxOffset = INDEX_CHARS + BYTES_PER_CHAR * max;
if ((info[charMinOffset] << 8) + info[charMinOffset + 1] > c || (info[charMaxOffset] << 8) + info[charMaxOffset + 1] < c) {
return -1;
}
// use dichotomic search
while (min <= max) {
var id = Math.round((max + min) / 2);
var charOffset = INDEX_CHARS + BYTES_PER_CHAR * id;
var val = (info[charOffset] << 8) + info[charOffset + 1];
if (val === c) {
return INDEX_CHARS + INFO_PER_CHAR * id + BYTES_PER_CHAR * count;
} else if (val > c) {
max = id - 1;
} else {
min = id + 1;
}
}
return -1;
};
export function FitFont(_ref) {
var _this = this;
var id = _ref.id,
font = _ref.font,
halign = _ref.halign,
valign = _ref.valign,
letterspacing = _ref.letterspacing;
this.root = typeof id === 'string' ? document.getElementById(id) : id;
this.style = this.root.style;
this.chars = this.root.getElementsByClassName('fitfont-char');
this._halign = halign || 'start';
this._valign = valign || 'baseline';
this._spacing = letterspacing || 0;
this._text = '';
this._width = 0;
this._ascent = 0;
this._descent = 0;
if (fonts[font] === undefined) {
try {
var fName = '/mnt/assets/resources/' + font + '/ff';
var stats = statSync(fName);
var file = openSync(fName, 'r');
var buffer = new ArrayBuffer(stats.size);
readSync(file, buffer, 0, stats.size, 0);
closeSync(file);
var bytes = new Uint8Array(buffer);
// Check if the binary file has the right format
if (bytes[INDEX_VERSION] !== CURRENT_VERSION) {
return;
}
fonts[font] = bytes;
} catch (e) {
console.error('Font ' + font + ' not found');
return;
}
}
this._info = fonts[font];
this.redraw = function () {
var val = _this._text + '';
var totalWidth = 0;
var i = 0;
while (i < val.length && i < _this.chars.length) {
var charCode = val.charCodeAt(i);
var index = getCharIndex(_this._info, charCode);
var charElem = _this.chars[i];
if (index === -1) {
// Char not found in the font
// console.error(`Char not found ${val[i]} in ${font}`)
charElem.href = '';
} else {
charElem.width = _this._info[index++];
charElem.height = _this._info[index++];
charElem.x = totalWidth - _this._info[index++];
charElem.y = _this._info[index++];
if (charElem.y > 200) charElem.y -= 256;
totalWidth += _this._info[index++];
charElem.href = font + '/' + charCode + '.png';
}
if (i < val.length - 1) {
totalWidth += _this._spacing;
}
i++;
}
for (; i < _this.chars.length; i++) {
_this.chars[i].href = '';
}
_this._width = totalWidth;
var offx = 0;
switch (_this._halign) {
case 'middle':
offx -= totalWidth / 2;break;
case 'end':
offx -= totalWidth;break;
}
var offy = 0;
switch (_this._valign) {
case 'top':
offy = 0;break;
case 'middle':
offy -= (_this._info[INDEX_ASCENT] + _this._info[INDEX_DESCENT]) / 2;break;
case 'bottom':
offy -= _this._info[INDEX_ASCENT] + _this._info[INDEX_DESCENT];break;
case 'baseline':
default:
offy -= _this._info[INDEX_ASCENT];break;
}
for (i = 0; i < _this.chars.length; i++) {
_this.chars[i].x += offx;
_this.chars[i].y += offy;
}
};
Object.defineProperty(this, 'text', {
get: function get() {
return _this._text;
},
set: function set(val) {
if (_this._text === val) return;
_this._text = val;
_this.redraw();
}
});
Object.defineProperty(this, 'halign', {
get: function get() {
return _this._halign;
},
set: function set(val) {
if (_this._halign === val) return;
_this._halign = val;
_this.redraw();
}
});
Object.defineProperty(this, 'valign', {
get: function get() {
return _this._valign;
},
set: function set(val) {
if (_this._valign === val) return;
_this._valign = val;
_this.redraw();
}
});
Object.defineProperty(this, 'letterspacing', {
get: function get() {
return _this._spacing;
},
set: function set(val) {
if (_this._spacing === val) return;
_this._spacing = val;
_this.redraw();
}
});
Object.defineProperty(this, 'width', {
get: function get() {
return _this._width;
}
});
}