OLD | NEW |
| (Empty) |
1 <!-- | |
2 @license | |
3 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. | |
4 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | |
5 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | |
6 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | |
7 Code distributed by Google as part of the polymer project is also | |
8 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | |
9 --> | |
10 | |
11 <link rel="import" href="../polymer/polymer.html"> | |
12 <link rel="import" href="../iron-meta/iron-meta.html"> | |
13 | |
14 <!-- | |
15 The `iron-iconset` element allows users to define their own icon sets. | |
16 The `src` property specifies the url of the icon image. Multiple icons may | |
17 be included in this image and they may be organized into rows. | |
18 The `icons` property is a space separated list of names corresponding to the | |
19 icons. The names must be ordered as the icons are ordered in the icon image. | |
20 Icons are expected to be square and are the size specified by the `size` | |
21 property. The `width` property corresponds to the width of the icon image | |
22 and must be specified if icons are arranged into multiple rows in the image. | |
23 | |
24 All `iron-iconset` elements are available for use by other `iron-iconset` | |
25 elements via a database keyed by id. Typically, an element author that wants | |
26 to support a set of custom icons uses a `iron-iconset` to retrieve | |
27 and use another, user-defined iconset. | |
28 | |
29 Example: | |
30 | |
31 <iron-iconset id="my-icons" src="my-icons.png" width="96" size="24" | |
32 icons="location place starta stopb bus car train walk"> | |
33 </iron-iconset> | |
34 | |
35 This will automatically register the icon set "my-icons" to the iconset | |
36 database. To use these icons from within another element, make a | |
37 `iron-iconset` element and call the `byId` method to retrieve a | |
38 given iconset. To apply a particular icon to an element, use the | |
39 `applyIcon` method. For example: | |
40 | |
41 iconset.applyIcon(iconNode, 'car'); | |
42 | |
43 Themed icon sets are also supported. The `iron-iconset` can contain child | |
44 `property` elements that specify a theme with an offsetX and offsetY of the | |
45 theme within the icon resource. For example. | |
46 | |
47 <iron-iconset id="my-icons" src="my-icons.png" width="96" size="24" | |
48 icons="location place starta stopb bus car train walk"> | |
49 <property theme="special" offsetX="256" offsetY="24"></property> | |
50 </iron-iconset> | |
51 | |
52 Then a themed icon can be applied like this: | |
53 | |
54 iconset.applyIcon(iconNode, 'car', 'special'); | |
55 | |
56 @element iron-iconset | |
57 --> | |
58 | |
59 <script> | |
60 | |
61 Polymer({ | |
62 | |
63 is: 'iron-iconset', | |
64 | |
65 properties: { | |
66 | |
67 /** | |
68 * The URL of the iconset image. | |
69 * | |
70 * @attribute src | |
71 * @type string | |
72 * @default '' | |
73 */ | |
74 src: { | |
75 type: String, | |
76 observer: '_srcChanged' | |
77 }, | |
78 | |
79 /** | |
80 * The name of the iconset. | |
81 * | |
82 * @attribute name | |
83 * @type string | |
84 * @default 'no-name' | |
85 */ | |
86 name: { | |
87 type: String, | |
88 observer: '_nameChanged' | |
89 }, | |
90 | |
91 /** | |
92 * The width of the iconset image. This must only be specified if the | |
93 * icons are arranged into separate rows inside the image. | |
94 * | |
95 * @attribute width | |
96 * @type number | |
97 * @default 0 | |
98 */ | |
99 width: { | |
100 type: Number, | |
101 value: 0 | |
102 }, | |
103 | |
104 /** | |
105 * A space separated list of names corresponding to icons in the iconset | |
106 * image file. This list must be ordered the same as the icon images | |
107 * in the image file. | |
108 * | |
109 * @attribute icons | |
110 * @type string | |
111 * @default '' | |
112 */ | |
113 icons: { | |
114 type: String | |
115 }, | |
116 | |
117 /** | |
118 * The size of an individual icon. Note that icons must be square. | |
119 * | |
120 * @attribute size | |
121 * @type number | |
122 * @default 24 | |
123 */ | |
124 size: { | |
125 type: Number, | |
126 value: 24 | |
127 }, | |
128 | |
129 /** | |
130 * The horizontal offset of the icon images in the inconset src image. | |
131 * This is typically used if the image resource contains additional images | |
132 * beside those intended for the iconset. | |
133 * | |
134 * @attribute offset-x | |
135 * @type number | |
136 * @default 0 | |
137 */ | |
138 _offsetX: { | |
139 type: Number, | |
140 value: 0 | |
141 }, | |
142 | |
143 /** | |
144 * The vertical offset of the icon images in the inconset src image. | |
145 * This is typically used if the image resource contains additional images | |
146 * beside those intended for the iconset. | |
147 * | |
148 * @attribute offset-y | |
149 * @type number | |
150 * @default 0 | |
151 */ | |
152 _offsetY: { | |
153 type: Number, | |
154 value: 0 | |
155 }, | |
156 | |
157 /** | |
158 * Array of fully-qualified names of icons in this set. | |
159 */ | |
160 iconNames: { | |
161 type: Array, | |
162 notify: true | |
163 } | |
164 | |
165 }, | |
166 | |
167 hostAttributes: { | |
168 // non-visual | |
169 style: 'display: none;' | |
170 }, | |
171 | |
172 ready: function() { | |
173 // theme data must exist at ready-time | |
174 this._themes = this._mapThemes(); | |
175 }, | |
176 | |
177 /** | |
178 * Applies an icon to the given element as a css background image. This | |
179 * method does not size the element, and it's usually necessary to set | |
180 * the element's height and width so that the background image is visible. | |
181 * | |
182 * @method applyIcon | |
183 * @param {Element} element The element to which the icon is applied. | |
184 * @param {String|Number} icon The name or index of the icon to apply. | |
185 * @param {String} theme (optional) The name or index of the icon to apply. | |
186 * @param {Number} scale (optional, defaults to 1) Icon scaling factor. | |
187 * @return {Element} The applied icon element. | |
188 */ | |
189 applyIcon: function(element, icon, theme, scale) { | |
190 this._validateIconMap(); | |
191 var offset = this._getThemedOffset(icon, theme); | |
192 if (element && offset) { | |
193 this._addIconStyles(element, this._srcUrl, offset, scale || 1, | |
194 this.size, this.width); | |
195 } | |
196 }, | |
197 | |
198 /** | |
199 * Remove an icon from the given element by undoing the changes effected | |
200 * by `applyIcon`. | |
201 * | |
202 * @param {Element} element The element from which the icon is removed. | |
203 */ | |
204 removeIcon: function(element) { | |
205 this._removeIconStyles(element.style); | |
206 }, | |
207 | |
208 _mapThemes: function() { | |
209 var themes = Object.create(null); | |
210 Polymer.dom(this).querySelectorAll('property[theme]') | |
211 .forEach(function(property) { | |
212 var offsetX = window.parseInt( | |
213 property.getAttribute('offset-x'), 10 | |
214 ) || 0; | |
215 var offsetY = window.parseInt( | |
216 property.getAttribute('offset-y'), 10 | |
217 ) || 0; | |
218 themes[property.getAttribute('theme')] = { | |
219 offsetX: offsetX, | |
220 offsetY: offsetY | |
221 }; | |
222 }); | |
223 return themes; | |
224 }, | |
225 | |
226 _srcChanged: function(src) { | |
227 // ensure `srcUrl` is always relative to the main document | |
228 this._srcUrl = this.ownerDocument !== document | |
229 ? this.resolveUrl(src) : src; | |
230 this._prepareIconset(); | |
231 }, | |
232 | |
233 _nameChanged: function(name) { | |
234 this._prepareIconset(); | |
235 }, | |
236 | |
237 _prepareIconset: function() { | |
238 new Polymer.IronMeta({type: 'iconset', key: this.name, value: this}); | |
239 }, | |
240 | |
241 _invalidateIconMap: function() { | |
242 this._iconMapValid = false; | |
243 }, | |
244 | |
245 _validateIconMap: function() { | |
246 if (!this._iconMapValid) { | |
247 this._recomputeIconMap(); | |
248 this._iconMapValid = true; | |
249 } | |
250 }, | |
251 | |
252 _recomputeIconMap: function() { | |
253 this.iconNames = this._computeIconNames(this.icons); | |
254 this.iconMap = this._computeIconMap(this._offsetX, this._offsetY, | |
255 this.size, this.width, this.iconNames); | |
256 }, | |
257 | |
258 _computeIconNames: function(icons) { | |
259 return icons.split(/\s+/g); | |
260 }, | |
261 | |
262 _computeIconMap: function(offsetX, offsetY, size, width, iconNames) { | |
263 var iconMap = {}; | |
264 if (offsetX !== undefined && offsetY !== undefined) { | |
265 var x0 = offsetX; | |
266 iconNames.forEach(function(iconName) { | |
267 iconMap[iconName] = { | |
268 offsetX: offsetX, | |
269 offsetY: offsetY | |
270 }; | |
271 if ((offsetX + size) < width) { | |
272 offsetX += size; | |
273 } else { | |
274 offsetX = x0; | |
275 offsetY += size; | |
276 } | |
277 }, this); | |
278 } | |
279 return iconMap; | |
280 }, | |
281 | |
282 /** | |
283 * Returns an object containing `offsetX` and `offsetY` properties which | |
284 * specify the pixel location in the iconset's src file for the given | |
285 * `icon` and `theme`. It's uncommon to call this method. It is useful, | |
286 * for example, to manually position a css backgroundImage to the proper | |
287 * offset. It's more common to use the `applyIcon` method. | |
288 * | |
289 * @method getThemedOffset | |
290 * @param {String|Number} identifier The name of the icon or the index of | |
291 * the icon within in the icon image. | |
292 * @param {String} theme The name of the theme. | |
293 * @returns {Object} An object specifying the offset of the given icon | |
294 * within the icon resource file; `offsetX` is the horizontal offset and | |
295 * `offsetY` is the vertical offset. Both values are in pixel units. | |
296 */ | |
297 _getThemedOffset: function(identifier, theme) { | |
298 var iconOffset = this._getIconOffset(identifier); | |
299 var themeOffset = this._themes[theme]; | |
300 if (iconOffset && themeOffset) { | |
301 return { | |
302 offsetX: iconOffset.offsetX + themeOffset.offsetX, | |
303 offsetY: iconOffset.offsetY + themeOffset.offsetY | |
304 }; | |
305 } | |
306 return iconOffset; | |
307 }, | |
308 | |
309 _getIconOffset: function(identifier) { | |
310 // TODO(sjmiles): consider creating offsetArray (indexed by Number) | |
311 // and having iconMap map names to indices, then and index is just | |
312 // iconMap[identifier] || identifier (be careful of zero, store indices | |
313 // as 1-based) | |
314 return this.iconMap[identifier] || | |
315 this.iconMap[this.iconNames[Number(identifier)]]; | |
316 }, | |
317 | |
318 _addIconStyles: function(element, url, offset, scale, size, width) { | |
319 var style = element.style; | |
320 style.backgroundImage = 'url(' + url + ')'; | |
321 style.backgroundPosition = | |
322 (-offset.offsetX * scale + 'px') + ' ' + | |
323 (-offset.offsetY * scale + 'px'); | |
324 style.backgroundSize = (scale === 1) ? 'auto' : width * scale + 'px'; | |
325 style.width = size + 'px'; | |
326 style.height = size + 'px'; | |
327 element.setAttribute('role', 'img'); | |
328 }, | |
329 | |
330 _removeIconStyles: function(style) { | |
331 style.background = ''; | |
332 } | |
333 | |
334 }); | |
335 | |
336 </script> | |
OLD | NEW |