Рубрики
Без рубрики

Сервировка кликабельная масштабируемая векторная графика (SVG) Часть 1

Это первый шаг в достижении анимированной страницы SVG. Это охватывает некоторую предварительную обработку.

Автор оригинала: Richard Leddy.

Выйти за пределы HTML

P1.PNG.PNG

В этом руководстве предполагает некоторые знания JavaScript, HTML и Node.js

SVG Масштабируемая векторная графика – это часть HTML5. Это также язык разметки.

SVG Допускает рендеринг графики в виде линейных рисунков. Вы делаете чертежи, которые выглядят как HTML-страница. Или вы можете создавать художественные мастер-кусочки.

Итак, почему бы не использовать его больше? Возможно, дизайнеры интерфейса не знают, насколько легко получить интерфейсы SVG. Есть инструменты с открытым исходным кодом, такие как Inkscape, которые можно использовать для наведения страниц SVG. И есть пакеты JavaScript, которые делают его довольно легко манипулировать чертежами SVG на веб-странице. Один такой пакет D3.

Где вы можете использовать SVG? В любом номере веб-браузера Google Chrome, Apple Safari, например. Webkit поддерживает это тоже.

Какое значение поддержки WebKit? Страницы SVG портативны по многим средам, которые могут быть в планшете или мобильном мире так же, как и в чем-то, принадлежащем на рабочем столе. WebKit можно найти как часть Android, QT, IOS и других.

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

Но есть и другие преимущества. Подумайте, сколько работы сделано для создания DIV в HTML и иметь их в правильном месте на веб-странице. В SVG работа по сути сделана. Элементы размещаются на пиксельных системах координат. И, SVG может быть масштабирован. Одна вещь, которая может произойти, это то, что один SVG может быть масштабирован и встроен в другой. Итак, подумайте о рекалировании на парении, довольно сложной компоненте, который придумывая, представляет кликабельные компоненты. SVG может перекрываться. И, так же динамично, как и любая HTML-страница.

В этом руководстве давайте приблизимся к SVG и как он взаимодействует с JavaScript. Это будет первый шаг, ведущий к поддержке интерактивных визуализаций и многое другое.

Есть несколько шагов, чтобы пройти до того, как мы сможем получить живую страницу. Вот те, которые мы возьмем в этом руководстве.

  • Создайте графику SVG для обслуживания на странице.
  • Сделайте небольшую утилиту JavaScript для создания некоторых кода для инструментов анимации.
  • Настройте простой сервер Node.js с использованием Express для обслуживания страницы
  • Создать JavaScript, который будет анимировать SVG
  • Запустите страницу в браузере.

Просто те несколько шагов могут быть очень сложными. Но мы все еще можем многое сделать без слишком большого количества труда. Мы будем придерживаться более легкой стороны вещей, но немного показывать, когда мы закончим.

Сделайте файл SVG для начала

Первое изображение на этой странице началась как файл SVG, сделанный с помощью программы Draiwing, которую вы можете получить бесплатно.

Для моего Mac я получил inkscape здесь: Inkscape для Mac Вы также можете получить его для Linux и Windows. Страница загрузки Inkscape

Рисунок картина не сложно. Это просто круги, рецепты и разъемные линии. Единственное, что вы не видите на картинке выше, состоит в том, что круги, и Rects были предоставлены специальные имена. Причина этого является то, что мы можем написать код для обработки изображения и включить его в функционирующий график, который имеет специальные свойства. В этом руководстве мы можем превратить график в простой функционирующую чистую Петри.

Источник для картины доступен в следующем расположении на GitHub: SVG Source.

Вы можете увидеть, что есть круг Элементы с идентификатором как Круг-вход – A или Круг-государство-G или Круг-выход-Q Отказ Есть rect Элементы с идентификатором как Regl-Transition-H-Q C. Итак, некоторые круги были маркированы, указывающие на то, что они предназначены для Intput, а некоторые для вывода. Другие круги являются внутренними, или их можно назвать «скрытым» в некоторых сетевых номенклатурах. По крайней мере, мы можем их идентифицировать и классифицировать их. Между слоями кругов, являются переходами. Рекс Были названы таким образом, чтобы мы могли видеть, какие круги являются вводами для переходов и которые являются выходами.

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

