2 * The `iron-iconset-svg` element allows users to define their own icon sets
3 * that contain svg icons. The svg icon elements should be children of the
4 * `iron-iconset-svg` element. Multiple icons should be given distinct id's.
6 * Using svg elements to create icons has a few advantages over traditional
7 * bitmap graphics like jpg or png. Icons that use svg are vector based so they
8 * are resolution independent and should look good on any device. They are
9 * stylable via css. Icons can be themed, colorized, and even animated.
13 * <iron-iconset-svg name="my-svg-icons" size="24">
17 * <rect x="50" y="50" width="50" height="50" />
18 * <circle cx="50" cy="50" r="50" />
24 * This will automatically register the icon set "my-svg-icons" to the iconset
25 * database. To use these icons from within another element, make a
26 * `iron-iconset` element and call the `byId` method
27 * to retrieve a given iconset. To apply a particular icon inside an
28 * element use the `applyIcon` method. For example:
30 * iconset.applyIcon(iconNode, 'car');
32 * @element iron-iconset-svg
33 * @demo demo/index.html
37 is: 'iron-iconset-svg',
42 * The name of the iconset.
49 observer: '_nameChanged'
53 * The size of an individual icon. Note that icons must be square.
67 * Construct an array of all icon names in this iconset.
69 * @return {!Array} Array of icon names.
71 getIconNames: function() {
72 this._icons = this._createIconMap();
73 return Object.keys(this._icons).map(function(n) {
74 return this.name + ':' + n;
79 * Applies an icon to the given element.
81 * An svg icon is prepended to the element's shadowRoot if it exists,
82 * otherwise to the element itself.
85 * @param {Element} element Element to which the icon is applied.
86 * @param {string} iconName Name of the icon to apply.
87 * @return {Element} The svg element which renders the icon.
89 applyIcon: function(element, iconName) {
90 // insert svg element into shadow root, if it exists
91 element = element.root || element;
92 // Remove old svg element
93 this.removeIcon(element);
94 // install new svg element
95 var svg = this._cloneIcon(iconName);
97 var pde = Polymer.dom(element);
98 pde.insertBefore(svg, pde.childNodes[0]);
99 return element._svgIcon = svg;
105 * Remove an icon from the given element by undoing the changes effected
108 * @param {Element} element The element from which the icon is removed.
110 removeIcon: function(element) {
111 // Remove old svg element
112 if (element._svgIcon) {
113 Polymer.dom(element).removeChild(element._svgIcon);
114 element._svgIcon = null;
120 * When name is changed, register iconset metadata
123 _nameChanged: function() {
124 new Polymer.IronMeta({type: 'iconset', key: this.name, value: this});
128 * Create a map of child SVG elements by id.
130 * @return {!Object} Map of id's to SVG elements.
132 _createIconMap: function() {
133 // Objects chained to Object.prototype (`{}`) have members. Specifically,
134 // on FF there is a `watch` method that confuses the icon map, so we
135 // need to use a null-based object here.
136 var icons = Object.create(null);
137 Polymer.dom(this).querySelectorAll('[id]')
138 .forEach(function(icon) {
139 icons[icon.id] = icon;
145 * Produce installable clone of the SVG element matching `id` in this
146 * iconset, or `undefined` if there is no matching element.
148 * @return {Element} Returns an installable clone of the SVG element
151 _cloneIcon: function(id) {
152 // create the icon map on-demand, since the iconset itself has no discrete
153 // signal to know when it's children are fully parsed
154 this._icons = this._icons || this._createIconMap();
155 return this._prepareSvgClone(this._icons[id], this.size);
159 * @param {Element} sourceSvg
160 * @param {number} size
163 _prepareSvgClone: function(sourceSvg, size) {
165 var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
166 svg.setAttribute('viewBox', ['0', '0', size, size].join(' '));
167 svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
168 // TODO(dfreedm): `pointer-events: none` works around https://crbug.com/370136
169 // TODO(sjmiles): inline style may not be ideal, but avoids requiring a shadow-root
170 svg.style.cssText = 'pointer-events: none; display: block; width: 100%; height: 100%;';
171 svg.appendChild(sourceSvg.cloneNode(true)).removeAttribute('id');