переименовать название стилей в SVG перед вставкой в другой SVG
Здравствуйте!
Тут наработанные сорцы: https://bitbucket.org/GerasimovGV/web_scada Вставляю SVG-фрагменты (подготовленные в редакторе) в соответствующие места (контейнеры) большого SVG (лежит в object но не суть) 1) загружаю фрагмент через XMLHttpRequest с ключом 'image/svg+xml' в итоге в var content получаю объект svg 2) через foreignObject вставляю фрагмент в большой SVG Короче меняю на лету фрагменты как хочу, всё вставляется, заменяется новыми фрагментами...НО!!! так как SVG-контейнер и SVG-фрагменты готовятся в одном и том же редакторе MS Visio, то стили фрагментов конфликтуют со стилями контейнера, тупо совпадают имена стилей, и это забавно... но мне надо без этого :) Решение: между 1 и 2-шагом должна быть функция, которая сделает "уникальными" имена стилей в SVG-фрагменте, переименует их Так выглядит SVGшка фрагмента:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="0.23622in" height="0.23622in" viewBox="0 0 17.0079 17.0079" xml:space="preserve" color-interpolation-filters="sRGB"
class="_st3">
<style type="text/css">
<![CDATA[
._st1 {fill:#7f7f7f;stroke:#595959;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
._st2 {fill:#595959;font-family:Calibri;font-size:0.833336em}
._st3 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
]]>
</style>
<g>
<g id="shape1-1">
<rect x="0" y="0" width="17.0079" height="17.0079" class="_st1"/>
<text x="6.19" y="11.5" class="_st2">?</text>
</g>
</g>
</svg>
Стили (_st1, _st2, _st3) находятся в CDATA, и потом встречаются в class элементов. Так как я получаю вначале SVG в виде строки (потом только преобразую в отбъект), я конечно могу потратить усилия распарсить строку найти все _stx заменить их на (например) _file_name_st1(2,3...) Но так как у меня есть и готовый SVG DOM-объект, то подскажите пожалуйста, какие есть способы изменить названия стилей заключёных в CDATA? |
Герасим,
А зачем у вас CDATA? Мне кажется, без нее будет то же самое |
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="0.23622in" height="0.23622in" viewBox="0 0 17.0079 17.0079" xml:space="preserve" color-interpolation-filters="sRGB"
class="_st3">
<style type="text/css">
<![CDATA[
._st1 {fill:#7f7f7f;stroke:#595959;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
._st2 {fill:#595959;font-family:Calibri;font-size:0.833336em}
._st3 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
]]>
</style>
<g>
<g id="shape1-1">
<rect x="0" y="0" width="17.0079" height="17.0079" class="_st1"/>
<text x="6.19" y="11.5" class="_st2">?</text>
</g>
</g>
</svg>
<script>
var svg = document.querySelector('svg');
svg.outerHTML = svg.outerHTML.replace(/_st/g,'_sv');
</script>
В DOM уже нет CDATA |
Очень-ультра-удобно рисовать мнемосхемы объектов в MS Visio, у него есть возможность сохранять изображения в SVG и они качественно отображаются в любых браузерах. Т.е. отказаться от Visio я не могу, чтобы в последствии сэкономить время Коллег на подготовку изображений (+ у нас их огромная база именно в Visio)
Visio сохраняет SVG именно и только так, вынося стили в CDATA. Дорабатывать каждый SVG руками, согласитесь не вариант. Тогда как лучше сделать: 1) на этапе, когда SVG ещё представляет собой строку загруженную из файла, пропарсить строку с её CDATA и упоминаниями class в элементах? 2) когда я получил DOM SVG-фрагмента, использовать функции работы с DOM для поиска и переименования стилей? тогда вопрос какие? |
Герасим,
Цитата:
Цитата:
Цитата:
В представленном вами фрагменте в исходном файле были классы типа _stN. Я заменил их на _svN - как в стилях, так и в элементах. CDATA нисколько не мешает ни в первом, ни во втором случае. |
Вообще правильней всего исключить дополнительную нагрузку раз и навсегда - сделать постобработку каждого файла, заменяя имена классов на уникальные и сохраняя уже в таком виде.
Вот написанный на коленке скрипт на виндовом jscript'е для этого:
(function(file){
var nextId = function(){
var hash = 0;
var index = 0;
for (var i = 0, chr; i < file.length; i++) {
chr = file.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0;
}
hash = hash.toString(36) + (+new Date()).toString(36);
return function(){
return 'st-' + hash + '-' + index++;
}
}();
var classMap = {};
var xml = new ActiveXObject("MSXML2.DOMDocument");
xml.load(file);
var style = xml.selectSingleNode('svg/style');
if(!style) return;
var css = style.text;
var elements = xml.selectNodes('//@class');
for (var i = 0, className; i < elements.length; i++) {
if(!classMap[className = elements[i].text]){
classMap[className] = nextId();
css = css.replace(
new RegExp('((?:^|\\})\\s*\\.)' + className + '(?=\\s|\\{)', 'mg'),
'$1' + classMap[className]
);
}
elements[i].text = classMap[className];
}
style.text = css;
xml.save(file)
}(WScript.arguments(0)));
(сохранить как файл js, перетянуть на него svg файл, либо вызывать с передачей адреса файла в параметре)Таким же образом с минимальными правками можно сделать на любом другом языке поддерживающем работу с xml, либо, как вы и хотели, на продакшене, но последнее я бы не рекомендовал. |
Благодарю всех за идеи!
сдала так (это метод класса):
//key - уникальное название картинки в массиве SVG-фрагментов (вот такой, например'switchOn')
//path - путь до картинки (вот такой, например './img/switchOn.svg')
this.loadImg = function (key, path){
//надо менять название стилей именно в CDATA так как хоть и названия
//стилей в элементах поменялись, но в CDATA они остались
//1) загрузил указанный имидж
var xmls = getSyncTextFileContent(path);
var content = strToXML(xmls, 'image/svg+xml');//это XML-документ
//2) получил из него svg-объект
var svg = content.querySelector('svg');
//Создаю массив элементов имеющих свойство class (т.е. со стилями)
var aec = [];//массив элементов имеющих стиль
var styles=[];//массив названий стилей
var i = content.all.length;//кол-во элементов в XML
//перебираю массив в поисках элементов имеющих свойство "class"
while (i--) {
if (content.all[i].classList.length){//у элементов имеющих аттрибут "class" classList.length не НОЛЬ
aec.push(content.all[i]);//нашёл, добавляю в массив
if (styles.indexOf(content.all[i].classList[0]) == -1)//если названия стиля ещё нет в массиве
styles.push(content.all[i].classList[0]); //добавить его туда
}
}
//и так на выходе у меня:
// aec[] - массив элементов имеющих стили
// styles[] - массив названий стилей
//Теперь возьму CDATA из SVG
var cdata = svg.querySelector('style').childNodes[1].nodeValue;
//И начну менять стили
i = styles.length;
while (i--){
var newClassName = styles[i]+'_'+key;//новое название стиля
//меняю название стилей у элементов
var j = aec.length;
while (j--){
if (aec[j].classList[0] == styles[i])
aec[j].setAttribute('class', newClassName);
}
//меняю названия стилей в копии CDATA
cdata = cdata.replace(styles[i],newClassName);
}
//устанавливаю новое значение CDATA
svg.querySelector('style').childNodes[1].nodeValue = cdata;
console.log(svg);
return svg;//возвращаю модифицированный SVG-фрагмент
}
Мои опасения:
|
Цитата:
function strToXML(xmlString){
var dom_parser = ("DOMParser" in window && (new DOMParser()).parseFromString) ||
(window.ActiveXObject && function(_xmlString) {
var xml_doc = new ActiveXObject('Microsoft.XMLDOM');
xml_doc.async = 'false';
xml_doc.loadXML(_xmlString);
return xml_doc;
});
if(!dom_parser){
return false;
}
return dom_parser.call("DOMParser" in window && (new DOMParser()) || window, xmlString, 'text/xml');
}
var xmls = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="0.23622in" height="0.23622in" viewBox="0 0 17.0079 17.0079" xml:space="preserve" color-interpolation-filters="sRGB" class="_st3">
<style type="text/css">
<![CDATA[
._st1 {fill:#7f7f7f;stroke:#595959;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.75}
._st2 {fill:#595959;font-family:Calibri;font-size:0.833336em}
._st3 {fill:none;fill-rule:evenodd;font-size:12px;overflow:visible;stroke-linecap:square;stroke-miterlimit:3}
]]>
</style>
<g>
<g id="shape1-1">
<rect x="0" y="0" width="17.0079" height="17.0079" class="_st1"/>
<text x="6.19" y="11.5" class="_st2">?</text>
</g>
</g>
</svg>`;
var content = strToXML(xmls, 'image/svg+xml');
var svg = content.querySelector('svg');
alert(svg.querySelector('style').childNodes[1].nodeName);
var cdata = svg.querySelector('style').childNodes[1].nodeValue;
alert(cdata);
alert(content.querySelectorAll('[class]').length);
В конце - все элементы с классом |
зачем городить такие навороты.
незнаю как в вашем редакторе - но в иллюстраторе при записи svg есть выбор "внутренняя таблица стилей" или без нее. вообще для svg самый лучший инструмент иллюстратор. |
к сожалению, инструмент не могу поменять, онли MS Visio.
но все ответившим выше Спасибо!, свой вопрос я благодаря подсказкам решил, проект продолжается, тормозов с обработкой svg на старте приложения не замечаем. |
| Часовой пояс GMT +3, время: 10:09. |