Если вы нарисуете картинку в Inkscape, вы можете установить идентификатор объектов, выбрав объект и работаю в панели свойств объекта.

Последнее о файле, состоит в том, что есть коллекция скрытых кругов, все это токены. Для нашей анимации мы хотим показать и скрыть жетоны в соответствии с нашими пожеланиями.

Сделайте инструмент для обработки страницы SVG.

Страница SVG имеет информацию в нем, которая описывает подключение графика. Я не люблю делать много работы, набрав все ту же информацию в программе JavaScript, просто для работы с информацией уже на рисунке. Итак, давайте напишем простой инструмент, который читает на странице и обрабатывает его.

Мы можем написать инструмент в JavaScript, используя Node.js. Все, что нам нужно сделать, это прочитать файл, обрабатывать его XML, получите информацию, которую мы нуждаемся, организуйте его в полезных структурах данных и выведите все наши вновь сделанные программитическими описаниями в файлы для использования на веб-странице. К счастью, поскольку Node.js имеет довольно большое общевое сообщество, трудно найти поддержку инструментов, которые делают задачу довольно легко.

Установите xmldom.

Первое, что мы должны иметь в виду, это то, что наш файл SVG – это версия XML. Было бы здорово, если бы мы могли найти маленькую библиотеку для работы на XML для нас, и мы можем просто работать с ним. И, повезло за нас, есть один. И, если Node.js установлен на вашей системе с NPM, это не должно быть проблемой.

Если вы еще не установили Node.js, NPM и решили в каталоге, сейчас было бы хорошим временем, чтобы позаботиться об этом. В этом руководстве откладываются на другие учебные пособия по инструкции о том, как это сделать.

Получите окно консоли клеммы вверх и запустите в каталоге, в котором вы планируете написать модули Node.js для этого упражнения. Введите следующее:

  npm install xmldom

Теперь мы готовы написать простой инструмент, который использует этот модуль в качестве его основы.

Быстро – сделать инструмент обработки XML для предварительной обработки сети

Это будет маленький node.js полезность.

Вот первый список мы сделаем. Это еще не работает программа, она нуждается в определении функции. Но он устанавливает основы, необходимые для начала загрузки данных и обработки структуры XML. Доступ к модулям, необходимым для управления файлами и манипуляциями XML. Обратите внимание, что DomParser является объектом, на который ссылается модуль XMLDOM. Приложение будет смотреть, чтобы загрузить файл, набранный на консоли. Этот файл хранится в процессе.argv [2].

var fs = require('fs');   // for reading and writing files.
var DOMP = require('xmldom');  // for parsing an xml file.
var DOMParser = DOMP.DOMParser;  // The parser object provided by xmldom

var filename = process.argv[2];   // get the file name from the command line.

// planning to output a description of the file
// the description can be stored as a json object.

var outFile = filename.replace('.json');

// node.js file system method call
fs.readFile(filename,(err,data) => {

                if ( err ) {  
                	// always check for error, there might 
                    // have been a typo on the command line
                    console.log(err);
                    return;
                }

        // The data is in a buffer at the moment. 
                // So, turn it into a string.
                var svgStr = data.toString(); 

                // This method is about to be defined.
                // The plan is that it will find the elements 
                // that our application will need
                // to manipulate in the end result, the working web page.
                var elementIds = getAllElementsIds(svgStr);

                // Let the parser do its work. 
                // The parser will return a detailed data
                // structure representing the document.
                var doc = new DOMParser().parseFromString(svgStr,'text/xml');
                
                // 

            });

Глядя на корпус обратного вызова readfile, вы можете увидеть, что программа вызывает getAllelementss в строке. Таким образом, план этого небольшого применения должен читать в идентификаторах, найденных в строке, который имеет SVG. После того, как строка отдается все свои идентификаторы элементов, передается в парсер DOM, чтобы сделать объект готов к дальнейшей обработке. Мы хотим выбрать идентификаторы для поиска элементов. Задача получения идентификаторов, возможно, была сделана после разбора, прогуливаясь по дереву элементов SVG. Но в этом небольшом применении программа просто будет искать текст для них.

