reactjs / react-art

React Bridge to the ART Drawing Library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Align API with SVG where possible

andru opened this issue · comments

Hi,
I'm converting a somewhat complex SVG component to work with ReactART. It's a huge thrill to see it rendering to canvas without rewriting the codebase, but the experience of learning the API has been a pretty painful groking of source. That's part lack of documentation but also that the prop names are sometimes consistent with SVG and other times not.

React has, except in cases of naming confict, maintained attribute similarity with HTML with an easy-enough camelCase translation. I think it would be a good approach for ReactART too. It would reduce cognitive load for developers by using an already familiar API, and it would make code reuse from SVG to ReactART all the easier.

I recognise that it could only ever be a subset of the ginormous SVG API, but a clearly defined subset could still be a lot easier to get up to speed with. At present, the API sometimes aligns with SVG, other times not, with no clear pattern for mental translation.

Examples that spring to mind...

  • opacity = opacity (same, i.e. not blend as in ART)
  • stroke-dasharray(string) = strokeDash(array)
  • stroke-linecap(string) = strokeCap(string)
  • text-anchor(start/middle/end) = alignment(left/center/right)
  • d for path property, mimicking SVG
  • <rect> = <Rectangle>

What do you think?

It is interesting because several people have actually asked that we unify more with the CSS model (e.g. background/border instead of fill/stroke) since people that are familiar with SVG is a very small subset compared to those who know CSS.

IMO, SVG made a few mistakes due to the DOM centric API. The string based data model won even though the DOM properties are rich data structures. The rich data structures are, however, very verbose and difficult to work with - and nobody really knows how to use them.

That's why I designed transforms, paths and gradients as rich objects but with a convenient API instead of strings and ids.

The ART <Rectangle /> is different than the SVG <rect /> because the rounded corner API is completely different. The ART one is closer to the CSS API. It was originally designed by Valerio Proietti but I think the rationale was that you often control different radius on different corners in modern designs. However, you rarely have different x/y radius which is what the SVG API opts for.

React at some point chose the camel-case PROPERTY names (className/htmlFor) rather than the equivalent ATTRIBUTE names (class/for). It seemed to make sense to use that for React ART as well. Hence strokeWidth etc. which has corresponding CSSOM properties in SVG. That's also much more convenient when you're working with objects in JS since you don't have to fallback to the bracket syntax.

The strokeCap/strokeDash APIs where added later on. We could rename them to strokeLinecap/strokeDasharray for consistency I suppose.

However, another consideration is that since the main target is Canvas and the Canvas API is seeing nicer API development and unification with newer SVG APIs maybe we should be trying to unify with the Canvas API rather than SVG. In that case, maybe lineCap and lineDash makes more sense.

Similarly Canvas calls it textAlign instead of textAnchor. I think at some point I had some rationale for why alignment made more sense when right-to-left isn't fully properly supported in some environment. That's a pretty weak argument. A better one would be that when people read alignment they'll know what it means. When people read textAnchor they'll only understand it if it they're already familiar with SVG which is, sadly, a very small set.

I suppose it is difficult to strike a fine balance between consistency amongst several competing standards, what people are most familiar with and what would be a nicer API if you had a chance to rethink assumptions.

I think the end goal is to create a nice ideal API to code dynamic content. It is not a primary goal to be a target for copy/pasting existing static SVG content. There is an automated SVG -> ART converter although sadly there is no React ART version. I'd love for someone to update it to support React ART output though.

Even though the JSX may make it seem strange, I think I'd rather error on the side of Canvas/CSS than SVG for consistency.

Given this context, what do you think? What changes would you suggest?

There is an automated SVG -> ART converter although sadly there is no React ART version. I'd love for someone to update it to support React ART output though.

Can you point me to that?

In principle it's the same to me whether the API aligns closer to SVG or Canvas. Whatever provides the cleanest declarative API should be appropriate. SVG seemed to me the more logical, since it's already a declarative drawing API much like react-art, but I take your point regarding the limitations of string based transformations.
It seems to me that a CSS approach would hit pitfalls quickly: it's designed for a box model, so it lacks a lot of concepts needed for a drawing library. That would mean defining a new API for anything outside of the CSS vocabulary, which is another thing for the developer to internalise
For me, Canvas could be as good an option as SVG because it means reusing an api that's solving similar problems. CSS feels like a bad fit.

I do think there is a strong argument to be made for an easy transition from SVG. Being able to export a design to SVG and, with minimal changes, have the option to render via Canvas is a big deal. This use case could be covered by a SVG > ReactART convertor, of course.

Another big deal, now that SVG has wide browser support, would be to not need an SVG renderer since the source would be a subset of SVG to begin with. ReactART could, with minimal tweaks to allow for enhanced API like programatic Transformations, output the SVG with very little changes.
Do you have any thoughts on that? Is that an avenue already pursued and rejected?

Regarding rect and rectangle, and as a general notion to the idea of a subset of SVG as an API, I would argue that there is no problem to providing additional API where is doesn't conflict with SVG. E.g. rx and ry behave as defined by the SVG spec, r could act as a shortcut property to assign the value to rx and ry, and the topRightRadius etc properties provide additional enhancement.

On the same note, the API could allow transformations to be set with a string or a Transform instance, providing consistency with the SVG API while also enriching it.

By using a subset of SVG as the source, a fallback also comes for free. Accessibility becomes a solved problem too; a fallback to the original SVG for screen readers could be implemented easily.

I'm not sure on the numbers of people familiar with SVG so I'll defer to your experience, but I do think SVG represents a well established standard for declarative drawing, albeit with some clumsy bits. textAnchor, for example.

I'm curious to know how an API aligned more closely with Canvas would look. SVG and Canvas already share a path description format. Beyond that would it just be property names? Or are there some areas where you would move away from the declarative?

Another question is, how is this library most used and approached? I'm coming at all this from the approach of someone working with SVG who needs to target canvas on mobile for performance. My browser compatibility targets on desktop already have great SVG support so for me SVG is the base from which I'd like to sometimes render to Canvas.
For that use, a library aligned with SVG makes a lot of sense.

It'd be great to hear your thoughts and experiences on other approaches to the library.

svgconverter here, I think: http://sebmarkbage.github.io/art/. Though it looks broken. It's possible that it works locally and is just broken on GitHub pages right now?