136 lines
4.1 KiB
JavaScript
136 lines
4.1 KiB
JavaScript
var Shape = require('./generic');
|
|
|
|
var fonts = {};
|
|
|
|
var parseFontString = function(font){
|
|
var regexp = /^\s*((?:(?:normal|bold|italic)\s+)*)(?:(\d+(?:\.\d+)?)[ptexm\%]*(?:\s*\/.*?)?\s+)?\s*\"?([^\"]*)/i,
|
|
match = regexp.exec(font);
|
|
return {
|
|
fontFamily: match[3],
|
|
fontSize: match[2],
|
|
fontStyle: (/italic/.exec(match[1]) || ''),
|
|
fontWeight: (/bold/.exec(match[1]) || '')
|
|
};
|
|
};
|
|
|
|
var Font = Shape(function(text, font, alignment){
|
|
if (typeof font == 'string') font = parseFontString(font);
|
|
if (font) this.font = font; else font = this.font;
|
|
|
|
var family = font.fontFamily || font['font-family'],
|
|
weight = font.fontWeight || font['font-weight'] || 'normal',
|
|
style = font.fontStyle || font['font-style'] || 'normal',
|
|
size = parseFloat(font.fontSize || font['font-size'] || font.size);
|
|
|
|
font = font.glyphs ? font : fonts[weight + style + family];
|
|
|
|
if (!font) throw new Error('The specified font has not been found.');
|
|
|
|
var scale = size / font.face['units-per-em'];
|
|
var width = 0, height = size, path = '', row = '';
|
|
|
|
var x = 0, y = scale * font.face.ascent || size - (scale * font.face.descent);
|
|
|
|
var regexp = /([mclrvxe])([^a-z]*)/g, match;
|
|
|
|
// TODO: Refactor to use SVG paths as the source
|
|
|
|
var cx = 0, cy = 0, fx = 0, fy = 0;
|
|
for (var i = 0, l = text.length; i < l; ++i){
|
|
if (text.charAt(i) == '\n'){
|
|
if (alignment == 'end' || alignment == 'right'){
|
|
cx -= x;
|
|
path += 'm' + (-x) + ',0';
|
|
}
|
|
if (alignment == 'middle' || alignment == 'center'){
|
|
cx -= x / 2;
|
|
path += 'm' + (-x / 2) + ',0';
|
|
}
|
|
path += row;
|
|
path += 'm' + (-cx) + ',' + (-cy);
|
|
cx = cy = 0;
|
|
row = '';
|
|
x = 0;
|
|
y += size * 1.1;
|
|
height += size * 1.1;
|
|
continue;
|
|
}
|
|
var glyph = font.glyphs[text.charAt(i)] || font.glyphs.missing || font.glyphs[' '];
|
|
if (!glyph) continue;
|
|
var w = scale * (glyph.w || font.w);
|
|
if (glyph.d){
|
|
var s = scale;
|
|
|
|
if (glyph.path){
|
|
var parts = glyph.path;
|
|
} else {
|
|
var parts = [], index = -1,
|
|
bits = ('m' + glyph.d + 'x').match(/[a-df-z]|[\-+]?(?:[\d\.]e[\-+]?|[^\s\-+,a-z])+/ig),
|
|
part;
|
|
|
|
for (var j = 0, k = bits.length; j < k; j++){
|
|
var bit = bits[j];
|
|
if (bit.match(/^[a-z]/i)){
|
|
parts[++index] = part = [bit];
|
|
} else {
|
|
part.push(Number(bit));
|
|
}
|
|
}
|
|
glyph.path = parts;
|
|
}
|
|
|
|
for (var j = 0; j < parts.length; j++){
|
|
var c = Array.prototype.slice.call(parts[j]), f = c.shift();
|
|
switch (f){
|
|
case 'l':
|
|
row += 'l ' + (x + (s * c[0]) - cx) + ',' + (y + (s * c[1]) - cy);
|
|
//row += 'L ' + (x + (s * c[0])) + ',' + (y + (s * c[1]));
|
|
cx = x + (s * c[0]); cy = y + (s * c[1]);
|
|
break;
|
|
case 'c':
|
|
row += 'c ' + (x + s * c[0] - cx) + ',' + (y + s * c[1] - cy) + ',' + (x + s * c[2] - cx) + ',' + (y + s * c[3] - cy) + ',' + (x + s * c[4] - cx) + ',' + (y + s * c[5] - cy);
|
|
cx = x + (s * c[4]); cy = y + (s * c[5]);
|
|
break;
|
|
case 'v':
|
|
row += 'c ' + (s * c[0]) + ',' + (s * c[1]) + ',' + (s * c[2]) + ',' + (s * c[3]) + ',' + (s * c[4]) + ',' + (s * c[5]);
|
|
cx += (s * c[4]); cy += (s * c[5]);
|
|
break;
|
|
case 'r':
|
|
row += 'l ' + (s * c[0]) + ',' + (s * c[1]);
|
|
cx += (s * c[0]); cy += (s * c[1]);
|
|
break;
|
|
case 'm':
|
|
row += 'm ' + (x + (s * c[0]) - cx) + ',' + (y + (s * c[1]) - cy);
|
|
fx = cx = x + (s * c[0]);
|
|
fy = cy = y + (s * c[1]);
|
|
break;
|
|
case 'x':
|
|
row += 'z';
|
|
cx = fx;
|
|
cy = fy;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
x += w;
|
|
if (x > width) width = x;
|
|
}
|
|
|
|
if (alignment == 'end' || alignment == 'right') path += 'm' + (-x) + ',0';
|
|
if (alignment == 'middle' || alignment == 'center') path += 'm' + (-x / 2) + ',0';
|
|
path += row;
|
|
this.path.push(path);
|
|
this.width = width;
|
|
this.height = height;
|
|
});
|
|
|
|
Font.register = function(font){
|
|
var face = font.face,
|
|
family = face['font-family'],
|
|
weight = (face['font-weight'] > 500 ? 'bold' : 'normal'),
|
|
style = (face['font-stretch'] == 'oblique' || face['font-style'] == 'oblique' || face['font-style'] == 'italic' ? 'italic' : 'normal');
|
|
fonts[weight + style + family] = font;
|
|
return this;
|
|
};
|
|
|
|
module.exports = Font; |