Способ, который будет искать текст для IDS, является GetAllelementsIDS. И вот как это написано.

function getAllElementsIds(svgStr) {

    // First find all non-conventional ids
    // This makes is so that the start of each
    // array elment is the beginning of an id definition.

    var idAll = svgStr.split(' id=');
    var elementIds = [];  // Initialize an array variable

    idAll.forEach( (nextStr) => {
    		// processes each array element.
            // Take them out as substrings.
            var idDef = nextStr.substr(0,nextStr.indexOf("\"",5)).substr(1);
            // Now use a regular expression to use onl id's that are
            // fairly much like variable.s
            if ( !((/[a-z]+[0-9]+$/).test(idDef)) ) {
            	elementIds.push(idDef);  // put those into our array.
            }
        } );

    // All the Id's we need.
    return(elementIds);
}

Вы можете поставить этот метод в файл JS. Найдите место для этого, который соответствует вашему стилю программирования. (Мне случается, как положить определения функций перед их использованием.)

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

   node .js p1.svg

Примечание. Я использую стиль <имя> «Ваше имя программы здесь».

Если вы запускаете программу, вы заметите, что это ничего не делает. Итак, давайте изменим это положение дел. Возможно, вы заметили тег <Полезный код пойдет сюда>. Именно здесь мы можем поставить код для сбора информации о наших специально названных элементах SVG.

То, что мы хотим сделать, это пройти через список идентификаторов, которые мы получили, и посмотрим, могут ли их использовать при разработке чистой Петри. Поскольку мы выбрали для названия некоторых элементов SVG с указанием имен, IDS, мы можем искать тех особенно. Итак, он выглядит как хорошая идея, чтобы пройти список идентификаторов и проверить их на наше имя. Затем, в зависимости от наших тестов, мы можем классифицировать их для использования или передавать их.

Теперь замена//<полезный код будет здесь> с новым кодом, мы расширяем код в дальнейшем как таковой:

// create a place to store descriptive information
var tagMap = {
'inputs' : [],
'outpus' : [],
'states' : [],
'tokens' : [],
'transitions' : []
};

// create a set of regular expressions to capture our naming scheme.
var circInputRegEx = new RegExp(/circle-input-\w+/)
var circOutputRegEx = new RegExp(/circle-output-\w+/)
var circStateRegEx = new RegExp(/circle-state-\w+/)
var circTokenRegEx = new RegExp(/circle-token-\w+/)
var rectTransitionRegEx = new RegExp(/rect-transition-\w+-\w+/)

var isPetriElement = (elId) => {
  return( circInputRegEx.test(elId)
   		|| circOutputRegEx.test(elId)
   		|| circStateRegEx.test(elId)
   		|| rectTransitionRegEx.test(elId)
   		|| circTokenRegEx.test(elId)
  );
}

// walk throught the list of ids that we scraped from the SVG text.
elementIds.forEach( elId => {

           // run the test function
           if ( isPetriElement(elId) ) {
               //
               // So, it is one of our elements go get information about.

               // The authors of xmldom thought enough to have a getElementById
               // which is familiar from HTML DOM JavaScript.

               // Calling this may be redundant.
               // But, besides showing the reader that this
               // call is available. We can check that our elId is a real element.
               var fObj = doc.getElementById(elId);

               if ( fObj ) {
                   // The tool that we are building here does not need much more
                   // than the ids. But, I just wanted to introduce this module.
                   // If you want to change the SVG, this can be done with this tool
                   // prior to hosting it.

                   // Having said that, I will go ahead and put code in here
                   // where the existence of the element is fairly well verified.

                   // This is a good place to further classify the element.
                   // Now that we know the elId is one of our patterns,
                   // we can use the pattern by breaking it into pieces and
                   // working with what it is describing. (Don't forget that
                   // we chose this pattern. So, we are processing one file.
                   // But, the tool is for any file where the pattern has been used.

                   // First split the pattern apart
                   var idPieces = elId.split('-');
                   
                   // id pieces
                   if ( idPieces.length > 2 ) {  // this should be true
                   		if (idPieces[0] === 'circle' ) {
                  			// this will be four types of cirlces
                   		} else {
                       		// this will be the transitions.
                   		}
                   }
               }
           }
       } )

Этот код отклоняет нас до места, где мы, наконец, решаем, что делать с Rects и Curres. Давайте добавим в этот код дальше.

Одна вещь, которую мы можем сделать сразу, просто классифицируйте элементы SVG. Следующее может заменить код//ID-код выше.

       if ( idPieces[0] === 'circle' ) {
           // this will be four types of cirlces
           var circType = idPieces[1];
           switch ( circType ) {
               case "input" : {
                   tagMap.inputs.push(elId);
                   break;
               }
               case "output" : {
                   tagMap.outpus.push(elId);
                   break;
               }
               case "state" : {
                   tagMap.states.push(elId);
                   break;
               }
               case "token" : {
                   tagMap.tokens.push(elId);
                   break;
               }
           }
       } else if ( idPieces[0] === 'rect' ) {
           // this will be the transitions.
           var rectType = idPieces[1];

           if ( rectType == "transition" ) {
               tagMap.transitions.push(elId);
           }
       }

В конце концов вы можете позвонить console.dir (tagmap) чтобы увидеть это на консоли. Вот вывод вы можете ожидать от собранного кода.

{ inputs: 
   [ 'circle-input-C',
     'circle-input-A',
     'circle-input-D',
     'circle-input-E',
     'circle-input-B' ],
  outpus: [ 'circle-output-Q', 'circle-output-P' ],
  states: [ 'circle-state-F', 'circle-state-G', 'circle-state-H' ],
  tokens: 
   [ 'circle-token-A',
     'circle-token-B',
     'circle-token-C',
     'circle-token-D',
     'circle-token-G',
     'circle-token-H',
     'circle-token-E',
     'circle-token-F',
     'circle-token-P',
     'circle-token-Q' ],
  transitions: 
   [ 'rect-transition-A:B-F',
     'rect-transition-F:G-P',
     'rect-transition-H-Q' ] }

Теперь это все хорошо и хорошо. Но иногда небольшая предварительная обработка поможет, когда она приходит к получению окончательного приложения. Итак, давайте настроим переходы, чтобы рассказать нам нечто большее, чем их имена. Поскольку их имена несут информацию, они могут быть проанализированы и готовы при запуске окончательного приложения. Но зачем положить эту обработку в конце? Это можно сделать сейчас и использоваться много раз спустя. Токены также могут быть обработаны тоже, хотя им может потребоваться меньше работы.

Для начала, давайте изменим массивы токенов на объекты, чтобы они могли использоваться в качестве отображений между именами элементов и их информационными объектами.

Мы можем переопределить тары следующим образом:

var tagMap = {
'inputs' : [],
'outpus' : [],
'states' : [],
'tokens' : {},  // These are for maps
'transitions' : {}
};

Теперь, вместо того, чтобы положить объект на тогдашний массив, они сопоставлены. И их позиции карты могут быть назначены информационные объекты. Информационные объекты могут указывать на входные и выходные имена, намекающие на имена переходов.

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

var findPetriState = (suffix) {
    // Try to find the element in the SVG DOM
    // But, the different classes have to be tested
    // because that information is not included in the token name.
    var target = "circle-input-" + suffix;
    if ( doc.getElementById(target) !== undefined ) {
        return(target)
    }
    target = "circle-output-" + suffix;
    if ( doc.getElementById(target) !== undefined ) {
        return(target)
    }
    target = "circle-state-" + suffix;
    if ( doc.getElementById(target) !== undefined ) {
        return(target)
    }
    return(undefined)
}

Обратите внимание, что xmldom Объект используется для поиска. Программист ленивый? Перах. Но файл SVG уже проанализирован, и инструмент, который собирает данные, все еще ищет узлов. Таким образом, узел может быть не учитывается. Таким образом, массивы в Tagmap не следует искать, чтобы узнать, если имя узла сделало его в файл SVG. Программа короче, чем это тоже, что это хорошо.

Теперь переходы требуют аналогичного поиска. Но для перехода необходимо сделать четкое различие между узлами ввода и вывода. Итак, нам все еще нужна поисковая рутина. Но вышеуказанная функция – это то, что нам нужно, хотя он делает слишком много одновременно. Таким образом, один план действий состоит в том, чтобы разбить функцию в более конкретные функции. Вот переписать вышеуказанную функцию, с помощниками, которые могут быть использованы переходами.

    var findPetriStateOfType = (ptype,suffix) => {
        var target = `circle-${ptype}-` + suffix;
        if ( doc.getElementById(target) !== null ) {
            return(target)
        }
        return(undefined)
    }
    
    var findTransitionInput = (suffix) => {
        var target = targetfindPetriStateOfType("input",suffix);
        if ( target ) return(target);
        target = targetfindPetriStateOfType("state",suffix);
        return(target);
    }
    
    var findTransitionOutput = (suffix) => {
        var target = targetfindPetriStateOfType("output",suffix);
        if ( target ) return(target);
        target = targetfindPetriStateOfType("state",suffix);
        return(target);
    }
    
    var findPetriState = (suffix) {
        var target = targetfindPetriStateOfType("input",suffix);
        if ( target ) return(target);
    
        target = targetfindPetriStateOfType("output",suffix);
        if ( target ) return(target);
    
        target = targetfindPetriStateOfType("state",suffix);
        return(target);
    }

Есть все виды способов сократить этот код. Но я не прекращаю, чтобы потратить время. Это довольно легко понять, и это сделает работу.

Таким образом, используя эти функции, у нас есть изменение в корпус токена следующим образом:

    case "token" : {
        var target = idPieces[2];
        target = findPetriState(target);
        if ( target !== undefined ) {
            tagMap.tokens[elId] = {
                'target' : target
            };
        }
        break;
    }

И изменение кода Tnanstions выглядит следующим образом:

if ( rectType == "transition" ) {

    if ( idPieces.length > 3 ) {

        // findTransitionInput
        // findTransitionOutput
        var inputs = idPieces[2];
        var outputs = idPieces[3];

        // For transitions, the pieces are node name hints
        // separated by colons ':'
        // So, we want to break these apart.

        // Using JavaScript type indifference to overwrite a source variable.
        // Sometimes coding requirements don't allow this. But, it's OK here.
        inputs = inputs.split(':');
        outputs = outputs.split(':');

        // now we can transform the hints into id's.

        inputs = inputs.map((nodeId) => {
                                 var input = findTransitionInput(nodeId);
                                 if ( input == undefined ) return("");
                                 return(input);
                             })

        outputs = outputs.map((nodeId) => {
                                 var output = findTransitionOutput(nodeId);
                                 if ( output == undefined ) return("");
                                 return(output);
                             })

        // before releasing this to the following processes.
        // make sure that we filter out the absent nodes.

        inputs = inputs.filter((nodeId) => {  return(nodeId.length > 0); })
        outputs = outputs.filter((nodeId) => {  return(nodeId.length > 0); })

        // now include the names with the transitions
        tagMap.transitions[elId] = {
            "inputs" : inputs,
            "outputs" : outputs
        }
    }
}

Когда вся сборка кода выполняется в файле, следующие результаты вывода:

{
  "inputs": [
    "circle-input-C",
    "circle-input-A",
    "circle-input-D",
    "circle-input-E",
    "circle-input-B"
  ],
  "outpus": [
    "circle-output-Q",
    "circle-output-P"
  ],
  "states": [
    "circle-state-F",
    "circle-state-G",
    "circle-state-H"
  ],
  "tokens": {
    "circle-token-A": {
      "target": "circle-input-A"
    },
    "circle-token-B": {
      "target": "circle-input-B"
    },
    "circle-token-C": {
      "target": "circle-input-C"
    },
    "circle-token-D": {
      "target": "circle-input-D"
    },
    "circle-token-G": {
      "target": "circle-state-G"
    },
    "circle-token-H": {
      "target": "circle-state-H"
    },
    "circle-token-E": {
      "target": "circle-input-E"
    },
    "circle-token-F": {
      "target": "circle-state-F"
    },
    "circle-token-P": {
      "target": "circle-output-P"
    },
    "circle-token-Q": {
      "target": "circle-output-Q"
    }
  },
  "transitions": {
    "rect-transition-A:B-F": {
      "inputs": [
        "circle-input-A",
        "circle-input-B"
      ],
      "outputs": [
        "circle-state-F"
      ]
    },
    "rect-transition-C-G": {
      "inputs": [
        "circle-input-C"
      ],
      "outputs": [
        "circle-state-G"
      ]
    },
    "rect-transition-F:G-P": {
      "inputs": [
        "circle-state-F",
        "circle-state-G"
      ],
      "outputs": [
        "circle-output-P"
      ]
    },
    "rect-transition-H-Q": {
      "inputs": [
        "circle-state-H"
      ],
      "outputs": [
        "circle-output-Q"
      ]
    }
  }
}

Итак, это хорошая отправная точка. Далее мы можем автоматизировать некоторые изменения в SVG, получая контент, который будет легко анимировать с довольно обобщенным кодом.

Сделайте инструмент для изменения страницы SVG.

Это помогает служить на странице SVG с действиями, указанными в SVG. Один из них, предварительно обработка, сделанная здесь, может подождать, пока страница не будет загружена. Но это не нужно. Кроме того, мы могли бы редактировать текст SVG вручную и добавить действия. Но, вместо того, чтобы всегда делать это, пусть программа сделает это. Таким образом, используя структуру, которая уже установлена в предыдущем инструменте, мы можем работать больше с элементами.

Мы уже установили xmldom к задаче разбора файла SVG. Теперь мы можем нам xmldom добавить ссылки на наши действия. Действия являются приходами к тегам в конце концов.

Итак, мы позволяем xmldom Получите элементы, которые мы желаем формулировать и устанавливать атрибуты.

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

var fs = require('fs');   // for reading and writing files.

var DOMP = require('xmldom');  // for parsing an xml file.

var DOMParser = DOMP.DOMParser;  // This is the actual parser object provided by xmldom


var filename = process.argv[2];   // get the file name from the command line.


// planning to output a description of the file
// the description can be stored as a json object.

var outFile = filename.split('.');
var suffix = outFile[outFile.length - 1];
outFile = outFile.join('.') + "-revised."
outFile += suffix;


function getAllElementsIds(svgStr) {

    // First find all non-conventional ids
    // This makes is so that the start of each
    // array elment is the beginning of an id definition.

    var idAll = svgStr.split(' id=');
    var elementIds = [];  // Initialize an array variable

    idAll.forEach( (nextStr) => {
                      // processes each array element.
                      // Take them out as substrings.
                      var idDef = nextStr.substr(0,nextStr.indexOf("\"",5)).substr(1);
                      // Now use a regular expression to use onl id's that are
                      // fairly much like variable.s
                      if ( !((/[a-z]+[0-9]+$/).test(idDef)) ) {
                          elementIds.push(idDef);  // put those into our array.
                      }
                  } );

    // All the Id's we need.
    return(elementIds);
}



