Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 25.04.2018, 17:49
Интересующийся
Отправить личное сообщение для Герасим Посмотреть профиль Найти все сообщения от Герасим
 
Регистрация: 22.09.2017
Сообщений: 24

переименовать название стилей в 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?
Ответить с цитированием
  #2 (permalink)  
Старый 25.04.2018, 18:19
Профессор
Отправить личное сообщение для Dilettante_Pro Посмотреть профиль Найти все сообщения от Dilettante_Pro
 
Регистрация: 27.11.2015
Сообщений: 2,899

Герасим,
А зачем у вас CDATA?
Мне кажется, без нее будет то же самое
Ответить с цитированием
  #3 (permalink)  
Старый 25.04.2018, 18:33
Профессор
Отправить личное сообщение для Dilettante_Pro Посмотреть профиль Найти все сообщения от Dilettante_Pro
 
Регистрация: 27.11.2015
Сообщений: 2,899

<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

Последний раз редактировалось Dilettante_Pro, 25.04.2018 в 18:46.
Ответить с цитированием
  #4 (permalink)  
Старый 25.04.2018, 19:23
Интересующийся
Отправить личное сообщение для Герасим Посмотреть профиль Найти все сообщения от Герасим
 
Регистрация: 22.09.2017
Сообщений: 24

Очень-ультра-удобно рисовать мнемосхемы объектов в MS Visio, у него есть возможность сохранять изображения в SVG и они качественно отображаются в любых браузерах. Т.е. отказаться от Visio я не могу, чтобы в последствии сэкономить время Коллег на подготовку изображений (+ у нас их огромная база именно в Visio)
Visio сохраняет SVG именно и только так, вынося стили в CDATA. Дорабатывать каждый SVG руками, согласитесь не вариант.
Тогда как лучше сделать:
1) на этапе, когда SVG ещё представляет собой строку загруженную из файла, пропарсить строку с её CDATA и упоминаниями class в элементах?
2) когда я получил DOM SVG-фрагмента, использовать функции работы с DOM для поиска и переименования стилей? тогда вопрос какие?
Ответить с цитированием
  #5 (permalink)  
Старый 26.04.2018, 11:22
Профессор
Отправить личное сообщение для Dilettante_Pro Посмотреть профиль Найти все сообщения от Dilettante_Pro
 
Регистрация: 27.11.2015
Сообщений: 2,899

Герасим,
Сообщение от Герасим
1) на этапе, когда SVG ещё представляет собой строку загруженную из файла
Парсить не надо, можно обработать точно таким же replace, как и в моем примере.
Сообщение от Герасим
2) когда я получил DOM SVG-фрагмента
Можно и на этом этапе - смотри фрагмент.
Сообщение от Герасим
вопрос какие?
Что значит - какие?
В представленном вами фрагменте в исходном файле были классы типа _stN. Я заменил их на _svN - как в стилях, так и в элементах.

CDATA нисколько не мешает ни в первом, ни во втором случае.
Ответить с цитированием
  #6 (permalink)  
Старый 26.04.2018, 12:11
Аватар для Aetae
Тлен
Отправить личное сообщение для Aetae Посмотреть профиль Найти все сообщения от Aetae
 
Регистрация: 02.01.2010
Сообщений: 5,935

Вообще правильней всего исключить дополнительную нагрузку раз и навсегда - сделать постобработку каждого файла, заменяя имена классов на уникальные и сохраняя уже в таком виде.

Вот написанный на коленке скрипт на виндовом 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, либо, как вы и хотели, на продакшене, но последнее я бы не рекомендовал.
__________________
29375, 35

Последний раз редактировалось Aetae, 26.04.2018 в 13:56.
Ответить с цитированием
  #7 (permalink)  
Старый 08.05.2018, 14:20
Интересующийся
Отправить личное сообщение для Герасим Посмотреть профиль Найти все сообщения от Герасим
 
Регистрация: 22.09.2017
Сообщений: 24

Благодарю всех за идеи!
сдала так (это метод класса):
//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-фрагмент
    }


Мои опасения:
  1. сделано опасное умозаключение что svg.querySelector('style').childNodes[1].nodeValue это CDATA... а вдруг оно будет в childNodes[2]?!
  2. в месте: //Создаю массив элементов имеющих свойство class (т.е. со стилями)
    я сделал перебор всего content.all через цикл while.
    Может быть в JS есть хитрый querySelector чтобы сразу получить массив элементов имеющих атрибут class?
Ответить с цитированием
  #8 (permalink)  
Старый 08.05.2018, 15:21
Профессор
Отправить личное сообщение для Dilettante_Pro Посмотреть профиль Найти все сообщения от Dilettante_Pro
 
Регистрация: 27.11.2015
Сообщений: 2,899

Цитата:
сделано опасное умозаключение что svg.querySelector('style').childNodes[1].nodeValue это CDATA... а вдруг оно будет в childNodes[2]?!
Это ведь можно проверить.
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);

В конце - все элементы с классом

Последний раз редактировалось Dilettante_Pro, 08.05.2018 в 15:47.
Ответить с цитированием
  #9 (permalink)  
Старый 05.06.2018, 12:01
Аспирант
Отправить личное сообщение для ghost666 Посмотреть профиль Найти все сообщения от ghost666
 
Регистрация: 07.02.2016
Сообщений: 52

зачем городить такие навороты.
незнаю как в вашем редакторе - но в иллюстраторе при записи svg есть выбор "внутренняя таблица стилей" или без нее.
вообще для svg самый лучший инструмент иллюстратор.
Ответить с цитированием
  #10 (permalink)  
Старый 09.06.2018, 09:16
Интересующийся
Отправить личное сообщение для Герасим Посмотреть профиль Найти все сообщения от Герасим
 
Регистрация: 22.09.2017
Сообщений: 24

к сожалению, инструмент не могу поменять, онли MS Visio.
но все ответившим выше Спасибо!, свой вопрос я благодаря подсказкам решил, проект продолжается, тормозов с обработкой svg на старте приложения не замечаем.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск