You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
168 lines
6.3 KiB
168 lines
6.3 KiB
/** |
|
* @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); |
|
} |
|
}
|
|
|