fs.readFile(filename,(err,data) => {

                if ( err ) {  // always check for error, there might have been a typo on the command line
                    console.log(err);
                    return;
                }

                var svgStr = data.toString(); // the data is in a buffer at the moment. So, turn it into a string.

                // This method is about to be defined.
                // The plan is that it will find the elements that our application will need
                // to manipulate in the end result, the working web page.
                var elementIds = getAllElementsIds(svgStr);

                // Let the parser do its work. It will return a detailed data structure representing the document.
                var doc = new DOMParser().parseFromString(svgStr,'text/xml');

                // create a set of regular expressions to capture our naming scheme.
                var circInputRegEx = new RegExp(/circle-input-\w+/)
                var circOutputRegEx = new RegExp(/circle-output-\w+/)
                var circStateRegEx = new RegExp(/circle-state-\w+/)
                var circTokenRegEx = new RegExp(/circle-token-\w+/)
                var rectTransitionRegEx = new RegExp(/rect-transition-(\w+|\:)+-\w+/)

                var petriElementType = (elId) => {
                    if ( circInputRegEx.test(elId) ) return("input");
                    if ( circOutputRegEx.test(elId) ) return("output");
                    if ( circStateRegEx.test(elId) ) return("state");
                    if ( circTokenRegEx.test(elId) ) return("token");
                    if ( rectTransitionRegEx.test(elId) ) return("transition");
                    return(undefined)
                }

                // walk throught the list of ids that we scraped from the SVG text.
                elementIds.forEach( elId => {

                                       var peType = petriElementType(elId)
                                       if ( peType ) {
                                           //
                                           var fObj = doc.getElementById(elId);

                                           if ( fObj ) {

                                               switch ( peType ) {
                                                   case "input" : {
                                                       fObj.setAttribute("class","svgPetriNodeInput");
                                                       fObj.setAttribute("onhover","svgPetriNodeHover(this,event,'input')");
                                                       fObj.setAttribute("onmouseenter","svgPetriNodeEnter(this,event,'input')");
                                                       fObj.setAttribute("onmouseleave","svgPetriNodeLeave(this,event,'input')");
                                                       fObj.setAttribute("onlcick","svgPetriNodeClick(this,event,'input')");
                                                       break;
                                                   }
                                                   case "output" : {
                                                       fObj.setAttribute("class","svgPetriNodeOutput");
                                                       fObj.setAttribute("onhover","svgPetriNodeHover(this,event,'output')");
                                                       fObj.setAttribute("onmouseenter","svgPetriNodeEnter(this,event,'output')");
                                                       fObj.setAttribute("onmouseleave","svgPetriNodeLeave(this,event,'output')");
                                                       fObj.setAttribute("onlcick","svgPetriNodeClick(this,event,'output')");
                                                       break;
                                                   }
                                                   case "state" : {
                                                       fObj.setAttribute("class","svgPetriNodeState");
                                                       fObj.setAttribute("onhover","svgPetriNodeHover(this,event,'state')");
                                                       fObj.setAttribute("onmouseenter","svgPetriNodeEnter(this,event,'state')");
                                                       fObj.setAttribute("onmouseleave","svgPetriNodeLeave(this,event,'state')");
                                                       fObj.setAttribute("onlcick","svgPetriNodeClick(this,event,'state')");
                                                       break;
                                                   }
                                                   case "token" : {
                                                       fObj.setAttribute("class","svgPetriNodeToken");
                                                       fObj.setAttribute("onhover","svgPetriNodeHover(this,event,'token')");
                                                       fObj.setAttribute("onmouseenter","svgPetriNodeEnter(this,event,'token')");
                                                       fObj.setAttribute("onmouseleave","svgPetriNodeLeave(this,event,'token')");
                                                       fObj.setAttribute("onlcick","svgPetriNodeClick(this,event,'token')");
                                                       break;
                                                   }
                                                   case "transition" : {
                                                       fObj.setAttribute("class","svgPetriTransition");
                                                       fObj.setAttribute("onhover","svgPetriNodeHover(this,event,'transition')");
                                                       fObj.setAttribute("onmouseenter","svgPetriNodeEnter(this,event,'transition')");
                                                       fObj.setAttribute("onmouseleave","svgPetriNodeLeave(this,event,'transition')");
                                                       fObj.setAttribute("onlcick","svgPetriNodeClick(this,event,'transition')");
                                                       break;
                                                   }
                                                   default : {
                                                       break;
                                                   }
                                               }

                                           }

                                       }

                                   });


                // The last thing we need to do is write out the new SVG file.
                // Fortunately, xmldom has a serializer.  It outputs SVG that
                // will load into the browser without a problem. Its detailed format
                // is something I am not going to worry about.

                var s = new DOMP.XMLSerializer();
                var str = s.serializeToString(doc);

                fs.writeFileSync(outfilename,str);

            });

Так что это полный список инструмента, который впрыскивает обработчики событий в SVG. Теперь мы захочем использовать его.

Скоро будет

Это часть одна из этих упражнений. Следующая часть будет адресовать настройку очень небольшого Express Server для обслуживания страницы.