├── demo ├── public │ ├── favicon.ico │ └── index.html ├── babel.config.js ├── src │ ├── main.js │ └── App.vue ├── README.md └── package.json ├── index.js ├── .gitignore ├── package.json ├── Skycon.vue ├── README.md └── skycons.js /demo/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timleland/vue-skycon/master/demo/public/favicon.ico -------------------------------------------------------------------------------- /demo/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import SkyconComponent from './Skycon'; 2 | 3 | export default { 4 | install: function(Vue) { 5 | Vue.component('skycon', SkyconComponent); 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /demo/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | import VueSkycons from 'vue-skycon'; 4 | 5 | Vue.use(VueSkycons); 6 | 7 | new Vue({ 8 | render: (h) => h(App), 9 | }).$mount('#app'); 10 | -------------------------------------------------------------------------------- /demo/README.md: -------------------------------------------------------------------------------- 1 | # Vue Skycons Demo App 2 | 3 | Easily use [Skycons](https://github.com/darkskyapp/skycons) in your VueJs apps. Example use [WeatherTab](https://timleland.com/weathertab/) 4 | 5 | ## Demo Example 6 | 7 | ``` 8 | npm i 9 | npm run serve 10 | browse to: http://localhost:8081/ 11 | ``` 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-skycon", 3 | "version": "1.0.4", 4 | "description": "Skycons weather icons in VueJS", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/timleland/vue-skycon.git" 9 | }, 10 | "keywords": [ 11 | "skycons", 12 | "skycon", 13 | "weather", 14 | "vue", 15 | "icons", 16 | "animated" 17 | ], 18 | "author": "Tim Leland", 19 | "license": "Apache v2.0", 20 | "bugs": { 21 | "url": "https://github.com/timleland/vue-skycon/issues" 22 | }, 23 | "homepage": "https://github.com/timleland/vue-skycon#readme" 24 | } 25 | -------------------------------------------------------------------------------- /demo/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-skycon", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "core-js": "^3.6.5", 12 | "vue": "^2.6.11", 13 | "vue-skycon": "^1.0.4" 14 | }, 15 | "devDependencies": { 16 | "@vue/cli-plugin-babel": "~4.5.0", 17 | "@vue/cli-plugin-eslint": "~4.5.0", 18 | "@vue/cli-service": "~4.5.0", 19 | "babel-eslint": "^10.1.0", 20 | "eslint": "^6.7.2", 21 | "eslint-plugin-vue": "^6.2.2", 22 | "vue-template-compiler": "^2.6.11" 23 | }, 24 | "eslintConfig": { 25 | "root": true, 26 | "env": { 27 | "node": true 28 | }, 29 | "extends": [ 30 | "plugin:vue/essential", 31 | "eslint:recommended" 32 | ], 33 | "parserOptions": { 34 | "parser": "babel-eslint" 35 | }, 36 | "rules": {} 37 | }, 38 | "browserslist": [ 39 | "> 1%", 40 | "last 2 versions", 41 | "not dead" 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /demo/src/App.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 40 | 41 | 43 | -------------------------------------------------------------------------------- /Skycon.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue Skycons 2 | Easily use [Skycons](https://t.ly/_ic0) in your VueJs apps. Example use [Weather Extension](https://weatherextension.com/) and [WeatherTab](https://timleland.com/weathertab/) 3 | 4 | DigitalOcean Referral Badge 5 | 6 | ## Installation 7 | ### NPM 8 | ``` 9 | npm i vue-skycon 10 | ``` 11 | 12 | ### YARN 13 | ``` 14 | yarn add vue-skycon 15 | ``` 16 | 17 | ## Installation 18 | ``` 19 | import Vue from 'vue' 20 | import VueSkycons from 'vue-skycon' 21 | 22 | Vue.use(VueSkycons) 23 | 24 | ``` 25 | 26 | ## Usage 27 | ``` 28 | 43 | ``` 44 | 45 | ## Props 46 | ``` 47 | // Icon size 48 | width: { 49 | type: Number, 50 | default: 64 51 | }, 52 | 53 | height: { 54 | type: Number, 55 | default: 64 56 | }, 57 | 58 | color: { 59 | type: String, 60 | default: 'black' 61 | }, 62 | 63 | // Weather condition 64 | condition: { 65 | type: String 66 | } 67 | ``` 68 | -------------------------------------------------------------------------------- /skycons.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* Set up a RequestAnimationFrame shim so we can animate efficiently FOR 4 | * GREAT JUSTICE. */ 5 | var requestInterval, cancelInterval; 6 | 7 | (function() { 8 | var global = window; 9 | 10 | var raf = global.requestAnimationFrame || global.webkitRequestAnimationFrame || global.mozRequestAnimationFrame || global.oRequestAnimationFrame || global.msRequestAnimationFrame, 11 | caf = global.cancelAnimationFrame || global.webkitCancelAnimationFrame || global.mozCancelAnimationFrame || global.oCancelAnimationFrame || global.msCancelAnimationFrame; 12 | 13 | if (raf && caf) { 14 | requestInterval = function(fn) { 15 | var handle = { value: null }; 16 | 17 | function loop() { 18 | handle.value = raf(loop); 19 | fn(); 20 | } 21 | 22 | loop(); 23 | return handle; 24 | }; 25 | 26 | cancelInterval = function(handle) { 27 | caf(handle.value); 28 | }; 29 | } else { 30 | requestInterval = setInterval; 31 | cancelInterval = clearInterval; 32 | } 33 | })(); 34 | 35 | /* Catmull-rom spline stuffs. */ 36 | /* 37 | function upsample(n, spline) { 38 | var polyline = [], 39 | len = spline.length, 40 | bx = spline[0], 41 | by = spline[1], 42 | cx = spline[2], 43 | cy = spline[3], 44 | dx = spline[4], 45 | dy = spline[5], 46 | i, j, ax, ay, px, qx, rx, sx, py, qy, ry, sy, t; 47 | 48 | for(i = 6; i !== spline.length; i += 2) { 49 | ax = bx; 50 | bx = cx; 51 | cx = dx; 52 | dx = spline[i ]; 53 | px = -0.5 * ax + 1.5 * bx - 1.5 * cx + 0.5 * dx; 54 | qx = ax - 2.5 * bx + 2.0 * cx - 0.5 * dx; 55 | rx = -0.5 * ax + 0.5 * cx ; 56 | sx = bx ; 57 | 58 | ay = by; 59 | by = cy; 60 | cy = dy; 61 | dy = spline[i + 1]; 62 | py = -0.5 * ay + 1.5 * by - 1.5 * cy + 0.5 * dy; 63 | qy = ay - 2.5 * by + 2.0 * cy - 0.5 * dy; 64 | ry = -0.5 * ay + 0.5 * cy ; 65 | sy = by ; 66 | 67 | for(j = 0; j !== n; ++j) { 68 | t = j / n; 69 | 70 | polyline.push( 71 | ((px * t + qx) * t + rx) * t + sx, 72 | ((py * t + qy) * t + ry) * t + sy 73 | ); 74 | } 75 | } 76 | 77 | polyline.push( 78 | px + qx + rx + sx, 79 | py + qy + ry + sy 80 | ); 81 | 82 | return polyline; 83 | } 84 | 85 | function downsample(n, polyline) { 86 | var len = 0, 87 | i, dx, dy; 88 | 89 | for(i = 2; i !== polyline.length; i += 2) { 90 | dx = polyline[i ] - polyline[i - 2]; 91 | dy = polyline[i + 1] - polyline[i - 1]; 92 | len += Math.sqrt(dx * dx + dy * dy); 93 | } 94 | 95 | len /= n; 96 | 97 | var small = [], 98 | target = len, 99 | min = 0, 100 | max, t; 101 | 102 | small.push(polyline[0], polyline[1]); 103 | 104 | for(i = 2; i !== polyline.length; i += 2) { 105 | dx = polyline[i ] - polyline[i - 2]; 106 | dy = polyline[i + 1] - polyline[i - 1]; 107 | max = min + Math.sqrt(dx * dx + dy * dy); 108 | 109 | if(max > target) { 110 | t = (target - min) / (max - min); 111 | 112 | small.push( 113 | polyline[i - 2] + dx * t, 114 | polyline[i - 1] + dy * t 115 | ); 116 | 117 | target += len; 118 | } 119 | 120 | min = max; 121 | } 122 | 123 | small.push(polyline[polyline.length - 2], polyline[polyline.length - 1]); 124 | 125 | return small; 126 | } 127 | */ 128 | 129 | /* Define skycon things. */ 130 | /* FIXME: I'm *really really* sorry that this code is so gross. Really, I am. 131 | * I'll try to clean it up eventually! Promise! */ 132 | var KEYFRAME = 500, 133 | STROKE = 0.08, 134 | TAU = 2.0 * Math.PI, 135 | TWO_OVER_SQRT_2 = 2.0 / Math.sqrt(2); 136 | 137 | function circle(ctx, x, y, r) { 138 | ctx.beginPath(); 139 | ctx.arc(x, y, r, 0, TAU, false); 140 | ctx.fill(); 141 | } 142 | 143 | function line(ctx, ax, ay, bx, by) { 144 | ctx.beginPath(); 145 | ctx.moveTo(ax, ay); 146 | ctx.lineTo(bx, by); 147 | ctx.stroke(); 148 | } 149 | 150 | function puff(ctx, t, cx, cy, rx, ry, rmin, rmax) { 151 | var c = Math.cos(t * TAU), 152 | s = Math.sin(t * TAU); 153 | 154 | rmax -= rmin; 155 | 156 | circle(ctx, cx - s * rx, cy + c * ry + rmax * 0.5, rmin + (1 - c * 0.5) * rmax); 157 | } 158 | 159 | function puffs(ctx, t, cx, cy, rx, ry, rmin, rmax) { 160 | var i; 161 | 162 | for (i = 5; i--; ) puff(ctx, t + i / 5, cx, cy, rx, ry, rmin, rmax); 163 | } 164 | 165 | function cloud(ctx, t, cx, cy, cw, s, color) { 166 | t /= 30000; 167 | 168 | var a = cw * 0.21, 169 | b = cw * 0.12, 170 | c = cw * 0.24, 171 | d = cw * 0.28; 172 | 173 | ctx.fillStyle = color; 174 | puffs(ctx, t, cx, cy, a, b, c, d); 175 | 176 | ctx.globalCompositeOperation = 'destination-out'; 177 | puffs(ctx, t, cx, cy, a, b, c - s, d - s); 178 | ctx.globalCompositeOperation = 'source-over'; 179 | } 180 | 181 | function sun(ctx, t, cx, cy, cw, s, color) { 182 | t /= 120000; 183 | 184 | var a = cw * 0.25 - s * 0.5, 185 | b = cw * 0.32 + s * 0.5, 186 | c = cw * 0.5 - s * 0.5, 187 | i, 188 | p, 189 | cos, 190 | sin; 191 | 192 | ctx.strokeStyle = color; 193 | ctx.lineWidth = s; 194 | ctx.lineCap = 'round'; 195 | ctx.lineJoin = 'round'; 196 | 197 | ctx.beginPath(); 198 | ctx.arc(cx, cy, a, 0, TAU, false); 199 | ctx.stroke(); 200 | 201 | for (i = 8; i--; ) { 202 | p = (t + i / 8) * TAU; 203 | cos = Math.cos(p); 204 | sin = Math.sin(p); 205 | line(ctx, cx + cos * b, cy + sin * b, cx + cos * c, cy + sin * c); 206 | } 207 | } 208 | 209 | function moon(ctx, t, cx, cy, cw, s, color) { 210 | t /= 15000; 211 | 212 | var a = cw * 0.29 - s * 0.5, 213 | b = cw * 0.05, 214 | c = Math.cos(t * TAU), 215 | p = (c * TAU) / -16; 216 | 217 | ctx.strokeStyle = color; 218 | ctx.lineWidth = s; 219 | ctx.lineCap = 'round'; 220 | ctx.lineJoin = 'round'; 221 | 222 | cx += c * b; 223 | 224 | ctx.beginPath(); 225 | ctx.arc(cx, cy, a, p + TAU / 8, p + (TAU * 7) / 8, false); 226 | ctx.arc(cx + Math.cos(p) * a * TWO_OVER_SQRT_2, cy + Math.sin(p) * a * TWO_OVER_SQRT_2, a, p + (TAU * 5) / 8, p + (TAU * 3) / 8, true); 227 | ctx.closePath(); 228 | ctx.stroke(); 229 | } 230 | 231 | function rain(ctx, t, cx, cy, cw, s, color) { 232 | t /= 1350; 233 | 234 | var a = cw * 0.16, 235 | b = (TAU * 11) / 12, 236 | c = (TAU * 7) / 12, 237 | i, 238 | p, 239 | x, 240 | y; 241 | 242 | ctx.fillStyle = color; 243 | 244 | for (i = 4; i--; ) { 245 | p = (t + i / 4) % 1; 246 | x = cx + ((i - 1.5) / 1.5) * (i === 1 || i === 2 ? -1 : 1) * a; 247 | y = cy + p * p * cw; 248 | ctx.beginPath(); 249 | ctx.moveTo(x, y - s * 1.5); 250 | ctx.arc(x, y, s * 0.75, b, c, false); 251 | ctx.fill(); 252 | } 253 | } 254 | 255 | function sleet(ctx, t, cx, cy, cw, s, color) { 256 | t /= 750; 257 | 258 | var a = cw * 0.1875, 259 | i, 260 | p, 261 | x, 262 | y; 263 | 264 | ctx.strokeStyle = color; 265 | ctx.lineWidth = s * 0.5; 266 | ctx.lineCap = 'round'; 267 | ctx.lineJoin = 'round'; 268 | 269 | for (i = 4; i--; ) { 270 | p = (t + i / 4) % 1; 271 | x = Math.floor(cx + ((i - 1.5) / 1.5) * (i === 1 || i === 2 ? -1 : 1) * a) + 0.5; 272 | y = cy + p * cw; 273 | line(ctx, x, y - s * 1.5, x, y + s * 1.5); 274 | } 275 | } 276 | 277 | function snow(ctx, t, cx, cy, cw, s, color) { 278 | t /= 3000; 279 | 280 | var a = cw * 0.16, 281 | b = s * 0.75, 282 | u = t * TAU * 0.7, 283 | ux = Math.cos(u) * b, 284 | uy = Math.sin(u) * b, 285 | v = u + TAU / 3, 286 | vx = Math.cos(v) * b, 287 | vy = Math.sin(v) * b, 288 | w = u + (TAU * 2) / 3, 289 | wx = Math.cos(w) * b, 290 | wy = Math.sin(w) * b, 291 | i, 292 | p, 293 | x, 294 | y; 295 | 296 | ctx.strokeStyle = color; 297 | ctx.lineWidth = s * 0.5; 298 | ctx.lineCap = 'round'; 299 | ctx.lineJoin = 'round'; 300 | 301 | for (i = 4; i--; ) { 302 | p = (t + i / 4) % 1; 303 | x = cx + Math.sin((p + i / 4) * TAU) * a; 304 | y = cy + p * cw; 305 | 306 | line(ctx, x - ux, y - uy, x + ux, y + uy); 307 | line(ctx, x - vx, y - vy, x + vx, y + vy); 308 | line(ctx, x - wx, y - wy, x + wx, y + wy); 309 | } 310 | } 311 | 312 | function fogbank(ctx, t, cx, cy, cw, s, color) { 313 | t /= 30000; 314 | 315 | var a = cw * 0.21, 316 | b = cw * 0.06, 317 | c = cw * 0.21, 318 | d = cw * 0.28; 319 | 320 | ctx.fillStyle = color; 321 | puffs(ctx, t, cx, cy, a, b, c, d); 322 | 323 | ctx.globalCompositeOperation = 'destination-out'; 324 | puffs(ctx, t, cx, cy, a, b, c - s, d - s); 325 | ctx.globalCompositeOperation = 'source-over'; 326 | } 327 | 328 | /* 329 | var WIND_PATHS = [ 330 | downsample(63, upsample(8, [ 331 | -1.00, -0.28, 332 | -0.75, -0.18, 333 | -0.50, 0.12, 334 | -0.20, 0.12, 335 | -0.04, -0.04, 336 | -0.07, -0.18, 337 | -0.19, -0.18, 338 | -0.23, -0.05, 339 | -0.12, 0.11, 340 | 0.02, 0.16, 341 | 0.20, 0.15, 342 | 0.50, 0.07, 343 | 0.75, 0.18, 344 | 1.00, 0.28 345 | ])), 346 | downsample(31, upsample(16, [ 347 | -1.00, -0.10, 348 | -0.75, 0.00, 349 | -0.50, 0.10, 350 | -0.25, 0.14, 351 | 0.00, 0.10, 352 | 0.25, 0.00, 353 | 0.50, -0.10, 354 | 0.75, -0.14, 355 | 1.00, -0.10 356 | ])) 357 | ]; 358 | */ 359 | 360 | var WIND_PATHS = [ 361 | [ 362 | -0.75, 363 | -0.18, 364 | -0.7219, 365 | -0.1527, 366 | -0.6971, 367 | -0.1225, 368 | -0.6739, 369 | -0.091, 370 | -0.6516, 371 | -0.0588, 372 | -0.6298, 373 | -0.0262, 374 | -0.6083, 375 | 0.0065, 376 | -0.5868, 377 | 0.0396, 378 | -0.5643, 379 | 0.0731, 380 | -0.5372, 381 | 0.1041, 382 | -0.5033, 383 | 0.1259, 384 | -0.4662, 385 | 0.1406, 386 | -0.4275, 387 | 0.1493, 388 | -0.3881, 389 | 0.153, 390 | -0.3487, 391 | 0.1526, 392 | -0.3095, 393 | 0.1488, 394 | -0.2708, 395 | 0.1421, 396 | -0.2319, 397 | 0.1342, 398 | -0.1943, 399 | 0.1217, 400 | -0.16, 401 | 0.1025, 402 | -0.129, 403 | 0.0785, 404 | -0.1012, 405 | 0.0509, 406 | -0.0764, 407 | 0.0206, 408 | -0.0547, 409 | -0.012, 410 | -0.0378, 411 | -0.0472, 412 | -0.0324, 413 | -0.0857, 414 | -0.0389, 415 | -0.1241, 416 | -0.0546, 417 | -0.1599, 418 | -0.0814, 419 | -0.1876, 420 | -0.1193, 421 | -0.1964, 422 | -0.1582, 423 | -0.1935, 424 | -0.1931, 425 | -0.1769, 426 | -0.2157, 427 | -0.1453, 428 | -0.229, 429 | -0.1085, 430 | -0.2327, 431 | -0.0697, 432 | -0.224, 433 | -0.0317, 434 | -0.2064, 435 | 0.0033, 436 | -0.1853, 437 | 0.0362, 438 | -0.1613, 439 | 0.0672, 440 | -0.135, 441 | 0.0961, 442 | -0.1051, 443 | 0.1213, 444 | -0.0706, 445 | 0.1397, 446 | -0.0332, 447 | 0.1512, 448 | 0.0053, 449 | 0.158, 450 | 0.0442, 451 | 0.1624, 452 | 0.0833, 453 | 0.1636, 454 | 0.1224, 455 | 0.1615, 456 | 0.1613, 457 | 0.1565, 458 | 0.1999, 459 | 0.15, 460 | 0.2378, 461 | 0.1402, 462 | 0.2749, 463 | 0.1279, 464 | 0.3118, 465 | 0.1147, 466 | 0.3487, 467 | 0.1015, 468 | 0.3858, 469 | 0.0892, 470 | 0.4236, 471 | 0.0787, 472 | 0.4621, 473 | 0.0715, 474 | 0.5012, 475 | 0.0702, 476 | 0.5398, 477 | 0.0766, 478 | 0.5768, 479 | 0.089, 480 | 0.6123, 481 | 0.1055, 482 | 0.6466, 483 | 0.1244, 484 | 0.6805, 485 | 0.144, 486 | 0.7147, 487 | 0.163, 488 | 0.75, 489 | 0.18 490 | ], 491 | [ 492 | -0.75, 493 | 0.0, 494 | -0.7033, 495 | 0.0195, 496 | -0.6569, 497 | 0.0399, 498 | -0.6104, 499 | 0.06, 500 | -0.5634, 501 | 0.0789, 502 | -0.5155, 503 | 0.0954, 504 | -0.4667, 505 | 0.1089, 506 | -0.4174, 507 | 0.1206, 508 | -0.3676, 509 | 0.1299, 510 | -0.3174, 511 | 0.1365, 512 | -0.2669, 513 | 0.1398, 514 | -0.2162, 515 | 0.1391, 516 | -0.1658, 517 | 0.1347, 518 | -0.1157, 519 | 0.1271, 520 | -0.0661, 521 | 0.1169, 522 | -0.017, 523 | 0.1046, 524 | 0.0316, 525 | 0.0903, 526 | 0.0791, 527 | 0.0728, 528 | 0.1259, 529 | 0.0534, 530 | 0.1723, 531 | 0.0331, 532 | 0.2188, 533 | 0.0129, 534 | 0.2656, 535 | -0.0064, 536 | 0.3122, 537 | -0.0263, 538 | 0.3586, 539 | -0.0466, 540 | 0.4052, 541 | -0.0665, 542 | 0.4525, 543 | -0.0847, 544 | 0.5007, 545 | -0.1002, 546 | 0.5497, 547 | -0.113, 548 | 0.5991, 549 | -0.124, 550 | 0.6491, 551 | -0.1325, 552 | 0.6994, 553 | -0.138, 554 | 0.75, 555 | -0.14 556 | ] 557 | ], 558 | WIND_OFFSETS = [{ start: 0.36, end: 0.11 }, { start: 0.56, end: 0.16 }]; 559 | 560 | function leaf(ctx, t, x, y, cw, s, color) { 561 | var a = cw / 8, 562 | b = a / 3, 563 | c = 2 * b, 564 | d = (t % 1) * TAU, 565 | e = Math.cos(d), 566 | f = Math.sin(d); 567 | 568 | ctx.fillStyle = color; 569 | ctx.strokeStyle = color; 570 | ctx.lineWidth = s; 571 | ctx.lineCap = 'round'; 572 | ctx.lineJoin = 'round'; 573 | 574 | ctx.beginPath(); 575 | ctx.arc(x, y, a, d, d + Math.PI, false); 576 | ctx.arc(x - b * e, y - b * f, c, d + Math.PI, d, false); 577 | ctx.arc(x + c * e, y + c * f, b, d + Math.PI, d, true); 578 | ctx.globalCompositeOperation = 'destination-out'; 579 | ctx.fill(); 580 | ctx.globalCompositeOperation = 'source-over'; 581 | ctx.stroke(); 582 | } 583 | 584 | function swoosh(ctx, t, cx, cy, cw, s, index, total, color) { 585 | t /= 2500; 586 | 587 | var path = WIND_PATHS[index], 588 | a = (t + index - WIND_OFFSETS[index].start) % total, 589 | c = (t + index - WIND_OFFSETS[index].end) % total, 590 | e = (t + index) % total, 591 | b, 592 | d, 593 | f, 594 | i; 595 | 596 | ctx.strokeStyle = color; 597 | ctx.lineWidth = s; 598 | ctx.lineCap = 'round'; 599 | ctx.lineJoin = 'round'; 600 | 601 | if (a < 1) { 602 | ctx.beginPath(); 603 | 604 | a *= path.length / 2 - 1; 605 | b = Math.floor(a); 606 | a -= b; 607 | b *= 2; 608 | b += 2; 609 | 610 | ctx.moveTo(cx + (path[b - 2] * (1 - a) + path[b] * a) * cw, cy + (path[b - 1] * (1 - a) + path[b + 1] * a) * cw); 611 | 612 | if (c < 1) { 613 | c *= path.length / 2 - 1; 614 | d = Math.floor(c); 615 | c -= d; 616 | d *= 2; 617 | d += 2; 618 | 619 | for (i = b; i !== d; i += 2) ctx.lineTo(cx + path[i] * cw, cy + path[i + 1] * cw); 620 | 621 | ctx.lineTo(cx + (path[d - 2] * (1 - c) + path[d] * c) * cw, cy + (path[d - 1] * (1 - c) + path[d + 1] * c) * cw); 622 | } else for (i = b; i !== path.length; i += 2) ctx.lineTo(cx + path[i] * cw, cy + path[i + 1] * cw); 623 | 624 | ctx.stroke(); 625 | } else if (c < 1) { 626 | ctx.beginPath(); 627 | 628 | c *= path.length / 2 - 1; 629 | d = Math.floor(c); 630 | c -= d; 631 | d *= 2; 632 | d += 2; 633 | 634 | ctx.moveTo(cx + path[0] * cw, cy + path[1] * cw); 635 | 636 | for (i = 2; i !== d; i += 2) ctx.lineTo(cx + path[i] * cw, cy + path[i + 1] * cw); 637 | 638 | ctx.lineTo(cx + (path[d - 2] * (1 - c) + path[d] * c) * cw, cy + (path[d - 1] * (1 - c) + path[d + 1] * c) * cw); 639 | 640 | ctx.stroke(); 641 | } 642 | 643 | if (e < 1) { 644 | e *= path.length / 2 - 1; 645 | f = Math.floor(e); 646 | e -= f; 647 | f *= 2; 648 | f += 2; 649 | 650 | leaf(ctx, t, cx + (path[f - 2] * (1 - e) + path[f] * e) * cw, cy + (path[f - 1] * (1 - e) + path[f + 1] * e) * cw, cw, s, color); 651 | } 652 | } 653 | 654 | var Skycons = function(opts) { 655 | this.list = []; 656 | this.interval = null; 657 | this.color = opts && opts.color ? opts.color : 'black'; 658 | this.resizeClear = !!(opts && opts.resizeClear); 659 | }; 660 | 661 | Skycons.CLEAR_DAY = function(ctx, t, color) { 662 | var w = ctx.canvas.width, 663 | h = ctx.canvas.height, 664 | s = Math.min(w, h); 665 | 666 | sun(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color); 667 | }; 668 | 669 | Skycons.CLEAR_NIGHT = function(ctx, t, color) { 670 | var w = ctx.canvas.width, 671 | h = ctx.canvas.height, 672 | s = Math.min(w, h); 673 | 674 | moon(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color); 675 | }; 676 | 677 | Skycons.PARTLY_CLOUDY_DAY = function(ctx, t, color) { 678 | var w = ctx.canvas.width, 679 | h = ctx.canvas.height, 680 | s = Math.min(w, h); 681 | 682 | sun(ctx, t, w * 0.625, h * 0.375, s * 0.75, s * STROKE, color); 683 | cloud(ctx, t, w * 0.375, h * 0.625, s * 0.75, s * STROKE, color); 684 | }; 685 | 686 | Skycons.PARTLY_CLOUDY_NIGHT = function(ctx, t, color) { 687 | var w = ctx.canvas.width, 688 | h = ctx.canvas.height, 689 | s = Math.min(w, h); 690 | 691 | moon(ctx, t, w * 0.667, h * 0.375, s * 0.75, s * STROKE, color); 692 | cloud(ctx, t, w * 0.375, h * 0.625, s * 0.75, s * STROKE, color); 693 | }; 694 | 695 | Skycons.CLOUDY = function(ctx, t, color) { 696 | var w = ctx.canvas.width, 697 | h = ctx.canvas.height, 698 | s = Math.min(w, h); 699 | 700 | cloud(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color); 701 | }; 702 | 703 | Skycons.RAIN = function(ctx, t, color) { 704 | var w = ctx.canvas.width, 705 | h = ctx.canvas.height, 706 | s = Math.min(w, h); 707 | 708 | rain(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); 709 | cloud(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); 710 | }; 711 | 712 | Skycons.SLEET = function(ctx, t, color) { 713 | var w = ctx.canvas.width, 714 | h = ctx.canvas.height, 715 | s = Math.min(w, h); 716 | 717 | sleet(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); 718 | cloud(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); 719 | }; 720 | 721 | Skycons.SNOW = function(ctx, t, color) { 722 | var w = ctx.canvas.width, 723 | h = ctx.canvas.height, 724 | s = Math.min(w, h); 725 | 726 | snow(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); 727 | cloud(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); 728 | }; 729 | 730 | Skycons.WIND = function(ctx, t, color) { 731 | var w = ctx.canvas.width, 732 | h = ctx.canvas.height, 733 | s = Math.min(w, h); 734 | 735 | swoosh(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, 0, 2, color); 736 | swoosh(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, 1, 2, color); 737 | }; 738 | 739 | Skycons.FOG = function(ctx, t, color) { 740 | var w = ctx.canvas.width, 741 | h = ctx.canvas.height, 742 | s = Math.min(w, h), 743 | k = s * STROKE; 744 | 745 | fogbank(ctx, t, w * 0.5, h * 0.32, s * 0.75, k, color); 746 | 747 | t /= 5000; 748 | 749 | var a = Math.cos(t * TAU) * s * 0.02, 750 | b = Math.cos((t + 0.25) * TAU) * s * 0.02, 751 | c = Math.cos((t + 0.5) * TAU) * s * 0.02, 752 | d = Math.cos((t + 0.75) * TAU) * s * 0.02, 753 | n = h * 0.936, 754 | e = Math.floor(n - k * 0.5) + 0.5, 755 | f = Math.floor(n - k * 2.5) + 0.5; 756 | 757 | ctx.strokeStyle = color; 758 | ctx.lineWidth = k; 759 | ctx.lineCap = 'round'; 760 | ctx.lineJoin = 'round'; 761 | 762 | line(ctx, a + w * 0.2 + k * 0.5, e, b + w * 0.8 - k * 0.5, e); 763 | line(ctx, c + w * 0.2 + k * 0.5, f, d + w * 0.8 - k * 0.5, f); 764 | }; 765 | 766 | Skycons.prototype = { 767 | _determineDrawingFunction: function(draw) { 768 | if (typeof draw === 'string') draw = Skycons[draw.toUpperCase().replace(/-/g, '_')] || null; 769 | 770 | return draw; 771 | }, 772 | add: function(el, draw) { 773 | var obj; 774 | 775 | if (typeof el === 'string') el = document.getElementById(el); 776 | 777 | // Does nothing if canvas name doesn't exists 778 | if (el === null) return; 779 | 780 | draw = this._determineDrawingFunction(draw); 781 | 782 | // Does nothing if the draw function isn't actually a function 783 | if (typeof draw !== 'function') return; 784 | 785 | obj = { 786 | element: el, 787 | context: el.getContext('2d'), 788 | drawing: draw 789 | }; 790 | 791 | this.list.push(obj); 792 | this.draw(obj, KEYFRAME); 793 | }, 794 | set: function(el, draw) { 795 | var i; 796 | 797 | if (typeof el === 'string') el = document.getElementById(el); 798 | 799 | for (i = this.list.length; i--; ) 800 | if (this.list[i].element === el) { 801 | this.list[i].drawing = this._determineDrawingFunction(draw); 802 | this.draw(this.list[i], KEYFRAME); 803 | return; 804 | } 805 | 806 | this.add(el, draw); 807 | }, 808 | remove: function(el) { 809 | var i; 810 | 811 | if (typeof el === 'string') el = document.getElementById(el); 812 | 813 | for (i = this.list.length; i--; ) 814 | if (this.list[i].element === el) { 815 | this.list.splice(i, 1); 816 | return; 817 | } 818 | }, 819 | draw: function(obj, time) { 820 | var canvas = obj.context.canvas; 821 | 822 | if (this.resizeClear) canvas.width = canvas.width; 823 | else obj.context.clearRect(0, 0, canvas.width, canvas.height); 824 | 825 | obj.drawing(obj.context, time, this.color); 826 | }, 827 | play: function() { 828 | var self = this; 829 | 830 | this.pause(); 831 | this.interval = requestInterval(function() { 832 | var now = Date.now(), 833 | i; 834 | 835 | for (i = self.list.length; i--; ) self.draw(self.list[i], now); 836 | }, 1000 / 60); 837 | }, 838 | pause: function() { 839 | if (this.interval) { 840 | cancelInterval(this.interval); 841 | this.interval = null; 842 | } 843 | } 844 | }; 845 | 846 | export default Skycons; 847 | --------------------------------------------------------------------------------