| <!-- |
| @license |
| Copyright (c) 2015 The Polymer Project Authors. All rights reserved. |
| This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
| The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
| The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
| Code distributed by Google as part of the polymer project is also |
| subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
| --> |
| |
| <link rel="import" href="../polymer/polymer.html"> |
| <link rel="import" href="../iron-meta/iron-meta.html"> |
| |
| <script> |
| /** |
| * The `iron-iconset-svg` element allows users to define their own icon sets |
| * that contain svg icons. The svg icon elements should be children of the |
| * `iron-iconset-svg` element. Multiple icons should be given distinct id's. |
| * |
| * Using svg elements to create icons has a few advantages over traditional |
| * bitmap graphics like jpg or png. Icons that use svg are vector based so |
| * they are resolution independent and should look good on any device. They |
| * are stylable via css. Icons can be themed, colorized, and even animated. |
| * |
| * Example: |
| * |
| * <iron-iconset-svg name="my-svg-icons" size="24"> |
| * <svg> |
| * <defs> |
| * <g id="shape"> |
| * <rect x="12" y="0" width="12" height="24" /> |
| * <circle cx="12" cy="12" r="12" /> |
| * </g> |
| * </defs> |
| * </svg> |
| * </iron-iconset-svg> |
| * |
| * This will automatically register the icon set "my-svg-icons" to the iconset |
| * database. To use these icons from within another element, make a |
| * `iron-iconset` element and call the `byId` method |
| * to retrieve a given iconset. To apply a particular icon inside an |
| * element use the `applyIcon` method. For example: |
| * |
| * iconset.applyIcon(iconNode, 'car'); |
| * |
| * @element iron-iconset-svg |
| * @demo demo/index.html |
| * @implements {Polymer.Iconset} |
| */ |
| Polymer({ |
| is: 'iron-iconset-svg', |
| |
| properties: { |
| |
| /** |
| * The name of the iconset. |
| */ |
| name: { |
| type: String, |
| observer: '_nameChanged' |
| }, |
| |
| /** |
| * The size of an individual icon. Note that icons must be square. |
| */ |
| size: { |
| type: Number, |
| value: 24 |
| } |
| |
| }, |
| |
| attached: function() { |
| this.style.display = 'none'; |
| }, |
| |
| /** |
| * Construct an array of all icon names in this iconset. |
| * |
| * @return {!Array} Array of icon names. |
| */ |
| getIconNames: function() { |
| this._icons = this._createIconMap(); |
| return Object.keys(this._icons).map(function(n) { |
| return this.name + ':' + n; |
| }, this); |
| }, |
| |
| /** |
| * Applies an icon to the given element. |
| * |
| * An svg icon is prepended to the element's shadowRoot if it exists, |
| * otherwise to the element itself. |
| * |
| * @method applyIcon |
| * @param {Element} element Element to which the icon is applied. |
| * @param {string} iconName Name of the icon to apply. |
| * @return {?Element} The svg element which renders the icon. |
| */ |
| applyIcon: function(element, iconName) { |
| // insert svg element into shadow root, if it exists |
| element = element.root || element; |
| // Remove old svg element |
| this.removeIcon(element); |
| // install new svg element |
| var svg = this._cloneIcon(iconName); |
| if (svg) { |
| var pde = Polymer.dom(element); |
| pde.insertBefore(svg, pde.childNodes[0]); |
| return element._svgIcon = svg; |
| } |
| return null; |
| }, |
| |
| /** |
| * Remove an icon from the given element by undoing the changes effected |
| * by `applyIcon`. |
| * |
| * @param {Element} element The element from which the icon is removed. |
| */ |
| removeIcon: function(element) { |
| // Remove old svg element |
| if (element._svgIcon) { |
| Polymer.dom(element).removeChild(element._svgIcon); |
| element._svgIcon = null; |
| } |
| }, |
| |
| /** |
| * |
| * When name is changed, register iconset metadata |
| * |
| */ |
| _nameChanged: function() { |
| new Polymer.IronMeta({type: 'iconset', key: this.name, value: this}); |
| this.async(function() { |
| this.fire('iron-iconset-added', this, {node: window}); |
| }); |
| }, |
| |
| /** |
| * Create a map of child SVG elements by id. |
| * |
| * @return {!Object} Map of id's to SVG elements. |
| */ |
| _createIconMap: function() { |
| // Objects chained to Object.prototype (`{}`) have members. Specifically, |
| // on FF there is a `watch` method that confuses the icon map, so we |
| // need to use a null-based object here. |
| var icons = Object.create(null); |
| Polymer.dom(this).querySelectorAll('[id]') |
| .forEach(function(icon) { |
| icons[icon.id] = icon; |
| }); |
| return icons; |
| }, |
| |
| /** |
| * Produce installable clone of the SVG element matching `id` in this |
| * iconset, or `undefined` if there is no matching element. |
| * |
| * @return {Element} Returns an installable clone of the SVG element |
| * matching `id`. |
| */ |
| _cloneIcon: function(id) { |
| // create the icon map on-demand, since the iconset itself has no discrete |
| // signal to know when it's children are fully parsed |
| this._icons = this._icons || this._createIconMap(); |
| return this._prepareSvgClone(this._icons[id], this.size); |
| }, |
| |
| /** |
| * @param {Element} sourceSvg |
| * @param {number} size |
| * @return {Element} |
| */ |
| _prepareSvgClone: function(sourceSvg, size) { |
| if (sourceSvg) { |
| var content = sourceSvg.cloneNode(true), |
| svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'), |
| viewBox = content.getAttribute('viewBox') || '0 0 ' + size + ' ' + size; |
| svg.setAttribute('viewBox', viewBox); |
| svg.setAttribute('preserveAspectRatio', 'xMidYMid meet'); |
| // TODO(dfreedm): `pointer-events: none` works around https://crbug.com/370136 |
| // TODO(sjmiles): inline style may not be ideal, but avoids requiring a shadow-root |
| svg.style.cssText = 'pointer-events: none; display: block; width: 100%; height: 100%;'; |
| svg.appendChild(content).removeAttribute('id'); |
| return svg; |
| } |
| return null; |
| } |
| |
| }); |
| </script> |