Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin: Working prototype of optimal group packing #1778

Open
maximilianMairinger opened this issue Aug 26, 2023 · 1 comment
Open

Plugin: Working prototype of optimal group packing #1778

maximilianMairinger opened this issue Aug 26, 2023 · 1 comment

Comments

@maximilianMairinger
Copy link

Is your plugin request related to a problem? Please describe.

Many (but not all) svg element attributes can be hoisted into a group if they are equal among two or more elements. This doesn't impact rendering oftentimes, is less verbose, and hence takes fewer characters. I am aware that moveElemsAttrsToGroup exists, however, it does not create groups. It just populates them if they already exist.

Describe what the plugin should do

I want to create a plugin that finds the best, or an approximation of the best, way of packing all elements into groups so that the minimum number of characters is emitted. The following examples should illustrate the desired behavior. Please note that the attributes names are dummies, and root (svg) element has been omitted for better legibility.

Input

<path x aaa/>
<path y aaa/>
<path z aaa/>

Output

<g aaa>
  <path x/>
  <path y/>
  <path z/>
</g>

Note that the attributes need to be this long, as otherwise the cost of making a group (7 characters + its attributes) would be greater than just leaving them alone

Input

<path x aaa/>
<path y aaa bbb ccc/>
<path z aaa bbb ccc/>

Output

<g aaa>
  <path x></path>
  <g bbb ccc>
    <path y></path>
    <path z></path>
  </g>
</g>

And lastly a less trivial example:

Input

<path x aaa/>
<path y aaa bbb cccc/>
<path z aaa bbb cccc/>
<path w cccc/>

Output

<path x aaa/>
<g cccc>
  <path w/>
  <g aaa bbb>
    <path y/>
    <path z/>
  </g>
</g>

Implementation

I think this problem is not analytically solvable, so exhaustively searching all possible arrangements is the only way to guarantee that we find the best solution. I have a working prototype that does this for up to 15 elements. More elements do not work, as I am memory limited and shortly after I reach maximum call stack size. I know that this is suboptimal, but making it work for element counts <= 15 would work and be better than nothing. We could also think about computing approximations for element counts > 15. The prototype I have is standalone, so not integrated into the svgo ecosystem, but I am sure that with some guidance, I can integrate it without much trouble. Are you open to making this a plugin? Or should I release this somewhere else, as standalone?

Open questions

I am not quite sure where I need to be cautious when hoisting attributes into groups, so that the visual rendering of the svg doesn't change. I took the following from moveElemsAttrsToGroup: If "style", "clip-path" or "mask" are present somewhere, abort everything. If "transform" is present, don't touch it, but continue with the rest. Maybe your expertise could help me here.

  • [ x ] Are you volunteering to work on this plugin?

Related

#801

@KTibow
Copy link
Contributor

KTibow commented Nov 5, 2023

I made something like this. However it just moved around attributes. Note:

  • Creating groups could have side effects
  • Consider just hoisting attributes to the parent svg
  • Keep in mind that you can use defaults to improve attribute ordering
  • Keep in mind that you should look at character count, not occurence count when handling defaults and overrides

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants