mirror of
https://github.com/Hopiu/fabric.js.git
synced 2026-05-11 15:23:10 +00:00
First stab at parsing + applying css rules to SVG elements. Needs unit tests!
This commit is contained in:
parent
1acbb04036
commit
580c0680f0
4 changed files with 161 additions and 13 deletions
73
dist/all.js
vendored
73
dist/all.js
vendored
|
|
@ -2506,7 +2506,7 @@ fabric.util.animate = animate;
|
|||
}, { });
|
||||
|
||||
|
||||
ownAttributes = extend(ownAttributes, fabric.parseStyleAttribute(element));
|
||||
ownAttributes = extend(ownAttributes, extend(getGlobalStylesForElement(element), fabric.parseStyleAttribute(element)));
|
||||
return extend(parentAttributes, ownAttributes);
|
||||
};
|
||||
|
||||
|
|
@ -2778,6 +2778,72 @@ fabric.util.animate = animate;
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns CSS rules for a given SVG document
|
||||
* @static
|
||||
* @function
|
||||
* @memberOf fabric
|
||||
* @method getCSSRules
|
||||
* @param {SVGDocument} doc SVG document to parse
|
||||
* @return {Object} CSS rules of this document
|
||||
*/
|
||||
function getCSSRules(doc) {
|
||||
var styles = doc.getElementsByTagName('style'),
|
||||
allRules = { },
|
||||
rules;
|
||||
|
||||
for (var i = 0, len = styles.length; i < len; i++) {
|
||||
var styleContents = styles[0].textContent;
|
||||
|
||||
styleContents = styleContents.replace(/\/\*[\s\S]*?\*\//g, '');
|
||||
|
||||
rules = styleContents.match(/[^{]*\{[\s\S]*?\}/g);
|
||||
rules = rules.map(function(rule) { return rule.trim() });
|
||||
|
||||
rules.forEach(function(rule) {
|
||||
var match = rule.match(/([\s\S]*?)\s*\{([^}]*)\}/),
|
||||
rule = match[1],
|
||||
declaration = match[2].trim(),
|
||||
propertyValuePairs = declaration.replace(/;$/, '').split(/\s*;\s*/);
|
||||
|
||||
if (!allRules[rule]) {
|
||||
allRules[rule] = { };
|
||||
}
|
||||
|
||||
for (var i = 0, len = propertyValuePairs.length; i < len; i++) {
|
||||
var pair = propertyValuePairs[i].split(/\s*:\s*/),
|
||||
property = pair[0],
|
||||
value = pair[1];
|
||||
|
||||
allRules[rule][property] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return allRules;
|
||||
}
|
||||
|
||||
function getGlobalStylesForElement(element) {
|
||||
var nodeName = element.nodeName,
|
||||
className = element.getAttribute('class'),
|
||||
id = element.getAttribute('id'),
|
||||
styles = { };
|
||||
|
||||
for (var rule in fabric.cssRules) {
|
||||
var ruleMatchesElement = (className && new RegExp('^\\.' + className).test(rule)) ||
|
||||
(id && new RegExp('^#' + id).test(rule)) ||
|
||||
(new RegExp('^' + nodeName).test(rule));
|
||||
|
||||
if (ruleMatchesElement) {
|
||||
for (var property in fabric.cssRules[rule]) {
|
||||
styles[property] = fabric.cssRules[rule][property];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an SVG document, converts it to an array of corresponding fabric.* instances and passes them to a callback
|
||||
* @static
|
||||
|
|
@ -2848,6 +2914,8 @@ fabric.util.animate = animate;
|
|||
};
|
||||
|
||||
fabric.gradientDefs = fabric.getGradientDefs(doc);
|
||||
fabric.cssRules = getCSSRules(doc);
|
||||
|
||||
|
||||
fabric.parseElements(elements, function(instances) {
|
||||
if (callback) {
|
||||
|
|
@ -2861,7 +2929,8 @@ fabric.util.animate = animate;
|
|||
parseAttributes: parseAttributes,
|
||||
parseElements: parseElements,
|
||||
parseStyleAttribute: parseStyleAttribute,
|
||||
parsePointsAttribute: parsePointsAttribute
|
||||
parsePointsAttribute: parsePointsAttribute,
|
||||
getCSSRules: getCSSRules
|
||||
});
|
||||
|
||||
})(this);
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@
|
|||
// add values parsed from style, which take precedence over attributes
|
||||
// (see: http://www.w3.org/TR/SVG/styling.html#UsingPresentationAttributes)
|
||||
|
||||
ownAttributes = extend(ownAttributes, fabric.parseStyleAttribute(element));
|
||||
ownAttributes = extend(ownAttributes, extend(getGlobalStylesForElement(element), fabric.parseStyleAttribute(element)));
|
||||
return extend(parentAttributes, ownAttributes);
|
||||
};
|
||||
|
||||
|
|
@ -359,6 +359,74 @@
|
|||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns CSS rules for a given SVG document
|
||||
* @static
|
||||
* @function
|
||||
* @memberOf fabric
|
||||
* @method getCSSRules
|
||||
* @param {SVGDocument} doc SVG document to parse
|
||||
* @return {Object} CSS rules of this document
|
||||
*/
|
||||
function getCSSRules(doc) {
|
||||
var styles = doc.getElementsByTagName('style'),
|
||||
allRules = { },
|
||||
rules;
|
||||
|
||||
// very crude parsing of style contents
|
||||
for (var i = 0, len = styles.length; i < len; i++) {
|
||||
var styleContents = styles[0].textContent;
|
||||
|
||||
// remove comments
|
||||
styleContents = styleContents.replace(/\/\*[\s\S]*?\*\//g, '');
|
||||
|
||||
rules = styleContents.match(/[^{]*\{[\s\S]*?\}/g);
|
||||
rules = rules.map(function(rule) { return rule.trim() });
|
||||
|
||||
rules.forEach(function(rule) {
|
||||
var match = rule.match(/([\s\S]*?)\s*\{([^}]*)\}/),
|
||||
rule = match[1],
|
||||
declaration = match[2].trim(),
|
||||
propertyValuePairs = declaration.replace(/;$/, '').split(/\s*;\s*/);
|
||||
|
||||
if (!allRules[rule]) {
|
||||
allRules[rule] = { };
|
||||
}
|
||||
|
||||
for (var i = 0, len = propertyValuePairs.length; i < len; i++) {
|
||||
var pair = propertyValuePairs[i].split(/\s*:\s*/),
|
||||
property = pair[0],
|
||||
value = pair[1];
|
||||
|
||||
allRules[rule][property] = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return allRules;
|
||||
}
|
||||
|
||||
function getGlobalStylesForElement(element) {
|
||||
var nodeName = element.nodeName,
|
||||
className = element.getAttribute('class'),
|
||||
id = element.getAttribute('id'),
|
||||
styles = { };
|
||||
|
||||
for (var rule in fabric.cssRules) {
|
||||
var ruleMatchesElement = (className && new RegExp('^\\.' + className).test(rule)) ||
|
||||
(id && new RegExp('^#' + id).test(rule)) ||
|
||||
(new RegExp('^' + nodeName).test(rule));
|
||||
|
||||
if (ruleMatchesElement) {
|
||||
for (var property in fabric.cssRules[rule]) {
|
||||
styles[property] = fabric.cssRules[rule][property];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an SVG document, converts it to an array of corresponding fabric.* instances and passes them to a callback
|
||||
* @static
|
||||
|
|
@ -433,7 +501,10 @@
|
|||
};
|
||||
|
||||
fabric.gradientDefs = fabric.getGradientDefs(doc);
|
||||
|
||||
fabric.cssRules = getCSSRules(doc);
|
||||
|
||||
// Precedence of rules: style > class > attribute
|
||||
|
||||
fabric.parseElements(elements, function(instances) {
|
||||
if (callback) {
|
||||
callback(instances, options);
|
||||
|
|
@ -446,7 +517,8 @@
|
|||
parseAttributes: parseAttributes,
|
||||
parseElements: parseElements,
|
||||
parseStyleAttribute: parseStyleAttribute,
|
||||
parsePointsAttribute: parsePointsAttribute
|
||||
parsePointsAttribute: parsePointsAttribute,
|
||||
getCSSRules: getCSSRules
|
||||
});
|
||||
|
||||
})(this);
|
||||
|
|
@ -28,7 +28,12 @@
|
|||
if (!xml) return;
|
||||
var doc = xml.documentElement;
|
||||
if (!doc) return;
|
||||
fabric.parseSVGDocument(doc, callback);
|
||||
|
||||
var startTime = new Date();
|
||||
fabric.parseSVGDocument(doc, function() {
|
||||
console.log((new Date() - startTime) + 'ms');
|
||||
callback.apply(this, arguments);
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -121,7 +126,7 @@
|
|||
.set('top', top)
|
||||
.set('angle', angle)
|
||||
.set('fill', '#' + getRandomColor())
|
||||
.scale(getRandomNum(0.75, 1.25))
|
||||
.scaleToWidth(300)
|
||||
.setCoords();
|
||||
|
||||
canvas.add(pathGroup);
|
||||
|
|
|
|||
|
|
@ -50,6 +50,13 @@
|
|||
|
||||
<p>Add <strong>SVG shapes</strong> to canvas:</p>
|
||||
<ul class="svg-shapes">
|
||||
<!-- <li><button class="shape" id="shape28"><strong>5378</strong> paths</button></li> -->
|
||||
<!-- <li><button class="shape" id="shape52"><strong>11285</strong> paths</button></li> -->
|
||||
<!-- <li><button class="shape" id="shape56"><strong>xxx</strong> paths</button></li> -->
|
||||
<!-- <li><button class="shape" id="shape60"><strong>xxx</strong> paths</button></li> -->
|
||||
<!-- <li><button class="shape" id="shape68"><strong>xxx</strong> paths</button></li> -->
|
||||
<!-- <li><button class="shape" id="shape70"><strong>xxx</strong> paths</button></li> -->
|
||||
<!-- <li><button class="shape" id="shape73"><strong>xxx</strong> paths</button></li> -->
|
||||
<li><button class="shape" id="shape54"><strong>1</strong> path</button></li>
|
||||
<li><button class="shape" id="shape66"><strong>1</strong> path</button></li>
|
||||
<li><button class="shape" id="shape25"><strong>36</strong> paths</button></li>
|
||||
|
|
@ -95,10 +102,8 @@
|
|||
<li><button class="shape" id="shape23"><strong>4418</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape42"><strong>4583</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape31"><strong>4768</strong> paths</button></li>
|
||||
<!-- <li><button class="shape" id="shape28"><strong>5378</strong> paths</button></li> -->
|
||||
<li><button class="shape" id="shape15"><strong>8325</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape22"><strong>9663</strong> paths</button></li>
|
||||
<!-- <li><button class="shape" id="shape52"><strong>11285</strong> paths</button></li> -->
|
||||
<li><button class="shape" id="shape41"><strong>12361</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape67"><strong>12604</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape24"><strong>12866</strong> paths</button></li>
|
||||
|
|
@ -108,11 +113,8 @@
|
|||
<li><button class="shape" id="shape20"><strong>19035</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape35"><strong>19271</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape44"><strong>22375</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape72"><strong>29303</strong> paths</button></li>
|
||||
<li><button class="shape" id="shape48"><strong>41787</strong> paths</button></li>
|
||||
<!-- <li><button class="shape" id="shape56"><strong>xxx</strong> paths</button></li> -->
|
||||
<!-- <li><button class="shape" id="shape60"><strong>xxx</strong> paths</button></li> -->
|
||||
<!-- <li><button class="shape" id="shape68"><strong>xxx</strong> paths</button></li> -->
|
||||
<!-- <li><button class="shape" id="shape70"><strong>xxx</strong> paths</button></li> -->
|
||||
</ul>
|
||||
|
||||
<ul>
|
||||
|
|
|
|||
Loading…
Reference in a new issue