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

Verbose SVG for improved human readability #340

Open
Crissov opened this issue Aug 12, 2017 · 10 comments
Open

Verbose SVG for improved human readability #340

Crissov opened this issue Aug 12, 2017 · 10 comments

Comments

@Crissov
Copy link

Crissov commented Aug 12, 2017

I wish there was a supplementary superset of SVG that made the rect, circle/ellipse, line, polyline and polygon optionally have a number of p children. The number of mandatory and optional p children varies by element type.

The p element is a point or coordinate, specified either absolutely by x and y attributes or relatively by dx and dy attributes. They all default to 0 initially, but x and y inherit the computed values of the previous sibling – or cousin in path – point. If both, x and dx or y and dy, are specified the relative values are added to the absolute ones to give the computed coordinate.

<rect><!-- 1 absolute and 1 relative point -->
	<p x="rect@x" y="rect@y"/>
	<p dx="rect@width" dy="rect@height"/>
	<!-- not sure how corner radii specified with rect@rx and rect@ry should be dealt with -->
</rect>
<rect><!-- 2 absolute points specify two corners -->
	<p x="rect@x" y="rect@y"/>
	<p x="rect@x + rect@width" y="rect@y + rect@height"/>
</rect>

<circle><!-- 2 points: center and on arc, `circle` aliases `ellipse` -->
	<p x="circle@cx" y="circle@cy"/>
	<p dx="circle@r" dy="circle@r"/>
</circle>
<circle>
	<p x="circle@cx" y="circle@cy"/>
	<p dx="circle@r"/>
</circle>
<circle>
	<p x="circle@cx" y="circle@cy"/>
	<p dy="circle@r"/>
</circle>
<ellipse>
	<p x="ellipse@cx" y="ellipse@cy"/>
	<p dx="ellipse@rx" dy="ellipse@ry"/>
</ellipse>

<line>
	<p x="line@x1" y="line@y1"/>
	<p x="line@x2" y="line@y2"/>
</line>
<line>
	<p x="line@x1" y="line@y1"/>
	<p dx="line@x2 - line@x1" dy="line@y2 - line@y1"/>
</line>

I believe a superset syntax like this would make editing by hand, especially reading, easier. The transformations to the legacy syntax are straightforward, but for these elements the argument is probably not convincing enough. It gets handier with elements that support more, i.e. an arbitrary number of points:

<polyline><!-- `polyline` aliases `line` -->
	<p x="polyline@points1" y="polyline@points2"/><!--+-->
</polyline>
<polyline>
	<p x="polyline@points1" y="polyline@points2"/>
	<p dx="polyline@points3 - polyline@points1" dy="polyline@points4 - polyline@points2"/><!--*-->
</polyline>
<polygon>
	<p x="polygon@points1" y="polygon@points2"/><!--+-->
</polygon>
<polygon>
	<p x="polygon@points1" y="polygon@points2"/>
	<p dx="polygon@points3 - polygon@points1" dy="polygon@points4 - polygon@points2"/><!--*-->
</polygon>

The path element on the other hand would have an additional layer of intermediate children that specify the drawing method otherwise encoded as a single case-sensitive letter inside its d attribute. Making its compact d notation more readable and editable is the main motivation for this issue.

<path>
	<!-- `moveto` -->
	<move><p x="M1" y="M2"/></move>
	<move><p dx="m1" dy="m2"/></move>
	<!-- `closepath` -->
	<close/><!--Z/z-->
	<!-- `lineto` -->
	<line><p x="L1" y="L2"/><!--+--></line>
	<line><p dx="l1" dy="l2"/><!--+--></line>
	<line><p x="H"/></line>
	<line><p dx="h"/></line>
	<line><p y="V"/></line>
	<line><p dy="v"/></line>
	<!-- cubic Bézier -->
	<curve><p x="C1" y="C2"/><p x="C3" y="C4"/><p x="C5" y="C6"/><!--+--></curve>
	<curve><p dx="c1" dy="c2"/><p dx="c3" dy="c4"/><p dx="c5" dy="c6"/><!--+--></curve>
	<spline><p x="S1" y="S2"/><p x="S3" y="S4"/><!--+--></spline>
	<spline><p dx="s1" dy="s2"/><p dx="s3" dy="s4"/><!--+--></spline>
	<!-- quadratic Bézier -->
	<qurve><p x="Q1" y="Q2"/><!--+--></qurve>
	<qurve><p dx="q1" dy="q2"/><!--+--></qurve>
	<t><p x="T1" y="T2"/><p x="T3" y="T4"/><p x="T5" y="T6"/><!--+--></t>
	<t><p dx="t1" dy="t2"/><p dx="t3" dy="t4"/><p dx="t5" dy="t6"/><!--+--></t>
	<!-- elliptical arc -->
	<arc rotation="A3" large-arc="A4" sweep="A5"><p dx="A1" dy="A2"/><p x="A6" y="A7"/></arc>
	<arc rotation="a3" large-arc="a4" sweep="a5"><p dx="a1" dy="a2"/><p dx="a6" dy="a7"/></arc>
	<!-- Catmull-Rom -->
	<rom><p x="R1" y="R2"/><p x="R3" y="R4"/><!-- --><p dx="R5" dy="R6"/><!--*--></rom>
	<rom><p dx="r1" dy="r2"/><p dx="r3" dy="r4"/><!-- --><p dx="r5" dy="r6"/><!--*--></rom>
	<!-- bearing ? -->
	<bear a="B"/>
	<bear da="b"/>
	<bear><p x="cos(B)" y="sin(B)"/></bear>
	<!-- * -->
