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

proposal: add support for ID and Class attributes to BezierPath #356

Closed
gferreira opened this issue Jan 28, 2020 · 18 comments
Closed

proposal: add support for ID and Class attributes to BezierPath #356

gferreira opened this issue Jan 28, 2020 · 18 comments

Comments

@gferreira
Copy link
Contributor

gferreira commented Jan 28, 2020

DrawBot can generate SVGs; SVGs can be embedded in HTML and styled with CSS just like the rest of the page.

SVG objects need an ID or class so that CSS can refer to them. in the example below, id and class attributes were added manually after the SVG was generated.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SVG test</title>
<style>
    svg { background-color: yellow; }
    #circle { fill: grey; }
    #circle:hover { stroke: magenta; }
    #square { stroke: red; stroke-width: 20px; }
    .shape:hover { fill: black !important; }
</style>
</head>
<body>
<!-- embedded SVG -->
<svg height="800" version="1.1" width="800" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 <path id='square' class='shape' d="M100,100 l400,0 l0,400 l-400,0 Z M100,100" fill="rgb(0,0,255)" transform="matrix(1,0,0,-1,0,800)"/>
 <path id='circle' class='shape' d="M641.42,358.58 c78.1,78.1,78.1,204.74,0,282.84 c-78.1,78.1,-204.74,78.1,-282.84,0 c-78.1,-78.1,-78.1,-204.74,0,-282.84 c78.1,-78.1,204.74,-78.1,282.84,0 Z M641.42,358.58" fill="rgb(255,0,0)" stroke="rgb(0,255,0)" stroke-width="20" transform="matrix(1,0,0,-1,0,800)"/>
</svg>
</body>
</html>

Proposal

add support for setting an ID and/or class when the BezierPath is created:

size(800, 800)

B1 = BezierPath(ID='square', Class='shape')
B1.rect(100, 100, 400, 400)
fill(0, 0, 1)
drawPath(B1)

B2 = BezierPath(ID='circle', Class='shape')
B2.oval(300, 300, 400, 400)
fill(1, 0, 0)
stroke(0, 1, 0)
strokeWidth(20)
drawPath(B2)

saveImage('output.svg')

thanks!

@typemytype
Copy link
Owner

typemytype commented Jan 28, 2020

This is indeed very handy... but Im not sure about the syntax: the init of a bezierPath would be heavily populated with svg specific arguments.

I would prefer a solution where additional data is provided in saveImage (same as for images, and animated output)

size(800, 800)

B1 = BezierPath()
B1.rect(100, 100, 400, 400)
fill(0, 0, 1)
drawPath(B1)

B2 = BezierPath()
B2.oval(300, 300, 400, 400)
fill(1, 0, 0)
stroke(0, 1, 0)
strokeWidth(20)
drawPath(B2)

saveImage('output.svg', 
    svgIDMap={
        B1: "square", 
        B2: "circle"}, 
    svgClassMap={
        B1:["shape"], 
        B2:["foo", "shape"]}
)

as such other objects like, FormattedString could also get an svg id, class...

@justvanrossum
Copy link
Collaborator

I don't think it's all bad to add things to the BezierPath object, but maybe indeed not in the constructor. How about separate methods or attributes?

b = BezierPath()
b.cssClass = "shape"
b.cssID = "circle"

(Could also work for FormattedString, in fact, neither BezierPath nor FormattedString need to be changed for this, only the SVG writer.)

@typemytype
Copy link
Owner

custom attributes are fine, they are harder to document

path.cssClass must be a list as an object can have multiple classes

@justvanrossum
Copy link
Collaborator

Properties can have doc strings:
image

path.cssClass must be a list as an object can have multiple classes

Or we make it a direct SVG class definition, and let it be a single string with spaces:

b.cssClass = "class1 class2"

Then at least the common case (one class) isn't burdened by the list syntax. Or define it to be a string of a list.

@gferreira
Copy link
Contributor Author

gferreira commented Jan 28, 2020

@justvanrossum I like the cleaner syntax, thanks.

wouldn’t it make more sense to prefix with svg instead of css though?

