How do I visually edit SVG without losing classes and attributes?
Asked Answered
F

1

9

TL;DR

When editing SVG > Illustrator > SVG, the original element classes are lost. How can I edit an svg file visually in a safe way?


A brief background. I was fascinated by the idea of a kind of GIS in miniature, based on a single svg-file. This is an interactive heat map of my hometown with color-coded architectural value of buildings and some visual effects not available in the Google Maps API. So, I have already managed to: convert the street map in the Mercator projection from OpenStreetMap to SVG with geo-referenced coordinates; link building polygons with addresses, number of floors and year of construction; achieve an acceptable scaling and scrolling performance (thanks to D3.js).

How I imagined working with SVG. Two sometimes alternating tasks:

  1. Visual geometry correction in Adobe Illustrator: correcting topographical errors, converting polygons into compound shapes (buildings with courtyards), etc.
  2. Work on data visualization using JavaScript and CSS in Chrome console. Adding multiple classes or data attributes to polygons, which are responsible for visual representation. Using different selectors and rules in the style sheet, I can, for example, create a glow around the polygon of a certain size, brightness and hue, according to the architectural style, height and time period in which the building was built: <polygon class="bld bld-type-public bld-age-soviet bld-style-constructivism" data-storeys="4" data-year="1927" id="b5270" points="2427,788 2435,786 2436,790 2433,791 2428,792"></polygon>

The process is long and iterative. A vector image requires periodic edits, in parallel with DOM manipulation based on the collected data.

Facing reality. Adobe Illustrator, as a powerful tool for editing complex vector images, converts the DOM of an SVG file into its own object model. But it doesn't do it completely. In my approach, some of the data is permanently lost after editing in Illustrator.

Data After editing in Adobe Illustrator
Point coordinates ✅ Saved as in the source SVG
Grouping of elements (<g>) ✅ Saved (available in the Layers panel)
IDs ✅ Saved (available as object names in the Layers panel)
CSS Classes ❌ Lost (any class list is replaced by a single class name like st0, st1... or a, b, c...)
Arbitrary (data-) attributes ❌ Lost

What to do?

All experiments were done on Adobe Illustrator CC 2019. The newest update cannot be installed on my macOS Mojave. I don't think anything has been updated in the SVG engine (or am I wrong?)

  • Are there any ways of setting up a vector editor for this kind of project?
  • Are there (suddenly) any secret ways to extend Chrome DevTools functionality for visual SVG editing in the browser?

Of course, there is always the option of postprocessing after each edit in Illustrator. Using ID I can restore the list of classes and/or attributes from an external data array (JSON). But I really don't want to complicate the process, which already seems a bit odd.

Minimum test SVG code:

<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 640 200" xml:space="preserve">
    <style type="text/css">
        .test {fill:red;}
        .test.blue {fill:blue;}
    </style>
    <g>
        <rect id="item1" data-test="1" x="190" y="20" class="test" width="120" height="120"/>
        <rect id="item2" data-test="1" x="322" y="20" class="test blue" width="120" height="120"/>
    </g>
</svg>