</path>
@longsonr
Copy link

longsonr commented Aug 15, 2017

What if there are multiple identical children? Sounds like a nightmare for performance, all the parents would need to listen for child content changes. I think I'm going to decline to implement this or see it implemented natively in Firefox. You could always write some kind of XSLT transform that implements your syntax and converts it to SVG native. Good luck with that as I think it's the way forward for you here.

@Herst
Copy link

Herst commented Aug 23, 2017

This would be a bit like what content MathML is to presentation MathML? But I see even less for this here since e.g. the semantic aspect for screen readers isn't there.

@struddysit
Copy link

struddysit commented Aug 31, 2017

I'm not sure why you would want to do it this way.

  • Major file size bloat.
  • p is already a HTML paragraph element.
  • Setting and getting attributes from javascript would be inconsistent, with additional checks required in every bit of code acting on SVGs.
  • There isn't much call for SVG to be human readable.
  • I've coded many SVGs by hand and would find your suggested format irritating to read.

@Crissov
Copy link
Author

Crissov commented Aug 31, 2017

My main issue is with the syntax within the d attribute of the path element, the rest are mostly logical conclusions from that. The existing syntax makes code concise but hardly readable, especially if minified. Using child elements, you could always immediately identify points from other values, for instance.

File size is not an issue for this particular use case. I also doubt that the difference is huge after compression has been applied, especially when compared to non-minified hand-written code which includes optional but helpful commas and whitespace.

I’m not strongly attached to the proposed p moniker, which stems from point obviously. An abbreviation of coordinate would work just as well.

If one of SVG’s strongest advantages wasn’t its readability by humans, it could have been a more efficient non-XML, binary format in the first place.

The syntax extension I am proposing would be an optional superset that can be converted easily to the traditional style. It is just more verbose.

@longsonr is right, I could preprocess a custom syntax into standard SVG, but that would benefit only myself, hence my suggestion to standardize it. My point is that parts of the current syntax are hostile to potential new authors. Path syntax also does not afford helpful GUI solutions.

I don’t get the JavaScript argument. Yes, additional nodes make the tree more complex, but they also make working with them more straightforward. Imagine a graphical image editor: if you are dragging an anchor point, it makes more sense and feels much cleaner to alter a single child element than to update a random part of a textual attribute node. In other words, it is a more appropriate mapping of the mental and visitation models into code. This is also true in particular for the difference between absolute and relative coordinates that are currently realized by the case of single letters.

@struddysit
Copy link

Given that most people would edit or create SVGs in a program like Inkscape, Adobe Illustrator, CorelDraw etc, readability is a non-issue. If it is for you, I would suggest just writing a script to insert a new line after each segment of a path.
E.g.

<path 
   fill="orange"
   stroke="black"
   stroke-width="3" 
   d="M 100 100 
        L 300 100
        L 200 300
        z
        "
/>

The current d attribute in path is logical. You can follow along each step of the way and know what it is doing, especially if everything is along relative paths. Mixing absolute points in requires more of an understanding about where the path is located overall, which can make things difficult. If you are struggling, why not throw in a quick h5h-10h5v5v-10v5 (adjust size to appropriate value), when you're editing, so you get a big + when displaying the SVG.

As to the javascript, if it expects an SVG element with AttributeNS, but your non standard SVG is served, it would need to instead loop through child nodes looking for values. So existing code would break.

@boggydigital
Copy link
Contributor

Not blocking updated 2.0 CR publication - assigning 2.1 WD milestone

@Crissov
Copy link
Author

Crissov commented Feb 13, 2020

I remembered this proposal today, because it would provide something for free that SVG does not have yet (as far as I know): named coordinates and reusable dimensions.

<defs>
  <p id="wxh" dx="123" dy="45"/>  
  <p id="xy1" x="67" y="89"><desc>upper left corner of rectangle</desc></p>  
  <p id="xy2" x="190" y="134"/>  
</defs>

<rect><!-- 1 absolute and 1 relative point -->
  <use xlink:href="#xy1"/>
  <use xlink:href="#wxh"/>
</rect>
<rect><!-- 2 absolute points specify two corners -->
  <use xlink:href="#xy1"/>
  <use xlink:href="#xy2"/>
</rect>

@Crissov
Copy link
Author

Crissov commented Nov 2, 2020

w3c/csswg-drafts#5674 reminded me of this issue today.

Instead of a universal <p> element, it could also make sense to have an absolute <to> or <abs> element and a relative <by> or <rel> element with unified x and y attributes:

<defs>
  <by id="wxh" x="123" y="45"/>  
  <to id="xy1" x="67" y="89"/>  
  <to id="xy2" x="190" y="134"/>  
</defs>
<defs>
  <rel id="wxh" x="123" y="45"/>  
  <abs id="xy1" x="67" y="89"/>  
  <abs id="xy2" x="190" y="134"/>  
</defs>

@longsonr
Copy link

longsonr commented Nov 2, 2020

You can achieve some of what you want with CSS variables on the elements that have their positioning as CSS properties i.e. circle, ellipse, rect

@Crissov
Copy link
Author

Crissov commented May 22, 2022

Just for the record, Fitbit supports a proprietary arc element (and some other extensions) in their clockface SVGs:

Draws an arc, circular or elliptical.

Attributes

  • arc-width: arc thickness in pixels, or %-expression. Maximum 31.
  • start-angle: start angle in degrees, with 0 at 12 o'clock.
  • sweep-angle: length of the arc in degrees.

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

No branches or pull requests

5 participants