Add support for parsing shorthand font declaration in styles, such as "font: italic 12px Arial,Helvetica,sans-serif"

This commit is contained in:
kangax 2013-05-12 13:01:23 -04:00
parent 0229df4a78
commit c65b1f5e7d
6 changed files with 136 additions and 53 deletions

View file

@ -1,4 +1,4 @@
### Fabric
### Fabric
[![Build Status](https://secure.travis-ci.org/kangax/fabric.js.png?branch=master)](http://travis-ci.org/#!/kangax/fabric.js)
<a href="https://npmjs.org/package/fabric"><img src="https://badge.fury.io/js/fabric.png"></a>
@ -12,7 +12,7 @@ Using Fabric.js, you can create and populate objects on canvas; objects like sim
### Goals
- Unit tested (1500+ tests at the moment)
- Unit tested (1570+ tests at the moment)
- Modular (~40 small "classes", modules, mixins)
- Cross-browser
- [Fast](https://github.com/kangax/fabric.js/wiki/Focus-on-speed)

109
dist/all.js vendored
View file

@ -4182,6 +4182,34 @@ fabric.util.string = {
return parsedPoints;
}
function parseFontDeclaration(value, oStyle) {
// TODO: support non-px font size
var match = value.match(/(normal|italic)?\s*(normal|small-caps)?\s*(normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900)?\s*(\d+)px\s+(.*)/);
if (!match) return;
var fontStyle = match[1];
// Font variant is not used
// var fontVariant = match[2];
var fontWeight = match[3];
var fontSize = match[4];
var fontFamily = match[5];
if (fontStyle) {
oStyle.fontStyle = fontStyle;
}
if (fontWeight) {
oStyle.fontSize = isNaN(parseFloat(fontWeight)) ? fontWeight : parseFloat(fontWeight);
}
if (fontSize) {
oStyle.fontSize = parseFloat(fontSize);
}
if (fontFamily) {
oStyle.fontFamily = fontFamily;
}
}
/**
* Parses "style" attribute, retuning an object with values
* @static
@ -4196,16 +4224,20 @@ fabric.util.string = {
if (!style) return oStyle;
if (typeof style === 'string') {
style = style.replace(/;$/, '').split(';').forEach(function (current) {
style.replace(/;$/, '').split(';').forEach(function (chunk) {
var pair = current.split(':');
var pair = chunk.split(':');
var attr = normalizeAttr(pair[0].trim().toLowerCase());
var value = normalizeValue(attr, pair[1].trim());
// TODO: need to normalize em, %, pt, etc. to px (!)
var parsed = parseFloat(value);
oStyle[attr] = isNaN(parsed) ? value : parsed;
if (attr === 'font') {
parseFontDeclaration(value, oStyle);
}
else {
// TODO: need to normalize em, %, pt, etc. to px (!)
var parsed = parseFloat(value);
oStyle[attr] = isNaN(parsed) ? value : parsed;
}
});
}
else {
@ -4214,9 +4246,15 @@ fabric.util.string = {
var attr = normalizeAttr(prop.toLowerCase());
var value = normalizeValue(attr, style[prop]);
var parsed = parseFloat(value);
oStyle[attr] = isNaN(parsed) ? value : parsed;
if (attr === 'font') {
parseFontDeclaration(value, oStyle);
}
else {
// TODO: need to normalize em, %, pt, etc. to px (!)
var parsed = parseFloat(value);
oStyle[attr] = isNaN(parsed) ? value : parsed;
}
}
}
@ -8845,6 +8883,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
/**
* @private
* @param {Event} e Event object fired on mousedown
*/
_onMouseDown: function (e) {
this.__onMouseDown(e);
@ -8861,6 +8900,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
/**
* @private
* @param {Event} e Event object fired on mouseup
*/
_onMouseUp: function (e) {
this.__onMouseUp(e);
@ -8877,6 +8917,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
/**
* @private
* @param {Event} e Event object fired on mousemove
*/
_onMouseMove: function (e) {
e.preventDefault && e.preventDefault();
@ -8969,7 +9010,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
* canvas so the current image can be placed on the top canvas and the rest
* in on the container one.
* @private
* @param e {Event} Event object fired on mousedown
* @param {Event} e Event object fired on mousedown
*/
__onMouseDown: function (e) {
@ -9004,6 +9045,10 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
this.deactivateAllWithDispatch();
target && target.selectable && this.setActiveObject(target, e);
}
else if (this._shouldHandleGroupLogic(e, target)) {
this._handleGroupLogic(e, target);
target = this.getActiveGroup();
}
else {
// determine if it's a drag or rotate case
this.stateful && target.saveState();
@ -9012,15 +9057,9 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
this.onBeforeScaleRotate(target);
}
if (this._shouldHandleGroupLogic(e, target)) {
this._handleGroupLogic(e, target);
target = this.getActiveGroup();
}
else {
if (target !== this.getActiveGroup() && target !== this.getActiveObject()) {
this.deactivateAll();
this.setActiveObject(target, e);
}
if (target !== this.getActiveGroup() && target !== this.getActiveObject()) {
this.deactivateAll();
this.setActiveObject(target, e);
}
this._setupCurrentTransform(e, target);
@ -9047,7 +9086,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
* all any other type of action.
* In case of an image transformation only the top canvas will be rendered.
* @private
* @param e {Event} Event object fired on mousemove
* @param {Event} e Event object fired on mousemove
*/
__onMouseMove: function (e) {
@ -9174,8 +9213,8 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
/**
* Sets the cursor depending on where the canvas is being hovered.
* Note: very buggy in Opera
* @param e {Event} Event object
* @param target {Object} Object that the mouse is hovering, if so.
* @param {Event} e Event object
* @param {Object} target Object that the mouse is hovering, if so.
*/
_setCursorFromEvent: function (e, target) {
var s = this.upperCanvasEl.style;
@ -15269,23 +15308,17 @@ fabric.Image.filters.Grayscale = fabric.util.createClass( /** @lends fabric.Imag
var context = canvasEl.getContext('2d'),
imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height),
data = imageData.data,
iLen = imageData.width,
jLen = imageData.height,
index, average, i, j;
for (i = 0; i < iLen; i++) {
for (j = 0; j < jLen; j++) {
index = (i * 4) * jLen + (j * 4);
average = (data[index] + data[index + 1] + data[index + 2]) / 3;
data[index] = average;
data[index + 1] = average;
data[index + 2] = average;
}
}
context.putImageData(imageData, 0, 0);
len = imageData.width * imageData.height * 4,
index = 0,
average;
while (index < len) {
average = (data[index] + data[index + 1] + data[index + 2]) / 3;
data[index] = average;
data[index + 1] = average;
data[index + 2] = average;
index += 4;
}
context.putImageData(imageData, 0, 0);
},
/**

10
dist/all.min.js vendored

File diff suppressed because one or more lines are too long

BIN
dist/all.min.js.gz vendored

Binary file not shown.

View file

@ -287,6 +287,34 @@
return parsedPoints;
}
function parseFontDeclaration(value, oStyle) {
// TODO: support non-px font size
var match = value.match(/(normal|italic)?\s*(normal|small-caps)?\s*(normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900)?\s*(\d+)px\s+(.*)/);
if (!match) return;
var fontStyle = match[1];
// Font variant is not used
// var fontVariant = match[2];
var fontWeight = match[3];
var fontSize = match[4];
var fontFamily = match[5];
if (fontStyle) {
oStyle.fontStyle = fontStyle;
}
if (fontWeight) {
oStyle.fontSize = isNaN(parseFloat(fontWeight)) ? fontWeight : parseFloat(fontWeight);
}
if (fontSize) {
oStyle.fontSize = parseFloat(fontSize);
}
if (fontFamily) {
oStyle.fontFamily = fontFamily;
}
}
/**
* Parses "style" attribute, retuning an object with values
* @static
@ -301,16 +329,20 @@
if (!style) return oStyle;
if (typeof style === 'string') {
style = style.replace(/;$/, '').split(';').forEach(function (current) {
style.replace(/;$/, '').split(';').forEach(function (chunk) {
var pair = current.split(':');
var pair = chunk.split(':');
var attr = normalizeAttr(pair[0].trim().toLowerCase());
var value = normalizeValue(attr, pair[1].trim());
// TODO: need to normalize em, %, pt, etc. to px (!)
var parsed = parseFloat(value);
oStyle[attr] = isNaN(parsed) ? value : parsed;
if (attr === 'font') {
parseFontDeclaration(value, oStyle);
}
else {
// TODO: need to normalize em, %, pt, etc. to px (!)
var parsed = parseFloat(value);
oStyle[attr] = isNaN(parsed) ? value : parsed;
}
});
}
else {
@ -319,9 +351,15 @@
var attr = normalizeAttr(prop.toLowerCase());
var value = normalizeValue(attr, style[prop]);
var parsed = parseFloat(value);
oStyle[attr] = isNaN(parsed) ? value : parsed;
if (attr === 'font') {
parseFontDeclaration(value, oStyle);
}
else {
// TODO: need to normalize em, %, pt, etc. to px (!)
var parsed = parseFloat(value);
oStyle[attr] = isNaN(parsed) ? value : parsed;
}
}
}

View file

@ -155,6 +155,18 @@
deepEqual(expectedObject, fabric.parseStyleAttribute(element));
});
test('parseStyleAttribute with short font declaration', function() {
var element = fabric.document.createElement('path');
element.setAttribute('style', 'font: italic 12px Arial,Helvetica,sans-serif');
var expectedObject = {
'fontSize': 12,
'fontStyle': 'italic',
'fontFamily': 'Arial,Helvetica,sans-serif'
};
deepEqual(expectedObject, fabric.parseStyleAttribute(element));
});
test('parseAttributes (style to have higher priority than attribute)', function() {
var element = fabric.document.createElement('path');
element.setAttribute('style', 'fill:red');