-
-
Notifications
You must be signed in to change notification settings - Fork 30
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
original id of <use> elements is lost #196
Comments
def test_issue_196(self):
q1 = io.StringIO(u'''<?xml version='1.0' encoding='UTF-8'?>
<svg version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>
<defs><circle id="circle" cx="0" cy="0" r="5" style="opacity:1" /></defs>
<g>
<use href="#circle" id="circle1" transform="translate(10,10)" style="opacity:0.5"/>
<use href="#circle" id="circle2" transform="translate(20,20)" style="opacity:0.2"/>
</g>
</svg>''')
layout = SVG.parse(
source=q1,
reify=False,
ppi=DEFAULT_PPI,
color="black",
transform=None,
context=None
)
elements = list(layout.elements())
for e in elements:
print(f"ID: {e.id}: {e}") Gives:
You'll notice that circle1 and circle2 are the id on the
There were a couple bugs that kicked off without doing things like this. Which was the last breaking change to make them work more correctly. |
Dear tatarize, The whole point of the issue is "how to setup a mapping between one original OK, I see from the output that from the list of Best regards, |
If you can show that this is what Chrome or Inkscape uses for those ids. I would absolutely change it. The spec says Use is the object there and is a structural element. And that id belongs to the Use. The issue here is in part that svgelements gives you the render tree and not the dom tree. In the dom tree the circles don't actually exist at all and as such they don't have ids. I invented them since I'm doing the rendering but they don't actually have any ids, so I read them out of the parsed tree structure. I didn't add them to Now granted these objects aren't really in the dom tree and the providing of the id is just useful (really rendered objects have no requirements to provide ids) you may be right. But, I could certainly see a lot of use cases where people might prefer the id given actually be the original id since you can actually reference a large branch of the dom tree in a So while this isn't covered by spec, it's generally okay, to spitball a little. I can't use the id of the use as every subobject's id, since that could basically wipe out the entire tree's ids. But, you are correct that this isn't really what I would expect to have intuitively. What about setting the id equal to We wouldn't have multiple circles with the id |
Dear tatarize, |
I'm open to some changes. It wouldn't be ideal but we could certainly make the id of objects within the use reference to be |
The writing of use objects that are created in actual tree might be a problem for writing out the data since by default it would reuse the id. I think this should actually be shifted so the use items are actually |
How about a version of from io import StringIO
from typing import Callable, Iterable, Optional
from svgelements import SVG, Group, Shape, SVGElement, Use
def select_with_parent_uses(group: Group, predicate: Optional[Callable[[SVGElement], bool]]=None) -> Iterable[tuple[SVGElement, tuple[Use,...]]]:
def select(e:SVGElement, parents: tuple[Use,...]):
if predicate is None or predicate(e):
yield e, parents
if isinstance(e, Use):
new_parents = *parents, e
for e2 in e:
yield from select(e2, new_parents)
elif isinstance(e, Group):
for e2 in e:
yield from select(e2, parents)
yield from select(group, tuple())
if __name__ == '__main__':
src = StringIO(u'''<?xml version='1.0' encoding='UTF-8'?>
<svg width="500" viewBox="-10 -10 35 30" version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'>
<defs>
<circle id="circle" cx="0" cy="0" r="5" style="opacity:1" />
<g id="two-circles">
<use href="#circle" id="blue_fill" transform="translate(-6 0)" fill="blue"/>
<use href="#circle" id="red_fill" transform="translate(+6 0)" fill="red"/>
</g>
</defs>
<g>
<use href="#two-circles" id="white_stroke" transform="translate(5,0)" stroke="white"/>
<use href="#two-circles" id="black_stroke" transform="translate(11,10)" stroke="black"/>
</g>
</svg>''')
parsed = SVG.parse(source=src, reify=False)
for e,uses in select_with_parent_uses(parsed, lambda e: isinstance(e, Shape)):
print('/'.join(u.id for u in [*uses,e]), f'-> fill: {e.fill}, stroke: {e.stroke}')
use_ids = set(u.id for u in uses)
assert ('blue_fill' in use_ids) == (str(e.fill) == '#0000ff')
assert ('red_fill' in use_ids) == (str(e.fill) == '#ff0000')
assert ('white_stroke' in use_ids) == (str(e.stroke) == '#ffffff')
assert ('black_stroke' in use_ids) == (str(e.stroke) == '#000000') prints:
|
it would be nice if the shapes defined through
<use ...>
could keep their original id - or at least have an attribute like "original_id" in the values dictionary - as well as for other properties like "style". (or an"original_values" attribute to held all original data)Indeed for such 2 elements:
the resulting 2 circles position are Ok, but both shapes have the same id "circle" instead of "circle1" and "circle2" which seems to be completely lost. The style as well is the one defined in the
<defs>
paragraph and not the one defined in the<use>
.The text was updated successfully, but these errors were encountered: