coolbutuseless / minisvg

Create SVG documents with R
https://coolbutuseless.github.io/package/minisvg/
MIT License
31 stars 3 forks source link

Challenges within <use> tag #5

Closed dmi3kno closed 4 years ago

dmi3kno commented 4 years ago

Today <use> tag does the following:

library(minisvg)
some_rect <- stag$rect(id='strec', x=0, y=0, width=30, height=30, fill="red")
moved_rect <- stag$use(href="#strec", svg_prop$transform$translate(20,20), some_rect)
doc <- svg_doc(width = 100, height = 100, moved_rect)
doc
#> <svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
#>   <use href="#strec" transform="translate(20 20)">
#>     <rect x="0" y="0" width="30" height="30" id="strec" fill="red" />
#>   </use>
#> </svg>

Couple of issues here: 1) The referencing to strec needs to be done using xlink:href

#>   <use xlink:href="#strec" transform="translate(20 20)">

This fixes the issue for librsvg, but I am also concerned about "double-referencing".

2) The geometry you are referencing is contained inside the <use> tag. In the tutorials I find around the web the use tag is not embracing any geometries. It can reference already existing (named) geometries. Or in case of "invisible" geometries ("loose stags") they are getting defined in the defs tag in the header (along with any patterns). I understand it might be more difficult to track all "loose stags" and place them into <defs></defs>, but today it leads to potential referencing confusion, where the different stags are used under the same name.

Is it possible that we may require to add "loose stags" via stag$defs(), so that they are placed in the header and referred to by xlink:href? While we're on it, could we make stag$defs()$pattern() produce "pattern" tag pair inside "defs" tag pair?

dmi3kno commented 4 years ago

I think second issue is non-issue really. It is just related to my wrong use of "loose stags". As you shown in the example for filters (refactored for clarity):

library(minisvg)

doc <- svg_doc(width="40%", height="40%", viewBox="0 0 150 360",
  preserveAspectRatio = "xMidYMid meet")
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  # 3 overlapping circles
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
threecircles <- stag$defs(
    stag$g(
      id="circles",
      stag$circle(cx=30, cy=30, r=20, fill="blue" , fill_opacity="0.5"),
      stag$circle(cx=20, cy=50, r=20, fill="green", fill_opacity="0.5"),
      stag$circle(cx=40, cy=50, r=20, fill="red"  , fill_opacity="0.5")
    )
  )
doc$append(threecircles)
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  # Reference rendering of the circles
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
doc$append(stag$use(href='#circles'))
doc$append(stag$text(x=70, y=50, "Reference"))

  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  # Applying a colour transformation matrix to these circles
  #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
colorfilter <- stag$filter(
    id="colorMeMatrix",
    stag$feColorMatrix(
      in_    = "SourceGraphic",
      type   = "matrix",         # matrix | saturate | hueRotate | luminanceToAlpha
      values = "0 0 0 0 0   1 1 1 1 0   0 0 0 0 0   0 0 0 1 0"
    )
  )
doc$append(colorfilter)
doc$append(stag$use(href='#circles', transform="translate(0 70)", filter="url(#colorMeMatrix)"))
doc$append(stag$text(x=70, y=120, "Matrix"))

doc$show()

This works perfectly fine and places the <g> inside the <defs> tag, as expected. Once xlink:href is fixed this issue can be closed.

Maybe documentation could read something like:

"instead of passing a stag object into a ellipsis of a use method, you should consider adding the stag you want to reuse into the defs and just reference it in use. This will result in cleaner code and help avoid confusions with referencing"

coolbutuseless commented 4 years ago

"xlink:href" is deprecated for <use>, and "href" is the preferred attribute. See: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use

If you really want, you can still do either of the following:

stag$use(xlink_href = "#circles")
stag$use(`xlink:href` = "#circles")  

I don't think I'm going to change this.

coolbutuseless commented 4 years ago

In regards to the documentation for <use> - I'm really relying on MDN documentation for how SVG is supposed to be constructed. That is, I don't necessarily want to replicate SVG documentation as part of this package.

minisvg provides a way to reliably give you syntactically valid SVG, but whether or not it is semantically valid is not something it tries to enforce. So, this does mean it will let you put a <rect> inside a <use> tag if you want, and a whole lot of other things which are meaningless.

I need to think about what level of docs I want to go to here. Maybe if I put in more links to MDN?

dmi3kno commented 4 years ago

This:

If you really want, you can still do either of the following: stag$use(xlink_href = "#circles") stag$use(`xlink:href` = "#circles")

closes the issue for me. Thank you!