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

Syntax to support units & calculations in path data strings #72

Open
AmeliaBR opened this issue Mar 21, 2016 · 7 comments
Open

Syntax to support units & calculations in path data strings #72

AmeliaBR opened this issue Mar 21, 2016 · 7 comments

Comments

@AmeliaBR
Copy link
Contributor

Path data (and also polygon/polyline points) can currently only be specified in terms of user units. Percentage-based coordinates, lengths, and combinations thereof are not supported.

The basic shapes support geometric parameters with units. By making them CSS properties in SVG 2, they will also support lengths defined in terms of calc() functions. Basic shapes can therefore only be represented as paths by converting them to the current used value (in px) for each length. A path data string cannot represent the flexible nature of a basic shape defined using percentages or font-relative units.

For polygons and polylines, there is the potential to synchronise with the CSS shapes polygon() syntax. This syntax allows units, percentages, and calc functions, albeit with more stringent rules (compared to SVG) for whitespace and commas.

For path data, however, there are complications:

  • Path data already includes letters in the form of segment commands, so the parser would need to be able to clearly distinguish between these and length units or function names.
  • Path data syntax is designed to support minimization in a way that isn't compatible with the CSS parser tokenization process.

This second aspect can actually be a good thing: since path data is not going to be parsed by CSS rules, we can create a syntax that works for this case rather than re-using CSS syntax.

As an initial proposal, I suggest introducing parentheses around any value that needs to be computed. The value inside the parentheses represents a single number in the basic path data syntax.

  • The value could be a single length with units: (1in), (3mm)
  • For certain parameters (in arc and bearing commands), it would be an angle with units instead: (0.25turn), (30deg)
  • It could be a percentage (of coordinate system width/height): (10%)
  • It could be a mathematical expression containing numbers to be interpretted as user units or degree angles, depending on the context: (100/3)
  • It could be a mathematical expression that computes to a length or angle: (100%-10px), (1em/3), (0.5turn + 5deg)
  • It could have nested parentheses as necessary to build complex mathematical expressions: ((1em + 1ex)/5)

Note that we'd specifically define that "units" will only ever consist of a string of letters or the % character, so we could avoid CSS calc's fussy rules about whitespace around mathematical operators.

So, the following rounded rectangle:

<rect width="100%" height="3in" y="1em" rx="10px" ry="5mm" />

would be equivalent to the following path data:

M(10px)(1em)
H(100%-10px)
A(10px)(5mm)0 0 0 (100%)(1em+5mm)
V(1em+3in-5mm)
A(10px)(5mm)0 0 0(100%-10px)(1em+3in)
H(10px)
A(10px)(5mm)0 0 0(0px)(1em+3in-5mm)
V(1em+5mm)
A(10px)(5mm)0 0 0 Z

I think this strikes the necessary balance between concise & readable while ensuring that there is always an unambiguous parser interpretation. But I am of course open to other suggestions.

I'd expect the new syntax to be defined in the dedicated SVG Paths module. It would then be incorporated by reference in all the specs that now or in future use SVG path notation, including Canvas 2D context and CSS Shapes.

@jarek-foksa
Copy link

Could we also have Infinity and -Infinity as allowed special values? Although not present in CSS, those are already supported by some other vector formats such as XAML.

Also, should path.getPathData() return the computed numerical values in user space or SVGLength instances that preserve the units?

@AmeliaBR
Copy link
Contributor Author

Interesting idea @jarek-foksa. I'd wondered about some way to access pi as a constant, hadn't thought about infinity. I assume this is so that you can do things like animate curves to straight lines by stretching control points or arc radii?

As far as the DOM methods, I would want to see two separate functions, one to get the "defined" value (with units, percentages, etc.), and one to get the current "used" value (everything converted to user units / presumed degree angles).

@jarek-foksa
Copy link

As far as I'm concerned, the Infinity would be handy when drawing overlays and guidelines in documents that can be zoomed and scrolled infinitely. For example in order to implement a dark overlay that covers everything except a rectangular area I have to use the following workaround:

let inf = 1000000; // pseudo-infinity

let d = `
  M ${-inf}, ${-inf}
  L ${inf * 2}, ${-inf}
  L ${inf * 2}, ${inf * 2}
  L ${-inf}, ${inf * 2}
  Z
  M ${x}, ${y}
  L ${x}, ${y + height}
  L ${x + width}, ${y + height}
  L ${x + width}, ${y}
  Z
`;

@tabatkins
Copy link
Member

Note that we'd specifically define that "units" will only ever consist of a string of letters or the % character, so we could avoid CSS calc's fussy rules about whitespace around mathematical operators.

You can't actually make that assumption, as it would shut out use of any future CSS unit that has a dash. We don't have plans at the moment to do such a thing, but we reserve the right to in the future. It also shuts out the ability to do math with keywords, which we do plan to allow in the future. Also makes it hard to include CSS functions, particularly var() and attr(), which are extremely useful for paths.

In general, continuing to define things in ways that don't naturally work with CSS is a non-starter. They're neither future- nor present-friendly.


If we're going to overhaul path syntax, I propose we do it wholesale. Current path syntax is an attempt at balancing hand-authorability against binary size, and it fails badly at both as a result: path syntax is borderline illegible unless carefully formatted, and some of the commands like arcs and curves are, for most people, impossible to write without having docs up; while on the other hand the syntax is still an ASCII format mostly composed of base-10 digits and punctuation, using ~4 bits of every 2 bytes in the string.

It would be much better to design something proper for the camps: for humans, design a more verbose, easy to read/write format (borrowing syntax from CSS so it interoperates well), and then if we need to, design a compact binary format, likely embedded in SVG as base64. This would be interconvertable, with some loss of authorability (the binary format would have single canonical forms of each segment type, for example, losing details of what variant the authoring format used) but no change in behavior. (This is similar to Wasm - a compact binary format with a well-defined "decompilation" to a Lisp-like human authoring format.)

@Crissov
Copy link

Crissov commented Nov 30, 2021

Just stumbling over this, I realize that my proposal in #340 may be what @tabatkins suggested for human readability, although it's doing it outside the d attribute.

@tabatkins
Copy link
Member

Not really, your #340 suggestion is far more verbose. I'm suggesting something more like just "path is a sequence of CSS functions for each command", so you get the full range of CSS values available to you.

@Crissov
Copy link

Crissov commented Dec 1, 2021

Okay, that would be w3c/csswg-drafts#5674 then, I guess.

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

No branches or pull requests

6 participants