vecty
vecty copied to clipboard
Inline SVG
I'm having trouble getting inline SVG working:
vecty.Tag(
"svg",
vecty.Markup(
vecty.Namespace("http://www.w3.org/2000/svg"),
vecty.Attribute("width", "14"),
vecty.Attribute("height", "16"),
vecty.Attribute("viewBox", "0 0 14 16"),
),
vecty.Tag(
"path",
vecty.Markup(
vecty.Attribute("fill-rule", "evenodd"),
vecty.Attribute("d", "M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"),
),
),
),
... this doesn't render anything... Am I doing something wrong?
Looks correct at first glance.
Is the element getting created in the DOM with the right attributes etc? i.e. have you looked at the Chrome inspector?
Here's a demo: https://play.jsgo.io/1a1c614313ff086b371850be83c16b48c403d64a
Should Namespace(...) be used for the xmlns attribute?
Adding the SVG in plain HTML works: https://jsfiddle.net/1L27s201/
Hmm... this is what I see in the Chrome inspector with the "path" tag selected in the plain HTML version (the jsfiddle):
... but the attributes are missing in the right-hand panel in the vecty version:
Should
Namespace(...)be used for thexmlnsattribute?
When vecty.Namespace is used, it results in vecty using document.createElementNS instead of document.createElement. See:
https://github.com/gopherjs/vecty/blob/19a11ec3acc3ae6c2e095b1ace2b7134c5f28c10/dom.go#L173-L176

Maybe it's worth trying to set it as a normal attribute?

I tried what I mentioned above, no effect.
I found a fix though. It's to set vecty.Namespace in the path element as well:
vecty.Tag(
"svg",
vecty.Markup(
vecty.Namespace("http://www.w3.org/2000/svg"),
vecty.Attribute("width", "14"),
vecty.Attribute("height", "16"),
vecty.Attribute("viewBox", "0 0 14 16"),
),
vecty.Tag(
"path",
vecty.Markup(
vecty.Namespace("http://www.w3.org/2000/svg"),
vecty.Attribute("fill-rule", "evenodd"),
vecty.Attribute("d", "M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"),
),
),
)
Try it at https://play.jsgo.io/e1bb676757854529b94715cf9f9a8766a7acc2b4.
I'm not sure if you're expected to do it manually, or if Vecty should be making the top-most Namespace apply recursively to all children.
I'm not sure if you're expected to do it manually, or if Vecty should be making the top-most Namespace apply recursively to all children.
Currently any tags that require an alternative namespace must have it specified explicitly. We could possibly propagate it down, though that means the only way to change namespace again is to set it explicitly, and we'd probably need to do some special handling for Components, since they may be nested inside a namespaced element, but perform localised rendering.
This behaviour is only really meant as a stop-gap to make SVGs at least possible to work with, until we can generate an SVG package: #54
This behaviour is only really meant as a stop-gap to make SVGs at least possible to work with, until we can generate an SVG package: #54
I actually don't think the generated SVG package will help here. After all, it still needs a simple API to create such elements as well. I see a few options:
- Implement the 'cascading' logic for namespaces -- this sounds complex and probably not worth it.
- Add something like
vecty.SVGTag("path", ...)instead of requiringvecty.Namespace. - Add a whitelist of element names (that do not conflict with HTML element names) that automatically get the svg namespace.
Not sure which of those would be the best. But writing your own SVGTag wrapper should be pretty easy today, regardless of what we decide to do here long term.
I actually don't think the generated SVG package will help here. After all, it still needs a simple API to create such elements as well.
The current approach is only annoying because you have to repeat the namespace call manually - for generated code, this is no problem, right?
Consider the generated elem.Anchor code:
func Anchor(markup ...vecty.MarkupOrChild) *vecty.HTML {
return vecty.Tag("a", markup...)
}
If we needed to specify the vecty.Namespace there, too, we'd end up with TONS of duplication in the generated code.
func Anchor(markup ...vecty.MarkupOrChild) *vecty.HTML {
return vecty.Tag("a", append(markup, vecty.Namespace("http://www.w3.org/2000/svg")...)
}
So instead we'd probably end up writing a helper function that does that repetitive logic, and I'm saying that may be useful here as well.
In general, I think we should think of the generated subpackages as "additional layers of type-safety", like how elem.Div prevents you from typo'ing "div" and not getting a compiler warning about it. But using the plain API without that type safety should also be doable, without a ton of hinderence, I think?
Hrm, I guess we need to worry about code size for GopherJS. I have no problem with SVGTag() (my original PR for namespacing actually implemented it using NamespacedTag() :wink: ), if that's the way you want to head.
Add a whitelist of element names (that do not conflict with HTML element names) that automatically get the svg namespace.
It looks like there's a few SVG elements that might conflict with HTML elements: https://developer.mozilla.org/en-US/docs/Web/SVG/Element
It seems that when doing the vecty.Namespace() on nested svgs (like this example) it doesn't work well.
vecty.Tag(
"svg",
vecty.Markup(
vecty.Attribute("xmlns", "http://www.w3.org/2000/svg"),
vecty.Namespace("http://www.w3.org/2000/svg"),
vecty.Attribute("viewbox", " 0 0 100 100"),
vecty.Attribute("fill", "grey"),
vecty.Attribute("stroke", "red"),
),
vecty.Tag(
"circle", vecty.Markup(
vecty.Namespace("http://www.w3.org/2000/svg"),
vecty.Attribute("cx", "50"),
vecty.Attribute("cy", "50"),
vecty.Attribute("r", "40"),
),
),
vecty.Tag(
"svg",
vecty.Markup(
vecty.Namespace("http://www.w3.org/2000/svg"),
vecty.Attribute("viewbox", " 0 0 10 10"),
vecty.Attribute("x", "200"),
vecty.Attribute("width", "100"),
),
vecty.Tag(
"circle", vecty.Markup(
vecty.Namespace("http://www.w3.org/2000/svg"),
vecty.Attribute("cx", "5"),
vecty.Attribute("cy", "5"),
vecty.Attribute("r", "4"),
),
),
),
),
Any thoughts on why a nested svg wouldn't work?
For what it's worth I made a simple svg lib to work with vecty. The above can be written like this:
return elem.Div(
svg.Render(
svg.SVG(
attr.Width(300),
attr.Height(100),
attr.ViewBox(0, 0, 300, 100),
attr.Stroke("red"),
attr.Fill("grey"),
elm.Circle(attr.Cx(50), attr.Cy(50), attr.R(40)),
elm.Circle(attr.Cx(150), attr.Cy(50), attr.R(4)),
),
),
)