iconic / illustrator-svg-exporter

A better way to generate SVGs from Illustrator.
603 stars 45 forks source link

Possible to define id or class in the layer name? #2

Closed danielbayley closed 9 years ago

danielbayley commented 9 years ago

I was looking through the script trying to figure out if (since it would be handy) this would translate layer names like .class into class="class" and #id to id="id" (and anything else to class="class" by default) in the output SVG.

Currently .class results in _x2E_class, and #id in _x23_id. I'm wondering if this is Illustrator's doing and beyond control of this script?

I'd attempt a PR to implement this, but obviously that'd be a waste of time if this isn't even possible.

somerandomdude commented 9 years ago

Hey Daniel, unfortunately we're completely hamstrung by Illustrator's SVG export engine. We do prettify path names so that Illustrator exports them as usable IDs. :( However, we've also made a Grunt SVG Toolkit which converts IDs to classes for you.

We've been chatting with the folks at Adobe for some time now and we're hoping to see some big improvements in how SVG is exported... Eventually...

danielbayley commented 9 years ago

Yeah I figured as much.

We do prettify path names so that Illustrator exports them as usable IDs. :( However, we've also made a Grunt SVG Toolkit which converts IDs to classes for you.

I actually prefer to use a front end makefile as opposed to Grunt and so far I've setup the following which will actually do what I outlined above along with a few other things. So now in this case the 'prettifying' actually gets in the way for me (since there's no way of distinguishing between . and # as they both resolve to --. I wonder if there's a more neutral approach that doesn't force the use of grunt and classes but leaves it optional?

svg:
    @rnm s/.*_// *.svg
    @prepend '<?xml-stylesheet type="text/css" href="'$(css)*.css'"?>' *.svg
    @sub '^<g[^\n]+\.svg">(.*)<.g>' \\1 $(svg)*.svg
    @sub "(g|path) id=['\"](?!_x23_)" '\1 class="' $(svg)*.svg && rmv _x2._ $(svg)*.svg
    @svgo --disable=cleanupIDs $(svg)*.svg #--pretty #-f $(svg)

(Those are just custom bash/perl functions by the way if that looks odd).

We've been chatting with the folks at Adobe for some time now and we're hoping to see some big improvements in how SVG is exported... Eventually…

Good luck with that.

somerandomdude commented 9 years ago

Hey Daniel, this is awesome! It's too bad we couldn't execute that from the Illustrator script after all the files are exported. Do you think that's possible?

danielbayley commented 9 years ago

I doubt it. Not without some really hacky workaround involving cluttering a project up with more files.

danielbayley commented 9 years ago

I happened to come across some really useful documentation (no thanks to Adobe) and it seems this is actually possible.

So far I have this working. I suppose it could easily be tweaked to loop over all the exported SVGs.

function modSVG(file)
{
   file.open('r');//e

   xml = file.read().replace(/^<g[^\n]+\.svg">(.*)<.g>/g,"$1")

   .replace(/(g|path) id=['\"](?!_x23_)/g,'$1 class="')

   .replace(/_(x2.|[0-9])_/g,'')

   .replace(/^<\?xml.*\?>/,'<?xml-stylesheet type="text/css" href="'+depth+css+'"?>');

   file.open('w'); file.write(xml)
}

Also, I'm wondering if/why it's necessary to open a new document when the export is running?

somerandomdude commented 9 years ago

Hey Daniel, I love it! I'll see if I can drop that in this week. Also, feel free to send a pull request if you're able to take a shot at it before me.

Opening a new document ends up being a much easier and less destructive way to adjust artboards for each SVG to export. It alleviates the challenge of capturing the state of all hidden/locked elements and then hiding all elements except the one you wish to export. Believe me, it saves SO much pain.

Thanks again, this is really a great idea!

danielbayley commented 9 years ago

I've been hacking at this script in short bursts over the past week, and I now have a working version which both adds support for #ids and .classes in layer/artboard names, as well as automatically finding the appropriate .css file and linking it in all of the exported SVGs.

It will create and link css/svg.css if no existing stylesheet is found anywhere under the root folder (which is the parent directory of the current Illustrator document). Also, it will output SVGs to img/svg by default (these defaults are just string variables set at the top of the script) unless an existing svg folder is found, in which case it will export there, along with prefixing the correct number of ../s to the style sheet link in each exported SVG file.

Working with SVG is a breeze now, I can easily style them with Sass. I'll probably add support for specifying an output folder path in the layer/artboard name next.

I commented out all the "pretty print" parts and also no dialogs appear so it's changed quite a bit.

//Defaults
var css = 'css/svg.css',
    svg = 'img/svg';

//CSS
css = search(project,/(^|\/)[^_]\w+\.css$/i) ? match : css ;

if (!File(project+'/'+css).exists)
{
    new Folder(project+enclosing(css)).create();

    new File(project+'/'+css).open('w')
}
//SVG
var depth = [];
for (var i = 0; i < css.split('/').length; i++) { depth.push('../')}

depth = depth.join('');

svg = search(project,/[^.]svg$/i) ? match : svg;

exportFolder = new Folder(project+'/'+svg);//Folder.selectDialog("Select Folder to Save Files");
exportFolder.create();

//---------------------------------------------------------------------------------------

function modSVG(file)
{
    file.open('r');//e

    xml = file.read().replace(/^<g[^\n]+\.svg">(.*)<.g>/g,"$1")

    .replace(/(g|path) id=['\"](?!_x23_)/g,'$1 class="')

    .replace(/_(x2.|[0-9])_/g,'')

    .replace(/^<\?xml.*\?>/,'<?xml-stylesheet type="text/css" href="'+depth+css+'"?>');

    file.open('w'); file.write(xml)
}

var matches = [];
function search(folder,pattern)
{
    var items = Folder(folder).getFiles().sort()

    for (var x in items)//(var i = 0; i < items.length; i++)
    {
        var item = items[x].toString().split(project+'/').pop();

        if (item.match(pattern)) { matches.push(item)}

        else if (items[x] instanceof Folder) { search(items[x],pattern)}
    }
    for (var x in matches) { if (matches[x].match(pattern)) { return match = matches[x] }}
}
function enclosing(file)//dirname
{
    file = File(file).toString();

    return file.substring(0,file.lastIndexOf('/'))
}

Opening a new document ends up being a much easier and less destructive way to adjust artboards for each SVG to export. It alleviates the challenge of capturing the state of all hidden/locked elements and then hiding all elements except the one you wish to export. Believe me, it saves SO much pain.

I'm sure that would be a nightmare, but since we can now easily modify the exported SVG code itself, wouldn't it be fairly straightforward to just modify the size after export and bypass most of that in the first place? Since the dialog is now obsolete, i'm thinking the next logical step would be to have nothing happening in the UI at all.

somerandomdude commented 9 years ago

Hey Daniel, I’m planning to look into this after I get back from paternity leave. Thanks for the patience!

On Mon, Mar 2, 2015 at 5:31 PM, Daniel notifications@github.com wrote:

I've been hacking at this script in short bursts over the past week, and I now have a working version which both adds support for #ids and .classes in layer/artboard names, as well as automatically finding the appropriate .css file and linking it in all of the exported SVGs. It will create and link css/svg.css if no existing stylesheet is found anywhere under the root folder (which is the parent directory of the current Illustrator document). Also, it will output SVGs to img/svg by default (these defaults are just string variables set at the top of the script) unless an existing svg folder is found, in which case it will export there, along with prefixing the correct number of ../s to the style sheet link in each exported SVG file. Working with SVG is a breeze now, I can easily style them with Sass. I'll probably add support for specifying an output folder path in the layer/artboard name next. I commented out all the "pretty print" parts and also no dialogs appear so it's changed quite a bit.

Opening a new document ends up being a much easier and less destructive way to adjust artboards for each SVG to export. It alleviates the challenge of capturing the state of all hidden/locked elements and then hiding all elements except the one you wish to export. Believe me, it saves SO much pain.

I'm sure that would be a nightmare, but since we can now easily modify the exported SVG code itself, wouldn't it be fairly straightforward to just modify the size after export and bypass most of that in the first place? Since the dialog is now obsolete, i'm thinking the next logical step would be to have nothing happening in the UI at all.

Reply to this email directly or view it on GitHub: https://github.com/iconic/illustrator-svg-exporter/issues/2#issuecomment-76862083