переименовать название стилей в 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, время: 18:03. |