Here is the result of saving in Illustrator (merging/renaming classes, removing attributes):

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     viewBox="0 0 640 200" style="enable-background:new 0 0 640 200;" xml:space="preserve">
<style type="text/css">
    .st0{fill:#FF0000;}
    .st1{fill:#0000FF;}
</style>
<g>
    <rect id="item1" x="190" y="20" class="st0" width="120" height="120"/>
    <rect id="item2" x="322" y="20" class="st1" width="120" height="120"/>
</g>
</svg>

Grateful to the SO community for any help and tips!

Fool answered 10/2, 2022 at 19:33 Comment(10)
As a guess, is Inkscape inkscape.org able to do it? SVG is native format for Inkscape after all. Unfortunately it works on macOS not exactly well, but it works to some degree.Rigsby
This sounds quite promising: wiki.inkscape.org/wiki/Style_EditorRigsby
Even if the question doesn't meet the formal rule, I think it's not wise to apply this rule to this particular question. Where is supposed to ask such questions if not here? And the author demonstrates a great amount of research efforts. I vote to open the question.Rigsby
No, we shouldn't declare that some questions are special snowflakes and somehow exempt from the rules. One possible place this could be asked is Software RecommendationsCranium
@Cranium thank you for the link. I've never seen this option (and I suppose Alexey haven't as well). It would be much better if this link was provided every time someone closes a question with 'software recommendation'Rigsby
@YuriKhristich Thank you so much for your support of the question. Linkscape is a great editor indeed, but it's very slow on my Mac compared to Illustrator. I guess that's the price of full SVG compatibility. Especially when the file size is large, over 5 MBFool
Alas. Inkscape doesn't show great performance, especially on Mac. It looks a bit like on macOS it works via some emulator. I don't know, perhaps it works faster on Linux. It's an app from the Linux world after all.Rigsby
Have you tried this solution? It won't solve the stripping of data attributes, but hopefully will keep classes names.Countryandwestern
@FelipeSaldanha Yes, I am aware of this solution. In my case, classes are always declared outside of AI... Anyway, it looks like the SVG file will have to exist in two states for different tasks.Fool
I think that the sensible approach would be to have your data linked to a point, that is inside the svg polygon. You can then have a local process where the inputs are the base SVG and the list of coordinate points + data. And the output is the extended SVG. You can use this functions: https://mcmap.net/q/975965/-recognize-point-x-y-is-inside-svg-path-or-outsideDogeatdog
I
3

I highly recommend Boxy SVG as a visual editor for SVGs. It doesn’t use a separate object model, it’s 100% SVG. I don’t know if it will preserve all your manual edits, but I think it will go a lot closer than Illustrator does.

Here is the result of saving your minimum SVG test code in Boxy SVG:

<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 640 200" xml:space="preserve">
    <style type="text/css">
        .test {fill:red;}
        .test.blue {fill:blue;}
    </style>
    <g>
        <rect id="item1" data-test="1" x="190" y="20" class="test" width="120" height="120"/>
        <rect id="item2" data-test="1" x="322" y="20" class="test blue" width="120" height="120"/>
    </g>
</svg>

As you can see, the code is identical, so the process of loading into Boxy SVG and doing Save As has not destroyed anything. As far as I can make out, Boxy SVG doesn’t touch your style block or class attributes — in fact, it doesn’t even provide a way to edit them, it just leaves them alone.

Any changes you make to fill or stroke colours within Boxy SVG will be added as a style attribute on the object, and will of course override any styles assigned by a class. Here is the result of defining a couple of named colours in Boxy SVG and assigning them to your two objects. As you can see, the named colours are defined in a <def> block, and assigned with a style attribute, so they override the colours assigned by the class, but your class attributes and the style block itself remain untouched.

<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 640 200" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
  <defs>
    <linearGradient id="color-0" bx:pinned="true">
      <title>greyish green</title>
      <stop style="stop-color: rgb(115, 169, 111);"/>
    </linearGradient>
    <linearGradient id="color-1" bx:pinned="true">
      <title>pinkish</title>
      <stop style="stop-color: rgb(214, 98, 187);"/>
    </linearGradient>
  </defs>
  <style type="text/css">
        .test {fill:red;}
        .test.blue {fill:blue;}
    </style>
  <g>
    <rect id="item1" data-test="1" x="190" y="20" class="test" width="120" height="120" style="fill: url(#color-0);"/>
    <rect id="item2" data-test="1" x="322" y="20" class="test blue" width="120" height="120" style="fill: url(#color-1);"/>
  </g>
</svg>

Note that Boxy SVG has now made a couple of minor changes to the attributes of your SVG root element; these may or may not be significant to what you want to do.

Iodism answered 10/7, 2022 at 23:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.