Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Polymer.js support inner SVG elements?

Tags:

svg

polymer

I see examples of using SVG elements within a custom element (such as here), but so far I haven't been able to figure out how to define a custom element to go inside an SVG element.

I've tried the following, and while the template content does appear in the web inspector, the circle doesn't appear visually.

<polymer-element name=my-element noscript>
  <template>
    <circle cx=10 cy=10 r=5 />
  </template>
</polymer-element>

<svg>
    <my-element />
</svg>

Is there a trick to getting custom elements to work within SVG elements?

like image 542
exupero Avatar asked Mar 14 '14 00:03

exupero


3 Answers

Unfortunately, you can't do this. Elements within the SVG namespace need to be within <svg>. Creating <my-element> creates a custom element that inherits from HTMLElement.

You can however, include <svg> in a custom element: http://jsbin.com/EXOWUFu/2/edit

Also, don't forget that custom elements cannot be self closing. So in your example, <my-element /> -> <my-element></<my-element>. This is because the HTML spec only allows a few elements to be self-closing.

Update

Turns out you can embed a custom element inside <svg> using <foreignObject>.

Demo: http://jsbin.com/hareyowi/1/edit

<foreignObject width="100" height="100">
  <x-foo></x-foo>
</foreignObject>
like image 123
ebidel Avatar answered Sep 27 '22 19:09

ebidel


According to this open ticket (https://github.com/Polymer/polymer/issues/1976), you actually CAN have a template element nested inside an svg element. The fix I will link to below is a port of the code from 0.5. The issue is described in detail here and in the open ticket, so no need to go over it again.

Important:

If you would like to indicate to Google and the polymer team that this is indeed an important feature, please make sure you leave a comment on the ticket.

  • It does give the intended functionality back in polymer 1.0.
  • It is required to be included at the top of the .js file of each web component which may use it.
  • It also assumes a specific html structure (which you will see below).
  • It only works in chrome right now.

Snippet: https://gist.github.com/bendavis78/15528ca2f501c44f2fa4

foo-svg.css

foo-svg svg {
    border: 2px solid yellowgreen;
    fill: transparent;
    height: 400px;
    width: 400px;
}

foo-svg.html

<dom-module id="foo-svg">
<link rel="stylesheet" href="foo-svg.css"/>

<template>
    <svg class="clock" version="1.1" xmlns="http://www.w3.org/2000/svg">
        <template is="dom-repeat" items="{{positions}}" as="cx">
            <circle cx$="{{cx}}" cy="25" r="25" stroke="black" />
        </template>
    </svg>
</template>
<script src="foo-svg.js"></script>

foo-svg.js

(function () {
  // START HACK
  var doc = document.currentScript.ownerDocument;
  var root = doc.querySelector('dom-module > template').content;
  var templates = root.querySelectorAll('svg template');
  var el, template, attribs, attrib, count, child, content;
  for (var i=0; i<templates.length; i++) {
    el = templates[i];
    template = el.ownerDocument.createElement('template');
    el.parentNode.insertBefore(template, el);
    attribs = el.attributes;
    count = attribs.length;
    while (count-- > 0) {
      attrib = attribs[count];
      template.setAttribute(attrib.name, attrib.value);
      el.removeAttribute(attrib.name);
    }
    el.parentNode.removeChild(el);
    content = template.content;
    while ((child = el.firstChild)) {
      content.appendChild(child);
    }
  }
  // END HACK

  Polymer({
    is: 'foo-svg',

    properties: {
      paths: {
        type: Array,
        value: []
      }
    },

    ready () {
      this.positions = [0, 100, 200, 300];
    }
  });
})();
like image 21
deadbabykitten Avatar answered Sep 27 '22 19:09

deadbabykitten


The Polymer FAQ shows that a template can be used within an <svg> element:

<svg>
    <template repeat="{{l in lights}}">
        <circle cx="100" cy="{{l.cy}}" r="50" fill="{{l.color}}"/>
    </template>
</svg>

https://www.polymer-project.org/0.5/resources/faq.html#templateinsvg

Indeed this works in Polymer 0.5! But it does not work in Polymer 0.9 or 1.0.

In changed Polymer 1.0 syntax it looks like this:

<svg>
    <template is="dom-repeat" items="{{lights}}">
        <circle cx="100" cy$="{{item.cy}}" r="50" fill$="{{item.color}}"/>
    </template>
</svg>

The element is not rendered and the browser console shows:

TypeError: node is undefined   in polymer.html:28

The error refers to Polymer's _parseNodeAnnotations() function.

That the FAQ example works in 0.5 apparently shows there is no reason why SVG should not work in Web Components or Polymer in principle. This let me hope the Polymer team will fix that soon.

like image 25
Jörg Richter Avatar answered Sep 27 '22 20:09

Jörg Richter