├── bower.json ├── README.md ├── index.html ├── demo.html ├── paper-spinner.html └── paper-spinner.css /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "paper-spinner", 3 | "private": true, 4 | "dependencies": { 5 | "polymer": "Polymer/polymer#master", 6 | "webcomponentsjs": "Polymer/webcomponentsjs#master" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | paper-spinner 2 | ============= 3 | 4 | **This element is compatible with Polymer 0.5 and lower only, and will be deprecated.** 5 | You can check out a similar 0.8-compatible version of this element at [https://github.com/polymerelements/paper-spinner](https://github.com/polymerelements/paper-spinner) 6 | 7 | A material-design circular activity indicator. 8 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /paper-spinner.html: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | 45 | 46 | 47 | 92 | 93 | 157 | 158 | -------------------------------------------------------------------------------- /paper-spinner.css: -------------------------------------------------------------------------------- 1 | /* 2 | @license 3 | Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 4 | This code may only be used under the BSD style license found at http://polymer.github.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/CONTRIBUTORS.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/PATENTS.txt 9 | */ 10 | 11 | /**************************/ 12 | /* STYLES FOR THE SPINNER */ 13 | /**************************/ 14 | 15 | /* 16 | * Constants: 17 | * STROKEWIDTH = 3px 18 | * ARCSIZE = 270 degrees (amount of circle the arc takes up) 19 | * ARCTIME = 1333ms (time it takes to expand and contract arc) 20 | * ARCSTARTROT = 216 degrees (how much the start location of the arc 21 | * should rotate each time, 216 gives us a 22 | * 5 pointed star shape (it's 360/5 * 3). 23 | * For a 7 pointed star, we might do 24 | * 360/7 * 3 = 154.286) 25 | * CONTAINERWIDTH = 28px 26 | * SHRINK_TIME = 400ms 27 | */ 28 | 29 | :host { 30 | display: inline-block; 31 | position: relative; 32 | width: 28px; /* CONTAINERWIDTH */ 33 | height: 28px; /* CONTAINERWIDTH */ 34 | } 35 | 36 | #spinnerContainer { 37 | width: 100%; 38 | height: 100%; 39 | } 40 | 41 | #spinnerContainer.active { 42 | /* duration: 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */ 43 | -webkit-animation: container-rotate 1568ms linear infinite; 44 | animation: container-rotate 1568ms linear infinite; 45 | } 46 | 47 | @-webkit-keyframes container-rotate { 48 | to { -webkit-transform: rotate(360deg) } 49 | } 50 | 51 | @keyframes container-rotate { 52 | to { transform: rotate(360deg) } 53 | } 54 | 55 | .spinner-layer { 56 | position: absolute; 57 | width: 100%; 58 | height: 100%; 59 | opacity: 0; 60 | } 61 | 62 | .blue { 63 | border-color: #4285f4; 64 | } 65 | 66 | .red { 67 | border-color: #db4437; 68 | } 69 | 70 | .yellow { 71 | border-color: #f4b400; 72 | } 73 | 74 | .green { 75 | border-color: #0f9d58; 76 | } 77 | 78 | /** 79 | * IMPORTANT NOTE ABOUT CSS ANIMATION PROPERTIES (keanulee): 80 | * 81 | * iOS Safari (tested on iOS 8.1) does not handle animation-delay very well - it doesn't 82 | * guarantee that the animation will start _exactly_ after that value. So we avoid using 83 | * animation-delay and instead set custom keyframes for each color (as redundant as it 84 | * seems). 85 | * 86 | * We write out each animation in full (instead of separating animation-name, 87 | * animation-duration, etc.) because under the polyfill, Safari does not recognize those 88 | * specific properties properly, treats them as -webkit-animation, and overrides the 89 | * other animation rules. See https://github.com/Polymer/platform/issues/53. 90 | */ 91 | .active .spinner-layer.blue { 92 | /* durations: 4 * ARCTIME */ 93 | -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; 94 | animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, blue-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; 95 | } 96 | 97 | .active .spinner-layer.red { 98 | /* durations: 4 * ARCTIME */ 99 | -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; 100 | animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, red-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; 101 | } 102 | 103 | .active .spinner-layer.yellow { 104 | /* durations: 4 * ARCTIME */ 105 | -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; 106 | animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, yellow-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; 107 | } 108 | 109 | .active .spinner-layer.green { 110 | /* durations: 4 * ARCTIME */ 111 | -webkit-animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; 112 | animation: fill-unfill-rotate 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both, green-fade-in-out 5332ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; 113 | } 114 | 115 | @-webkit-keyframes fill-unfill-rotate { 116 | 12.5% { -webkit-transform: rotate(135deg); } /* 0.5 * ARCSIZE */ 117 | 25% { -webkit-transform: rotate(270deg); } /* 1 * ARCSIZE */ 118 | 37.5% { -webkit-transform: rotate(405deg); } /* 1.5 * ARCSIZE */ 119 | 50% { -webkit-transform: rotate(540deg); } /* 2 * ARCSIZE */ 120 | 62.5% { -webkit-transform: rotate(675deg); } /* 2.5 * ARCSIZE */ 121 | 75% { -webkit-transform: rotate(810deg); } /* 3 * ARCSIZE */ 122 | 87.5% { -webkit-transform: rotate(945deg); } /* 3.5 * ARCSIZE */ 123 | to { -webkit-transform: rotate(1080deg); } /* 4 * ARCSIZE */ 124 | } 125 | 126 | @keyframes fill-unfill-rotate { 127 | 12.5% { transform: rotate(135deg); } /* 0.5 * ARCSIZE */ 128 | 25% { transform: rotate(270deg); } /* 1 * ARCSIZE */ 129 | 37.5% { transform: rotate(405deg); } /* 1.5 * ARCSIZE */ 130 | 50% { transform: rotate(540deg); } /* 2 * ARCSIZE */ 131 | 62.5% { transform: rotate(675deg); } /* 2.5 * ARCSIZE */ 132 | 75% { transform: rotate(810deg); } /* 3 * ARCSIZE */ 133 | 87.5% { transform: rotate(945deg); } /* 3.5 * ARCSIZE */ 134 | to { transform: rotate(1080deg); } /* 4 * ARCSIZE */ 135 | } 136 | 137 | /** 138 | * HACK: Even though the intention is to have the current .spinner-layer at 139 | * `opacity: 1`, we set it to `opacity: 0.99` instead since this forces Chrome 140 | * to do proper subpixel rendering for the elements being animated. This is 141 | * especially visible in Chrome 39 on Ubuntu 14.04. See: 142 | * 143 | * - https://github.com/Polymer/paper-spinner/issues/9 144 | * - https://code.google.com/p/chromium/issues/detail?id=436255 145 | */ 146 | @-webkit-keyframes blue-fade-in-out { 147 | from { opacity: 0.99; } 148 | 25% { opacity: 0.99; } 149 | 26% { opacity: 0; } 150 | 89% { opacity: 0; } 151 | 90% { opacity: 0.99; } 152 | 100% { opacity: 0.99; } 153 | } 154 | 155 | @keyframes blue-fade-in-out { 156 | from { opacity: 0.99; } 157 | 25% { opacity: 0.99; } 158 | 26% { opacity: 0; } 159 | 89% { opacity: 0; } 160 | 90% { opacity: 0.99; } 161 | 100% { opacity: 0.99; } 162 | } 163 | 164 | @-webkit-keyframes red-fade-in-out { 165 | from { opacity: 0; } 166 | 15% { opacity: 0; } 167 | 25% { opacity: 0.99; } 168 | 50% { opacity: 0.99; } 169 | 51% { opacity: 0; } 170 | } 171 | 172 | @keyframes red-fade-in-out { 173 | from { opacity: 0; } 174 | 15% { opacity: 0; } 175 | 25% { opacity: 0.99; } 176 | 50% { opacity: 0.99; } 177 | 51% { opacity: 0; } 178 | } 179 | 180 | @-webkit-keyframes yellow-fade-in-out { 181 | from { opacity: 0; } 182 | 40% { opacity: 0; } 183 | 50% { opacity: 0.99; } 184 | 75% { opacity: 0.99; } 185 | 76% { opacity: 0; } 186 | } 187 | 188 | @keyframes yellow-fade-in-out { 189 | from { opacity: 0; } 190 | 40% { opacity: 0; } 191 | 50% { opacity: 0.99; } 192 | 75% { opacity: 0.99; } 193 | 76% { opacity: 0; } 194 | } 195 | 196 | @-webkit-keyframes green-fade-in-out { 197 | from { opacity: 0; } 198 | 65% { opacity: 0; } 199 | 75% { opacity: 0.99; } 200 | 90% { opacity: 0.99; } 201 | 100% { opacity: 0; } 202 | } 203 | 204 | @keyframes green-fade-in-out { 205 | from { opacity: 0; } 206 | 65% { opacity: 0; } 207 | 75% { opacity: 0.99; } 208 | 90% { opacity: 0.99; } 209 | 100% { opacity: 0; } 210 | } 211 | 212 | /** 213 | * Patch the gap that appear between the two adjacent div.circle-clipper while the 214 | * spinner is rotating (appears on Chrome 38, Safari 7.1, and IE 11). 215 | * 216 | * Update: the gap no longer appears on Chrome when .spinner-layer's opacity is 0.99, 217 | * but still does on Safari and IE. 218 | */ 219 | .gap-patch { 220 | position: absolute; 221 | box-sizing: border-box; 222 | top: 0; 223 | left: 45%; 224 | width: 10%; 225 | height: 100%; 226 | overflow: hidden; 227 | border-color: inherit; 228 | } 229 | 230 | .gap-patch .circle { 231 | width: 1000%; 232 | left: -450%; 233 | } 234 | 235 | .circle-clipper { 236 | display: inline-block; 237 | position: relative; 238 | width: 50%; 239 | height: 100%; 240 | overflow: hidden; 241 | border-color: inherit; 242 | } 243 | 244 | .circle-clipper .circle { 245 | width: 200%; 246 | } 247 | 248 | .circle { 249 | box-sizing: border-box; 250 | height: 100%; 251 | border-width: 3px; /* STROKEWIDTH */ 252 | border-style: solid; 253 | border-color: inherit; 254 | border-bottom-color: transparent !important; 255 | border-radius: 50%; 256 | -webkit-animation: none; 257 | animation: none; 258 | } 259 | 260 | .circle-clipper.left .circle { 261 | border-right-color: transparent !important; 262 | -webkit-transform: rotate(129deg); 263 | transform: rotate(129deg); 264 | } 265 | 266 | .circle-clipper.right .circle { 267 | left: -100%; 268 | border-left-color: transparent !important; 269 | -webkit-transform: rotate(-129deg); 270 | transform: rotate(-129deg); 271 | } 272 | 273 | .active .circle-clipper.left .circle { 274 | /* duration: ARCTIME */ 275 | -webkit-animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; 276 | animation: left-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; 277 | } 278 | 279 | .active .circle-clipper.right .circle { 280 | /* duration: ARCTIME */ 281 | -webkit-animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; 282 | animation: right-spin 1333ms cubic-bezier(0.4, 0.0, 0.2, 1) infinite both; 283 | } 284 | 285 | @-webkit-keyframes left-spin { 286 | from { -webkit-transform: rotate(130deg); } 287 | 50% { -webkit-transform: rotate(-5deg); } 288 | to { -webkit-transform: rotate(130deg); } 289 | } 290 | 291 | @keyframes left-spin { 292 | from { transform: rotate(130deg); } 293 | 50% { transform: rotate(-5deg); } 294 | to { transform: rotate(130deg); } 295 | } 296 | 297 | @-webkit-keyframes right-spin { 298 | from { -webkit-transform: rotate(-130deg); } 299 | 50% { -webkit-transform: rotate(5deg); } 300 | to { -webkit-transform: rotate(-130deg); } 301 | } 302 | 303 | @keyframes right-spin { 304 | from { transform: rotate(-130deg); } 305 | 50% { transform: rotate(5deg); } 306 | to { transform: rotate(-130deg); } 307 | } 308 | 309 | #spinnerContainer.cooldown { 310 | /* duration: SHRINK_TIME */ 311 | -webkit-animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0.0, 0.2, 1); 312 | animation: container-rotate 1568ms linear infinite, fade-out 400ms cubic-bezier(0.4, 0.0, 0.2, 1); 313 | } 314 | 315 | @-webkit-keyframes fade-out { 316 | from { opacity: 0.99; } 317 | to { opacity: 0; } 318 | } 319 | 320 | @keyframes fade-out { 321 | from { opacity: 0.99; } 322 | to { opacity: 0; } 323 | } 324 | --------------------------------------------------------------------------------