b = BezierPath()
b.svgID = "circle"
b.svgClass = "shape foo"
b.svgCursor = "move" # sneaked another one here ;)

(here’s a list of all SVG path attributes)

hyperlinks would be really useful too (thinking about the FontParts map, for example). a link is not an attribute of path, but it can be wrapped around it:

<a xlink:href="https://drawbot.com/">
<path id='square' class='shape' d="M100,100 l400,0 l0,400 l-400,0 Z M100,100" fill="rgb(0,0,255)" transform="matrix(1,0,0,-1,0,800)"/>
</a>

edit: possible syntax for links:

B.svgLink = 'http://www.drawbot.com/'

# + a better syntax for PDF links?
B1.pdfLinkDestination = 'example'
B2.pdfLink = 'example'

@justvanrossum
Copy link
Collaborator

wouldn’t it make more sense to prefix with svg instead of css though?

Yes, you're right.

@typemytype
Copy link
Owner

I know properties can have docs but if we only change the svgContext those properties does not exists...

@typemytype
Copy link
Owner

pdf links are already supported in with linkDestination and linkRect.

svgLink is cool
svgCursor can be solved with css attribute, no?

@justvanrossum
Copy link
Collaborator

I know properties can have docs but if we only change the svgContext those properties does not exists...

If we only change svgContext then there is no documentation for those attrs. If we want documentation of those attrs, we need to add them as properties. What is the problem?

@typemytype
Copy link
Owner

I dont like to add context specific attributes in main classes

this could work in the svgContext.py

from drawBot.context.baseContext import BezierPath

def _get_svgID(self):
    return getattr(self, "_svgID", None)
    
def _set_svgID(self, value):
    self._svgID = value
    
BezierPath.svgID = property(_get_svgID, _set_svgID, doc="svg ID")

wonder if this ends up in the docs

and so can every context add his own attributes for specific objects

@justvanrossum
Copy link
Collaborator

BezierPath.svgID = property(_get_svgID, _set_svgID, doc="svg ID")

This still adds the property to BezierPath globally.

I don't see a big problem with having a few context-specific attributes on main objects. However, an alternative could be:

from svgObjects import BezierPath, FormattedString

b = BezierPath()
b.svgClass = "sadsadsa"

@typemytype
Copy link
Owner

typemytype commented Jan 28, 2020

Im just afraid if lots of those properties are added, it becomes un manageable.

While hosting those properties in a context (even if they are added to the main objects) its feels like only the svgContext (in this case) is responsible for those properties.

see the PR #357

@gferreira
Copy link
Contributor Author

gferreira commented Feb 3, 2020

weekend idea: the original proposal (“add support for ID and Class”) could be generalized into “add support for SVG path attributes”. it could be implemented as a single function which takes the attribute name and the value:

B = BezierPath()
B.svgAttribute("class", "foo bar)
B.svgAttribute("id", "square")
B.svgAttribute("cursor", "move")

seems more elegant and more flexible (?)

@typemytype
Copy link
Owner

Or

path  = BezierPath()
path.svgAttributes = dict(foo="bar")

@justvanrossum
Copy link
Collaborator

  1. Do you really need "cursor"?
  2. Are there other svg attrs we may need to set?

Smells like overgeneralization to me.

@gferreira
Copy link
Contributor Author

ID and class are the ones I need at the moment, I’m fine if only those are added.

(I have little experience with SVGs though, and the list of supported attributes is very extensive. they must be useful to someone :)

cursor can be added by the ‘behavior layer’ (JS), see this example.

thanks! looking forward to put it to good use

@justvanrossum
Copy link
Collaborator

and the list of supported attributes is very extensive. they must be useful to someone

Sure, but DrawBot cannot be the ultimate SVG generator: there are way more things that SVG can do that DB can't (and shouldn't). For DB, SVG is simply one of the output formats. If we can add something to make SVG a lot more useful in some contexts (such as class and id attrs) then by all means, let's do that, but let's also keep in mind that writing SVG is not DB's core business :)

@typemytype
Copy link
Owner

added #357

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

3 participants