169 lines
6.3 KiB
JavaScript
169 lines
6.3 KiB
JavaScript
/**
|
||
* @license
|
||
* The MIT License
|
||
*
|
||
* Copyright © 2012–2016 Kir Belevich
|
||
*
|
||
* Permission is hereby granted, free of charge, to any person
|
||
* obtaining a copy of this software and associated documentation
|
||
* files (the "Software"), to deal in the Software without
|
||
* restriction, including without limitation the rights to use,
|
||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
* copies of the Software, and to permit persons to whom the
|
||
* Software is furnished to do so, subject to the following
|
||
* conditions:
|
||
*
|
||
* The above copyright notice and this permission notice shall be
|
||
* included in all copies or substantial portions of the Software.
|
||
*
|
||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||
* OTHER DEALINGS IN THE SOFTWARE.
|
||
*
|
||
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
*
|
||
* Лицензия MIT
|
||
*
|
||
* Copyright © 2012–2016 Кир Белевич
|
||
*
|
||
* Данная лицензия разрешает лицам, получившим копию
|
||
* данного
|
||
* программного обеспечения и сопутствующей
|
||
* документации
|
||
* (в дальнейшем именуемыми «Программное Обеспечение»),
|
||
* безвозмездно
|
||
* использовать Программное Обеспечение без
|
||
* ограничений, включая
|
||
* неограниченное право на использование, копирование,
|
||
* изменение,
|
||
* добавление, публикацию, распространение,
|
||
* сублицензирование
|
||
* и/или продажу копий Программного Обеспечения, также
|
||
* как и лицам,
|
||
* которым предоставляется данное Программное
|
||
* Обеспечение,
|
||
* при соблюдении следующих условий:
|
||
*
|
||
* Указанное выше уведомление об авторском праве и
|
||
* данные условия
|
||
* должны быть включены во все копии или значимые части
|
||
* данного
|
||
* Программного Обеспечения.
|
||
*
|
||
* ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК
|
||
* ЕСТЬ»,
|
||
* БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНО ВЫРАЖЕННЫХ ИЛИ
|
||
* ПОДРАЗУМЕВАЕМЫХ,
|
||
* ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ ТОВАРНОЙ
|
||
* ПРИГОДНОСТИ,
|
||
* СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И
|
||
* ОТСУТСТВИЯ НАРУШЕНИЙ
|
||
* ПРАВ. НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ
|
||
* НЕСУТ
|
||
* ОТВЕТСТВЕННОСТИ ПО ИСКАМ О ВОЗМЕЩЕНИИ УЩЕРБА, УБЫТКОВ
|
||
* ИЛИ ДРУГИХ
|
||
* ТРЕБОВАНИЙ ПО ДЕЙСТВУЮЩИМ КОНТРАКТАМ, ДЕЛИКТАМ ИЛИ
|
||
* ИНОМУ,
|
||
* ВОЗНИКШИМ ИЗ, ИМЕЮЩИМ ПРИЧИНОЙ ИЛИ СВЯЗАННЫМ С
|
||
* ПРОГРАММНЫМ
|
||
* ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ПРОГРАММНОГО
|
||
* ОБЕСПЕЧЕНИЯ
|
||
* ИЛИ ИНЫМИ ДЕЙСТВИЯМИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.
|
||
*/
|
||
|
||
'use strict';
|
||
|
||
var JSAPI = require('../lib/svgo/jsAPI');
|
||
|
||
exports.type = 'full';
|
||
|
||
exports.active = false;
|
||
|
||
exports.description = 'Finds <path> elements with the same d, fill, and ' +
|
||
'stroke, and converts them to <use> elements ' +
|
||
'referencing a single <path> def.';
|
||
|
||
/**
|
||
* Finds <path> elements with the same d, fill, and stroke, and converts them to
|
||
* <use> elements referencing a single <path> def.
|
||
*
|
||
* @author Jacob Howcroft
|
||
*/
|
||
exports.fn = function(data) {
|
||
const seen = new Map();
|
||
let count = 0;
|
||
const defs = [];
|
||
traverse(data, item => {
|
||
if (!item.isElem('path') || !item.hasAttr('d')) {
|
||
return;
|
||
}
|
||
const d = item.attr('d').value;
|
||
const fill = (item.hasAttr('fill') && item.attr('fill').value) || '';
|
||
const stroke = (item.hasAttr('stroke') && item.attr('stroke').value) || '';
|
||
const key = d + ';s:' + stroke + ';f:' + fill;
|
||
const hasSeen = seen.get(key);
|
||
if (!hasSeen) {
|
||
seen.set(key, {elem: item, reused: false});
|
||
return;
|
||
}
|
||
if (!hasSeen.reused) {
|
||
hasSeen.reused = true;
|
||
if (!hasSeen.elem.hasAttr('id')) {
|
||
hasSeen.elem.addAttr({name: 'id', local: 'id',
|
||
prefix: '', value: 'reuse-' + (count++)});
|
||
}
|
||
defs.push(hasSeen.elem);
|
||
}
|
||
item = convertToUse(item, hasSeen.elem.attr('id').value);
|
||
});
|
||
const defsTag = new JSAPI({
|
||
elem: 'defs', prefix: '', local: 'defs', content: [], attrs: []}, data);
|
||
data.content[0].spliceContent(0, 0, defsTag);
|
||
for (let def of defs) {
|
||
// Remove class and style before copying to avoid circular refs in
|
||
// JSON.stringify. This is fine because we don't actually want class or
|
||
// style information to be copied.
|
||
const style = def.style;
|
||
const defClass = def.class;
|
||
delete def.style;
|
||
delete def.class;
|
||
const defClone = def.clone();
|
||
def.style = style;
|
||
def.class = defClass;
|
||
defClone.removeAttr('transform');
|
||
defsTag.spliceContent(0, 0, defClone);
|
||
// Convert the original def to a use so the first usage isn't duplicated.
|
||
def = convertToUse(def, defClone.attr('id').value);
|
||
def.removeAttr('id');
|
||
}
|
||
return data;
|
||
};
|
||
|
||
/** */
|
||
function convertToUse(item, href) {
|
||
item.renameElem('use');
|
||
item.removeAttr('d');
|
||
item.removeAttr('stroke');
|
||
item.removeAttr('fill');
|
||
item.addAttr({name: 'xlink:href', local: 'xlink:href',
|
||
prefix: 'none', value: '#' + href});
|
||
delete item.pathJS;
|
||
return item;
|
||
}
|
||
|
||
/** */
|
||
function traverse(parent, callback) {
|
||
if (parent.isEmpty()) {
|
||
return;
|
||
}
|
||
for (let child of parent.content) {
|
||
callback(child);
|
||
traverse(child, callback);
|
||
}
|
||
}
|