├── script ├── deploy.ts ├── build.ts ├── util.ts └── start.ts ├── example ├── collide_04 │ ├── canvas │ │ └── collide.ts │ └── index.ts ├── collide_05 │ ├── canvas │ │ └── collide.ts │ └── index.ts ├── sh │ ├── img │ │ ├── 1.jpg │ │ ├── 10.jpg │ │ ├── 11.jpg │ │ ├── 12.jpg │ │ ├── 13.jpg │ │ ├── 14.jpg │ │ ├── 15.jpg │ │ ├── 16.jpg │ │ ├── 17.jpg │ │ ├── 18.jpg │ │ ├── 19.jpg │ │ ├── 2.jpg │ │ ├── 20.jpg │ │ ├── 21.jpg │ │ ├── 22.jpg │ │ ├── 23.jpg │ │ ├── 24.jpg │ │ ├── 25.jpg │ │ ├── 26.jpg │ │ ├── 27.jpg │ │ ├── 28.jpg │ │ ├── 29.jpg │ │ ├── 3.jpg │ │ ├── 30.jpg │ │ ├── 31.jpg │ │ ├── 32.jpg │ │ ├── 33.jpg │ │ ├── 4.jpg │ │ ├── 5.jpg │ │ ├── 6.jpg │ │ ├── 7.jpg │ │ ├── 8.jpg │ │ └── 9.jpg │ ├── audio │ │ └── bgm.mp3 │ ├── index.ts │ └── canvas │ │ ├── word.ts │ │ ├── meteorCanvas.ts │ │ ├── bgCanvas.ts │ │ ├── loadingCanvas.ts │ │ ├── star.ts │ │ └── imgCanvas.ts ├── zoom │ ├── img │ │ └── 1.jpeg │ ├── index.ts │ └── canvas │ │ └── zoom.ts ├── collide_02 │ ├── img │ │ └── bucket.png │ ├── index.ts │ └── canvas │ │ ├── engine.ts │ │ ├── collide.ts │ │ └── index.ts ├── collide_03 │ ├── canvas │ │ ├── projection.ts │ │ ├── vector.ts │ │ └── collide.ts │ └── index.ts ├── clock │ └── index.ts ├── shape │ └── index.ts ├── cutout │ └── index.ts ├── axes │ ├── index.ts │ └── canvas │ │ ├── index.ts │ │ └── grid.ts ├── editor │ ├── index.ts │ └── canvas │ │ └── cursor.ts ├── free_fall │ ├── index.ts │ └── canvas │ │ └── ball.ts ├── collide_01 │ ├── index.ts │ └── canvas │ │ ├── sprite.ts │ │ └── collide.ts ├── main │ └── index.ts ├── animate │ ├── canvas │ │ ├── timeSystem.ts │ │ └── ball.ts │ └── index.ts └── loading │ └── index.ts ├── .gitignore ├── favicon.ico ├── .vscode └── settings.json ├── window.d.ts ├── dist ├── 11.b058e7419e3392bd56a3.js ├── 12.8821bacad1c38b8b748c.js ├── 38.b0884dc48ed61da96761.js ├── 37.1049f79c7e21d6ebdf0c.js ├── images │ ├── 1.18d12255a792809c320cfff34c146e7f.jpeg │ ├── 1.7d6d9da5ebbd9cb985ed67f1672ff1b1.jpg │ ├── 10.423b34a0a67987b4ff4140b850953e2f.jpg │ ├── 11.548bebbb1c98b2935990628ac14626ef.jpg │ ├── 12.56e67a0874204535bb9ae9d8f997fcef.jpg │ ├── 13.9f5dc1a9e208373c6bad054a029255fe.jpg │ ├── 14.da2c44a249cdafbfe5833b4900efab44.jpg │ ├── 15.d408f6054fef92780ea1a90ee10d17f5.jpg │ ├── 16.ffbdfb40a6cb31b23507a3413b3c1ebe.jpg │ ├── 17.e681121d03cf6edca03e63a95fc33899.jpg │ ├── 18.926401fa7d4b954352937f99e20ba29d.jpg │ ├── 19.67dafd4ddfc70afb92a4dfa8899df2f3.jpg │ ├── 2.fd1e5d12d881bce10de767cc00a6fcdc.jpg │ ├── 20.efbaee53899a473b72250b964fb512e3.jpg │ ├── 21.e75740aa255c117c00b44e4548fd9123.jpg │ ├── 22.7c0b6113a2edcc29654a15864884ffe0.jpg │ ├── 23.2da23ff31d0c767922af6df989cc2c99.jpg │ ├── 24.c7fc91bdb428ed1d875eb5632d8c94a2.jpg │ ├── 25.eba6bbe68c76fbdd0677ef6b0ecaa846.jpg │ ├── 26.9460919bc455ef86785a660cbbf10d09.jpg │ ├── 27.a50f7cd33127024c1fe90bb7e51fc8cc.jpg │ ├── 28.8d45efdf4168c1568d61753a52c0b498.jpg │ ├── 29.5c8fe007a12506edc298ba9af3c009ea.jpg │ ├── 3.9db0e0e9044cd6f5d1b1855382ee8b87.jpg │ ├── 30.32032a9467839ab31d4824479c6e3533.jpg │ ├── 31.89c24cfbe7eb38d303fc91be6c5423a0.jpg │ ├── 32.8327328e39e4a25eeb5f5f6ae11472ce.jpg │ ├── 33.891398418682f1e1777650458da7a979.jpg │ ├── 4.e85c75de9bfa6814a3b6327cd49ffa46.jpg │ ├── 5.0277eb1ff78570dede8ff84d9d194809.jpg │ ├── 6.b32366f9db801ea9db7910b853f46a15.jpg │ ├── 7.80fbdb20b58c0f12a3e9c8adab4cc5da.jpg │ ├── 8.a2ba31aaf41c1d002c776ffff902d2ed.jpg │ ├── 9.a1942c74daf925c96720e63bccd9e5d5.jpg │ └── bucket.5d48015fe4e6d9e9343be64264a9177e.png ├── media │ └── bgm.d12f266adcddb6b3fb6dc5a9548bd59d.mp3 ├── 55.53f9d9b3f5a0813b3285.js ├── 56.2511737b103e3aa56e8c.js ├── 57.e867c842e663b0479e4d.js ├── 58.170d808c8244ad23f86d.js ├── 59.131f73056941c4af9479.js ├── 60.5964b807542f78c2cfd9.js ├── 61.20bb6a61d9c87b0f1a48.js ├── 62.d5d368730c3dc71161b1.js ├── 63.390f0742e7786dcd8f32.js ├── 64.80bfe8554086122f475a.js ├── 65.643831b71abb178348d5.js ├── 66.b18ae1af8c65e8c7fa04.js ├── 67.3b798083a5a36af5d4e6.js ├── 68.4eab6d7f9d6e1c78133b.js ├── 69.c26b0d142c9d8c7e9357.js ├── 70.aaf86ba2ea89073a0afb.js ├── 71.1eabe773d2608053a54e.js ├── 72.1fce6f769d24ca5b3af2.js ├── 73.af4dda0ac78917a1c575.js ├── 74.89719493f406a24bec9e.js ├── 75.bcc3ba8ec88d66e78fd1.js ├── 76.8813ae58fcb560000e7c.js ├── 77.c6ce4e46d7a0303478f2.js ├── 78.b6427f6aae4b8a0007e0.js ├── 79.07e1a1c0dcd21b6918f6.js ├── 80.364eca0bc34eab39adf2.js ├── 81.a8c7d119345f55e445fb.js ├── 82.4e62bc7d145b80c696e9.js ├── 83.75c206739b6b872711ef.js ├── 84.44a5708faa348234969b.js ├── 85.2857da345b5cfb0f0c1a.js ├── 86.f9caad4398522801a275.js ├── 87.5758221903eb8822fc81.js ├── 88.b03f0fc088692bc2c80f.js ├── 89.54d80d799666cab0f020.js ├── 90.509d06d3662422e5d4f3.js ├── 46.d89541ac62699f44e73d.js ├── 41.622ebfe30f647a07cf2c.js ├── 25.7410c517ee40388c58c0.js ├── 39.3c93645707ea3ce929b4.js ├── 47.8ea33a87be31fdb5d89b.js ├── 48.e72d8d2b3f74db214e7c.js ├── 42.d96f8cfa9e6695e6ce20.js ├── workbox │ └── workbox-v3.3.0 │ │ ├── workbox-cacheable-response.prod.js │ │ ├── workbox-cacheable-response.prod.js.map │ │ ├── workbox-broadcast-cache-update.prod.js │ │ ├── workbox-broadcast-cache-update.prod.js.map │ │ ├── workbox-sw.js │ │ ├── workbox-sw.js.map │ │ ├── workbox-range-requests.prod.js │ │ ├── workbox-streams.prod.js │ │ ├── workbox-streams.prod.js.map │ │ ├── workbox-range-requests.prod.js.map │ │ ├── workbox-google-analytics.prod.js │ │ ├── workbox-google-analytics.prod.js.map │ │ ├── workbox-routing.prod.js │ │ ├── workbox-routing.prod.js.map │ │ ├── workbox-background-sync.prod.js │ │ ├── workbox-background-sync.prod.js.map │ │ ├── workbox-cache-expiration.prod.js │ │ └── workbox-cache-expiration.prod.js.map ├── 52.2948fe1d5b4c72e2e812.js ├── 53.b631846237cd194524d8.js ├── 49.5ac65633e0bbdddd5fd3.js ├── 50.330365c62a5f8289ba55.js ├── 35.2085267ed496d0c63a8a.js ├── service-worker.js ├── 7.bcf0c10c62961db7e7c1.js ├── 33.2a80f96ad12518c714cc.js ├── 26.6668f355362a66e3f56e.js ├── 28.5657e743fea8ab107ea0.js ├── 43.2f5e17ce7bf50dcf305e.js ├── 29.cb22759ea651dd5594f1.js ├── 24.2d62ae5a92ed2b0cf06d.js ├── 27.2b2f82cdb7d3406d095e.js ├── 44.861ee2e30edbf35af9f0.js ├── 30.e3e3b3cd97ac5f508b65.js ├── 40.aeb3dfabd1530c8c8464.js ├── 31.e009360861da5a3394e0.js ├── 19.1c4f12e2a7e2671669d5.js ├── 23.63a71ad02d460735b260.js └── 32.293a725104a70dcfef11.js ├── .browserslistrc ├── coverage ├── lcov-report │ ├── sort-arrow-sprite.png │ ├── prettify.css │ └── block-navigation.js └── lcov.info ├── index.scss.d.ts ├── postcss.config.js ├── common ├── CONSTANT.ts ├── storage.ts ├── render │ ├── index.scss.d.ts │ └── index.scss ├── browser.ts ├── canvas.ts ├── github.ts └── util.ts ├── tsconfig.webpack.json ├── template.html ├── .stylelintrc ├── index.html ├── tsconfig.json ├── index.ts ├── README.md ├── LICENSE ├── config ├── webpack.base.ts ├── webpack.dev.ts └── webpack.pro.ts ├── plugins └── html-webpack-assert-plugin.ts ├── package.json └── index.scss /script/deploy.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/collide_04/canvas/collide.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/collide_04/index.ts: -------------------------------------------------------------------------------- 1 | /* 像素检查法 */ -------------------------------------------------------------------------------- /example/collide_05/canvas/collide.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/collide_05/index.ts: -------------------------------------------------------------------------------- 1 | /* 九宫格法 */ -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules/ 3 | .DS_Store 4 | .lock 5 | .log 6 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/favicon.ico -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib" 3 | } -------------------------------------------------------------------------------- /window.d.ts: -------------------------------------------------------------------------------- 1 | declare global { 2 | namespace Window { ExampleModules: string[]; } 3 | } 4 | -------------------------------------------------------------------------------- /example/sh/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/1.jpg -------------------------------------------------------------------------------- /example/sh/img/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/10.jpg -------------------------------------------------------------------------------- /example/sh/img/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/11.jpg -------------------------------------------------------------------------------- /example/sh/img/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/12.jpg -------------------------------------------------------------------------------- /example/sh/img/13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/13.jpg -------------------------------------------------------------------------------- /example/sh/img/14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/14.jpg -------------------------------------------------------------------------------- /example/sh/img/15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/15.jpg -------------------------------------------------------------------------------- /example/sh/img/16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/16.jpg -------------------------------------------------------------------------------- /example/sh/img/17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/17.jpg -------------------------------------------------------------------------------- /example/sh/img/18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/18.jpg -------------------------------------------------------------------------------- /example/sh/img/19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/19.jpg -------------------------------------------------------------------------------- /example/sh/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/2.jpg -------------------------------------------------------------------------------- /example/sh/img/20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/20.jpg -------------------------------------------------------------------------------- /example/sh/img/21.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/21.jpg -------------------------------------------------------------------------------- /example/sh/img/22.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/22.jpg -------------------------------------------------------------------------------- /example/sh/img/23.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/23.jpg -------------------------------------------------------------------------------- /example/sh/img/24.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/24.jpg -------------------------------------------------------------------------------- /example/sh/img/25.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/25.jpg -------------------------------------------------------------------------------- /example/sh/img/26.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/26.jpg -------------------------------------------------------------------------------- /example/sh/img/27.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/27.jpg -------------------------------------------------------------------------------- /example/sh/img/28.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/28.jpg -------------------------------------------------------------------------------- /example/sh/img/29.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/29.jpg -------------------------------------------------------------------------------- /example/sh/img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/3.jpg -------------------------------------------------------------------------------- /example/sh/img/30.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/30.jpg -------------------------------------------------------------------------------- /example/sh/img/31.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/31.jpg -------------------------------------------------------------------------------- /example/sh/img/32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/32.jpg -------------------------------------------------------------------------------- /example/sh/img/33.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/33.jpg -------------------------------------------------------------------------------- /example/sh/img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/4.jpg -------------------------------------------------------------------------------- /example/sh/img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/5.jpg -------------------------------------------------------------------------------- /example/sh/img/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/6.jpg -------------------------------------------------------------------------------- /example/sh/img/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/7.jpg -------------------------------------------------------------------------------- /example/sh/img/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/8.jpg -------------------------------------------------------------------------------- /example/sh/img/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/img/9.jpg -------------------------------------------------------------------------------- /example/sh/audio/bgm.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/sh/audio/bgm.mp3 -------------------------------------------------------------------------------- /example/zoom/img/1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/zoom/img/1.jpeg -------------------------------------------------------------------------------- /dist/11.b058e7419e3392bd56a3.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[11],{sy1G:function(n,w){}}]); -------------------------------------------------------------------------------- /dist/12.8821bacad1c38b8b748c.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[12],{C6UM:function(n,w){}}]); -------------------------------------------------------------------------------- /dist/38.b0884dc48ed61da96761.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[38],{UuTF:function(n,w){}}]); -------------------------------------------------------------------------------- /dist/37.1049f79c7e21d6ebdf0c.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[37],{"8X/g":function(n,w){}}]); -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | [production] 2 | > 1% 3 | ie 10 4 | 5 | [development] 6 | last 1 chrome version 7 | last 1 firefox version -------------------------------------------------------------------------------- /example/collide_02/img/bucket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/example/collide_02/img/bucket.png -------------------------------------------------------------------------------- /coverage/lcov-report/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/coverage/lcov-report/sort-arrow-sprite.png -------------------------------------------------------------------------------- /index.scss.d.ts: -------------------------------------------------------------------------------- 1 | //This file is automatically generated by typings-for-css-modules. 2 | // Please do not change this file! 3 | export {}; 4 | -------------------------------------------------------------------------------- /dist/images/1.18d12255a792809c320cfff34c146e7f.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/1.18d12255a792809c320cfff34c146e7f.jpeg -------------------------------------------------------------------------------- /dist/images/1.7d6d9da5ebbd9cb985ed67f1672ff1b1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/1.7d6d9da5ebbd9cb985ed67f1672ff1b1.jpg -------------------------------------------------------------------------------- /dist/images/10.423b34a0a67987b4ff4140b850953e2f.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/10.423b34a0a67987b4ff4140b850953e2f.jpg -------------------------------------------------------------------------------- /dist/images/11.548bebbb1c98b2935990628ac14626ef.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/11.548bebbb1c98b2935990628ac14626ef.jpg -------------------------------------------------------------------------------- /dist/images/12.56e67a0874204535bb9ae9d8f997fcef.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/12.56e67a0874204535bb9ae9d8f997fcef.jpg -------------------------------------------------------------------------------- /dist/images/13.9f5dc1a9e208373c6bad054a029255fe.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/13.9f5dc1a9e208373c6bad054a029255fe.jpg -------------------------------------------------------------------------------- /dist/images/14.da2c44a249cdafbfe5833b4900efab44.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/14.da2c44a249cdafbfe5833b4900efab44.jpg -------------------------------------------------------------------------------- /dist/images/15.d408f6054fef92780ea1a90ee10d17f5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/15.d408f6054fef92780ea1a90ee10d17f5.jpg -------------------------------------------------------------------------------- /dist/images/16.ffbdfb40a6cb31b23507a3413b3c1ebe.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/16.ffbdfb40a6cb31b23507a3413b3c1ebe.jpg -------------------------------------------------------------------------------- /dist/images/17.e681121d03cf6edca03e63a95fc33899.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/17.e681121d03cf6edca03e63a95fc33899.jpg -------------------------------------------------------------------------------- /dist/images/18.926401fa7d4b954352937f99e20ba29d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/18.926401fa7d4b954352937f99e20ba29d.jpg -------------------------------------------------------------------------------- /dist/images/19.67dafd4ddfc70afb92a4dfa8899df2f3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/19.67dafd4ddfc70afb92a4dfa8899df2f3.jpg -------------------------------------------------------------------------------- /dist/images/2.fd1e5d12d881bce10de767cc00a6fcdc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/2.fd1e5d12d881bce10de767cc00a6fcdc.jpg -------------------------------------------------------------------------------- /dist/images/20.efbaee53899a473b72250b964fb512e3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/20.efbaee53899a473b72250b964fb512e3.jpg -------------------------------------------------------------------------------- /dist/images/21.e75740aa255c117c00b44e4548fd9123.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/21.e75740aa255c117c00b44e4548fd9123.jpg -------------------------------------------------------------------------------- /dist/images/22.7c0b6113a2edcc29654a15864884ffe0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/22.7c0b6113a2edcc29654a15864884ffe0.jpg -------------------------------------------------------------------------------- /dist/images/23.2da23ff31d0c767922af6df989cc2c99.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/23.2da23ff31d0c767922af6df989cc2c99.jpg -------------------------------------------------------------------------------- /dist/images/24.c7fc91bdb428ed1d875eb5632d8c94a2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/24.c7fc91bdb428ed1d875eb5632d8c94a2.jpg -------------------------------------------------------------------------------- /dist/images/25.eba6bbe68c76fbdd0677ef6b0ecaa846.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/25.eba6bbe68c76fbdd0677ef6b0ecaa846.jpg -------------------------------------------------------------------------------- /dist/images/26.9460919bc455ef86785a660cbbf10d09.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/26.9460919bc455ef86785a660cbbf10d09.jpg -------------------------------------------------------------------------------- /dist/images/27.a50f7cd33127024c1fe90bb7e51fc8cc.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/27.a50f7cd33127024c1fe90bb7e51fc8cc.jpg -------------------------------------------------------------------------------- /dist/images/28.8d45efdf4168c1568d61753a52c0b498.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/28.8d45efdf4168c1568d61753a52c0b498.jpg -------------------------------------------------------------------------------- /dist/images/29.5c8fe007a12506edc298ba9af3c009ea.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/29.5c8fe007a12506edc298ba9af3c009ea.jpg -------------------------------------------------------------------------------- /dist/images/3.9db0e0e9044cd6f5d1b1855382ee8b87.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/3.9db0e0e9044cd6f5d1b1855382ee8b87.jpg -------------------------------------------------------------------------------- /dist/images/30.32032a9467839ab31d4824479c6e3533.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/30.32032a9467839ab31d4824479c6e3533.jpg -------------------------------------------------------------------------------- /dist/images/31.89c24cfbe7eb38d303fc91be6c5423a0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/31.89c24cfbe7eb38d303fc91be6c5423a0.jpg -------------------------------------------------------------------------------- /dist/images/32.8327328e39e4a25eeb5f5f6ae11472ce.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/32.8327328e39e4a25eeb5f5f6ae11472ce.jpg -------------------------------------------------------------------------------- /dist/images/33.891398418682f1e1777650458da7a979.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/33.891398418682f1e1777650458da7a979.jpg -------------------------------------------------------------------------------- /dist/images/4.e85c75de9bfa6814a3b6327cd49ffa46.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/4.e85c75de9bfa6814a3b6327cd49ffa46.jpg -------------------------------------------------------------------------------- /dist/images/5.0277eb1ff78570dede8ff84d9d194809.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/5.0277eb1ff78570dede8ff84d9d194809.jpg -------------------------------------------------------------------------------- /dist/images/6.b32366f9db801ea9db7910b853f46a15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/6.b32366f9db801ea9db7910b853f46a15.jpg -------------------------------------------------------------------------------- /dist/images/7.80fbdb20b58c0f12a3e9c8adab4cc5da.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/7.80fbdb20b58c0f12a3e9c8adab4cc5da.jpg -------------------------------------------------------------------------------- /dist/images/8.a2ba31aaf41c1d002c776ffff902d2ed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/8.a2ba31aaf41c1d002c776ffff902d2ed.jpg -------------------------------------------------------------------------------- /dist/images/9.a1942c74daf925c96720e63bccd9e5d5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/9.a1942c74daf925c96720e63bccd9e5d5.jpg -------------------------------------------------------------------------------- /dist/media/bgm.d12f266adcddb6b3fb6dc5a9548bd59d.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/media/bgm.d12f266adcddb6b3fb6dc5a9548bd59d.mp3 -------------------------------------------------------------------------------- /dist/images/bucket.5d48015fe4e6d9e9343be64264a9177e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snayan/canvas-demo/HEAD/dist/images/bucket.5d48015fe4e6d9e9343be64264a9177e.png -------------------------------------------------------------------------------- /dist/55.53f9d9b3f5a0813b3285.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[55],{"/aIi":function(p,c){p.exports="dist/images/1.18d12255a792809c320cfff34c146e7f.jpeg"}}]); -------------------------------------------------------------------------------- /dist/56.2511737b103e3aa56e8c.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[56],{"Rn/i":function(c,n){c.exports="dist/images/9.a1942c74daf925c96720e63bccd9e5d5.jpg"}}]); -------------------------------------------------------------------------------- /dist/57.e867c842e663b0479e4d.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[57],{"9d0C":function(a,d){a.exports="dist/images/8.a2ba31aaf41c1d002c776ffff902d2ed.jpg"}}]); -------------------------------------------------------------------------------- /dist/58.170d808c8244ad23f86d.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[58],{Iqvv:function(a,c){a.exports="dist/images/7.80fbdb20b58c0f12a3e9c8adab4cc5da.jpg"}}]); -------------------------------------------------------------------------------- /dist/59.131f73056941c4af9479.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[59],{X6iU:function(p,b){p.exports="dist/images/6.b32366f9db801ea9db7910b853f46a15.jpg"}}]); -------------------------------------------------------------------------------- /dist/60.5964b807542f78c2cfd9.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[60],{"2mwZ":function(d,e){d.exports="dist/images/5.0277eb1ff78570dede8ff84d9d194809.jpg"}}]); -------------------------------------------------------------------------------- /dist/61.20bb6a61d9c87b0f1a48.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[61],{iwPU:function(p,w){p.exports="dist/images/4.e85c75de9bfa6814a3b6327cd49ffa46.jpg"}}]); -------------------------------------------------------------------------------- /dist/62.d5d368730c3dc71161b1.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[62],{lWpA:function(p,n){p.exports="dist/images/33.891398418682f1e1777650458da7a979.jpg"}}]); -------------------------------------------------------------------------------- /dist/63.390f0742e7786dcd8f32.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[63],{"uy+u":function(e,p){e.exports="dist/images/32.8327328e39e4a25eeb5f5f6ae11472ce.jpg"}}]); -------------------------------------------------------------------------------- /dist/64.80bfe8554086122f475a.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[64],{"6BM6":function(c,e){c.exports="dist/images/31.89c24cfbe7eb38d303fc91be6c5423a0.jpg"}}]); -------------------------------------------------------------------------------- /dist/65.643831b71abb178348d5.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[65],{hS7P:function(p,n){p.exports="dist/images/30.32032a9467839ab31d4824479c6e3533.jpg"}}]); -------------------------------------------------------------------------------- /dist/66.b18ae1af8c65e8c7fa04.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[66],{ePGt:function(e,p){e.exports="dist/images/3.9db0e0e9044cd6f5d1b1855382ee8b87.jpg"}}]); -------------------------------------------------------------------------------- /dist/67.3b798083a5a36af5d4e6.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[67],{o1tX:function(a,e){a.exports="dist/images/29.5c8fe007a12506edc298ba9af3c009ea.jpg"}}]); -------------------------------------------------------------------------------- /dist/68.4eab6d7f9d6e1c78133b.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[68],{io3w:function(o,p){o.exports="dist/images/28.8d45efdf4168c1568d61753a52c0b498.jpg"}}]); -------------------------------------------------------------------------------- /dist/69.c26b0d142c9d8c7e9357.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[69],{nQqT:function(c,n){c.exports="dist/images/27.a50f7cd33127024c1fe90bb7e51fc8cc.jpg"}}]); -------------------------------------------------------------------------------- /dist/70.aaf86ba2ea89073a0afb.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[70],{rtUp:function(p,n){p.exports="dist/images/26.9460919bc455ef86785a660cbbf10d09.jpg"}}]); -------------------------------------------------------------------------------- /dist/71.1eabe773d2608053a54e.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[71],{"2C+m":function(e,b){e.exports="dist/images/25.eba6bbe68c76fbdd0677ef6b0ecaa846.jpg"}}]); -------------------------------------------------------------------------------- /dist/72.1fce6f769d24ca5b3af2.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[72],{WSPY:function(d,p){d.exports="dist/images/24.c7fc91bdb428ed1d875eb5632d8c94a2.jpg"}}]); -------------------------------------------------------------------------------- /dist/73.af4dda0ac78917a1c575.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[73],{"Xg+O":function(c,p){c.exports="dist/images/23.2da23ff31d0c767922af6df989cc2c99.jpg"}}]); -------------------------------------------------------------------------------- /dist/74.89719493f406a24bec9e.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[74],{"ow/0":function(o,p){o.exports="dist/images/22.7c0b6113a2edcc29654a15864884ffe0.jpg"}}]); -------------------------------------------------------------------------------- /dist/75.bcc3ba8ec88d66e78fd1.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[75],{"4cLG":function(p,c){p.exports="dist/images/21.e75740aa255c117c00b44e4548fd9123.jpg"}}]); -------------------------------------------------------------------------------- /dist/76.8813ae58fcb560000e7c.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[76],{rjXB:function(e,p){e.exports="dist/images/20.efbaee53899a473b72250b964fb512e3.jpg"}}]); -------------------------------------------------------------------------------- /dist/77.c6ce4e46d7a0303478f2.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[77],{ekPa:function(c,d){c.exports="dist/images/2.fd1e5d12d881bce10de767cc00a6fcdc.jpg"}}]); -------------------------------------------------------------------------------- /dist/78.b6427f6aae4b8a0007e0.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[78],{hWNC:function(d,a){d.exports="dist/images/19.67dafd4ddfc70afb92a4dfa8899df2f3.jpg"}}]); -------------------------------------------------------------------------------- /dist/79.07e1a1c0dcd21b6918f6.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[79],{icJf:function(p,i){p.exports="dist/images/18.926401fa7d4b954352937f99e20ba29d.jpg"}}]); -------------------------------------------------------------------------------- /dist/80.364eca0bc34eab39adf2.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[80],{"+o/5":function(e,o){e.exports="dist/images/17.e681121d03cf6edca03e63a95fc33899.jpg"}}]); -------------------------------------------------------------------------------- /dist/81.a8c7d119345f55e445fb.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[81],{Pcl3:function(b,p){b.exports="dist/images/16.ffbdfb40a6cb31b23507a3413b3c1ebe.jpg"}}]); -------------------------------------------------------------------------------- /dist/82.4e62bc7d145b80c696e9.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[82],{gOSJ:function(e,p){e.exports="dist/images/15.d408f6054fef92780ea1a90ee10d17f5.jpg"}}]); -------------------------------------------------------------------------------- /dist/83.75c206739b6b872711ef.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[83],{"70nu":function(a,n){a.exports="dist/images/14.da2c44a249cdafbfe5833b4900efab44.jpg"}}]); -------------------------------------------------------------------------------- /dist/84.44a5708faa348234969b.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[84],{"e+Dm":function(e,p){e.exports="dist/images/13.9f5dc1a9e208373c6bad054a029255fe.jpg"}}]); -------------------------------------------------------------------------------- /dist/85.2857da345b5cfb0f0c1a.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[85],{RIS0:function(e,p){e.exports="dist/images/12.56e67a0874204535bb9ae9d8f997fcef.jpg"}}]); -------------------------------------------------------------------------------- /dist/86.f9caad4398522801a275.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[86],{sQL6:function(b,p){b.exports="dist/images/11.548bebbb1c98b2935990628ac14626ef.jpg"}}]); -------------------------------------------------------------------------------- /dist/87.5758221903eb8822fc81.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[87],{DoPr:function(o,p){o.exports="dist/images/10.423b34a0a67987b4ff4140b850953e2f.jpg"}}]); -------------------------------------------------------------------------------- /dist/88.b03f0fc088692bc2c80f.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[88],{"Q/K1":function(d,p){d.exports="dist/images/1.7d6d9da5ebbd9cb985ed67f1672ff1b1.jpg"}}]); -------------------------------------------------------------------------------- /dist/89.54d80d799666cab0f020.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[89],{ctPg:function(d,b){d.exports="dist/media/bgm.d12f266adcddb6b3fb6dc5a9548bd59d.mp3"}}]); -------------------------------------------------------------------------------- /dist/90.509d06d3662422e5d4f3.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[90],{"ag+s":function(e,n){e.exports="dist/images/bucket.5d48015fe4e6d9e9343be64264a9177e.png"}}]); -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-import'), 4 | require('postcss-cssnext'), 5 | require('stylelint'), 6 | require('postcss-reporter')({ clearReportedMessages: true }) 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /dist/46.d89541ac62699f44e73d.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[46],{"4ZCd":function(e,s,t){"use strict";t.r(s);s.default=class{isPaused(){return this.timeSystem.isPaused}getGameTime(){return this.timeSystem.getElapsed()}}}}]); -------------------------------------------------------------------------------- /dist/41.622ebfe30f647a07cf2c.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[41],{iSVj:function(n,i,s){"use strict";s.r(i),s.d(i,"default",function(){return t});class t{constructor(n,i){this.min=n,this.max=i}overlaps(n){return this.max>n.min&&n.max>this.min}}}}]); -------------------------------------------------------------------------------- /dist/25.7410c517ee40388c58c0.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[25],{QmmR:function(t,s,i){"use strict";i.r(s);s.default=class{constructor(t,s,i,h){this.value=t,this.x=s,this.y=i,this.alpha=h,this.gray=.98,this.count=0}drop(t,s){this.x+=t,this.y+=s+this.gray*this.count,this.count+=1/60}}}}]); -------------------------------------------------------------------------------- /common/CONSTANT.ts: -------------------------------------------------------------------------------- 1 | import browser from './browser'; 2 | 3 | /* 默认宽度 */ 4 | export const WIDTH = 500; 5 | /* 默认高度 */ 6 | export const HEIGHT = 500; 7 | /* 默认字体大小 */ 8 | export const FONT = `${browser.pc ? 24 : 16}px sans-serif`; 9 | /* 项目链接 */ 10 | export const LINK = 'https://snayan.github.io/canvas-demo/'; 11 | -------------------------------------------------------------------------------- /example/collide_03/canvas/projection.ts: -------------------------------------------------------------------------------- 1 | /* 投影 */ 2 | 3 | export default class Projection { 4 | min: number; 5 | max: number; 6 | constructor(min: number, max: number) { 7 | this.min = min; 8 | this.max = max; 9 | } 10 | /* 投影是否重叠 */ 11 | overlaps(p: Projection) { 12 | return this.max > p.min && p.max > this.min; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tsconfig.webpack.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "allowJs": true, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "typeRoots": ["./node_modules/@types"], 9 | "moduleResolution": "node" 10 | }, 11 | "include": ["config/**/*", "scripts/**/*"] 12 | } 13 | -------------------------------------------------------------------------------- /template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | canvas demo 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard", 3 | "rules":{ 4 | "selector-pseudo-class-no-unknown": [true, { 5 | "ignorePseudoClasses": ["global"] 6 | }], 7 | "block-closing-brace-newline-before": null, 8 | "rule-empty-line-before": null, 9 | "comment-empty-line-before": null, 10 | "at-rule-empty-line-before": null, 11 | "number-leading-zero": null 12 | } 13 | } -------------------------------------------------------------------------------- /example/clock/index.ts: -------------------------------------------------------------------------------- 1 | import CommonRender from 'common/render'; 2 | import { isSingleModule } from 'common/util'; 3 | import ClockCanvas from './canvas'; 4 | 5 | const moduleName = 'clock'; 6 | 7 | export default class Clock extends CommonRender { 8 | constructor() { 9 | super(moduleName); 10 | this.canvasInstances.push(new ClockCanvas()); 11 | } 12 | } 13 | 14 | if (isSingleModule(moduleName)) { 15 | new Clock().render(); 16 | } 17 | -------------------------------------------------------------------------------- /example/zoom/index.ts: -------------------------------------------------------------------------------- 1 | import CommonRender from 'common/render'; 2 | import { isSingleModule } from 'common/util'; 3 | import ZoomCanvas from './canvas/zoom'; 4 | 5 | const moduleName = 'zoom'; 6 | 7 | export default class Zoom extends CommonRender { 8 | constructor() { 9 | super(moduleName); 10 | this.canvasInstances.push(new ZoomCanvas()); 11 | } 12 | } 13 | 14 | if (isSingleModule(moduleName)) { 15 | new Zoom().render(); 16 | } 17 | -------------------------------------------------------------------------------- /example/shape/index.ts: -------------------------------------------------------------------------------- 1 | import CommonRender from 'common/render'; 2 | import { isSingleModule } from 'common/util'; 3 | import ShapeCanvas from './canvas/shape'; 4 | 5 | const moduleName = 'shape'; 6 | 7 | export default class Shape extends CommonRender { 8 | constructor() { 9 | super(moduleName); 10 | this.canvasInstances.push(new ShapeCanvas()); 11 | } 12 | } 13 | 14 | if (isSingleModule(moduleName)) { 15 | new Shape().render(); 16 | } 17 | -------------------------------------------------------------------------------- /example/cutout/index.ts: -------------------------------------------------------------------------------- 1 | import CommonRender from 'common/render'; 2 | import { isSingleModule } from 'common/util'; 3 | import CircleCanvas from './canvas/circle'; 4 | 5 | const moduleName = 'cutout'; 6 | 7 | export default class Cutout extends CommonRender { 8 | constructor() { 9 | super(moduleName); 10 | this.canvasInstances.push(new CircleCanvas()); 11 | } 12 | } 13 | 14 | if (isSingleModule(moduleName)) { 15 | new Cutout().render(); 16 | } 17 | -------------------------------------------------------------------------------- /example/axes/index.ts: -------------------------------------------------------------------------------- 1 | import CommonRender from 'common/render'; 2 | import { isSingleModule } from 'common/util'; 3 | import AxesCanvas from './canvas'; 4 | 5 | const moduleName = 'axes'; 6 | 7 | export default class Axes extends CommonRender { 8 | canvasInstances: AxesCanvas[]; 9 | constructor() { 10 | super(moduleName); 11 | this.canvasInstances.push(new AxesCanvas()); 12 | } 13 | } 14 | 15 | if (isSingleModule(moduleName)) { 16 | new Axes().render(); 17 | } 18 | -------------------------------------------------------------------------------- /example/editor/index.ts: -------------------------------------------------------------------------------- 1 | import CommonRender from 'common/render'; 2 | import { isSingleModule } from 'common/util'; 3 | import EditorCanvas from './canvas/editor'; 4 | 5 | const moduleName = 'editor'; 6 | 7 | class Editor extends CommonRender { 8 | constructor() { 9 | super(moduleName); 10 | this.canvasInstances.push(new EditorCanvas()); 11 | } 12 | } 13 | 14 | if (isSingleModule(moduleName)) { 15 | new Editor().render(); 16 | } 17 | 18 | export default Editor; 19 | -------------------------------------------------------------------------------- /example/free_fall/index.ts: -------------------------------------------------------------------------------- 1 | import CommonRender from 'common/render'; 2 | import { isSingleModule } from 'common/util'; 3 | import FreeFallCanvas from './canvas/freeFall'; 4 | 5 | const moduleName = 'free_fall'; 6 | 7 | export default class FreeFall extends CommonRender { 8 | constructor() { 9 | super(moduleName); 10 | this.canvasInstances.push(new FreeFallCanvas()); 11 | } 12 | } 13 | 14 | if (isSingleModule(moduleName)) { 15 | new FreeFall().render(); 16 | } 17 | -------------------------------------------------------------------------------- /example/collide_01/index.ts: -------------------------------------------------------------------------------- 1 | /* 外接图形判别法 */ 2 | 3 | import CommonRender from 'common/render'; 4 | import { isSingleModule } from 'common/util'; 5 | import CollideCanvas from './canvas'; 6 | 7 | const moduleName = 'collide_01'; 8 | 9 | export default class Collide01 extends CommonRender { 10 | constructor() { 11 | super(moduleName); 12 | this.canvasInstances.push(new CollideCanvas()); 13 | } 14 | } 15 | 16 | if (isSingleModule(moduleName)) { 17 | new Collide01().render(); 18 | } 19 | -------------------------------------------------------------------------------- /example/collide_02/index.ts: -------------------------------------------------------------------------------- 1 | /* 光线投射法 */ 2 | 3 | import CommonRender from 'common/render'; 4 | import { isSingleModule } from 'common/util'; 5 | import CollideCanvas from './canvas'; 6 | 7 | const moduleName = 'collide_02'; 8 | 9 | export default class Collide02 extends CommonRender { 10 | constructor() { 11 | super(moduleName); 12 | this.canvasInstances.push(new CollideCanvas()); 13 | } 14 | } 15 | 16 | if (isSingleModule(moduleName)) { 17 | new Collide02().render(); 18 | } 19 | -------------------------------------------------------------------------------- /example/collide_03/index.ts: -------------------------------------------------------------------------------- 1 | /* 分轴离定理 2 | 适用于圆和凸多边形 3 | */ 4 | 5 | import CommonRender from 'common/render'; 6 | import { isSingleModule } from 'common/util'; 7 | import CollideCanvas from './canvas'; 8 | 9 | const moduleName = 'collide_03'; 10 | 11 | export default class Collide03 extends CommonRender { 12 | constructor() { 13 | super(moduleName); 14 | this.canvasInstances.push(new CollideCanvas()); 15 | } 16 | } 17 | 18 | if (isSingleModule(moduleName)) { 19 | new Collide03().render(); 20 | } 21 | -------------------------------------------------------------------------------- /example/sh/index.ts: -------------------------------------------------------------------------------- 1 | import CommonRender from 'common/render'; 2 | import Canvas from 'common/canvas'; 3 | import { isSingleModule } from 'common/util'; 4 | import browser from 'common/browser'; 5 | import ShCanvas from './canvas'; 6 | 7 | const moduleName = 'sh'; 8 | 9 | export default class Sh extends CommonRender { 10 | constructor() { 11 | super(moduleName); 12 | this.canvasInstances.push(new ShCanvas()); 13 | } 14 | } 15 | 16 | if (isSingleModule(moduleName)) { 17 | new Sh().render(); 18 | } 19 | -------------------------------------------------------------------------------- /common/storage.ts: -------------------------------------------------------------------------------- 1 | const KEY_PREFIX = '__canvas__demo__storage__'.toUpperCase(); 2 | const KEY_SUFFIX = '__'; 3 | 4 | export default { 5 | get(key) { 6 | try { 7 | return JSON.parse(window.sessionStorage.getItem(KEY_PREFIX + key.toUpperCase() + KEY_SUFFIX)); 8 | } catch (e) { 9 | return null; 10 | } 11 | }, 12 | set(key, value) { 13 | try { 14 | window.sessionStorage.setItem(KEY_PREFIX + key.toUpperCase() + KEY_SUFFIX, JSON.stringify(value)); 15 | } catch (e) {} 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /dist/39.3c93645707ea3ce929b4.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[39],{honw:function(t,n,e){"use strict";e.r(n),e.d(n,"default",function(){return i});var s=e("ysz4");class i{constructor(t,n){this.x=t,this.y=n}getMagnitude(){return Object(s.a)(0,0,this.x,this.y)}add(t){return new i(this.x+t.x,this.y+t.y)}subtract(t){return new i(this.x-t.x,this.y-t.y)}dotProduct(t){return this.x*t.x+this.y*t.y}perpendicular(){return new i(this.y,-this.x)}normalize(){let t=this.getMagnitude();return t?new i(this.x/t,this.y/t):new i(0,0)}}}}]); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | canvas demo 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /example/sh/canvas/word.ts: -------------------------------------------------------------------------------- 1 | /* 文字 */ 2 | 3 | class Word { 4 | x: number; 5 | y: number; 6 | alpha: number; 7 | value: string; 8 | gray: number; 9 | count: number; 10 | constructor(value, x, y, alpha) { 11 | this.value = value; 12 | this.x = x; 13 | this.y = y; 14 | this.alpha = alpha; 15 | this.gray = 0.98; 16 | this.count = 0; 17 | } 18 | public drop(x, y) { 19 | this.x += x; 20 | this.y += y + this.gray * this.count; 21 | this.count += 1 / 60; 22 | // this.alpha -= 0.1; 23 | } 24 | } 25 | 26 | export default Word; 27 | -------------------------------------------------------------------------------- /dist/47.8ea33a87be31fdb5d89b.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[47],{PAOK:function(t,i,o){"use strict";o.r(i),o.d(i,"default",function(){return c});class c{constructor(t){this.canvas=t}isCandidateForCollide(t){return t.isVisible&&!this.isBallOutCanvas(t)}isBallOutCanvas(t){let{width:i,height:o}=this.canvas,{x:c,y:e,radius:s}=t;return c+s<0||c-s>i||e-s>o}didCollide(t,i){let o=t.verticalVelocity/t.horizontalVelocity,c=t.y-o*t.x,e=(i.mockTop-c)/o;return e>i.mockLeft&&ei.mockLeft&&t.xi.mockTop&&t.yt.headers.get(s)===this.s[s])),s}}return t.CacheableResponse=s,t.Plugin=class{constructor(t){this.e=new s(t)}cacheWillUpdate({response:t}){return this.e.isResponseCacheable(t)?t:null}},t}({}); 2 | 3 | //# sourceMappingURL=workbox-cacheable-response.prod.js.map 4 | -------------------------------------------------------------------------------- /script/build.ts: -------------------------------------------------------------------------------- 1 | import process from 'process'; 2 | import webpack from 'webpack'; 3 | import ora from 'ora'; 4 | import config from '../config/webpack.pro'; 5 | 6 | let spinner = new ora(); 7 | spinner.start('start build\n'); 8 | 9 | webpack(config, (error: Error, stats: webpack.Stats) => { 10 | spinner.stop(); 11 | if (error) { 12 | throw error; 13 | } 14 | process.stdout.write( 15 | stats.toString({ 16 | colors: true, 17 | modules: false, 18 | children: true, 19 | chunks: false, 20 | chunkModules: false, 21 | }) + '\n\n', 22 | ); 23 | 24 | if (stats.hasErrors()) { 25 | process.exit(1); 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /coverage/lcov-report/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} 2 | -------------------------------------------------------------------------------- /example/main/index.ts: -------------------------------------------------------------------------------- 1 | import Clock from '../clock'; 2 | import Axes from '../axes'; 3 | import Cutout from '../cutout'; 4 | import Shape from '../shape'; 5 | import Editor from '../editor'; 6 | import Zoom from '../zoom'; 7 | import Collide01 from '../collide_01'; 8 | import Collide02 from '../collide_02'; 9 | import Collide03 from '../collide_03'; 10 | import Animate from '../animate'; 11 | 12 | new Shape().render(); 13 | new Clock().render(); 14 | new Axes().render(); 15 | new Cutout().render(); 16 | new Editor().render(); 17 | new Zoom().render(); 18 | new Collide01().render(); 19 | new Collide02().render(); 20 | new Collide03().render(); 21 | let time = new Animate(); 22 | time.render().then(() => time.createButton()); 23 | -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-cacheable-response.prod.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"names":[],"mappings":"","sources":["packages/workbox-cacheable-response/browser.mjs"],"sourcesContent":["this.workbox=this.workbox||{},this.workbox.cacheableResponse=function(t){\"use strict\";try{self.workbox.v[\"workbox:cacheable-response:3.3.0\"]=1}catch(t){}class s{constructor(t={}){this.t=t.statuses,this.s=t.headers}isResponseCacheable(t){let s=!0;return this.t&&(s=this.t.includes(t.status)),this.s&&s&&(s=Object.keys(this.s).some(s=>t.headers.get(s)===this.s[s])),s}}return t.CacheableResponse=s,t.Plugin=class{constructor(t){this.e=new s(t)}cacheWillUpdate({response:t}){return this.e.isResponseCacheable(t)?t:null}},t}({});\n"],"file":"workbox-cacheable-response.prod.js"} -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "ESNext", 4 | "target": "ESNext", 5 | "sourceMap": true, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "experimentalDecorators": true, 9 | "moduleResolution": "node", 10 | "traceResolution": false, 11 | "noImplicitAny":false, 12 | "noImplicitReturns": true, 13 | "noImplicitThis":true, 14 | "noUnusedLocals":false, 15 | "noUnusedParameters":true, 16 | "pretty": true, 17 | "strictNullChecks": false, 18 | "typeRoots": ["../node_modules/@types"], 19 | "baseUrl": ".", 20 | "paths": { 21 | "common/*": ["common/*"], 22 | "@/*": ["example/*"] 23 | } 24 | }, 25 | "exclude": ["node_modules"] 26 | } 27 | -------------------------------------------------------------------------------- /common/render/index.scss.d.ts: -------------------------------------------------------------------------------- 1 | //This file is automatically generated by typings-for-css-modules. 2 | // Please do not change this file! 3 | export const single: string; 4 | export const collect: string; 5 | export const collectMobile: string; 6 | export const codes: string; 7 | export const codesTab: string; 8 | export const otherTab: string; 9 | export const activeTab: string; 10 | export const codesSection: string; 11 | export const otherSection: string; 12 | export const activeSection: string; 13 | export const result: string; 14 | export const mobileResult: string; 15 | export const loading: string; 16 | export const spin: string; 17 | export const mobile: string; 18 | export const loaded: string; 19 | export const error: string; 20 | export const errorTitle: string; 21 | export const errorTip: string; 22 | -------------------------------------------------------------------------------- /dist/52.2948fe1d5b4c72e2e812.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[52],{V1Io:function(t,n,i){"use strict";i.r(n);class s{constructor(t,n=s.linear()){this.timeFunc=n,this.duration=t,this.isRunning=!1}start(t){"function"==typeof t&&(this.timeFunc=t),this.startTime=Date.now(),this.isRunning=!0}getElapsedTime(){if(this.isOver())return this.duration;let t=Date.now()-this.startTime,n=t/this.duration;return t*(this.timeFunc(n)/n)}stop(){this.startTime=null,this.isRunning=!1}isOver(){return!this.isRunning||Date.now()-this.startTime>this.duration}static linear(){return function(t){return t}}static easeIn(t=1){return function(n){return Math.pow(n,2*t)}}static easeOut(t=1){return function(n){return 1-Math.pow(1-n,2*t)}}static easeInOut(){return function(t){return t-Math.sin(t*Math.PI*2)/(2*Math.PI)}}}n.default=s}}]); -------------------------------------------------------------------------------- /common/browser.ts: -------------------------------------------------------------------------------- 1 | export interface BrowserObject { 2 | ios: boolean; 3 | android: boolean; 4 | mobile: boolean; 5 | pc: boolean; 6 | } 7 | 8 | function getBrowserObject(ua: string): BrowserObject { 9 | const browser = {} as BrowserObject; 10 | const isIos = ua.indexOf('iPhone') >= 0 || ua.indexOf('iPad') >= 0 || ua.indexOf('iPod') >= 0; 11 | const isAndroid = ua.indexOf('Android') > 0; 12 | 13 | browser.ios = isIos; 14 | browser.android = isAndroid; 15 | browser.mobile = isIos || isAndroid; 16 | browser.pc = !isIos && !isAndroid; 17 | 18 | return browser; 19 | } 20 | 21 | function detectBrowser(): BrowserObject { 22 | const ua = window.navigator.userAgent; 23 | const originalUrl = window.location.href; 24 | return getBrowserObject(ua); 25 | } 26 | 27 | const browser = detectBrowser(); 28 | export default browser; 29 | -------------------------------------------------------------------------------- /dist/53.b631846237cd194524d8.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[53],{RH81:function(e,t,s){"use strict";s.r(t);t.default=class{constructor(e,t,s){this.x=e,this.y=t,this.radius=s,this.rotate=0,this.offset=0,this.moveSpeed=0,this.rotateSpeed=0,this.behaviors=[]}setMoveSpeed(e){this.moveSpeed=e,this.setRotateSpeed(e/this.radius)}setRotateSpeed(e){this.rotateSpeed=e}addBehavior(e){Array.isArray(e)?this.behaviors=[...this.behaviors,...e]:this.behaviors=[...this.behaviors,e]}update(e){for(let t of this.behaviors)t.call(null,this,e)}render(e){let{x:t,y:s,radius:o,rotate:i,offset:a}=this;e.save(),e.translate(t+a,s),e.rotate(i),e.beginPath(),e.arc(0,0,o,0,2*Math.PI,!1),e.moveTo(-o,0),e.lineTo(o,0),e.moveTo(0,-o),e.lineTo(0,o),e.fill(),e.stroke(),e.restore()}reset(){this.rotate=0,this.offset=0}static rotate(e,t){let s=e.rotateSpeed*t;s%=2*Math.PI,e.rotate=s}static move(e,t){let{moveSpeed:s}=e,o=e.moveSpeed*t;e.offset=o}}}}]); -------------------------------------------------------------------------------- /dist/49.5ac65633e0bbdddd5fd3.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[49],{"lLY/":function(t,e,i){"use strict";i.r(e),i.d(e,"default",function(){return l});var d=i("ysz4");class l{constructor(){return this instanceof l?this:new l}isCandidateForCollide(t,e){return t.visible&&e.visible&&t!==e}didCollide(t,e){let i=t.type,d=e.type;return"rect"===i&&"rect"===d?this.didRectCollide(t,e):"circle"===i&&"circle"===d?this.didCircleCollide(t,e):"rect"===i?this.didRectWidthCircleCollide(t,e):this.didRectWidthCircleCollide(e,t)}didRectCollide(t,e){let i=t.left+t.width>e.left&&t.lefte.top;return i&&d}didCircleCollide(t,e){return Object(d.a)(t.x,t.y,e.x,e.y)e+h?(this.draw(),this.lastShowTime=t):a>e&&this.erase(),this.timer=window.requestAnimationFrame(this.blink.bind(this))}move(t,i){let{ctx:e,width:h,height:s,timer:a}=this;this.erase(),this.imgData=e.getImageData(0,0,e.canvas.width,e.canvas.height),this.left=t,this.bottom=i,this.lastShowTime=0,window.cancelAnimationFrame(a),this.blink(performance.now())}}}}]); -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | import { getQuery } from 'common/util'; 2 | import './index.scss'; 3 | 4 | function success() { 5 | console.log('load module success'); 6 | } 7 | 8 | function fail() { 9 | console.log('load module fail'); 10 | } 11 | 12 | async function main() { 13 | let query = getQuery(); 14 | let example = query.module || 'main'; 15 | if (example === 'main') { 16 | await import(/* webpackPreload: true */ './example/main'); 17 | } else { 18 | await import(`./example/${example}`); 19 | } 20 | } 21 | 22 | /* register pwa */ 23 | function registerPWA() { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | window.addEventListener('load', () => { 26 | navigator.serviceWorker 27 | .register('./dist/service-worker.js') 28 | .then((registration) => { 29 | console.log('SW registered: ', registration); 30 | }) 31 | .catch((registrationError) => { 32 | console.log('SW registration failed: ', registrationError); 33 | }); 34 | }); 35 | } 36 | } 37 | 38 | /* 主函数 */ 39 | main(); 40 | registerPWA(); 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # canvas-demo 2 | 最近项目需求中要写较多H5小游戏,游戏本身体量不是很复杂,主要是承载较多业务逻辑,所以决定用canvas来完成游戏部分。之前只是知道H5中有canvas这个东西,也知道它大概是画图的,但具体怎么用,还是一无所知的。在[MDN](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial)在看了一些相关资料,一口气也看了[HTML 5 Canvas 核心技术](https://book.douban.com/subject/24533314/)和[HTML5 2D 游戏编程核心技术](https://book.douban.com/subject/27088021/),对canvas H5 游戏编程有了大致的了解,发现canvas游戏编程其实挺有趣的。目前也在学习webgl相关知识,打算把前端可视化这一块也深入学习。现在先记录一些自己认为canvas比较重要的知识,回顾和再学习。后续在记录webgl相关知识。 3 | 4 | **canvas demo仓库**主要是我自己在学习canvas时动手写的一些示例,没有使用其他任何前端框架,只专注于canvas。在学习的过程中,只有自己动手实现,才能更好的理解canvas中的相关知识点。 5 | 6 | demo预览地址:https://snayan.github.io/canvas-demo/ 7 | 8 | #### 主要知识点 9 | 10 | 1. 基础知识,学习如何绘制线段,图形,图片,文本等。 11 | 2. 动画知识,学习如何用canvas实现简单的动画以及相关影响因素 12 | 3. 碰撞检测,学习如何检测两个物体在运动过程中是否发生碰撞 13 | 4. 2D游戏开发,学习用canvas开发2D游戏 14 | 5. canvas相关小知识点, 15 | 16 | 我会按照上面的主要知识点,分篇幅来学习和回顾canvas 相关的核心技术。主要如下: 17 | 18 | * canvas核心技术-如何绘制线段 19 | * canvas核心技术-如何绘制图形 20 | * canvas核心技术-如何图片和文本 21 | * canvas核心技术-如何实现简单动画 22 | * canvas核心技术-如何实现复杂动画 23 | * canvas核心技术-如何实现碰撞检测 24 | * canvas核心技术-如何实现一个简单的2D游戏引擎 25 | * canvas核心技术-宽高,渐变,绘制真正1px线段 26 | * canvas核心技术-向量,三角函数 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 三只小羊 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-broadcast-cache-update.prod.js: -------------------------------------------------------------------------------- 1 | this.workbox=this.workbox||{},this.workbox.broadcastUpdate=function(t){"use strict";try{self.workbox.v["workbox:broadcast-cache-update:3.3.0"]=1}catch(t){}const e=(t,e,s)=>{return!s.some(s=>t.headers.has(s)&&e.headers.has(s))||s.every(s=>{const a=t.headers.has(s)===e.headers.has(s),n=t.headers.get(s)===e.headers.get(s);return a&&n})};var s={CACHE_UPDATED:"CACHE_UPDATED"};const a=(t,e,a,n)=>{"BroadcastChannel"in self&&t&&t.postMessage({type:s.CACHE_UPDATED,meta:n,payload:{cacheName:e,updatedUrl:a}})};class n{constructor(t,{headersToCheck:e,source:s}={}){this.t=t,this.e=e||["content-length","etag","last-modified"],this.s=s||"workbox-broadcast-cache-update"}a(){return"BroadcastChannel"in self&&!this.n&&(this.n=new BroadcastChannel(this.t)),this.n}notifyIfUpdated(t,s,n,c){e(t,s,this.e)||a(this.a(),c,n,this.s)}}return t.BroadcastCacheUpdate=n,t.Plugin=class{constructor(t,e){this.c=new n(t,e)}cacheDidUpdate({cacheName:t,oldResponse:e,newResponse:s,request:a}){e&&this.c.notifyIfUpdated(e,s,a.url,t)}},t.broadcastUpdate=a,t.messageTypes=s,t}({}); 2 | 3 | //# sourceMappingURL=workbox-broadcast-cache-update.prod.js.map 4 | -------------------------------------------------------------------------------- /dist/service-worker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome to your Workbox-powered service worker! 3 | * 4 | * You'll need to register this file in your web app and you should 5 | * disable HTTP caching for this file too. 6 | * See https://goo.gl/nhQhGp 7 | * 8 | * The rest of the code is auto-generated. Please don't update this file 9 | * directly; instead, make changes to your Workbox build configuration 10 | * and re-run your build process. 11 | * See https://goo.gl/2aRDsh 12 | */ 13 | 14 | importScripts("/canvas-demo/dist/workbox/workbox-v3.3.0/workbox-sw.js"); 15 | workbox.setConfig({modulePathPrefix: "/canvas-demo/dist/workbox/workbox-v3.3.0"}); 16 | 17 | importScripts( 18 | "/canvas-demo/dist/workbox/precache-manifest.0e40cc01ece54abc92d84ff3a8a2682c.js" 19 | ); 20 | 21 | workbox.skipWaiting(); 22 | workbox.clientsClaim(); 23 | 24 | /** 25 | * The workboxSW.precacheAndRoute() method efficiently caches and responds to 26 | * requests for URLs in the manifest. 27 | * See https://goo.gl/S9QRab 28 | */ 29 | self.__precacheManifest = [].concat(self.__precacheManifest || []); 30 | workbox.precaching.suppressWarnings(); 31 | workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); 32 | -------------------------------------------------------------------------------- /dist/7.bcf0c10c62961db7e7c1.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[7],{UwLk:function(t,i,s){"use strict";s.r(i);i.default=class{constructor(t,i={}){this.ctx=t,this.radius=i.radius||5,this.count=i.count||6,this.duration=i.duration||8,this.margin=i.margin||10,this.color="#f48041",this.index=0,this.show=this.duration,this.point=this.computerPoint(),this.isLoading=!1}computerPoint(){let t=[],{ctx:i,count:s,radius:n,margin:a}=this,r=s*n*2+(s-1)*a,o=(i.canvas.width-r)/2;for(let i=0;i=s&&(this.index=0),this.duration-=1,t.clearRect(0,0,t.canvas.width,t.canvas.height),this.isLoading&&(t.save(),t.fillStyle=i,this.startLoading(),t.restore(),window.requestAnimationFrame(this.animate.bind(this)))}start(){this.isLoading=!0,this.animate()}stop(){let{ctx:t}=this;this.isLoading=!1}}}}]); -------------------------------------------------------------------------------- /dist/33.2a80f96ad12518c714cc.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[33],{"17XO":function(e,t,i){"use strict";i.r(t);const s=9.81;t.default=class{constructor(e,t,i,{verticalHeight:s=0,pixelPerMiter:r=1,useGravity:h=!1,useRebound:a=!1}={}){this.x=e,this.y=t,this.radius=i,this.offset=0,this.moveSpeed=0,this.currentSpeed=0,this.behaviors=[],this.pixelPerMiter=r,this.useGravity=h,this.useRebound=a,this.verticalHeight=s,this.isStill=!1}setSpeed(e){this.moveSpeed=e,this.currentSpeed=e}addBehavior(e){Array.isArray(e)?this.behaviors=[...this.behaviors,...e]:this.behaviors=[...this.behaviors,e]}update(e){for(let t of this.behaviors)t.call(null,this,e)}render(e){let{x:t,y:i,radius:s,offset:r,pixelPerMiter:h}=this;e.save(),e.translate(t,i+r*h),e.beginPath(),e.arc(0,0,s,0,2*Math.PI,!1),e.fill(),e.stroke(),e.restore()}reset(){this.offset=0,this.currentSpeed=this.moveSpeed}static move(e,t){if(e.isStill)return;let{currentSpeed:i}=e,r=t/1e3;e.useGravity&&(e.currentSpeed+=s*r);let h=e.currentSpeed*r;e.offset+h>e.verticalHeight?e.useRebound?(e.offset=e.verticalHeight,e.currentSpeed=.6*-e.currentSpeed,h*e.pixelPerMiter/r<1&&(e.isStill=!0,e.currentSpeed=0)):(e.isStill=!0,e.currentSpeed=0,e.offset=e.verticalHeight):e.offset+=h}}}}]); -------------------------------------------------------------------------------- /example/sh/canvas/meteorCanvas.ts: -------------------------------------------------------------------------------- 1 | import Canvas from 'common/canvas'; 2 | import Star from './star'; 3 | 4 | class MeteorCanvas extends Canvas { 5 | ctx: CanvasRenderingContext2D; 6 | font: string; 7 | meteorCount: number; 8 | meteors: Star[]; 9 | constructor(width, height) { 10 | super(); 11 | this.ctx = this.getContext('2d'); 12 | this.meteorCount = 50; 13 | this.meteors = []; 14 | this.initCanvasSize(width, height); 15 | this.createMeteor(); 16 | } 17 | /* 生成流星 */ 18 | private createMeteor() { 19 | let { meteorCount, width, height, ctx } = this; 20 | let option; 21 | for (let i = 0; i < meteorCount; i++) { 22 | setTimeout(() => { 23 | option = { 24 | isBlink: false, 25 | isMeteor: true, 26 | }; 27 | this.meteors.push(new Star(ctx, option)); 28 | }, i * 300); 29 | } 30 | } 31 | /* 画流星 */ 32 | private drawMeteor() { 33 | for (let star of this.meteors) { 34 | star.render(); 35 | } 36 | } 37 | /* 渲染 */ 38 | public render() { 39 | let { ctx, width, height } = this; 40 | ctx.clearRect(0, 0, width, height); 41 | this.drawMeteor(); 42 | return this; 43 | } 44 | } 45 | 46 | export default MeteorCanvas; 47 | -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-broadcast-cache-update.prod.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"names":[],"mappings":"","sources":["packages/workbox-broadcast-cache-update/browser.mjs"],"sourcesContent":["this.workbox=this.workbox||{},this.workbox.broadcastUpdate=function(t){\"use strict\";try{self.workbox.v[\"workbox:broadcast-cache-update:3.3.0\"]=1}catch(t){}const e=(t,e,s)=>{return!s.some(s=>t.headers.has(s)&&e.headers.has(s))||s.every(s=>{const a=t.headers.has(s)===e.headers.has(s),n=t.headers.get(s)===e.headers.get(s);return a&&n})};var s={CACHE_UPDATED:\"CACHE_UPDATED\"};const a=(t,e,a,n)=>{\"BroadcastChannel\"in self&&t&&t.postMessage({type:s.CACHE_UPDATED,meta:n,payload:{cacheName:e,updatedUrl:a}})};class n{constructor(t,{headersToCheck:e,source:s}={}){this.t=t,this.e=e||[\"content-length\",\"etag\",\"last-modified\"],this.s=s||\"workbox-broadcast-cache-update\"}a(){return\"BroadcastChannel\"in self&&!this.n&&(this.n=new BroadcastChannel(this.t)),this.n}notifyIfUpdated(t,s,n,c){e(t,s,this.e)||a(this.a(),c,n,this.s)}}return t.BroadcastCacheUpdate=n,t.Plugin=class{constructor(t,e){this.c=new n(t,e)}cacheDidUpdate({cacheName:t,oldResponse:e,newResponse:s,request:a}){e&&this.c.notifyIfUpdated(e,s,a.url,t)}},t.broadcastUpdate=a,t.messageTypes=s,t}({});\n"],"file":"workbox-broadcast-cache-update.prod.js"} -------------------------------------------------------------------------------- /dist/26.6668f355362a66e3f56e.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[26],{d4kT:function(t,i,s){"use strict";s.r(i);i.default=class{constructor(t,i){this.renderCtx=t,this.isBlink=!!i.isBlink,this.isMeteor=!!i.isMeteor;let{x:s,y:a}=this.createPoint();this.x=s,this.y=a,this.radius=this.isMeteor?this.random(3,8):this.random(1,3),this.alpha=this.isMeteor?1:this.random(0,1),this.initCanvas()}initCanvas(){let t=this.radius,i=document.createElement("canvas");i.width=2*t,i.height=2*t;let s=i.getContext("2d"),a=s.createRadialGradient(t,t,0,t,t,t);a.addColorStop(.25,"#fff"),a.addColorStop(.4,"#ccc"),a.addColorStop(.9,"hsl(217, 61%, 33%)"),a.addColorStop(1,"transparent"),s.fillStyle=a,s.beginPath(),s.arc(t,t,t,0,2*Math.PI),s.fill(),this.canvas=i}random(t,i){return Math.floor(Math.random()*(i-t+1))+t}createPoint(){let{renderCtx:t,isMeteor:i,radius:s}=this,{width:a,height:e}=t.canvas;return{x:this.random(0,i?2*a:a),y:i?-3:this.random(0,e)}}blink(){this.isBlink&&(this.alpha<0?this.alpha+=.01:this.alpha-=.01)}meteor(){let{renderCtx:t}=this,{width:i,height:s}=t.canvas;if(this.x<0||this.y>s){let{x:t,y:i}=this.createPoint();this.x=t,this.y=i}this.x-=1*this.radius/10,this.y+=2*this.radius/10}render(){let{renderCtx:t,canvas:i,isMeteor:s,isBlink:a}=this;return a&&this.blink(),s&&this.meteor(),t.save(),t.globalAlpha=this.alpha,t.drawImage(i,this.x,this.y,this.radius,this.radius),t.restore(),this}}}}]); -------------------------------------------------------------------------------- /example/sh/canvas/bgCanvas.ts: -------------------------------------------------------------------------------- 1 | import Canvas from 'common/canvas'; 2 | import Star from './star'; 3 | 4 | class BgCanvas extends Canvas { 5 | ctx: CanvasRenderingContext2D; 6 | font: string; 7 | starCount: number; 8 | stars: Star[]; 9 | constructor(width, height) { 10 | super(); 11 | this.ctx = this.getContext('2d'); 12 | this.starCount = 280; 13 | this.stars = []; 14 | this.initCanvasSize(width, height); 15 | this.createStars(); 16 | } 17 | /* 画背景 */ 18 | private drawBg(ctx: CanvasRenderingContext2D) { 19 | ctx.save(); 20 | ctx.fillStyle = 'hsla(217, 84%, 6%, 2)'; 21 | ctx.fillRect(0, 0, this.width, this.height); 22 | ctx.restore(); 23 | } 24 | /* 生成星星 */ 25 | private createStars() { 26 | let { starCount, width, height, ctx } = this; 27 | let option; 28 | for (let i = 0; i < starCount; i++) { 29 | option = { 30 | isBlink: false, 31 | isMeteor: false, 32 | }; 33 | this.stars.push(new Star(ctx, option)); 34 | } 35 | } 36 | /* 画星星 */ 37 | private drawStars() { 38 | for (let star of this.stars) { 39 | star.render(); 40 | } 41 | } 42 | 43 | /* 渲染 */ 44 | public render() { 45 | let { ctx, width, height } = this; 46 | ctx.clearRect(0, 0, width, height); 47 | this.drawBg(this.ctx); 48 | this.drawStars(); 49 | return this; 50 | } 51 | } 52 | 53 | export default BgCanvas; 54 | -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-sw.js: -------------------------------------------------------------------------------- 1 | var workbox=function(){"use strict";try{self.workbox.v["workbox:sw:3.3.0"]=1}catch(t){}const t="https://storage.googleapis.com/workbox-cdn/releases/3.3.0",e={backgroundSync:"background-sync",broadcastUpdate:"broadcast-cache-update",cacheableResponse:"cacheable-response",core:"core",expiration:"cache-expiration",googleAnalytics:"google-analytics",precaching:"precaching",rangeRequests:"range-requests",routing:"routing",strategies:"strategies",streams:"streams"};return new class{constructor(){return this.v={},this.t={debug:"localhost"===self.location.hostname,modulePathPrefix:null,modulePathCb:null},this.e=this.t.debug?"dev":"prod",this.s=!1,new Proxy(this,{get(t,s){if(t[s])return t[s];const o=e[s];return o&&t.loadModule(`workbox-${o}`),t[s]}})}setConfig(t={}){if(this.s)throw new Error("Config must be set before accessing workbox.* modules");Object.assign(this.t,t),this.e=this.t.debug?"dev":"prod"}skipWaiting(){self.addEventListener("install",()=>self.skipWaiting())}clientsClaim(){self.addEventListener("activate",()=>self.clients.claim())}loadModule(t){const e=this.o(t);try{importScripts(e),this.s=!0}catch(s){throw console.error(`Unable to import module '${t}' from '${e}'.`),s}}o(e){if(this.t.modulePathCb)return this.t.modulePathCb(e,this.t.debug);let s=[t];const o=`${e}.${this.e}.js`,r=this.t.modulePathPrefix;return r&&""===(s=r.split("/"))[s.length-1]&&s.splice(s.length-1,1),s.push(o),s.join("/")}}}(); 2 | 3 | //# sourceMappingURL=workbox-sw.js.map 4 | -------------------------------------------------------------------------------- /example/collide_02/canvas/collide.ts: -------------------------------------------------------------------------------- 1 | /* 碰撞检测 2 | 光线透射法:通过检测两个物体的速度矢量是否存在交点,且该交点满足一定条件。 3 | 优点:适合运动速度快的物体,避免了速度过快,在一帧内被检测物体位置检测失效情况 4 | 缺点:适应场景有限,比如球投桶游戏 5 | */ 6 | 7 | // import Game from './game'; 8 | import { CircleSprite, ImageSprite } from './sprite'; 9 | 10 | export default class Collide { 11 | canvas: HTMLCanvasElement; 12 | constructor(canvas) { 13 | this.canvas = canvas; 14 | } 15 | 16 | /* 检查是否满足判断碰撞的条件 17 | 比如,可以过滤掉不可见sprite,或者在当前帧下根本就不会发送碰撞, 18 | 常用手法:空间分割法 19 | */ 20 | public isCandidateForCollide(ball: CircleSprite) { 21 | return ball.isVisible && !this.isBallOutCanvas(ball); 22 | } 23 | 24 | /* 检测小球是否已经落入到canvas外面了 */ 25 | public isBallOutCanvas(ball: CircleSprite) { 26 | let { width, height } = this.canvas; 27 | let { x, y, radius } = ball; 28 | return x + radius < 0 || x - radius > width || y - radius > height; 29 | } 30 | 31 | /* 是否发生碰撞 */ 32 | public didCollide(ball: CircleSprite, bucket: ImageSprite) { 33 | let k1 = ball.verticalVelocity / ball.horizontalVelocity; 34 | let b1 = ball.y - k1 * ball.x; 35 | let inertSectionY = bucket.mockTop; 36 | let insertSectionX = (inertSectionY - b1) / k1; 37 | return ( 38 | insertSectionX > bucket.mockLeft && 39 | insertSectionX < bucket.mockLeft + bucket.mockWidth && 40 | ball.x > bucket.mockLeft && 41 | ball.x < bucket.mockLeft + bucket.mockWidth && 42 | ball.y > bucket.mockTop && 43 | ball.y < bucket.mockTop + bucket.mockHeight 44 | ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-sw.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"names":[],"mappings":"","sources":["packages/workbox-sw/browser.mjs"],"sourcesContent":["var workbox=function(){\"use strict\";try{self.workbox.v[\"workbox:sw:3.3.0\"]=1}catch(t){}const t=\"https://storage.googleapis.com/workbox-cdn/releases/3.3.0\",e={backgroundSync:\"background-sync\",broadcastUpdate:\"broadcast-cache-update\",cacheableResponse:\"cacheable-response\",core:\"core\",expiration:\"cache-expiration\",googleAnalytics:\"google-analytics\",precaching:\"precaching\",rangeRequests:\"range-requests\",routing:\"routing\",strategies:\"strategies\",streams:\"streams\"};return new class{constructor(){return this.v={},this.t={debug:\"localhost\"===self.location.hostname,modulePathPrefix:null,modulePathCb:null},this.e=this.t.debug?\"dev\":\"prod\",this.s=!1,new Proxy(this,{get(t,s){if(t[s])return t[s];const o=e[s];return o&&t.loadModule(`workbox-${o}`),t[s]}})}setConfig(t={}){if(this.s)throw new Error(\"Config must be set before accessing workbox.* modules\");Object.assign(this.t,t),this.e=this.t.debug?\"dev\":\"prod\"}skipWaiting(){self.addEventListener(\"install\",()=>self.skipWaiting())}clientsClaim(){self.addEventListener(\"activate\",()=>self.clients.claim())}loadModule(t){const e=this.o(t);try{importScripts(e),this.s=!0}catch(s){throw console.error(`Unable to import module '${t}' from '${e}'.`),s}}o(e){if(this.t.modulePathCb)return this.t.modulePathCb(e,this.t.debug);let s=[t];const o=`${e}.${this.e}.js`,r=this.t.modulePathPrefix;return r&&\"\"===(s=r.split(\"/\"))[s.length-1]&&s.splice(s.length-1,1),s.push(o),s.join(\"/\")}}}();\n"],"file":"workbox-sw.js"} -------------------------------------------------------------------------------- /example/collide_01/canvas/sprite.ts: -------------------------------------------------------------------------------- 1 | /* 精灵,一般代表某一个具体的物体 */ 2 | 3 | interface SpriteOption { 4 | type?: string; 5 | name?: string; 6 | visible?: boolean; 7 | fillStyle?: string; 8 | } 9 | 10 | type RectSpriteOption = SpriteOption & { 11 | left: number; 12 | top: number; 13 | width: number; 14 | height: number; 15 | }; 16 | 17 | type CircleSpriteOption = SpriteOption & { 18 | x: number; 19 | y: number; 20 | radius: number; 21 | }; 22 | 23 | export default class Sprite { 24 | public type: string; 25 | public name: string; 26 | public visible: boolean; 27 | public fillStyle: string; 28 | constructor({ type, fillStyle, name = 'anonymous', visible = false }: SpriteOption = {}) { 29 | this.type = type; 30 | this.name = name; 31 | this.visible = visible; 32 | this.fillStyle = fillStyle; 33 | } 34 | } 35 | 36 | export class RectSprite extends Sprite { 37 | public left: number; 38 | public top: number; 39 | public width: number; 40 | public height: number; 41 | constructor(options: RectSpriteOption) { 42 | super(options); 43 | this.type = 'rect'; 44 | this.left = options.left; 45 | this.top = options.top; 46 | this.width = options.width; 47 | this.height = options.height; 48 | } 49 | } 50 | 51 | export class CircleSprite extends Sprite { 52 | public x: number; 53 | public y: number; 54 | public radius: number; 55 | constructor(options: CircleSpriteOption) { 56 | super(options); 57 | this.type = 'circle'; 58 | this.x = options.x; 59 | this.y = options.y; 60 | this.radius = options.radius; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-range-requests.prod.js: -------------------------------------------------------------------------------- 1 | this.workbox=this.workbox||{},this.workbox.rangeRequests=function(e,n){"use strict";try{self.workbox.v["workbox:range-requests:3.3.0"]=1}catch(e){}let t=(r=babelHelpers.asyncToGenerator(function*(e,t){try{const r=e.headers.get("range");if(!r)throw new n.WorkboxError("no-range-header");const s=function(e){const t=e.trim().toLowerCase();if(!t.startsWith("bytes="))throw new n.WorkboxError("unit-must-be-bytes",{normalizedRangeHeader:t});if(t.includes(","))throw new n.WorkboxError("single-range-only",{normalizedRangeHeader:t});const r=/(\d*)-(\d*)/.exec(t);if(null===r||!r[1]&&!r[2])throw new n.WorkboxError("invalid-range-values",{normalizedRangeHeader:t});return{start:""===r[1]?null:Number(r[1]),end:""===r[2]?null:Number(r[2])}}(r),a=yield t.blob(),i=function(e,t,r){const s=e.size;if(r>s||t<0)throw new n.WorkboxError("range-not-satisfiable",{size:s,end:r,start:t});let a,i;return null===t?(a=s-r,i=s):null===r?(a=t,i=s):(a=t,i=r+1),{start:a,end:i}}(a,s.start,s.end),l=a.slice(i.start,i.end),o=l.size,u=new Response(l,{status:206,statusText:"Partial Content",headers:t.headers});return u.headers.set("Content-Length",o),u.headers.set("Content-Range",`bytes ${i.start}-${i.end-1}/`+a.size),u}catch(e){return new Response("",{status:416,statusText:"Range Not Satisfiable"})}}),function(e,n){return r.apply(this,arguments)});var r;return e.createPartialResponse=t,e.Plugin=class{cachedResponseWillBeUsed({request:e,cachedResponse:n}){return babelHelpers.asyncToGenerator(function*(){return n&&e.headers.has("range")?yield t(e,n):n})()}},e}({},workbox.core._private); 2 | 3 | //# sourceMappingURL=workbox-range-requests.prod.js.map 4 | -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-streams.prod.js: -------------------------------------------------------------------------------- 1 | this.workbox=this.workbox||{},this.workbox.streams=function(){"use strict";try{self.workbox.v["workbox:streams:3.3.0"]=1}catch(e){}function e(e){const n=e.map(e=>Promise.resolve(e).then(e=>(e=e).body&&e.body.getReader?e.body.getReader():e.getReader?e.getReader():new Response(e).body.getReader()));var t;let r,o;let s=0;return{done:new Promise((e,n)=>{r=e,o=n}),stream:new ReadableStream({pull(e){return n[s].then(e=>e.read()).then(t=>{if(t.done)return++s>=n.length?(e.close(),void r()):this.pull(e);e.enqueue(t.value)}).catch(e=>{throw o(e),e})},cancel(){r()}})}}function n(e={}){const n=new Headers(e);return n.has("content-type")||n.set("content-type","text/html"),n}function t(t,r){const{done:o,stream:s}=e(t),c=n(r);return{done:o,response:new Response(s,{headers:c})}}let r=void 0;function o(){if(void 0===r)try{new ReadableStream({start(){}}),r=!0}catch(e){r=!1}return r}var s=Object.freeze({concatenate:e,concatenateToResponse:t,isSupported:o});var c={concatenate:e,concatenateToResponse:t,isSupported:o,strategy:function(e,r){return s=babelHelpers.asyncToGenerator(function*({event:s,url:c,params:a}){if(o()){const{done:n,response:o}=t(e.map(function(e){return e({event:s,url:c,params:a})}),r);return s.waitUntil(n),o}const u=yield Promise.all(e.map(function(e){return e({event:s,url:c,params:a})}).map((i=babelHelpers.asyncToGenerator(function*(e){const n=yield e;return n instanceof Response?n.blob():n}),function(e){return i.apply(this,arguments)})));var i;const l=n(r);return new Response(new Blob(u),{headers:l})}),function(e){return s.apply(this,arguments)};var s}};return Object.assign(c,s)}(); 2 | 3 | //# sourceMappingURL=workbox-streams.prod.js.map 4 | -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-streams.prod.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"names":[],"mappings":"","sources":["packages/workbox-streams/browser.mjs"],"sourcesContent":["this.workbox=this.workbox||{},this.workbox.streams=function(){\"use strict\";try{self.workbox.v[\"workbox:streams:3.3.0\"]=1}catch(e){}function e(e){const n=e.map(e=>Promise.resolve(e).then(e=>(e=e).body&&e.body.getReader?e.body.getReader():e.getReader?e.getReader():new Response(e).body.getReader()));var t;let r,o;let s=0;return{done:new Promise((e,n)=>{r=e,o=n}),stream:new ReadableStream({pull(e){return n[s].then(e=>e.read()).then(t=>{if(t.done)return++s>=n.length?(e.close(),void r()):this.pull(e);e.enqueue(t.value)}).catch(e=>{throw o(e),e})},cancel(){r()}})}}function n(e={}){const n=new Headers(e);return n.has(\"content-type\")||n.set(\"content-type\",\"text/html\"),n}function t(t,r){const{done:o,stream:s}=e(t),c=n(r);return{done:o,response:new Response(s,{headers:c})}}let r=void 0;function o(){if(void 0===r)try{new ReadableStream({start(){}}),r=!0}catch(e){r=!1}return r}var s=Object.freeze({concatenate:e,concatenateToResponse:t,isSupported:o});var c={concatenate:e,concatenateToResponse:t,isSupported:o,strategy:function(e,r){return s=babelHelpers.asyncToGenerator(function*({event:s,url:c,params:a}){if(o()){const{done:n,response:o}=t(e.map(function(e){return e({event:s,url:c,params:a})}),r);return s.waitUntil(n),o}const u=yield Promise.all(e.map(function(e){return e({event:s,url:c,params:a})}).map((i=babelHelpers.asyncToGenerator(function*(e){const n=yield e;return n instanceof Response?n.blob():n}),function(e){return i.apply(this,arguments)})));var i;const l=n(r);return new Response(new Blob(u),{headers:l})}),function(e){return s.apply(this,arguments)};var s}};return Object.assign(c,s)}();\n"],"file":"workbox-streams.prod.js"} -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-range-requests.prod.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"names":[],"mappings":"","sources":["packages/workbox-range-requests/browser.mjs"],"sourcesContent":["this.workbox=this.workbox||{},this.workbox.rangeRequests=function(e,n){\"use strict\";try{self.workbox.v[\"workbox:range-requests:3.3.0\"]=1}catch(e){}let t=(r=babelHelpers.asyncToGenerator(function*(e,t){try{const r=e.headers.get(\"range\");if(!r)throw new n.WorkboxError(\"no-range-header\");const s=function(e){const t=e.trim().toLowerCase();if(!t.startsWith(\"bytes=\"))throw new n.WorkboxError(\"unit-must-be-bytes\",{normalizedRangeHeader:t});if(t.includes(\",\"))throw new n.WorkboxError(\"single-range-only\",{normalizedRangeHeader:t});const r=/(\\d*)-(\\d*)/.exec(t);if(null===r||!r[1]&&!r[2])throw new n.WorkboxError(\"invalid-range-values\",{normalizedRangeHeader:t});return{start:\"\"===r[1]?null:Number(r[1]),end:\"\"===r[2]?null:Number(r[2])}}(r),a=yield t.blob(),i=function(e,t,r){const s=e.size;if(r>s||t<0)throw new n.WorkboxError(\"range-not-satisfiable\",{size:s,end:r,start:t});let a,i;return null===t?(a=s-r,i=s):null===r?(a=t,i=s):(a=t,i=r+1),{start:a,end:i}}(a,s.start,s.end),l=a.slice(i.start,i.end),o=l.size,u=new Response(l,{status:206,statusText:\"Partial Content\",headers:t.headers});return u.headers.set(\"Content-Length\",o),u.headers.set(\"Content-Range\",`bytes ${i.start}-${i.end-1}/`+a.size),u}catch(e){return new Response(\"\",{status:416,statusText:\"Range Not Satisfiable\"})}}),function(e,n){return r.apply(this,arguments)});var r;return e.createPartialResponse=t,e.Plugin=class{cachedResponseWillBeUsed({request:e,cachedResponse:n}){return babelHelpers.asyncToGenerator(function*(){return n&&e.headers.has(\"range\")?yield t(e,n):n})()}},e}({},workbox.core._private);\n"],"file":"workbox-range-requests.prod.js"} -------------------------------------------------------------------------------- /example/animate/canvas/timeSystem.ts: -------------------------------------------------------------------------------- 1 | export type TimingFunc = (percent: number) => number; 2 | 3 | class TimeSysTem { 4 | private startTime: number; 5 | public isRunning: boolean; 6 | public timeFunc: TimingFunc; 7 | public duration: number; 8 | constructor(duration, timeFunc = TimeSysTem.linear()) { 9 | this.timeFunc = timeFunc; 10 | this.duration = duration; 11 | this.isRunning = false; 12 | } 13 | public start(timeFunc?: TimingFunc) { 14 | if (typeof timeFunc === 'function') { 15 | this.timeFunc = timeFunc; 16 | } 17 | this.startTime = Date.now(); 18 | this.isRunning = true; 19 | } 20 | 21 | public getElapsedTime() { 22 | if (this.isOver()) { 23 | return this.duration; 24 | } 25 | let actualElapsed = Date.now() - this.startTime; 26 | let percent = actualElapsed / this.duration; 27 | return actualElapsed * (this.timeFunc(percent) / percent); 28 | } 29 | public stop() { 30 | this.startTime = null; 31 | this.isRunning = false; 32 | } 33 | 34 | public isOver() { 35 | return !this.isRunning || Date.now() - this.startTime > this.duration; 36 | } 37 | 38 | static linear() { 39 | return function(percent: number) { 40 | return percent; 41 | }; 42 | } 43 | static easeIn(strength: number = 1) { 44 | return function(percent: number) { 45 | return Math.pow(percent, strength * 2); 46 | }; 47 | } 48 | static easeOut(strength: number = 1) { 49 | return function(percent: number) { 50 | return 1 - Math.pow(1 - percent, strength * 2); 51 | }; 52 | } 53 | static easeInOut() { 54 | return function(percent: number) { 55 | return percent - Math.sin(percent * Math.PI * 2) / (2 * Math.PI); 56 | }; 57 | } 58 | } 59 | 60 | export default TimeSysTem; 61 | -------------------------------------------------------------------------------- /config/webpack.base.ts: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack'; 2 | import { resolveByRootDir, DIST } from '../script/util'; 3 | 4 | let isProduction = process.env.NODE_ENV === 'production'; 5 | 6 | const config: webpack.Configuration = { 7 | entry: resolveByRootDir('index.ts'), 8 | resolve: { 9 | extensions: ['.ts', '.js'], 10 | modules: [resolveByRootDir('example'), resolveByRootDir('common'), 'node_modules'], 11 | alias: { 12 | '@': resolveByRootDir('example'), 13 | common: resolveByRootDir('common'), 14 | }, 15 | }, 16 | module: { 17 | rules: [ 18 | { 19 | test: /\.ts$/, 20 | loader: 'ts-loader', 21 | include: [resolveByRootDir('index.ts'), resolveByRootDir('example'), resolveByRootDir('common')], 22 | exclude: /node_modules/, 23 | }, 24 | { 25 | test: /\.(png|jpg|jpeg|gif)$/, 26 | use: [ 27 | { 28 | loader: 'file-loader', 29 | options: { 30 | name: '[name].[hash].[ext]', 31 | outputPath: 'images/', 32 | publicPath: isProduction ? `${DIST}/images/` : '', 33 | }, 34 | }, 35 | ], 36 | }, 37 | { 38 | test: /\.(mp3)$/, 39 | use: [ 40 | { 41 | loader: 'file-loader', 42 | options: { 43 | name: '[name].[hash].[ext]', 44 | outputPath: 'media/', 45 | publicPath: isProduction ? `${DIST}/media/` : '', 46 | }, 47 | }, 48 | ], 49 | }, 50 | ], 51 | }, 52 | target: 'web', 53 | stats: { 54 | assets: true, 55 | colors: true, 56 | errors: true, 57 | warnings: true, 58 | }, 59 | plugins: [new webpack.EnvironmentPlugin(['NODE_ENV'])], 60 | }; 61 | 62 | export default config; 63 | -------------------------------------------------------------------------------- /example/collide_03/canvas/collide.ts: -------------------------------------------------------------------------------- 1 | /* 分离抽判别法 */ 2 | 3 | import { distance } from 'common/util'; 4 | import Sprite, { Polygon, Circle } from './sprite'; 5 | 6 | export default class Collide { 7 | constructor() { 8 | if (this instanceof Collide) { 9 | return this; 10 | } 11 | return new Collide(); 12 | } 13 | 14 | /* 检查是否满足判断碰撞的条件 15 | 比如,可以过滤掉不可见sprite,或者在当前帧下根本就不会发送碰撞, 16 | 常用手法:空间分割法 17 | */ 18 | public isCandidateForCollide(sprite: Sprite, otherSprite: Sprite) { 19 | return sprite.visible && otherSprite.visible && sprite !== otherSprite; 20 | } 21 | 22 | /* 判断是否发生碰撞 */ 23 | public didCollide(sprite: Sprite, otherSprite: Sprite) { 24 | if (sprite.type === 'circle' && otherSprite.type === 'circle') { 25 | // 圆和圆发生碰撞检测 26 | let x1 = (sprite as Circle).x; 27 | let y1 = (sprite as Circle).y; 28 | let r1 = (sprite as Circle).radius; 29 | let x2 = (otherSprite as Circle).x; 30 | let y2 = (otherSprite as Circle).y; 31 | let r2 = (otherSprite as Circle).radius; 32 | return distance(x1, y1, x2, y2) <= r1 + r2; 33 | } 34 | let axes1 = sprite.type === 'circle' ? (sprite as Circle).getAxes(otherSprite as Polygon) : (sprite as Polygon).getAxes(); 35 | let axes2 = otherSprite.type === 'circle' ? (otherSprite as Circle).getAxes(sprite as Polygon) : (otherSprite as Polygon).getAxes(); 36 | // 第一步:获取所有的投影轴 37 | // 第二步:获取多边形在各个投影轴的投影 38 | // 第三步:判断是否存在一条投影轴上,多边形的投影不相交,如果存在不相交的投影则直接返回false,如果有所的投影轴上的投影都存在相交,则说明相碰了。 39 | let axes = [...axes1, ...axes2]; 40 | for (let axis of axes) { 41 | let projections1 = sprite.getProjection(axis); 42 | let projections2 = otherSprite.getProjection(axis); 43 | if (!projections1.overlaps(projections2)) { 44 | return false; 45 | } 46 | } 47 | return true; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /example/animate/index.ts: -------------------------------------------------------------------------------- 1 | import CommonRender from 'common/render'; 2 | import { isSingleModule } from 'common/util'; 3 | import AnimateCanvas from './canvas/animateCanvas'; 4 | 5 | const moduleName = 'animate'; 6 | 7 | export default class Time extends CommonRender { 8 | constructor() { 9 | super(moduleName); 10 | let duration = 3000; 11 | this.canvasInstances.push(new AnimateCanvas(duration, 'linear')); 12 | this.canvasInstances.push(new AnimateCanvas(duration, 'easeIn')); 13 | this.canvasInstances.push(new AnimateCanvas(duration, 'easeOut')); 14 | this.canvasInstances.push(new AnimateCanvas(duration, 'easeInOut')); 15 | } 16 | public createButton() { 17 | let btn = document.createElement('button'); 18 | btn.style.position = 'absolute'; 19 | btn.style.left = '50%'; 20 | btn.style.top = '10px'; 21 | btn.style.width = 80 + 'px'; 22 | btn.style.height = 30 + 'px'; 23 | btn.style.textAlign = 'center'; 24 | btn.style.border = 'none'; 25 | btn.style.background = 'green'; 26 | btn.style.color = 'white'; 27 | btn.style.borderRadius = '10px'; 28 | btn.style.transform = 'translateX(-50%)'; 29 | btn.style.zIndex = '3'; 30 | btn.innerText = 'start'; 31 | (this.el.lastChild as HTMLElement).style.position = 'relative'; 32 | this.el.lastChild.appendChild(btn); 33 | btn.addEventListener( 34 | 'click', 35 | () => { 36 | setTimeout(() => { 37 | this.canvasInstances.forEach((instance: AnimateCanvas) => { 38 | if (instance.checked) { 39 | instance.reset(); 40 | instance.start(); 41 | } 42 | }); 43 | }); 44 | }, 45 | false, 46 | ); 47 | } 48 | } 49 | 50 | if (isSingleModule(moduleName)) { 51 | let time = new Time(); 52 | time.render().then(() => time.createButton()); 53 | } 54 | -------------------------------------------------------------------------------- /example/axes/canvas/index.ts: -------------------------------------------------------------------------------- 1 | import Canvas from 'common/canvas'; 2 | import Grid from './grid'; 3 | import Axes, { AxesData } from './axes'; 4 | import browser from 'common/browser'; 5 | import { random, windowToCanvas, throttle } from 'common/util'; 6 | 7 | class AxesCanvas extends Canvas { 8 | ctx: CanvasRenderingContext2D; 9 | grid: Grid; 10 | axes: Axes; 11 | data: AxesData[]; 12 | constructor() { 13 | super(); 14 | this.ctx = this.getContext('2d'); 15 | this.initData(); 16 | this.bindMouseEvent(); 17 | } 18 | 19 | /* 初始化随机数据 */ 20 | initData() { 21 | let rangeX = [0, 100]; 22 | let rangeY = [0, 100]; 23 | let count = 10; 24 | let data = []; 25 | for (let i = 0; i < count; i++) { 26 | data.push({ 27 | x: random(rangeX[0], rangeX[1]), 28 | y: random(rangeY[0], rangeY[1]), 29 | }); 30 | } 31 | this.data = data; 32 | } 33 | 34 | /* 绑定鼠标移动事件 */ 35 | bindMouseEvent() { 36 | let { el } = this; 37 | el.addEventListener(browser.mobile ? 'touchmove' : 'mousemove', throttle(this.drawGuide.bind(this), 100), false); 38 | } 39 | 40 | /* 绘制提示线 */ 41 | drawGuide(e: MouseEvent | TouchEvent) { 42 | let x; 43 | let y; 44 | let { el } = this; 45 | e.preventDefault(); 46 | if (browser.pc) { 47 | e = e as MouseEvent; 48 | x = e.x; 49 | y = e.y; 50 | } else { 51 | x = (e as TouchEvent).changedTouches[0].pageX; 52 | y = (e as TouchEvent).changedTouches[0].pageY; 53 | } 54 | let canvasPoint = windowToCanvas(el, x, y); 55 | this.axes.drawGuide(canvasPoint.x, canvasPoint.y); 56 | } 57 | 58 | /* 渲染 */ 59 | render(container: HTMLElement) { 60 | super.render(container); 61 | // this.grid = new Grid(this.ctx); 62 | this.axes = new Axes(this.ctx, this.data); 63 | // this.grid.render(); 64 | this.axes.render(); 65 | } 66 | } 67 | 68 | export default AxesCanvas; 69 | -------------------------------------------------------------------------------- /script/util.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import fs from 'fs'; 3 | import opn from 'opn'; 4 | import webpack from 'webpack'; 5 | 6 | export const DIST = 'dist'; 7 | 8 | export function resolveByRootDir(...paths: string[]) { 9 | return path.resolve(__dirname, '../', ...paths); 10 | } 11 | 12 | export function resolveExampleDir() { 13 | let example = resolveByRootDir('example'); 14 | return fs.readdirSync(example).filter((v) => { 15 | let stats = fs.statSync(resolveByRootDir('example', v)); 16 | return stats.isDirectory(); 17 | }); 18 | } 19 | 20 | export function exampleEntry() { 21 | let modules = resolveExampleDir(); 22 | let current = Date.now(); 23 | let buildEntry = modules.reduce((entries, example) => { 24 | entries[`${example}.${current}`] = resolveByRootDir('example', example, 'index.ts'); 25 | return entries; 26 | }, {}); 27 | let globalVariable = modules.reduce((variable, example) => { 28 | variable[example] = path.join(process.env.NODE_ENV === 'production' ? DIST : '', `${example}.${current}.js`); 29 | return variable; 30 | }, {}); 31 | return { 32 | entry: buildEntry, 33 | variable: globalVariable, 34 | }; 35 | } 36 | 37 | export function clearConsole() { 38 | process.stdout.write(process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H'); 39 | } 40 | 41 | export function openBrowser(url) { 42 | try { 43 | var options = { app: undefined }; 44 | opn(url, options).catch(() => {}); 45 | return true; 46 | } catch (err) { 47 | return false; 48 | } 49 | } 50 | 51 | export function formatMessage(stats: webpack.Stats) { 52 | return stats.toString({ 53 | colors: true, 54 | hash: false, 55 | timings: false, 56 | performance: false, 57 | version: false, 58 | assets: false, 59 | entrypoints: false, 60 | modules: false, 61 | children: false, 62 | chunks: false, 63 | chunkModules: false, 64 | warnings: true, 65 | errors: true, 66 | }); 67 | } 68 | -------------------------------------------------------------------------------- /common/github.ts: -------------------------------------------------------------------------------- 1 | /* 获取GitHub源代码 */ 2 | 3 | import storage from './storage'; 4 | 5 | export interface GitHubApiResult { 6 | name: string; 7 | path: string; 8 | sha: string; 9 | size: number; 10 | url: string; 11 | html_url: string; 12 | git_url: string; 13 | download_url: string; 14 | type: string; 15 | content?: string; 16 | encoding?: string; 17 | } 18 | 19 | class Github { 20 | moduleName: string; 21 | sourcePath: string; 22 | requestPath: string; 23 | constructor(moduleName: string) { 24 | this.moduleName = moduleName; 25 | this.sourcePath = `example/${moduleName}/canvas`; 26 | this.requestPath = `https://api.github.com/repos/snayan/canvas-demo/contents`; 27 | } 28 | private fetch(path: string) { 29 | return fetch(`${this.requestPath}/${path}`, { credentials: 'omit', method: 'get', mode: 'cors' }); 30 | } 31 | public async getCanvasFiles() { 32 | if (process.env.NODE_ENV !== 'production') { 33 | throw new Error(JSON.stringify({ status: '400', statusText: 'forbidden', url: "development env don't request code" })); 34 | } 35 | let files: GitHubApiResult[]; 36 | let contents: GitHubApiResult[] = []; 37 | let content: GitHubApiResult[] = storage.get(this.moduleName); 38 | if (content && content.length) { 39 | return content; 40 | } 41 | 42 | let res = await this.fetch(this.sourcePath); 43 | if (!res.ok) { 44 | throw new Error( 45 | JSON.stringify({ 46 | status: res.status, 47 | statusText: res.statusText, 48 | body: await res.text(), 49 | url: res.url, 50 | }), 51 | ); 52 | } 53 | files = await res.json(); 54 | for (let file of files) { 55 | if (file.type === 'file') { 56 | res = await this.fetch(file.path); 57 | res.ok && contents.push(await res.json()); 58 | } 59 | } 60 | storage.set(this.moduleName, contents); 61 | return contents; 62 | } 63 | } 64 | 65 | export default Github; 66 | -------------------------------------------------------------------------------- /dist/28.5657e743fea8ab107ea0.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[28],{"0Pcb":function(t,i,n){"use strict";const e=function(){const t=window.navigator.userAgent;return window.location.href,function(t){const i={},n=t.indexOf("iPhone")>=0||t.indexOf("iPad")>=0||t.indexOf("iPod")>=0,e=t.indexOf("Android")>0;return i.ios=n,i.android=e,i.mobile=n||e,i.pc=!n&&!e,i}(t)}();i.a=e},Qb4n:function(t,i,n){"use strict";var e=n("kZAv");i.a=class{constructor(){this.el=document.createElement("canvas")}initCanvasSize(t,i){this.el.width=t,this.el.height=i,this.width=t,this.height=i}getContext(t,i){return this.el.getContext(t,i)}render(t){this.container=t;let{width:i,height:n}=t.getBoundingClientRect();this.initCanvasSize(i||e.d,n||e.b),this.container.innerHTML="",this.container.appendChild(this.el)}}},ReMq:function(t,i,n){"use strict";n.r(i);var e=n("Qb4n");i.default=class extends e.a{constructor(t,i){super(),this.ctx=this.getContext("2d"),this.radius=5,this.count=6,this.index=0,this.duration=10,this.show=this.duration,this.margin=10,this.color="#f48041",this.initCanvasSize(t,i),this.point=this.computerPoint()}computerPoint(){let t=[],{width:i,count:n,radius:e,margin:s}=this,r=(i-(n*e*2+(n-1)*s))/2;for(let i=0;i=s&&(this.index=0),this.duration-=1,t.clearRect(0,0,i,n),t.save(),t.fillStyle=e,this.startLoading(),t.restore(),this}}},kZAv:function(t,i,n){"use strict";n.d(i,"d",function(){return e}),n.d(i,"b",function(){return s}),n.d(i,"a",function(){return r}),n.d(i,"c",function(){return o});const e=500,s=500,r=`${n("0Pcb").a.pc?24:16}px sans-serif`,o="https://snayan.github.io/canvas-demo/"}}]); -------------------------------------------------------------------------------- /config/webpack.dev.ts: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'development'; 2 | 3 | import webpack from 'webpack'; 4 | import merge from 'webpack-merge'; 5 | import HtmlWebpackPlugin from 'html-webpack-plugin'; 6 | import baseConfig from './webpack.base'; 7 | import { resolveByRootDir, DIST } from '../script/util'; 8 | 9 | const config: webpack.Configuration = { 10 | mode: 'development', 11 | devtool: 'inline-source-map', 12 | output: { 13 | path: resolveByRootDir(DIST), 14 | filename: '[name].[hash].js', 15 | publicPath: '/', 16 | }, 17 | module: { 18 | rules: [ 19 | { 20 | test: /\.s?css$/, 21 | use: [ 22 | { 23 | loader: 'style-loader', 24 | options: { 25 | hmr: true, 26 | sourceMap: true, 27 | }, 28 | }, 29 | { 30 | loader: 'typings-for-css-modules-loader', 31 | options: { 32 | minimize: false, 33 | importLoaders: 2, 34 | modules: true, 35 | sourceMap: true, 36 | namedExport: true, 37 | camelCase: true, 38 | localIdentName: '[local]', 39 | banner: '//This file is automatically generated by typings-for-css-modules.\n// Please do not change this file!', 40 | }, 41 | }, 42 | { 43 | loader: 'postcss-loader', 44 | options: { 45 | sourceMap: true, 46 | }, 47 | }, 48 | { 49 | loader: 'sass-loader', 50 | options: { 51 | sourceMap: true, 52 | }, 53 | }, 54 | ], 55 | }, 56 | ], 57 | }, 58 | plugins: [ 59 | new HtmlWebpackPlugin({ 60 | template: 'template.html', 61 | filename: 'index.html', 62 | }), 63 | new webpack.NamedModulesPlugin(), 64 | new webpack.HotModuleReplacementPlugin(), 65 | new webpack.WatchIgnorePlugin([/scss\.d\.ts/]), 66 | ], 67 | }; 68 | 69 | export default merge(baseConfig, config); 70 | -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-google-analytics.prod.js: -------------------------------------------------------------------------------- 1 | this.workbox=this.workbox||{},this.workbox.googleAnalytics=function(e,n,t,o,r,c,s){"use strict";try{self.workbox.v["workbox:google-analytics:3.3.0"]=1}catch(e){}const l=/^\/(\w+\/)?collect/,i=(a=babelHelpers.asyncToGenerator(function*(e){return yield new Promise(function(n,t){const o=new FileReader;o.onloadend=function(){return n(o.result)},o.onerror=function(){return t(o.error)},o.readAsText(e)})}),function(e){return a.apply(this,arguments)});var a;const w=e=>(u=babelHelpers.asyncToGenerator(function*(n){let t,{url:o,requestInit:r,timestamp:c}=n;if(o=new URL(o),r.body){const e=r.body instanceof Blob?yield i(r.body):r.body;t=new URLSearchParams(e)}else t=o.searchParams;const s=c-(Number(t.get("qt"))||0),l=Date.now()-s;if(t.set("qt",l),e.parameterOverrides)for(const n of Object.keys(e.parameterOverrides)){const o=e.parameterOverrides[n];t.set(n,o)}"function"==typeof e.hitFilter&&e.hitFilter.call(null,t),r.body=t.toString(),r.method="POST",r.mode="cors",r.credentials="omit",r.headers={"Content-Type":"text/plain"},n.url=`${o.origin}${o.pathname}`}),function(e){return u.apply(this,arguments)});var u;return e.initialize=((e={})=>{const i=t.cacheNames.getGoogleAnalyticsName(e.cacheName),a=new n.Plugin("workbox-google-analytics",{maxRetentionTime:2880,callbacks:{requestWillReplay:w(e)}}),u=[(e=>{const n=new c.NetworkFirst({cacheName:e});return new o.Route(({url:e})=>"www.google-analytics.com"===e.hostname&&"/analytics.js"===e.pathname,n,"GET")})(i),(e=>{const n=new c.NetworkFirst({cacheName:e});return new o.Route(({url:e})=>"www.googletagmanager.com"===e.hostname&&"/gtag/js"===e.pathname,n,"GET")})(i),...(e=>{const n=({url:e})=>"www.google-analytics.com"===e.hostname&&l.test(e.pathname),t=new s.NetworkOnly({plugins:[e]});return[new o.Route(n,t,"GET"),new o.Route(n,t,"POST")]})(a)],f=new r.Router;for(const e of u)f.registerRoute(e);self.addEventListener("fetch",e=>{const n=f.handleRequest(e);n&&e.respondWith(n)})}),e}({},workbox.backgroundSync,workbox.core._private,workbox.routing,workbox.routing,workbox.strategies,workbox.strategies); 2 | 3 | //# sourceMappingURL=workbox-google-analytics.prod.js.map 4 | -------------------------------------------------------------------------------- /coverage/lcov-report/block-navigation.js: -------------------------------------------------------------------------------- 1 | var jumpToCode = (function init () { 2 | // Classes of code we would like to highlight 3 | var missingCoverageClasses = [ '.cbranch-no', '.cstat-no', '.fstat-no' ]; 4 | 5 | // We don't want to select elements that are direct descendants of another match 6 | var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` 7 | 8 | // Selecter that finds elements on the page to which we can jump 9 | var selector = notSelector + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` 10 | 11 | // The NodeList of matching elements 12 | var missingCoverageElements = document.querySelectorAll(selector); 13 | 14 | var currentIndex; 15 | 16 | function toggleClass(index) { 17 | missingCoverageElements.item(currentIndex).classList.remove('highlighted'); 18 | missingCoverageElements.item(index).classList.add('highlighted'); 19 | } 20 | 21 | function makeCurrent(index) { 22 | toggleClass(index); 23 | currentIndex = index; 24 | missingCoverageElements.item(index) 25 | .scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'center' }); 26 | } 27 | 28 | function goToPrevious() { 29 | var nextIndex = 0; 30 | if (typeof currentIndex !== 'number' || currentIndex === 0) { 31 | nextIndex = missingCoverageElements.length - 1; 32 | } else if (missingCoverageElements.length > 1) { 33 | nextIndex = currentIndex - 1; 34 | } 35 | 36 | makeCurrent(nextIndex); 37 | } 38 | 39 | function goToNext() { 40 | var nextIndex = 0; 41 | 42 | if (typeof currentIndex === 'number' && currentIndex < (missingCoverageElements.length - 1)) { 43 | nextIndex = currentIndex + 1; 44 | } 45 | 46 | makeCurrent(nextIndex); 47 | } 48 | 49 | return function jump(event) { 50 | switch (event.which) { 51 | case 78: // n 52 | case 74: // j 53 | goToNext(); 54 | break; 55 | case 66: // b 56 | case 75: // k 57 | case 80: // p 58 | goToPrevious(); 59 | break; 60 | } 61 | }; 62 | }()); 63 | window.addEventListener('keydown', jumpToCode); 64 | -------------------------------------------------------------------------------- /dist/43.2f5e17ce7bf50dcf305e.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[43],{mVJc:function(t,e,s){"use strict";s.r(e),s.d(e,"StopWatch",function(){return i}),s.d(e,"AnimationTimer",function(){return a});class i{constructor(){this.startTime=0,this.elapsed=0,this.running=!1}start(){this.startTime=Date.now(),this.running=!0,this.elapsed=0}stop(){this.running=!1,this.elapsed=Date.now()-this.startTime}getElapsedTime(){return this.running?Date.now()-this.startTime:this.elapsed}reset(){this.startTime=Date.now(),this.elapsed=0}isRunning(){return this.running}}class a extends i{constructor(t=1e3,e=a.makeLinear()){super(),this.duration=t,this.transducer=e}getElapsedTime(){if(!this.isRunning()||!this.duration)return 0;let t=super.getElapsedTime(),e=t/this.duration;return t*(this.transducer(e)/e)}isExpired(){return this.getElapsedTime()>this.duration}static makeLinear(){return function(t){return t}}static makeEaseIn(t=1){return function(e){return Math.pow(e,2*t)}}static makeEaseOut(t=1){return function(e){return 1-Math.pow(1-e,2*t)}}static makeEaseInOut(){return function(t){return t-Math.sin(2*t*Math.PI)/(2*Math.PI)}}static makeElastic(t=3){return function(e){return(1-Math.cos(e*Math.PI*t))*(1-e)+e}}static makeBounce(t){let e=a.makeElastic(t);return function(t){return(t=e(t))<=1?t:2-t}}}e.default=class{constructor(){this.elapsed=0,this.isPaused=!1,this.isStart=!1,this.transducer=(t=>t),this.transducerStartTime=0}calculateElapsed(t){let{transducerStartTime:e,transducer:s,isPaused:i}=this;if(!this.isPaused){let i=t-e;"function"==typeof s&&(i=s(i)),this.elapsed+=i,this.transducerStartTime=t}}start(t=Date.now()){void 0==t&&(t=Date.now()),this.elapsed=0,this.isStart=!0,this.transducerStartTime=t}reset(){this.elapsed=0,this.isStart=!1,this.transducerStartTime=Date.now()}paused(t=Date.now()){void 0==t&&(t=Date.now()),this.isPaused||(this.calculateElapsed(t),this.isPaused=!0)}unPaused(){this.isPaused&&(this.transducerStartTime=Date.now(),this.isPaused=!1)}getElapsed(t=Date.now()){let{transducerStartTime:e,transducer:s,isPaused:i}=this;if(this.isPaused)return this.elapsed;let a=t-e;return"function"==typeof s&&(a=s(a)),this.elapsed+a}setTransducer(t,e,s=Date.now()){let{transducer:i}=this;this.calculateElapsed(s),this.transducer=t,Number.isFinite(e)&&setTimeout(this.setTransducer.bind(this,i),e)}}}}]); -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-google-analytics.prod.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"names":[],"mappings":"","sources":["packages/workbox-google-analytics/browser.mjs"],"sourcesContent":["this.workbox=this.workbox||{},this.workbox.googleAnalytics=function(e,n,t,o,r,c,s){\"use strict\";try{self.workbox.v[\"workbox:google-analytics:3.3.0\"]=1}catch(e){}const l=/^\\/(\\w+\\/)?collect/,i=(a=babelHelpers.asyncToGenerator(function*(e){return yield new Promise(function(n,t){const o=new FileReader;o.onloadend=function(){return n(o.result)},o.onerror=function(){return t(o.error)},o.readAsText(e)})}),function(e){return a.apply(this,arguments)});var a;const w=e=>(u=babelHelpers.asyncToGenerator(function*(n){let t,{url:o,requestInit:r,timestamp:c}=n;if(o=new URL(o),r.body){const e=r.body instanceof Blob?yield i(r.body):r.body;t=new URLSearchParams(e)}else t=o.searchParams;const s=c-(Number(t.get(\"qt\"))||0),l=Date.now()-s;if(t.set(\"qt\",l),e.parameterOverrides)for(const n of Object.keys(e.parameterOverrides)){const o=e.parameterOverrides[n];t.set(n,o)}\"function\"==typeof e.hitFilter&&e.hitFilter.call(null,t),r.body=t.toString(),r.method=\"POST\",r.mode=\"cors\",r.credentials=\"omit\",r.headers={\"Content-Type\":\"text/plain\"},n.url=`${o.origin}${o.pathname}`}),function(e){return u.apply(this,arguments)});var u;return e.initialize=((e={})=>{const i=t.cacheNames.getGoogleAnalyticsName(e.cacheName),a=new n.Plugin(\"workbox-google-analytics\",{maxRetentionTime:2880,callbacks:{requestWillReplay:w(e)}}),u=[(e=>{const n=new c.NetworkFirst({cacheName:e});return new o.Route(({url:e})=>\"www.google-analytics.com\"===e.hostname&&\"/analytics.js\"===e.pathname,n,\"GET\")})(i),(e=>{const n=new c.NetworkFirst({cacheName:e});return new o.Route(({url:e})=>\"www.googletagmanager.com\"===e.hostname&&\"/gtag/js\"===e.pathname,n,\"GET\")})(i),...(e=>{const n=({url:e})=>\"www.google-analytics.com\"===e.hostname&&l.test(e.pathname),t=new s.NetworkOnly({plugins:[e]});return[new o.Route(n,t,\"GET\"),new o.Route(n,t,\"POST\")]})(a)],f=new r.Router;for(const e of u)f.registerRoute(e);self.addEventListener(\"fetch\",e=>{const n=f.handleRequest(e);n&&e.respondWith(n)})}),e}({},workbox.backgroundSync,workbox.core._private,workbox.routing,workbox.routing,workbox.strategies,workbox.strategies);\n"],"file":"workbox-google-analytics.prod.js"} -------------------------------------------------------------------------------- /example/axes/canvas/grid.ts: -------------------------------------------------------------------------------- 1 | /* grid class */ 2 | 3 | export interface GridOption { 4 | width?: number; 5 | height?: number; 6 | axisSpaceX?: number; 7 | axisSpaceY?: number; 8 | lineColor?: string; 9 | } 10 | 11 | class Grid { 12 | width: number; 13 | height: number; 14 | lineColor: string; 15 | numHorizontalStep: number; 16 | numVerticalStep: number; 17 | axisSpaceX: number; 18 | axisSpaceY: number; 19 | ctx: CanvasRenderingContext2D; 20 | constructor(ctx: CanvasRenderingContext2D, options: GridOption = {}) { 21 | this.ctx = ctx; 22 | this.width = options.width; 23 | this.height = options.height; 24 | this.lineColor = options.lineColor || 'lightgray'; 25 | this.axisSpaceX = options.axisSpaceX || 10; 26 | this.axisSpaceY = options.axisSpaceY || 10; 27 | this.initGrid(); 28 | } 29 | 30 | /* 初始化网格数据 */ 31 | initGrid() { 32 | let { ctx, width, height, axisSpaceX, axisSpaceY } = this; 33 | let canvasWidth = ctx.canvas.width; 34 | let canvasHeight = ctx.canvas.height; 35 | width = width || (this.width = canvasWidth); 36 | height = height || (this.height = canvasHeight); 37 | let gridWidth = width - 1; //防止在绘制最后的垂直线在边界外的0.5像素处不可见,所以先预留1px 38 | let gridHeight = height - 1; //防止在绘制最后的水平线在边界外的0.5像素处不可见,所以先预留1px 39 | this.numHorizontalStep = Math.floor(gridWidth / axisSpaceX); 40 | this.numVerticalStep = Math.floor(gridHeight / axisSpaceY); 41 | this.axisSpaceX = gridWidth / this.numHorizontalStep; 42 | this.axisSpaceY = gridHeight / this.numVerticalStep; 43 | } 44 | 45 | /* 渲染网格 */ 46 | render() { 47 | let { ctx, width, height, lineColor, axisSpaceX, axisSpaceY, numHorizontalStep, numVerticalStep } = this; 48 | ctx.save(); 49 | ctx.lineWidth = 0.5; 50 | ctx.strokeStyle = lineColor; 51 | ctx.translate(0, 0); 52 | ctx.beginPath(); 53 | for (let i = 0; i < numHorizontalStep + 1; i += 1) { 54 | ctx.moveTo(i * axisSpaceX + 0.5, 0); 55 | ctx.lineTo(i * axisSpaceX + 0.5, height - 1); 56 | } 57 | for (let i = 0; i < numVerticalStep + 1; i += 1) { 58 | ctx.moveTo(0, i * axisSpaceY + 0.5); 59 | ctx.lineTo(width - 1, i * axisSpaceY + 0.5); 60 | } 61 | ctx.stroke(); 62 | ctx.restore(); 63 | } 64 | } 65 | 66 | export default Grid; 67 | -------------------------------------------------------------------------------- /example/sh/canvas/loadingCanvas.ts: -------------------------------------------------------------------------------- 1 | import Canvas from 'common/canvas'; 2 | 3 | class LoadingCanvas extends Canvas { 4 | ctx: CanvasRenderingContext2D; 5 | radius: number; 6 | count: number; 7 | color: string; 8 | index: number; 9 | duration: number; 10 | show: number; 11 | margin: number; 12 | point: number[]; 13 | constructor(width, height) { 14 | super(); 15 | this.ctx = this.getContext('2d'); 16 | this.radius = 5; 17 | this.count = 6; 18 | this.index = 0; 19 | this.duration = 10; 20 | this.show = this.duration; 21 | this.margin = 10; 22 | this.color = '#f48041'; 23 | this.initCanvasSize(width, height); 24 | this.point = this.computerPoint(); 25 | } 26 | /* 创建坐标 */ 27 | private computerPoint() { 28 | let point = []; 29 | let { width, count, radius, margin } = this; 30 | let totalLength = count * radius * 2 + (count - 1) * margin; 31 | let left = (width - totalLength) / 2; 32 | for (let i = 0; i < count; i++) { 33 | point[i] = left + radius + (radius * 2 + margin) * i; 34 | } 35 | return point; 36 | } 37 | /* 绘制圆点 */ 38 | private renderArc(index, scale) { 39 | let { ctx, radius, point, height } = this; 40 | let x = point[index]; 41 | let y = height / 2; 42 | ctx.save(); 43 | ctx.beginPath(); 44 | ctx.arc(x, y, radius * scale, 0, Math.PI * 2); 45 | ctx.fill(); 46 | ctx.restore(); 47 | } 48 | /* 开始loading */ 49 | private startLoading() { 50 | let { index, count, margin, duration, show } = this; 51 | for (let i = 0; i < count; i++) { 52 | if (i === index) { 53 | this.renderArc(i, 0.8 + 0.6 * duration / show); 54 | } else { 55 | this.renderArc(i, 0.8); 56 | } 57 | } 58 | } 59 | /* 渲染 */ 60 | public render() { 61 | let { ctx, width, height, color, count, show } = this; 62 | if (this.duration < 1) { 63 | this.duration = show; 64 | this.index += 1; 65 | } 66 | if (this.index >= count) { 67 | this.index = 0; 68 | } 69 | this.duration -= 1; 70 | ctx.clearRect(0, 0, width, height); 71 | ctx.save(); 72 | ctx.fillStyle = color; 73 | this.startLoading(); 74 | ctx.restore(); 75 | return this; 76 | } 77 | } 78 | 79 | export default LoadingCanvas; 80 | -------------------------------------------------------------------------------- /plugins/html-webpack-assert-plugin.ts: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack'; 2 | import path from 'path'; 3 | import { resolveByRootDir, DIST } from '../script/util'; 4 | 5 | class HtmlWebpackAssertPlugin { 6 | chunks: string[]; 7 | title: string; 8 | dev: boolean; 9 | constructor({ chunks, title, dev = true }: { chunks: string[]; title: string; dev?: boolean }) { 10 | this.chunks = chunks; 11 | this.title = title; 12 | this.dev = dev; 13 | } 14 | apply(compiler: webpack.Compiler) { 15 | compiler.hooks.emit.tapAsync('emit', (compilation, callback) => { 16 | // generated file: 17 | var fidelis = ` 18 | 19 | 20 | 21 | 22 | 23 | ${this.title} 24 | 25 | 26 | 27 | ${this.chunks 28 | .map((chunk) => { 29 | let url = this.assert(compilation, chunk); 30 | if (!this.dev) { 31 | url = path.relative(resolveByRootDir(), path.join(DIST, url)); 32 | } 33 | return ``; 34 | }) 35 | .join('\n')} 36 | 37 | `; 38 | let paths = this.dev ? 'index.html' : path.relative(resolveByRootDir(DIST), 'index.html'); 39 | // Insert this list into the webpack build as a new file asset: 40 | compilation.assets[paths] = { 41 | source: function() { 42 | return fidelis; 43 | }, 44 | size: function() { 45 | return fidelis.length; 46 | }, 47 | }; 48 | 49 | callback(); 50 | }); 51 | } 52 | assert(compilation: webpack.compilation.Compilation, chunk: string) { 53 | let chunks = compilation.chunks; 54 | for (let i = 0, j = chunks.length; i < j; i++) { 55 | if (chunks[i].name === chunk) { 56 | return chunks[i].files.reduce((s, v) => { 57 | if (!s && /\.js$/.test(v)) { 58 | s = v; 59 | } 60 | return s; 61 | }, ''); 62 | } 63 | } 64 | return null; 65 | } 66 | } 67 | 68 | export default HtmlWebpackAssertPlugin; 69 | -------------------------------------------------------------------------------- /example/editor/canvas/cursor.ts: -------------------------------------------------------------------------------- 1 | /* 光标的一些属性参数 */ 2 | export interface CursorOptions { 3 | width?: number; 4 | height?: number; 5 | fillStyle?: string; 6 | } 7 | 8 | /* 光标 */ 9 | class Cursor { 10 | height: number; 11 | width: number; 12 | fillStyle: string; 13 | ctx: CanvasRenderingContext2D; 14 | imgData: ImageData; 15 | left: number; 16 | bottom: number; 17 | blinkOn: number; 18 | blinkOff: number; 19 | lastShowTime: number; 20 | timer: number; 21 | constructor(ctx, options: CursorOptions = {}) { 22 | this.ctx = ctx; 23 | this.width = options.width || 1; 24 | this.height = options.height || this.getHeight(); 25 | this.fillStyle = 'rgba(0,0,0,0.8)'; 26 | this.blinkOn = 500; 27 | this.blinkOff = 500; 28 | this.lastShowTime = 0; 29 | } 30 | 31 | /* 获取当前字体的大致高度 */ 32 | private getHeight() { 33 | let { ctx } = this; 34 | let h = ctx.measureText('M').width; 35 | return h + h / 6; 36 | } 37 | 38 | /* 擦掉光标 */ 39 | private erase() { 40 | let { ctx, imgData, width, height, left, bottom } = this; 41 | if (imgData) { 42 | ctx.putImageData(imgData, 0, 0, left - 1, bottom - height - 1, width + 2, height + 2); 43 | } 44 | } 45 | 46 | /* 绘制光标 */ 47 | private draw() { 48 | let { ctx, left, bottom, width, height, fillStyle } = this; 49 | ctx.save(); 50 | ctx.fillStyle = fillStyle; 51 | ctx.lineWidth = width; 52 | ctx.fillRect(left, bottom - height, width, height); 53 | ctx.restore(); 54 | } 55 | 56 | /* 闪烁光标 */ 57 | private blink(time: number) { 58 | let { ctx, blinkOn, blinkOff, lastShowTime } = this; 59 | let delta = time - lastShowTime; 60 | if (delta > blinkOn + blinkOff) { 61 | this.draw(); 62 | this.lastShowTime = time; 63 | } else if (delta > blinkOn) { 64 | this.erase(); 65 | } 66 | this.timer = window.requestAnimationFrame(this.blink.bind(this)); 67 | } 68 | 69 | /* 绘制光标 */ 70 | public move(left: number, bottom: number) { 71 | let { ctx, width, height, timer } = this; 72 | this.erase(); 73 | this.imgData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height); 74 | this.left = left; 75 | this.bottom = bottom; 76 | this.lastShowTime = 0; 77 | window.cancelAnimationFrame(timer); 78 | this.blink(performance.now()); 79 | } 80 | } 81 | 82 | export default Cursor; 83 | -------------------------------------------------------------------------------- /example/animate/canvas/ball.ts: -------------------------------------------------------------------------------- 1 | type Behavior = (ball: Ball, elapsed: number) => void; 2 | 3 | class Ball { 4 | public behaviors: Behavior[]; 5 | public radius: number; 6 | public x: number; 7 | public y: number; 8 | public rotate: number; 9 | public offset: number; 10 | public moveSpeed: number; 11 | public rotateSpeed: number; 12 | constructor(x: number, y: number, radius: number) { 13 | this.x = x; 14 | this.y = y; 15 | this.radius = radius; 16 | this.rotate = 0; 17 | this.offset = 0; 18 | this.moveSpeed = 0; 19 | this.rotateSpeed = 0; 20 | this.behaviors = []; 21 | } 22 | 23 | /* 设置移动速度 */ 24 | public setMoveSpeed(speed: number) { 25 | this.moveSpeed = speed; 26 | this.setRotateSpeed(speed / this.radius); 27 | } 28 | 29 | /* 设置旋转速度 */ 30 | public setRotateSpeed(speed: number) { 31 | this.rotateSpeed = speed; 32 | } 33 | 34 | /* 添加小球 */ 35 | public addBehavior(behavior: Behavior | Behavior[]) { 36 | if (Array.isArray(behavior)) { 37 | this.behaviors = [...this.behaviors, ...behavior]; 38 | } else { 39 | this.behaviors = [...this.behaviors, behavior]; 40 | } 41 | } 42 | 43 | /* 更新小球 */ 44 | public update(elapsed: number) { 45 | for (let behavior of this.behaviors) { 46 | behavior.call(null, this, elapsed); 47 | } 48 | } 49 | 50 | /* 绘制小球 */ 51 | public render(ctx: CanvasRenderingContext2D) { 52 | let { x, y, radius, rotate, offset } = this; 53 | ctx.save(); 54 | ctx.translate(x + offset, y); 55 | ctx.rotate(rotate); 56 | ctx.beginPath(); 57 | ctx.arc(0, 0, radius, 0, Math.PI * 2, false); 58 | ctx.moveTo(-radius, 0); 59 | ctx.lineTo(radius, 0); 60 | ctx.moveTo(0, -radius); 61 | ctx.lineTo(0, radius); 62 | ctx.fill(); 63 | ctx.stroke(); 64 | ctx.restore(); 65 | } 66 | 67 | /* 重置 */ 68 | public reset() { 69 | this.rotate = 0; 70 | this.offset = 0; 71 | } 72 | 73 | /* 旋转 */ 74 | static rotate(ball: Ball, elapsed: number) { 75 | let angle = ball.rotateSpeed * elapsed; 76 | angle = angle % (Math.PI * 2); 77 | ball.rotate = angle; 78 | } 79 | 80 | /* 移动 */ 81 | static move(ball: Ball, elapsed: number) { 82 | let { moveSpeed } = ball; 83 | let distance = ball.moveSpeed * elapsed; 84 | ball.offset = distance; 85 | } 86 | } 87 | 88 | export default Ball; 89 | -------------------------------------------------------------------------------- /config/webpack.pro.ts: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'production'; 2 | 3 | import webpack from 'webpack'; 4 | import merge from 'webpack-merge'; 5 | import CleanWebpackPlugin from 'clean-webpack-plugin'; 6 | import UglifyJsPlugin from 'uglifyjs-webpack-plugin'; 7 | import HtmlWebpackPlugin from 'html-webpack-plugin'; 8 | import WorkboxPlugin from 'workbox-webpack-plugin'; 9 | import { resolveByRootDir, DIST } from '../script/util'; 10 | import baseConfig from './webpack.base'; 11 | 12 | const config: webpack.Configuration = { 13 | mode: 'production', 14 | devtool: false, 15 | output: { 16 | path: resolveByRootDir(DIST), 17 | filename: '[name].[chunkhash].js', 18 | publicPath: '/canvas-demo/' + DIST + '/', 19 | }, 20 | optimization: { 21 | runtimeChunk: 'single', 22 | minimize: true, 23 | minimizer: [ 24 | new UglifyJsPlugin({ 25 | sourceMap: false, 26 | cache: true, 27 | uglifyOptions: { 28 | ecma: 6, 29 | mangle: true, 30 | compress: { 31 | drop_debugger: true, 32 | }, 33 | }, 34 | }), 35 | ], 36 | splitChunks: { 37 | chunks: 'all', 38 | }, 39 | }, 40 | module: { 41 | rules: [ 42 | { 43 | test: /\.s?css$/, 44 | use: [ 45 | { loader: 'style-loader' }, 46 | { 47 | loader: 'css-loader', 48 | options: { 49 | minimize: true, 50 | importLoaders: 2, 51 | modules: true, 52 | sourceMap: false, 53 | }, 54 | }, 55 | { 56 | loader: 'postcss-loader', 57 | }, 58 | { 59 | loader: 'sass-loader', 60 | }, 61 | ], 62 | }, 63 | ], 64 | }, 65 | plugins: [ 66 | new CleanWebpackPlugin([DIST], { root: resolveByRootDir() }), 67 | new HtmlWebpackPlugin({ 68 | template: 'template.html', 69 | filename: '../index.html', 70 | }), 71 | new webpack.HashedModuleIdsPlugin(), 72 | new WorkboxPlugin.GenerateSW({ 73 | // these options encourage the ServiceWorkers to get in there fast 74 | // and not allow any straggling "old" SWs to hang around 75 | clientsClaim: true, 76 | skipWaiting: true, 77 | importWorkboxFrom: 'local', 78 | importsDirectory: 'workbox', 79 | exclude: [/\.htm$/, /\.html$/], 80 | }), 81 | ], 82 | }; 83 | 84 | export default merge(baseConfig, config); 85 | -------------------------------------------------------------------------------- /dist/29.cb22759ea651dd5594f1.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[29],{"0Pcb":function(t,i,e){"use strict";const n=function(){const t=window.navigator.userAgent;return window.location.href,function(t){const i={},e=t.indexOf("iPhone")>=0||t.indexOf("iPad")>=0||t.indexOf("iPod")>=0,n=t.indexOf("Android")>0;return i.ios=e,i.android=n,i.mobile=e||n,i.pc=!e&&!n,i}(t)}();i.a=n},"K2/Z":function(t,i,e){"use strict";e.r(i);var n=e("Qb4n");i.default=class extends n.a{constructor(t,i,e){super(),this.ctx=this.getContext("2d"),this.images=e,this.marginLeft=20,this.marginTop=Math.floor(this.marginLeft*i/t),this.maxAngle=45,this.angle=this.random(-this.maxAngle,this.maxAngle),this.nextAngle=this.random(-this.maxAngle,this.maxAngle),this.index=-1,this.alpha=1,this.duration=180,this.show=this.duration,this.initCanvasSize(t,i)}random(t,i){return Math.floor(Math.random()*(i-t+1))+t}rotate(t){let{ctx:i}=this;i.rotate(t*Math.PI/180)}translate(){let{ctx:t,width:i,height:e}=this;t.translate(i/2,e/2)}clip(){let{ctx:t,marginLeft:i,marginTop:e,width:n,height:s}=this;t.beginPath(),t.rect(i,e,n-2*i,s-2*e),t.clip()}computeSize(t){let{width:i,height:e}=this,n=t.width;return{dstW:i,dstH:i*t.height/n}}renderImage(){let{ctx:t,width:i,height:e,alpha:n,index:s,images:h}=this,a=h[s],r=h[(this.index+1)%h.length],o=this.computeSize(r),d=o.dstW,c=o.dstH;r&&(t.save(),this.rotate(this.nextAngle),t.globalAlpha=1-n,this.ctx.drawImage(r,-d/2,-c/2,d,c),t.restore()),a&&(t.save(),t.globalAlpha=n,d=(o=this.computeSize(a)).dstW,c=o.dstH,this.rotate(this.angle),this.ctx.drawImage(a,-d/2,-c/2,d,c),t.restore())}render(){let{ctx:t,width:i,height:e,maxAngle:n,images:s}=this;return s.length?(t.clearRect(0,0,i,e),t.save(),this.clip(),this.translate(),this.duration<=0&&(this.alpha=1,this.index+=1,this.angle=this.nextAngle,this.nextAngle=this.random(-n,n),this.duration=this.show),this.duration<30&&(this.alpha-=1/30),this.index>=this.images.length&&(this.index=0),this.duration-=1,this.renderImage(),t.restore(),this):this}}},Qb4n:function(t,i,e){"use strict";var n=e("kZAv");i.a=class{constructor(){this.el=document.createElement("canvas")}initCanvasSize(t,i){this.el.width=t,this.el.height=i,this.width=t,this.height=i}getContext(t,i){return this.el.getContext(t,i)}render(t){this.container=t;let{width:i,height:e}=t.getBoundingClientRect();this.initCanvasSize(i||n.d,e||n.b),this.container.innerHTML="",this.container.appendChild(this.el)}}},kZAv:function(t,i,e){"use strict";e.d(i,"d",function(){return n}),e.d(i,"b",function(){return s}),e.d(i,"a",function(){return h}),e.d(i,"c",function(){return a});const n=500,s=500,h=`${e("0Pcb").a.pc?24:16}px sans-serif`,a="https://snayan.github.io/canvas-demo/"}}]); -------------------------------------------------------------------------------- /dist/24.2d62ae5a92ed2b0cf06d.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[24],{"0Pcb":function(e,t,i){"use strict";const n=function(){const e=window.navigator.userAgent;return window.location.href,function(e){const t={},i=e.indexOf("iPhone")>=0||e.indexOf("iPad")>=0||e.indexOf("iPod")>=0,n=e.indexOf("Android")>0;return t.ios=i,t.android=n,t.mobile=i||n,t.pc=!i&&!n,t}(e)}();t.a=n},"1atV":function(e,t,i){"use strict";i.r(t);var n=i("Qb4n");t.default=class extends n.a{constructor(){super(),this.shapeWidth=100,this.shapeHeight=100,this.shapeCount=6,this.shapes=[],this.ctx=this.getContext("2d")}calculate(){let{width:e,height:t,shapeWidth:i,shapeHeight:n,shapeCount:o,shapes:s}=this,a=Math.min(Math.floor(e/i),4),h=(e-a*i)/(a+1),r=Math.ceil(o/a);for(;h<20&&a>1;)a-=1,r=Math.ceil(o/a),h=(e-a*i)/(a+1);let c=(t-n*r-h*(r-1))/2;for(let e=0;e=o);t++)s.push({x:(t+1)*h+t*i,y:c+e*(n+h)});this.shapes=s}drawShapes(){let{shapes:e,shapeWidth:t,shapeHeight:i,ctx:n}=this;n.save(),n.lineWidth=.5;let o,s,a=0,h=e[a++];o=h.x,s=h.y,n.beginPath(),n.moveTo(o+t/2,s),n.lineTo(o,s+i),n.lineTo(o+t,s+i),n.closePath(),n.stroke();let r=e[a++];o=r.x,s=r.y,n.beginPath(),n.rect(o,s,t,i),n.closePath(),n.stroke();let c=e[a++];o=c.x,s=c.y,n.beginPath(),n.moveTo(o+20,s),n.lineTo(o+t-20,s),n.arcTo(o+t,s,o+t,s+20,20),n.lineTo(o+t,s+i-20),n.arcTo(o+t,s+i,o+t-20,s+i,20),n.lineTo(o+20,s+i),n.arcTo(o,s+i,o,s+i-20,20),n.lineTo(o,s+20),n.arcTo(o,s,o+20,s,20),n.stroke(),n.save(),n.setLineDash([2,2]);let l=e[a++];o=l.x,s=l.y,n.beginPath(),n.moveTo(o+30,s),n.lineTo(o+t-30,s),n.arcTo(o+t,s,o+t,s+30,30),n.lineTo(o+t,s+i-30),n.arcTo(o+t,s+i,o+t-30,s+i,30),n.lineTo(o+30,s+i),n.arcTo(o,s+i,o,s+i-30,30),n.lineTo(o,s+30),n.arcTo(o,s,o+30,s,30),n.stroke(),n.restore();let d=e[a++];o=d.x,s=d.y,n.beginPath(),n.moveTo(o+20,s),n.lineTo(o+t-20,s),n.lineTo(o+t,s+20),n.lineTo(o+t,s+i-20),n.lineTo(o+t-20,s+i),n.lineTo(o+20,s+i),n.lineTo(o,s+i-20),n.lineTo(o,s+20),n.closePath(),n.stroke();let u=e[a++];o=u.x,s=u.y;let T=Math.min(t/2,i/2);n.beginPath(),n.arc(o+T,s+T,T,0,2*Math.PI,!1),n.stroke()}render(e){super.render(e),this.calculate(),this.drawShapes()}}},Qb4n:function(e,t,i){"use strict";var n=i("kZAv");t.a=class{constructor(){this.el=document.createElement("canvas")}initCanvasSize(e,t){this.el.width=e,this.el.height=t,this.width=e,this.height=t}getContext(e,t){return this.el.getContext(e,t)}render(e){this.container=e;let{width:t,height:i}=e.getBoundingClientRect();this.initCanvasSize(t||n.d,i||n.b),this.container.innerHTML="",this.container.appendChild(this.el)}}},kZAv:function(e,t,i){"use strict";i.d(t,"d",function(){return n}),i.d(t,"b",function(){return o}),i.d(t,"a",function(){return s}),i.d(t,"c",function(){return a});const n=500,o=500,s=`${i("0Pcb").a.pc?24:16}px sans-serif`,a="https://snayan.github.io/canvas-demo/"}}]); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "canvas-demo", 3 | "version": "1.0.0", 4 | "description": "canvas demo ", 5 | "main": "index.ts", 6 | "scripts": { 7 | "build": " ts-node --project tsconfig.webpack.json script/build.ts", 8 | "start": " ts-node --project tsconfig.webpack.json script/start.ts", 9 | "test": "jest --bail --coverage" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/snayan/canvas-demo.git" 14 | }, 15 | "keywords": [ 16 | "canvas", 17 | "game", 18 | "h5" 19 | ], 20 | "author": "snayan", 21 | "license": "MIT", 22 | "bugs": { 23 | "url": "https://github.com/snayan/canvas-demo/issues" 24 | }, 25 | "homepage": "https://github.com/snayan/canvas-demo#readme", 26 | "dependencies": { 27 | "@types/clean-webpack-plugin": "^0.1.2", 28 | "@types/html-webpack-plugin": "^2.30.3", 29 | "@types/node": "^10.0.3", 30 | "@types/ora": "^1.3.4", 31 | "@types/webpack": "^4.1.4", 32 | "@types/webpack-dev-server": "^2.9.4", 33 | "@types/webpack-merge": "^4.1.3", 34 | "chalk": "^2.4.1", 35 | "clean-webpack-plugin": "^0.1.19", 36 | "css-loader": "^0.28.11", 37 | "file-loader": "^1.1.11", 38 | "html-webpack-inline-source-plugin": "^0.0.10", 39 | "html-webpack-plugin": "^3.2.0", 40 | "inline-chunk-manifest-html-webpack-plugin": "^2.0.0", 41 | "js-base64": "^2.4.3", 42 | "mini-css-extract-plugin": "^0.4.0", 43 | "node-sass": "^4.9.0", 44 | "opn": "^5.3.0", 45 | "ora": "^2.1.0", 46 | "portfinder": "^1.0.13", 47 | "postcss-cssnext": "^3.1.0", 48 | "postcss-import": "^11.1.0", 49 | "postcss-loader": "^2.1.5", 50 | "postcss-reporter": "^5.0.0", 51 | "prismjs": "^1.14.0", 52 | "sass-loader": "^7.0.1", 53 | "style-loader": "^0.21.0", 54 | "stylelint": "^9.2.0", 55 | "stylelint-config-standard": "^18.2.0", 56 | "ts-loader": "^4.3.0", 57 | "ts-node": "^6.0.2", 58 | "tsconfig-paths": "^3.3.1", 59 | "typescript": "^2.8.3", 60 | "typings-for-css-modules-loader": "^1.7.0", 61 | "uglifyjs-webpack-plugin": "^1.2.6", 62 | "webpack": "^4.6.0", 63 | "webpack-dev-server": "^3.1.4", 64 | "webpack-merge": "^4.1.2", 65 | "workbox-webpack-plugin": "^3.3.0" 66 | }, 67 | "sideEffects": [ 68 | "*.css", 69 | "*.scss" 70 | ], 71 | "devDependencies": { 72 | "@types/jest": "^23.1.1", 73 | "jest": "^23.1.0", 74 | "ts-jest": "^22.4.6" 75 | }, 76 | "jest": { 77 | "transform": { 78 | "^.+\\.tsx?$": "ts-jest" 79 | }, 80 | "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 81 | "moduleFileExtensions": [ 82 | "ts", 83 | "tsx", 84 | "js", 85 | "jsx", 86 | "json", 87 | "node" 88 | ] 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /example/loading/index.ts: -------------------------------------------------------------------------------- 1 | interface LoadingOptions { 2 | radius?: number; 3 | count?: number; 4 | duration?: number; 5 | margin?: number; 6 | } 7 | 8 | class LoadingCanvas { 9 | ctx: CanvasRenderingContext2D; 10 | radius: number; 11 | count: number; 12 | color: string; 13 | index: number; 14 | duration: number; 15 | show: number; 16 | margin: number; 17 | point: number[]; 18 | isLoading: boolean; 19 | constructor(ctx: CanvasRenderingContext2D, options: LoadingOptions = {}) { 20 | this.ctx = ctx; 21 | this.radius = options.radius || 5; 22 | this.count = options.count || 6; 23 | this.duration = options.duration || 8; 24 | this.margin = options.margin || 10; 25 | this.color = '#f48041'; 26 | this.index = 0; 27 | this.show = this.duration; 28 | this.point = this.computerPoint(); 29 | this.isLoading = false; 30 | } 31 | /* 创建坐标 */ 32 | private computerPoint() { 33 | let point = []; 34 | let { ctx, count, radius, margin } = this; 35 | let totalLength = count * radius * 2 + (count - 1) * margin; 36 | let left = (ctx.canvas.width - totalLength) / 2; 37 | for (let i = 0; i < count; i++) { 38 | point[i] = left + radius + (radius * 2 + margin) * i; 39 | } 40 | return point; 41 | } 42 | /* 绘制圆点 */ 43 | private renderArc(index, scale) { 44 | let { ctx, radius, point } = this; 45 | let x = point[index]; 46 | let y = ctx.canvas.height / 2; 47 | ctx.save(); 48 | ctx.beginPath(); 49 | ctx.arc(x, y, radius * scale, 0, Math.PI * 2); 50 | ctx.fill(); 51 | ctx.restore(); 52 | } 53 | /* 开始loading */ 54 | private startLoading() { 55 | let { index, count, margin, duration, show } = this; 56 | for (let i = 0; i < count; i++) { 57 | if (i === index) { 58 | this.renderArc(i, 0.8 + (0.6 * duration) / show); 59 | } else { 60 | this.renderArc(i, 0.8); 61 | } 62 | } 63 | } 64 | 65 | private animate() { 66 | let { ctx, color, count, show } = this; 67 | if (this.duration < 1) { 68 | this.duration = show; 69 | this.index += 1; 70 | } 71 | if (this.index >= count) { 72 | this.index = 0; 73 | } 74 | this.duration -= 1; 75 | ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); 76 | if (this.isLoading) { 77 | ctx.save(); 78 | ctx.fillStyle = color; 79 | this.startLoading(); 80 | ctx.restore(); 81 | window.requestAnimationFrame(this.animate.bind(this)); 82 | } 83 | } 84 | 85 | /* 开始loading */ 86 | public start() { 87 | this.isLoading = true; 88 | this.animate(); 89 | } 90 | 91 | /* 停止loading */ 92 | public stop() { 93 | let { ctx } = this; 94 | this.isLoading = false; 95 | } 96 | } 97 | 98 | export default LoadingCanvas; 99 | -------------------------------------------------------------------------------- /example/collide_01/canvas/collide.ts: -------------------------------------------------------------------------------- 1 | /* 外接图形判别法 */ 2 | 3 | import { distance } from 'common/util'; 4 | import Sprite, { RectSprite, CircleSprite } from './sprite'; 5 | 6 | export default class Collide { 7 | constructor() { 8 | if (this instanceof Collide) { 9 | return this; 10 | } 11 | return new Collide(); 12 | } 13 | 14 | /* 检查是否满足判断碰撞的条件 15 | 比如,可以过滤掉不可见sprite,或者在当前帧下根本就不会发送碰撞, 16 | 常用手法:空间分割法 17 | */ 18 | public isCandidateForCollide(sprite: Sprite, otherSprite: Sprite) { 19 | return sprite.visible && otherSprite.visible && sprite !== otherSprite; 20 | } 21 | 22 | /* 判断是否发生碰撞 */ 23 | public didCollide(sprite: Sprite, otherSprite: Sprite) { 24 | let sType = sprite.type; 25 | let oType = otherSprite.type; 26 | if (sType === 'rect' && oType === 'rect') { 27 | return this.didRectCollide(sprite as RectSprite, otherSprite as RectSprite); 28 | } else if (sType === 'circle' && oType === 'circle') { 29 | return this.didCircleCollide(sprite as CircleSprite, otherSprite as CircleSprite); 30 | } else if (sType === 'rect') { 31 | return this.didRectWidthCircleCollide(sprite as RectSprite, otherSprite as CircleSprite); 32 | } else { 33 | return this.didRectWidthCircleCollide(otherSprite as RectSprite, sprite as CircleSprite); 34 | } 35 | } 36 | 37 | /* 判断是否两个矩形发生碰撞 */ 38 | private didRectCollide(sprite: RectSprite, otherSprite: RectSprite) { 39 | let horizontal = sprite.left + sprite.width > otherSprite.left && sprite.left < otherSprite.left + otherSprite.width; 40 | let vertical = sprite.top < otherSprite.top + otherSprite.height && sprite.top + sprite.height > otherSprite.top; 41 | return horizontal && vertical; 42 | } 43 | 44 | /* 判断是否两个圆发生碰撞 */ 45 | private didCircleCollide(sprite: CircleSprite, otherSprite: CircleSprite) { 46 | return distance(sprite.x, sprite.y, otherSprite.x, otherSprite.y) < sprite.radius + otherSprite.radius; 47 | } 48 | 49 | /* 判断是否矩形和圆形发生碰撞 */ 50 | private didRectWidthCircleCollide(rectSprite: RectSprite, circleSprite: CircleSprite) { 51 | let closePoint = { x: undefined, y: undefined }; 52 | if (circleSprite.x < rectSprite.left) { 53 | closePoint.x = rectSprite.left; 54 | } else if (circleSprite.x < rectSprite.left + rectSprite.width) { 55 | closePoint.x = circleSprite.x; 56 | } else { 57 | closePoint.x = rectSprite.left + rectSprite.width; 58 | } 59 | if (circleSprite.y < rectSprite.top) { 60 | closePoint.y = rectSprite.top; 61 | } else if (circleSprite.y < rectSprite.top + rectSprite.height) { 62 | closePoint.y = circleSprite.y; 63 | } else { 64 | closePoint.y = rectSprite.top + rectSprite.height; 65 | } 66 | return distance(circleSprite.x, circleSprite.y, closePoint.x, closePoint.y) < circleSprite.radius; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-routing.prod.js: -------------------------------------------------------------------------------- 1 | this.workbox=this.workbox||{},this.workbox.routing=function(t,e){"use strict";try{self.workbox.v["workbox:routing:3.3.0"]=1}catch(t){}const r="GET";var s=t=>t&&"object"==typeof t?t:{handle:t};class n{constructor(t,e,n){this.handler=s(e),this.match=t,this.method=n||r}}class o extends n{constructor(t,e,r){super(({url:e})=>{const r=t.exec(e.href);return r?e.origin!==location.origin&&0!==r.index?null:r.slice(1):null},e,r)}}class i{constructor(){this.t=new Map}handleRequest(t){const e=new URL(t.request.url);if(!e.protocol.startsWith("http"))return;let r=null,s=null,n=null;const o=this.e(t,e);if(s=o.handler,n=o.params,r=o.route,!s&&this.r&&(s=this.r),!s)return;let i;try{i=s.handle({url:e,event:t,params:n})}catch(t){i=Promise.reject(t)}return i&&this.s&&(i=i.catch(r=>this.s.handle({url:e,event:t,err:r}))),i}e(t,e){const r=this.t.get(t.request.method)||[];for(const s of r){let r=s.match({url:e,event:t});if(r)return Array.isArray(r)&&0===r.length?r=void 0:(r.constructor===Object&&0===Object.keys(r).length||!0===r)&&(r=void 0),{route:s,params:r,handler:s.handler}}return{handler:void 0,params:void 0}}setDefaultHandler(t){this.r=s(t)}setCatchHandler(t){this.s=s(t)}registerRoute(t){this.t.has(t.method)||this.t.set(t.method,[]),this.t.get(t.method).push(t)}unregisterRoute(e){if(!this.t.has(e.method))throw new t.WorkboxError("unregister-route-but-not-found-with-method",{method:e.method});const r=this.t.get(e.method).indexOf(e);if(!(r>-1))throw new t.WorkboxError("unregister-route-route-not-registered");this.t.get(e.method).splice(r,1)}}class u extends n{constructor(t,{whitelist:e=[/./],blacklist:r=[]}={}){super((...t)=>this.n(...t),t),this.o=e,this.i=r}n({event:t,url:e}){if("navigate"!==t.request.mode)return!1;const r=e.pathname+e.search;return!this.i.some(t=>t.test(r))&&!!this.o.some(t=>t.test(r))}}var a=Object.freeze({RegExpRoute:o,Route:n,Router:i,NavigationRoute:u});const c=new class extends i{registerRoute(e,r,s="GET"){let i;if("string"==typeof e){const t=new URL(e,location);i=new n(({url:e})=>e.href===t.href,r,s)}else if(e instanceof RegExp)i=new o(e,r,s);else if("function"==typeof e)i=new n(e,r,s);else{if(!(e instanceof n))throw new t.WorkboxError("unsupported-route-type",{moduleName:"workbox-routing",className:"DefaultRouter",funcName:"registerRoute",paramName:"capture"});i=e}return super.registerRoute(i),i}registerNavigationRoute(t,r={}){const s=e.cacheNames.getPrecacheName(r.cacheName),n=new u(()=>caches.match(t,{cacheName:s}).then(e=>{if(e)return e;throw new Error(`The cache ${s} did not have an entry for `+`${t}.`)}).catch(e=>fetch(t)),{whitelist:r.whitelist,blacklist:r.blacklist});return super.registerRoute(n),n}};return self.addEventListener("fetch",t=>{const e=c.handleRequest(t);e&&t.respondWith(e)}),Object.assign(c,a)}(workbox.core._private,workbox.core._private); 2 | 3 | //# sourceMappingURL=workbox-routing.prod.js.map 4 | -------------------------------------------------------------------------------- /dist/27.2b2f82cdb7d3406d095e.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[27,26],{"0Pcb":function(t,i,e){"use strict";const s=function(){const t=window.navigator.userAgent;return window.location.href,function(t){const i={},e=t.indexOf("iPhone")>=0||t.indexOf("iPad")>=0||t.indexOf("iPod")>=0,s=t.indexOf("Android")>0;return i.ios=e,i.android=s,i.mobile=e||s,i.pc=!e&&!s,i}(t)}();i.a=s},HYut:function(t,i,e){"use strict";e.r(i);var s=e("Qb4n"),n=e("d4kT");i.default=class extends s.a{constructor(t,i){super(),this.ctx=this.getContext("2d"),this.meteorCount=50,this.meteors=[],this.initCanvasSize(t,i),this.createMeteor()}createMeteor(){let t,{meteorCount:i,width:e,height:s,ctx:r}=this;for(let e=0;e{t={isBlink:!1,isMeteor:!0},this.meteors.push(new n.default(r,t))},300*e)}drawMeteor(){for(let t of this.meteors)t.render()}render(){let{ctx:t,width:i,height:e}=this;return t.clearRect(0,0,i,e),this.drawMeteor(),this}}},Qb4n:function(t,i,e){"use strict";var s=e("kZAv");i.a=class{constructor(){this.el=document.createElement("canvas")}initCanvasSize(t,i){this.el.width=t,this.el.height=i,this.width=t,this.height=i}getContext(t,i){return this.el.getContext(t,i)}render(t){this.container=t;let{width:i,height:e}=t.getBoundingClientRect();this.initCanvasSize(i||s.d,e||s.b),this.container.innerHTML="",this.container.appendChild(this.el)}}},d4kT:function(t,i,e){"use strict";e.r(i);i.default=class{constructor(t,i){this.renderCtx=t,this.isBlink=!!i.isBlink,this.isMeteor=!!i.isMeteor;let{x:e,y:s}=this.createPoint();this.x=e,this.y=s,this.radius=this.isMeteor?this.random(3,8):this.random(1,3),this.alpha=this.isMeteor?1:this.random(0,1),this.initCanvas()}initCanvas(){let t=this.radius,i=document.createElement("canvas");i.width=2*t,i.height=2*t;let e=i.getContext("2d"),s=e.createRadialGradient(t,t,0,t,t,t);s.addColorStop(.25,"#fff"),s.addColorStop(.4,"#ccc"),s.addColorStop(.9,"hsl(217, 61%, 33%)"),s.addColorStop(1,"transparent"),e.fillStyle=s,e.beginPath(),e.arc(t,t,t,0,2*Math.PI),e.fill(),this.canvas=i}random(t,i){return Math.floor(Math.random()*(i-t+1))+t}createPoint(){let{renderCtx:t,isMeteor:i,radius:e}=this,{width:s,height:n}=t.canvas;return{x:this.random(0,i?2*s:s),y:i?-3:this.random(0,n)}}blink(){this.isBlink&&(this.alpha<0?this.alpha+=.01:this.alpha-=.01)}meteor(){let{renderCtx:t}=this,{width:i,height:e}=t.canvas;if(this.x<0||this.y>e){let{x:t,y:i}=this.createPoint();this.x=t,this.y=i}this.x-=1*this.radius/10,this.y+=2*this.radius/10}render(){let{renderCtx:t,canvas:i,isMeteor:e,isBlink:s}=this;return s&&this.blink(),e&&this.meteor(),t.save(),t.globalAlpha=this.alpha,t.drawImage(i,this.x,this.y,this.radius,this.radius),t.restore(),this}}},kZAv:function(t,i,e){"use strict";e.d(i,"d",function(){return s}),e.d(i,"b",function(){return n}),e.d(i,"a",function(){return r}),e.d(i,"c",function(){return h});const s=500,n=500,r=`${e("0Pcb").a.pc?24:16}px sans-serif`,h="https://snayan.github.io/canvas-demo/"}}]); -------------------------------------------------------------------------------- /common/util.ts: -------------------------------------------------------------------------------- 1 | import storage from 'common/storage'; 2 | 3 | /* translate query to object */ 4 | export function getQuery() { 5 | let search = window.location.search; 6 | let query = Object.create(null); 7 | if (!search) { 8 | return query; 9 | } 10 | let reg = /[\?|&](\w+)=(\w+)/g; 11 | let matches = null; 12 | while ((matches = reg.exec(search))) { 13 | query[matches[1]] = matches[2]; 14 | } 15 | return query; 16 | } 17 | 18 | /* if there is single module */ 19 | export function isSingleModule(m: string) { 20 | let query = getQuery(); 21 | return query && query.module === m; 22 | } 23 | 24 | /* translate window point to canvas point */ 25 | export function windowToCanvas(canvas: HTMLCanvasElement, x, y) { 26 | let box = canvas.getBoundingClientRect(); 27 | return { x: x - box.left * (canvas.width / box.width), y: y - box.top * (canvas.height / box.height) }; 28 | } 29 | 30 | /* export random between min and max */ 31 | export function random(min, max) { 32 | return Math.random() * (max - min) + min; 33 | } 34 | 35 | /* The distance between two points */ 36 | export function distance(x1: number, y1: number, x2: number, y2: number) { 37 | let x = Math.abs(x1 - x2); 38 | let y = Math.abs(y1 - y2); 39 | return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); 40 | } 41 | 42 | /* throttle function */ 43 | export function throttle(fn, delay) { 44 | let lastTime = Date.now(); 45 | let timer = null; 46 | return function(...args) { 47 | let currentTime = Date.now(); 48 | if (currentTime - lastTime > delay) { 49 | window.clearTimeout(timer); 50 | fn.apply(null, args); 51 | lastTime = currentTime; 52 | } 53 | window.clearTimeout(timer); 54 | timer = setTimeout(() => { 55 | fn.apply(null, args); 56 | lastTime = currentTime; 57 | }, delay); 58 | }; 59 | } 60 | 61 | /* 是否支持passive */ 62 | export const isSupportPassive = (function() { 63 | const IS_SUPPORT_PASSIVE = 'IS_SUPPORT_PASSIVE'; 64 | let isSupportPassive = storage.get(IS_SUPPORT_PASSIVE); 65 | if (isSupportPassive != null) { 66 | return isSupportPassive; 67 | } 68 | try { 69 | let opts = Object.defineProperty({}, 'passive', { 70 | get: function() { 71 | isSupportPassive = true; 72 | }, 73 | }); 74 | window.addEventListener('testPassive', null, opts); 75 | window.removeEventListener('testPassive', null, opts); 76 | } catch (e) {} 77 | storage.set(IS_SUPPORT_PASSIVE, isSupportPassive); 78 | return isSupportPassive; 79 | })(); 80 | 81 | /* 保留小数位 */ 82 | export function RoundDecimal(value: number, digital: number = 2) { 83 | digital = Math.max(0, digital); 84 | return Number(value.toFixed(digital)); 85 | } 86 | 87 | /* 转换弧度为角度 */ 88 | export function transToAngle(radian: number) { 89 | return (180 * radian) / Math.PI; 90 | } 91 | 92 | /* 转换角度为弧度 */ 93 | export function transToRadian(angle: number) { 94 | return (Math.PI * angle) / 180; 95 | } 96 | -------------------------------------------------------------------------------- /example/collide_02/canvas/index.ts: -------------------------------------------------------------------------------- 1 | import Canvas from 'common/canvas'; 2 | import browser from 'common/browser'; 3 | import { windowToCanvas } from 'common/util'; 4 | import Game from './game'; 5 | 6 | export default class CollideCanvas extends Canvas { 7 | game: Game; 8 | constructor() { 9 | super(); 10 | } 11 | 12 | /* touch start or mouse down */ 13 | private startMove({ x, y }) { 14 | let { game } = this; 15 | if (!game.isBallFlying) { 16 | game.isLaunching = true; 17 | game.lastMouseX = x; 18 | game.lastMouseY = y; 19 | game.calculateInitLaunchData(); 20 | } 21 | } 22 | 23 | /* touch move or mouse move */ 24 | private moving({ x, y }) { 25 | let { game } = this; 26 | if (game.isLaunching && !game.isBallFlying) { 27 | let ball = game.ball; 28 | game.lastMouseX = x; 29 | game.lastMouseY = y; 30 | game.calculateInitLaunchData(); 31 | } 32 | } 33 | 34 | /* touch end or mouse up */ 35 | private endMove({ x, y }) { 36 | let { game } = this; 37 | if (game.isLaunching && !game.isBallFlying) { 38 | game.lastMouseX = x; 39 | game.lastMouseY = y; 40 | game.calculateInitLaunchData(); 41 | game.launchBall(); 42 | game.isLaunching = false; 43 | } 44 | } 45 | 46 | /* 暂停/恢复 */ 47 | private togglePause(e: KeyboardEvent) { 48 | if (e.which === 80) { 49 | // 按下p键 50 | let { game } = this; 51 | if (game.isPaused()) { 52 | game.unPause(); 53 | } else { 54 | game.pause(); 55 | } 56 | } 57 | } 58 | 59 | /* 监听事件 */ 60 | private addEventListener() { 61 | let { el } = this; 62 | let handleEvent = (handler: (point: { x: number; y: number }) => void) => (e: MouseEvent | TouchEvent) => { 63 | let x; 64 | let y; 65 | e.preventDefault(); 66 | if (browser.pc) { 67 | e = e as MouseEvent; 68 | x = e.x; 69 | y = e.y; 70 | } else { 71 | e = e as TouchEvent; 72 | x = e.changedTouches[0].pageX; 73 | y = e.changedTouches[0].pageY; 74 | } 75 | handler.call(this, windowToCanvas(el, x, y)); 76 | }; 77 | 78 | el.addEventListener(browser.pc ? 'mousedown' : 'touchstart', handleEvent(this.startMove), false); 79 | el.addEventListener(browser.pc ? 'mousemove' : 'touchmove', handleEvent(this.moving), false); 80 | el.addEventListener(browser.pc ? 'mouseup' : 'touchend', handleEvent(this.endMove), false); 81 | el.addEventListener(browser.pc ? 'mouseleave' : 'touchcancel', handleEvent(this.endMove), false); 82 | if (browser.pc) { 83 | document.addEventListener('keyup', this.togglePause.bind(this), false); 84 | } 85 | } 86 | 87 | /* 渲染 */ 88 | public render(container: HTMLElement) { 89 | super.render(container); 90 | this.addEventListener(); 91 | this.game = new Game('game001', this.getContext('2d')); 92 | this.game.start(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /dist/44.861ee2e30edbf35af9f0.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[44],{G12C:function(t,i,s){"use strict";var e;s.r(i),s.d(i,"Sprite",function(){return h}),s.d(i,"CircleSprite",function(){return a}),s.d(i,"RectSprite",function(){return l}),s.d(i,"ImageSprite",function(){return r}),function(t){t[t.Circle=0]="Circle",t[t.Rect=1]="Rect",t[t.Image=2]="Image"}(e||(e={}));class h{constructor(t,i,s){this.name=t,this.ctx=i,this.isVisible=s.isVisible||!0,this.type=s.type||e.Rect,this.fillStyle=s.fillStyle||this.ctx.fillStyle,this.lineWidth=s.lineWidth||this.ctx.lineWidth,this.strokeStyle=s.strokeStyle||this.ctx.strokeStyle,this.shadowOffsetX=s.shadowOffsetX||this.ctx.shadowOffsetX,this.shadowOffsetY=s.shadowOffsetY||this.ctx.shadowOffsetY,this.shadowBlur=s.shadowBlur||this.ctx.shadowBlur,this.shadowColor=s.shadowColor||this.ctx.shadowColor,this.horizontalVelocity=s.horizontalVelocity||0,this.verticalVelocity=s.verticalVelocity||0,this.behaviors=s.behaviors||[]}applyStyle(){let{ctx:t,fillStyle:i,lineWidth:s,strokeStyle:e,shadowOffsetX:h,shadowOffsetY:a,shadowBlur:l,shadowColor:r}=this;t.fillStyle=i,t.lineWidth=s,t.strokeStyle=e}addBehavior(t){Array.isArray(t)?this.behaviors.concat(t):this.behaviors.push(t)}update(t,i,s){for(let e of this.behaviors)e.execute(this,t,i,s)}draw(){this.artist&&"function"==typeof this.artist.draw&&this.artist.draw(this)}}class a extends h{constructor(t,i,s={}){super(t,i,{...s,type:e.Circle}),this.x=s.x||0,this.y=s.y||0,this.radius=s.radius||10,this.startAngle=s.startAngle||0,this.endAngle=s.endAngle||2*Math.PI,this.anticlockwise=s.anticlockwise||!1,this.artist=s.artist||{draw:function(t){let{ctx:i,x:s,y:e,radius:h,startAngle:a,endAngle:l,anticlockwise:r}=t;i.save(),t.applyStyle(),i.beginPath(),i.arc(s,e,h,a,l,r),i.fill(),i.stroke(),i.restore()}}}}class l extends h{constructor(t,i,s){super(t,i,{...s,type:e.Rect}),this.left=s.left||0,this.top=s.top||0,this.width=s.width||10,this.height=s.height||10,this.artist=s.artist||{draw:function(t){let{ctx:i,left:s,top:e,width:h,height:a}=t;i.save(),t.applyStyle(),i.beginPath(),i.rect(s,e,h,a),i.fill(),i.stroke(),i.restore()}}}}class r extends h{constructor(t,i,s){super(t,i,{...s,type:e.Image,isVisible:!1}),this.src=s.src,this.left=s.left||0,this.top=s.top||0,this.isLoaded=!1,this.isLoading=!1,this.el=document.createElement("img"),this.loadCallBack=s.loadCallBack,this.artist=s.artist||{draw:function(t){let{ctx:i,el:s,left:e,top:h,width:a,height:l}=t;i.save(),t.applyStyle(),i.drawImage(s,e,h,a,l),i.restore()}},this.loadImage()}loadImage(t){if(this.isLoading||this.isLoaded)return;let i=()=>{this.isVisible=!0,this.isLoaded=!0,this.isLoading=!1,this.width||(this.width=this.el.width),this.height||(this.height=this.el.height),"function"==typeof this.loadCallBack&&this.loadCallBack(this),"function"==typeof t&&t.call(this)};this.isLoading=!0,this.el.addEventListener("load",i),this.el.addEventListener("error",i),this.el.src=this.src}async draw(){if(!this.isLoaded)return this.loadImage(this.draw);super.draw()}}}}]); -------------------------------------------------------------------------------- /example/sh/canvas/star.ts: -------------------------------------------------------------------------------- 1 | /* 星星 */ 2 | 3 | interface StarOption { 4 | isBlink?: boolean; 5 | isMeteor?: boolean; 6 | } 7 | 8 | class Star { 9 | x: number; 10 | y: number; 11 | radius: number; 12 | alpha: number; 13 | isBlink: boolean; 14 | isMeteor: boolean; 15 | renderCtx: CanvasRenderingContext2D; 16 | canvas: HTMLCanvasElement; 17 | constructor(renderCtx: CanvasRenderingContext2D, option: StarOption) { 18 | this.renderCtx = renderCtx; 19 | this.isBlink = !!option.isBlink; 20 | this.isMeteor = !!option.isMeteor; 21 | let { x, y } = this.createPoint(); 22 | this.x = x; 23 | this.y = y; 24 | this.radius = this.isMeteor ? this.random(3, 8) : this.random(1, 3); 25 | this.alpha = this.isMeteor ? 1 : this.random(0, 1); 26 | this.initCanvas(); 27 | } 28 | /* 初始化星星canvas */ 29 | private initCanvas() { 30 | let radius = this.radius; 31 | let canvas = document.createElement('canvas'); 32 | canvas.width = radius * 2; 33 | canvas.height = radius * 2; 34 | let starCtx = canvas.getContext('2d'); 35 | let gradient = starCtx.createRadialGradient(radius, radius, 0, radius, radius, radius); 36 | gradient.addColorStop(0.25, '#fff'); 37 | gradient.addColorStop(0.4, '#ccc'); 38 | gradient.addColorStop(0.9, 'hsl(217, 61%, 33%)'); 39 | gradient.addColorStop(1, 'transparent'); 40 | starCtx.fillStyle = gradient; 41 | starCtx.beginPath(); 42 | starCtx.arc(radius, radius, radius, 0, Math.PI * 2); 43 | starCtx.fill(); 44 | this.canvas = canvas; 45 | } 46 | /* 随机数 */ 47 | private random(min, max) { 48 | return Math.floor(Math.random() * (max - min + 1)) + min; 49 | } 50 | /* 创建坐标 */ 51 | private createPoint() { 52 | let { renderCtx, isMeteor, radius } = this; 53 | let { width, height } = renderCtx.canvas; 54 | let x = this.random(0, isMeteor ? width * 2 : width); 55 | let y = isMeteor ? -3 : this.random(0, height); 56 | return { x, y }; 57 | } 58 | /* 闪烁 */ 59 | private blink() { 60 | if (this.isBlink) { 61 | if (this.alpha < 0) { 62 | this.alpha += 0.01; 63 | } else { 64 | this.alpha -= 0.01; 65 | } 66 | } 67 | } 68 | /* 流星 */ 69 | private meteor() { 70 | let { renderCtx } = this; 71 | let { width, height } = renderCtx.canvas; 72 | if (this.x < 0 || this.y > height) { 73 | let { x, y } = this.createPoint(); 74 | this.x = x; 75 | this.y = y; 76 | } 77 | this.x -= 1 * this.radius / 10; 78 | this.y += 2 * this.radius / 10; 79 | } 80 | /* 绘制 */ 81 | public render() { 82 | let { renderCtx, canvas, isMeteor, isBlink } = this; 83 | isBlink && this.blink(); 84 | isMeteor && this.meteor(); 85 | renderCtx.save(); 86 | renderCtx.globalAlpha = this.alpha; 87 | renderCtx.drawImage(canvas, this.x, this.y, this.radius, this.radius); 88 | renderCtx.restore(); 89 | return this; 90 | } 91 | } 92 | 93 | export default Star; 94 | -------------------------------------------------------------------------------- /dist/30.e3e3b3cd97ac5f508b65.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[30,26],{"0Pcb":function(t,i,s){"use strict";const e=function(){const t=window.navigator.userAgent;return window.location.href,function(t){const i={},s=t.indexOf("iPhone")>=0||t.indexOf("iPad")>=0||t.indexOf("iPod")>=0,e=t.indexOf("Android")>0;return i.ios=s,i.android=e,i.mobile=s||e,i.pc=!s&&!e,i}(t)}();i.a=e},LGf6:function(t,i,s){"use strict";s.r(i);var e=s("Qb4n"),n=s("d4kT");i.default=class extends e.a{constructor(t,i){super(),this.ctx=this.getContext("2d"),this.starCount=280,this.stars=[],this.initCanvasSize(t,i),this.createStars()}drawBg(t){t.save(),t.fillStyle="hsla(217, 84%, 6%, 2)",t.fillRect(0,0,this.width,this.height),t.restore()}createStars(){let t,{starCount:i,width:s,height:e,ctx:r}=this;for(let s=0;ss){let{x:t,y:i}=this.createPoint();this.x=t,this.y=i}this.x-=1*this.radius/10,this.y+=2*this.radius/10}render(){let{renderCtx:t,canvas:i,isMeteor:s,isBlink:e}=this;return e&&this.blink(),s&&this.meteor(),t.save(),t.globalAlpha=this.alpha,t.drawImage(i,this.x,this.y,this.radius,this.radius),t.restore(),this}}},kZAv:function(t,i,s){"use strict";s.d(i,"d",function(){return e}),s.d(i,"b",function(){return n}),s.d(i,"a",function(){return r}),s.d(i,"c",function(){return a});const e=500,n=500,r=`${s("0Pcb").a.pc?24:16}px sans-serif`,a="https://snayan.github.io/canvas-demo/"}}]); -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-routing.prod.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"names":[],"mappings":"","sources":["packages/workbox-routing/browser.mjs"],"sourcesContent":["this.workbox=this.workbox||{},this.workbox.routing=function(t,e){\"use strict\";try{self.workbox.v[\"workbox:routing:3.3.0\"]=1}catch(t){}const r=\"GET\";var s=t=>t&&\"object\"==typeof t?t:{handle:t};class n{constructor(t,e,n){this.handler=s(e),this.match=t,this.method=n||r}}class o extends n{constructor(t,e,r){super(({url:e})=>{const r=t.exec(e.href);return r?e.origin!==location.origin&&0!==r.index?null:r.slice(1):null},e,r)}}class i{constructor(){this.t=new Map}handleRequest(t){const e=new URL(t.request.url);if(!e.protocol.startsWith(\"http\"))return;let r=null,s=null,n=null;const o=this.e(t,e);if(s=o.handler,n=o.params,r=o.route,!s&&this.r&&(s=this.r),!s)return;let i;try{i=s.handle({url:e,event:t,params:n})}catch(t){i=Promise.reject(t)}return i&&this.s&&(i=i.catch(r=>this.s.handle({url:e,event:t,err:r}))),i}e(t,e){const r=this.t.get(t.request.method)||[];for(const s of r){let r=s.match({url:e,event:t});if(r)return Array.isArray(r)&&0===r.length?r=void 0:(r.constructor===Object&&0===Object.keys(r).length||!0===r)&&(r=void 0),{route:s,params:r,handler:s.handler}}return{handler:void 0,params:void 0}}setDefaultHandler(t){this.r=s(t)}setCatchHandler(t){this.s=s(t)}registerRoute(t){this.t.has(t.method)||this.t.set(t.method,[]),this.t.get(t.method).push(t)}unregisterRoute(e){if(!this.t.has(e.method))throw new t.WorkboxError(\"unregister-route-but-not-found-with-method\",{method:e.method});const r=this.t.get(e.method).indexOf(e);if(!(r>-1))throw new t.WorkboxError(\"unregister-route-route-not-registered\");this.t.get(e.method).splice(r,1)}}class u extends n{constructor(t,{whitelist:e=[/./],blacklist:r=[]}={}){super((...t)=>this.n(...t),t),this.o=e,this.i=r}n({event:t,url:e}){if(\"navigate\"!==t.request.mode)return!1;const r=e.pathname+e.search;return!this.i.some(t=>t.test(r))&&!!this.o.some(t=>t.test(r))}}var a=Object.freeze({RegExpRoute:o,Route:n,Router:i,NavigationRoute:u});const c=new class extends i{registerRoute(e,r,s=\"GET\"){let i;if(\"string\"==typeof e){const t=new URL(e,location);i=new n(({url:e})=>e.href===t.href,r,s)}else if(e instanceof RegExp)i=new o(e,r,s);else if(\"function\"==typeof e)i=new n(e,r,s);else{if(!(e instanceof n))throw new t.WorkboxError(\"unsupported-route-type\",{moduleName:\"workbox-routing\",className:\"DefaultRouter\",funcName:\"registerRoute\",paramName:\"capture\"});i=e}return super.registerRoute(i),i}registerNavigationRoute(t,r={}){const s=e.cacheNames.getPrecacheName(r.cacheName),n=new u(()=>caches.match(t,{cacheName:s}).then(e=>{if(e)return e;throw new Error(`The cache ${s} did not have an entry for `+`${t}.`)}).catch(e=>fetch(t)),{whitelist:r.whitelist,blacklist:r.blacklist});return super.registerRoute(n),n}};return self.addEventListener(\"fetch\",t=>{const e=c.handleRequest(t);e&&t.respondWith(e)}),Object.assign(c,a)}(workbox.core._private,workbox.core._private);\n"],"file":"workbox-routing.prod.js"} -------------------------------------------------------------------------------- /script/start.ts: -------------------------------------------------------------------------------- 1 | import process from 'process'; 2 | import webpack from 'webpack'; 3 | import webpackDevServer from 'webpack-dev-server'; 4 | import portfinder from 'portfinder'; 5 | import chalk from 'chalk'; 6 | import ora from 'ora'; 7 | import config from '../config/webpack.dev'; 8 | import { clearConsole, openBrowser, formatMessage } from './util'; 9 | 10 | const isInteractive = process.stdout.isTTY; 11 | 12 | let spinner = new ora(); 13 | spinner.start('start server\n'); 14 | 15 | let serverConfig: webpackDevServer.Configuration = { 16 | clientLogLevel: 'warning', 17 | compress: true, 18 | historyApiFallback: true, 19 | inline: true, 20 | open: true, 21 | overlay: { 22 | warnings: true, 23 | errors: true, 24 | }, 25 | hot: true, 26 | port: 8080, 27 | host: 'localhost', 28 | quiet: true, 29 | ...config.devServer, 30 | }; 31 | 32 | webpackDevServer.addDevServerEntrypoints(config, serverConfig); 33 | 34 | portfinder 35 | .getPortPromise({ port: serverConfig.port, host: serverConfig.host }) 36 | .then((port: number) => { 37 | let url = `http://${serverConfig.host}:${port}`; 38 | let compiler = webpack(config); 39 | 40 | // "invalid" event fires when you have changed a file, and Webpack is 41 | // recompiling a bundle. WebpackDevServer takes care to pause serving the 42 | // bundle, so if you refresh, it'll wait instead of serving the old one. 43 | // "invalid" is short for "bundle invalidated", it doesn't imply any errors. 44 | compiler.hooks.invalid.tap('invalid', () => { 45 | if (isInteractive) { 46 | clearConsole(); 47 | } 48 | console.log('Compiling...'); 49 | }); 50 | 51 | // "done" event fires when Webpack has finished recompiling the bundle. 52 | // Whether or not you have warnings or errors, you will get this event. 53 | compiler.hooks.done.tap('done', (stats) => { 54 | let message = formatMessage(stats); 55 | if (stats.hasErrors()) { 56 | console.log(chalk.red('compile error occur:\n')); 57 | console.log(message + '\n\n'); 58 | return; 59 | } 60 | if (stats.hasWarnings()) { 61 | console.log(chalk.red('compile warn occur:\n')); 62 | console.log(message + '\n\n'); 63 | } 64 | console.log(chalk.green(`application is running here:`, url)); 65 | }); 66 | compiler.hooks.run.tap('run', (compilation) => { 67 | let message = formatMessage(compilation.getStats()); 68 | process.stdout.write(message + '\n\n'); 69 | }); 70 | let server = new webpackDevServer(compiler, serverConfig); 71 | 72 | server.listen(port, serverConfig.host, (err) => { 73 | spinner.stop(); 74 | if (err) { 75 | process.stdout.write(JSON.stringify(err)); 76 | process.exit(1); 77 | } 78 | if (isInteractive) { 79 | clearConsole(); 80 | } 81 | openBrowser(url); 82 | }); 83 | }) 84 | .catch((err) => { 85 | process.stdout.write(JSON.stringify(err)); 86 | process.exit(1); 87 | }); 88 | -------------------------------------------------------------------------------- /dist/40.aeb3dfabd1530c8c8464.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[40,39,41],{Vz5x:function(t,e,i){"use strict";i.r(e),i.d(e,"default",function(){return l}),i.d(e,"Polygon",function(){return a}),i.d(e,"Circle",function(){return h});var s=i("honw"),n=i("iSVj"),r=i("ysz4");class l{constructor({type:t,fillStyle:e,name:i="anonymous",visible:s=!1}={}){this.type=t,this.name=i,this.visible=s,this.fillStyle=e}}class a extends l{constructor(t){super(t),this.type="rect",this.edges=t.edges,this.radius=t.radius,this.x=t.x,this.y=t.y,this.createPoint()}createPoint(){let{x:t,y:e,edges:i,radius:s}=this,n=2*Math.PI/i,r=[];for(let l=0;l({x:i.x+t,y:i.y+e}))}}class h extends l{constructor(t){super(t),this.type="circle",this.x=t.x,this.y=t.y,this.radius=t.radius}render(t){t.save(),t.fillStyle=this.fillStyle,t.beginPath(),t.arc(this.x,this.y,this.radius,0,2*Math.PI,!1),t.fill(),t.restore()}getAxes(t){let{x:e,y:i}=this,n=null,l=Number.MAX_SAFE_INTEGER;for(let[s,a]of t.points.entries()){let t=Object(r.a)(e,i,a.x,a.y);tt.min&&t.max>this.min}}}}]); -------------------------------------------------------------------------------- /dist/31.e009360861da5a3394e0.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[31,25],{"0Pcb":function(t,e,i){"use strict";const s=function(){const t=window.navigator.userAgent;return window.location.href,function(t){const e={},i=t.indexOf("iPhone")>=0||t.indexOf("iPad")>=0||t.indexOf("iPod")>=0,s=t.indexOf("Android")>0;return e.ios=i,e.android=s,e.mobile=i||s,e.pc=!i&&!s,e}(t)}();e.a=s},Qb4n:function(t,e,i){"use strict";var s=i("kZAv");e.a=class{constructor(){this.el=document.createElement("canvas")}initCanvasSize(t,e){this.el.width=t,this.el.height=e,this.width=t,this.height=e}getContext(t,e){return this.el.getContext(t,e)}render(t){this.container=t;let{width:e,height:i}=t.getBoundingClientRect();this.initCanvasSize(e||s.d,i||s.b),this.container.innerHTML="",this.container.appendChild(this.el)}}},QmmR:function(t,e,i){"use strict";i.r(e);e.default=class{constructor(t,e,i,s){this.value=t,this.x=e,this.y=i,this.alpha=s,this.gray=.98,this.count=0}drop(t,e){this.x+=t,this.y+=e+this.gray*this.count,this.count+=1/60}}},bMxf:function(t,e,i){"use strict";i.r(e);var s=i("Qb4n"),n=i("QmmR");e.default=class extends s.a{constructor(t,e){super(),this.ctx=this.getContext("2d"),this.btnWidth=160,this.btnHeight=40,this.btnLeft=t/2-this.btnWidth/2,this.btnTop=.75*e,this.startDrop=!1,this.lines=[],this.btnText=[],this.duration=0,this.isOut=!1,this.gray=.98,this.initCanvasSize(t,e),this.createTextLine(),this.createBtnText()}createTextLine(){let t,{ctx:e,width:i,height:s}=this,h=.3*s,r=[{text:"小猪猪",space:30,y:h},{text:"对不起",space:10,y:h+60},{text:"不要生气",space:10,y:h+120}];for(let[s,{text:h,space:o,y:a}]of r.entries()){this.lines[s]=[];let r=h.split("");t=i/2-(e.measureText(h).width+o*(r.length-1))/2;for(let i of r){let h=e.measureText(i).width;this.lines[s].push(new n.default(i,t,a,1)),t=t+h+o}}}createBtnText(){let t,{ctx:e,btnTop:i,btnHeight:s,width:h}=this,r=i+s/2+e.measureText("M").width/2,o="接受道歉".split("");t=h/2-(e.measureText("接受道歉").width+6*(o.length-1))/2;for(let i of o){let s=e.measureText(i).width;this.btnText.push(new n.default(i,t,r,1)),t=t+s+6}}drawBtn(){let{ctx:t,btnLeft:e,btnTop:i,btnWidth:s,btnHeight:n,btnText:h,startDrop:r,duration:o,gray:a}=this;t.save(),t.fillStyle="#ffffff",t.shadowOffsetX=3,t.shadowOffsetY=3,t.shadowBlur=4,t.shadowColor="#cea3a3",t.fillRect(e,i,s,n),t.restore(),t.save(),t.font="18px sans-serif",t.fillStyle="#916c2b";for(let e of h)r&&e.drop(-.6,1),t.fillText(e.value,e.x,e.y);r&&(this.btnLeft-=.6,this.btnTop+=1+a*(o/60)),t.restore()}drawText(){let{ctx:t,width:e,height:i,lines:s,startDrop:n,duration:h}=this;t.save(),t.font="18px sans-serif",t.fillStyle="#ffffff";let r,o,a=Math.floor(h/20);for(let h=0,c=s.length;he||o.y>i);t.restore()}drop(){this.startDrop=!0}render(){let{ctx:t,width:e,height:i,startDrop:s}=this;return t.clearRect(0,0,e,i),this.drawText(),this.drawBtn(),s&&(this.duration+=1),this}}},kZAv:function(t,e,i){"use strict";i.d(e,"d",function(){return s}),i.d(e,"b",function(){return n}),i.d(e,"a",function(){return h}),i.d(e,"c",function(){return r});const s=500,n=500,h=`${i("0Pcb").a.pc?24:16}px sans-serif`,r="https://snayan.github.io/canvas-demo/"}}]); -------------------------------------------------------------------------------- /coverage/lcov.info: -------------------------------------------------------------------------------- 1 | TN: 2 | SF:/Users/yang.zhang/Documents/github/canvas-demo/example/collide_02/canvas/timeSystem.ts 3 | FN:8,(anonymous_0) 4 | FN:15,(anonymous_1) 5 | FN:22,(anonymous_2) 6 | FN:28,(anonymous_3) 7 | FN:33,(anonymous_4) 8 | FN:39,(anonymous_5) 9 | FN:48,(anonymous_6) 10 | FN:55,(anonymous_7) 11 | FN:66,(anonymous_8) 12 | FN:71,(anonymous_9) 13 | FN:72,(anonymous_10) 14 | FN:78,(anonymous_11) 15 | FN:79,(anonymous_12) 16 | FN:85,(anonymous_13) 17 | FN:86,(anonymous_14) 18 | FN:92,(anonymous_15) 19 | FN:93,(anonymous_16) 20 | FN:99,(anonymous_17) 21 | FN:100,(anonymous_18) 22 | FN:106,(anonymous_19) 23 | FN:108,(anonymous_20) 24 | FN:121,(anonymous_21) 25 | FN:124,(anonymous_22) 26 | FN:129,(anonymous_23) 27 | FN:142,(anonymous_24) 28 | FN:148,(anonymous_25) 29 | FN:156,(anonymous_26) 30 | FN:163,(anonymous_27) 31 | FN:176,(anonymous_28) 32 | FNF:29 33 | FNH:3 34 | FNDA:1,(anonymous_0) 35 | FNDA:1,(anonymous_1) 36 | FNDA:0,(anonymous_2) 37 | FNDA:1,(anonymous_3) 38 | FNDA:0,(anonymous_4) 39 | FNDA:0,(anonymous_5) 40 | FNDA:0,(anonymous_6) 41 | FNDA:0,(anonymous_7) 42 | FNDA:0,(anonymous_8) 43 | FNDA:0,(anonymous_9) 44 | FNDA:0,(anonymous_10) 45 | FNDA:0,(anonymous_11) 46 | FNDA:0,(anonymous_12) 47 | FNDA:0,(anonymous_13) 48 | FNDA:0,(anonymous_14) 49 | FNDA:0,(anonymous_15) 50 | FNDA:0,(anonymous_16) 51 | FNDA:0,(anonymous_17) 52 | FNDA:0,(anonymous_18) 53 | FNDA:0,(anonymous_19) 54 | FNDA:0,(anonymous_20) 55 | FNDA:0,(anonymous_21) 56 | FNDA:0,(anonymous_22) 57 | FNDA:0,(anonymous_23) 58 | FNDA:0,(anonymous_24) 59 | FNDA:0,(anonymous_25) 60 | FNDA:0,(anonymous_26) 61 | FNDA:0,(anonymous_27) 62 | FNDA:0,(anonymous_28) 63 | DA:9,1 64 | DA:10,1 65 | DA:11,1 66 | DA:16,1 67 | DA:17,1 68 | DA:18,1 69 | DA:23,0 70 | DA:24,0 71 | DA:29,1 72 | DA:34,0 73 | DA:35,0 74 | DA:40,0 75 | DA:49,0 76 | DA:50,0 77 | DA:51,0 78 | DA:56,0 79 | DA:57,0 80 | DA:60,0 81 | DA:61,0 82 | DA:62,0 83 | DA:67,0 84 | DA:72,0 85 | DA:73,0 86 | DA:79,0 87 | DA:80,0 88 | DA:86,0 89 | DA:87,0 90 | DA:93,0 91 | DA:94,0 92 | DA:100,0 93 | DA:101,0 94 | DA:107,0 95 | DA:108,0 96 | DA:109,0 97 | DA:110,0 98 | DA:122,0 99 | DA:123,0 100 | DA:124,0 101 | DA:125,0 102 | DA:130,0 103 | DA:131,0 104 | DA:132,0 105 | DA:133,0 106 | DA:134,0 107 | DA:136,0 108 | DA:137,0 109 | DA:143,0 110 | DA:144,0 111 | DA:149,0 112 | DA:150,0 113 | DA:151,0 114 | DA:157,0 115 | DA:158,0 116 | DA:159,0 117 | DA:164,0 118 | DA:165,0 119 | DA:166,0 120 | DA:168,0 121 | DA:169,0 122 | DA:170,0 123 | DA:172,0 124 | DA:177,0 125 | DA:178,0 126 | DA:179,0 127 | DA:180,0 128 | DA:181,0 129 | LF:66 130 | LH:7 131 | BRDA:29,0,0,1 132 | BRDA:29,0,1,0 133 | BRDA:48,1,0,0 134 | BRDA:48,2,0,0 135 | BRDA:56,3,0,0 136 | BRDA:56,3,1,0 137 | BRDA:56,4,0,0 138 | BRDA:56,4,1,0 139 | BRDA:78,5,0,0 140 | BRDA:85,6,0,0 141 | BRDA:99,7,0,0 142 | BRDA:110,8,0,0 143 | BRDA:110,8,1,0 144 | BRDA:131,9,0,0 145 | BRDA:131,9,1,0 146 | BRDA:133,10,0,0 147 | BRDA:133,10,1,0 148 | BRDA:149,11,0,0 149 | BRDA:149,11,1,0 150 | BRDA:157,12,0,0 151 | BRDA:157,12,1,0 152 | BRDA:165,13,0,0 153 | BRDA:165,13,1,0 154 | BRDA:169,14,0,0 155 | BRDA:169,14,1,0 156 | BRDA:180,15,0,0 157 | BRDA:180,15,1,0 158 | BRF:27 159 | BRH:1 160 | end_of_record 161 | -------------------------------------------------------------------------------- /dist/19.1c4f12e2a7e2671669d5.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[19],{"0Pcb":function(t,e,i){"use strict";const n=function(){const t=window.navigator.userAgent;return window.location.href,function(t){const e={},i=t.indexOf("iPhone")>=0||t.indexOf("iPad")>=0||t.indexOf("iPod")>=0,n=t.indexOf("Android")>0;return e.ios=i,e.android=n,e.mobile=i||n,e.pc=!i&&!n,e}(t)}();e.a=n},Qb4n:function(t,e,i){"use strict";var n=i("kZAv");e.a=class{constructor(){this.el=document.createElement("canvas")}initCanvasSize(t,e){this.el.width=t,this.el.height=e,this.width=t,this.height=e}getContext(t,e){return this.el.getContext(t,e)}render(t){this.container=t;let{width:e,height:i}=t.getBoundingClientRect();this.initCanvasSize(e||n.d,i||n.b),this.container.innerHTML="",this.container.appendChild(this.el)}}},jJnk:function(t,e,i){"use strict";i.r(e);var n=i("Qb4n"),s=i("kZAv");e.default=class extends n.a{constructor(){super(),this.ctx=this.getContext("2d")}initVariable(){this.radius=Math.min(this.width,this.height)/2*.8,this.radius=Math.min(this.radius,200),this.centerRadius=10,this.marginBound=20,this.font=s.a,this.secondPointerLength=this.radius-this.marginBound,this.minutePointerLength=.8*this.secondPointerLength,this.hourPointerLength=.6*this.secondPointerLength}setCtxAttribute(){let{ctx:t}=this;t.fillStyle="#000000",t.strokeStyle="#000000",t.lineWidth=.5,t.font=this.font}drawDisc(t){t.beginPath(),t.arc(0,0,this.radius,0,2*Math.PI),t.stroke()}drawScale(t){let e,i=this.radius-this.marginBound,n=["1","2","3","4","5","6","7","8","9","10","11","12"];t.save(),t.textAlign="center",t.textBaseline="middle";for(let s=0,r=n.length;s code[class*='language-'], 114 | pre[class*='language-'] { 115 | background: #f5f2f0; 116 | } 117 | 118 | pre[class*='language-']::-moz-selection, 119 | pre[class*='language-'] ::-moz-selection, 120 | code[class*='language-']::-moz-selection, 121 | code[class*='language-'] ::-moz-selection { 122 | text-shadow: none; 123 | background: #b3d4fc; 124 | } 125 | 126 | pre[class*='language-']::selection, 127 | pre[class*='language-'] ::selection, 128 | code[class*='language-']::selection, 129 | code[class*='language-'] ::selection { 130 | text-shadow: none; 131 | background: #b3d4fc; 132 | } 133 | 134 | @media print { 135 | code[class*='language-'], 136 | pre[class*='language-'] { 137 | text-shadow: none; 138 | } 139 | } 140 | 141 | /* Inline code */ 142 | :not(pre) > code[class*='language-'] { 143 | padding: 0.1em; 144 | border-radius: 0.3em; 145 | white-space: normal; 146 | } 147 | 148 | button { 149 | border: none; 150 | background: none; 151 | &:active { 152 | outline: none; 153 | } 154 | &:focus { 155 | outline: none; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-background-sync.prod.js: -------------------------------------------------------------------------------- 1 | this.workbox=this.workbox||{},this.workbox.backgroundSync=function(e,t){"use strict";try{self.workbox.v["workbox:background-sync:3.3.0"]=1}catch(e){}const r=["method","referrer","referrerPolicy","mode","credentials","cache","redirect","integrity","keepalive"];class s{static fromRequest(e){return babelHelpers.asyncToGenerator(function*(){const t={headers:{}};"GET"!==e.method&&(t.body=yield e.clone().blob());for(const[r,s]of e.headers.entries())t.headers[r]=s;for(const s of r)void 0!==e[s]&&(t[s]=e[s]);return new s({url:e.url,requestInit:t})})()}constructor({url:e,requestInit:t,timestamp:r=Date.now()}){this.url=e,this.requestInit=t,this.e=r}get timestamp(){return this.e}toObject(){return{url:this.url,timestamp:this.timestamp,requestInit:this.requestInit}}toRequest(){return new Request(this.url,this.requestInit)}clone(){const e=Object.assign({},this.requestInit);return e.headers=Object.assign({},this.requestInit.headers),this.requestInit.body&&(e.body=this.requestInit.body.slice()),new s({url:this.url,timestamp:this.timestamp,requestInit:e})}}const i="workbox-background-sync",n="requests",u="queueName",c="workbox-background-sync",o=10080;class l{constructor(t){this.t=t,this.r=new e.DBWrapper(i,1,{onupgradeneeded:e=>e.target.result.createObjectStore(n,{autoIncrement:!0}).createIndex(u,u,{unique:!1})})}addEntry(e){var t=this;return babelHelpers.asyncToGenerator(function*(){yield t.r.add(n,{queueName:t.t.name,storableRequest:e.toObject()})})()}getAndRemoveOldestEntry(){var e=this;return babelHelpers.asyncToGenerator(function*(){const[t]=yield e.r.getAllMatching(n,{index:u,query:IDBKeyRange.only(e.t.name),count:1,includeKeys:!0});if(t)return yield e.r.delete(n,t.primaryKey),new s(t.value.storableRequest)})()}}const a=new Set;class h{constructor(e,{callbacks:r={},maxRetentionTime:s=o}={}){if(a.has(e))throw new t.WorkboxError("duplicate-queue-name",{name:e});a.add(e),this.s=e,this.i=r,this.n=s,this.u=new l(this),this.c()}get name(){return this.s}addRequest(e){var t=this;return babelHelpers.asyncToGenerator(function*(){const r=yield s.fromRequest(e.clone());yield t.o("requestWillEnqueue",r),yield t.u.addEntry(r),yield t.l()})()}replayRequests(){var e=this;return babelHelpers.asyncToGenerator(function*(){const r=Date.now(),s=[],i=[];let n;for(;n=yield e.u.getAndRemoveOldestEntry();){const t=n.clone(),u=60*e.n*1e3;if(r-n.timestamp>u)continue;yield e.o("requestWillReplay",n);const c={request:n.toRequest()};try{c.response=yield fetch(c.request.clone())}catch(e){c.error=e,i.push(t)}s.push(c)}if(yield e.o("queueDidReplay",s),i.length)throw yield Promise.all(i.map(function(t){return e.u.addEntry(t)})),new t.WorkboxError("queue-replay-failed",{name:e.s,count:i.length})})()}o(e,...t){var r=this;return babelHelpers.asyncToGenerator(function*(){"function"==typeof r.i[e]&&(yield r.i[e].apply(null,t))})()}c(){"sync"in registration?self.addEventListener("sync",e=>{e.tag===`${c}:${this.s}`&&e.waitUntil(this.replayRequests())}):this.replayRequests()}l(){var e=this;return babelHelpers.asyncToGenerator(function*(){if("sync"in registration)try{yield registration.sync.register(`${c}:${e.s}`)}catch(e){}})()}static get a(){return a}}return Object.freeze({Queue:h,Plugin:class{constructor(...e){this.t=new h(...e),this.fetchDidFail=this.fetchDidFail.bind(this)}fetchDidFail({request:e}){var t=this;return babelHelpers.asyncToGenerator(function*(){yield t.t.addRequest(e)})()}}})}(workbox.core._private,workbox.core._private); 2 | 3 | //# sourceMappingURL=workbox-background-sync.prod.js.map 4 | -------------------------------------------------------------------------------- /example/free_fall/canvas/ball.ts: -------------------------------------------------------------------------------- 1 | type Behavior = (ball: Ball, elapsed: number) => void; 2 | interface BallOption { 3 | verticalHeight?: number; 4 | pixelPerMiter?: number; 5 | useGravity?: boolean; 6 | useRebound?: boolean; 7 | } 8 | 9 | const GRAVITY = 9.81; //重力加速度9.8m/s 10 | 11 | class Ball { 12 | public behaviors: Behavior[]; 13 | public radius: number; 14 | public x: number; 15 | public y: number; 16 | public offset: number; 17 | public moveSpeed: number; 18 | public currentSpeed: number; 19 | public pixelPerMiter: number; 20 | public useGravity: boolean; 21 | public useRebound: boolean; 22 | public verticalHeight: number; 23 | public isStill: boolean; 24 | constructor(x: number, y: number, radius: number, { verticalHeight = 0, pixelPerMiter = 1, useGravity = false, useRebound = false }: BallOption = {}) { 25 | this.x = x; 26 | this.y = y; 27 | this.radius = radius; 28 | this.offset = 0; 29 | this.moveSpeed = 0; 30 | this.currentSpeed = 0; 31 | this.behaviors = []; 32 | this.pixelPerMiter = pixelPerMiter; 33 | this.useGravity = useGravity; 34 | this.useRebound = useRebound; 35 | this.verticalHeight = verticalHeight; 36 | this.isStill = false; 37 | } 38 | 39 | /* 设置速度 */ 40 | public setSpeed(speed: number) { 41 | this.moveSpeed = speed; 42 | this.currentSpeed = speed; 43 | } 44 | 45 | /* 添加小球 */ 46 | public addBehavior(behavior: Behavior | Behavior[]) { 47 | if (Array.isArray(behavior)) { 48 | this.behaviors = [...this.behaviors, ...behavior]; 49 | } else { 50 | this.behaviors = [...this.behaviors, behavior]; 51 | } 52 | } 53 | 54 | /* 更新小球 */ 55 | public update(elapsed: number) { 56 | for (let behavior of this.behaviors) { 57 | behavior.call(null, this, elapsed); 58 | } 59 | } 60 | 61 | /* 绘制小球 */ 62 | public render(ctx: CanvasRenderingContext2D) { 63 | let { x, y, radius, offset, pixelPerMiter } = this; 64 | ctx.save(); 65 | ctx.translate(x, y + offset * pixelPerMiter); 66 | ctx.beginPath(); 67 | ctx.arc(0, 0, radius, 0, Math.PI * 2, false); 68 | ctx.fill(); 69 | ctx.stroke(); 70 | ctx.restore(); 71 | } 72 | 73 | /* 重置 */ 74 | public reset() { 75 | this.offset = 0; 76 | this.currentSpeed = this.moveSpeed; 77 | } 78 | 79 | /* 移动 */ 80 | static move(ball: Ball, elapsed: number) { 81 | //小球是静止状态,不更新 82 | if (ball.isStill) { 83 | return; 84 | } 85 | let { currentSpeed } = ball; 86 | let t = elapsed / 1000; //elapsed是毫秒, 而速度单位是m/s,所以要除1000 87 | //更新速度 88 | if (ball.useGravity) { 89 | ball.currentSpeed += GRAVITY * t; 90 | } 91 | let distance = ball.currentSpeed * t; 92 | if (ball.offset + distance > ball.verticalHeight) { 93 | //落到地面了 94 | //使用反弹效果 95 | if (ball.useRebound) { 96 | ball.offset = ball.verticalHeight; 97 | ball.currentSpeed = -ball.currentSpeed * 0.6; 98 | if ((distance * ball.pixelPerMiter) / t < 1) { 99 | //当前移动距离小于1px,应该静止了, 100 | ball.isStill = true; 101 | ball.currentSpeed = 0; 102 | } 103 | } else { 104 | ball.isStill = true; 105 | ball.currentSpeed = 0; 106 | ball.offset = ball.verticalHeight; 107 | } 108 | } else { 109 | ball.offset += distance; 110 | } 111 | } 112 | } 113 | 114 | export default Ball; 115 | -------------------------------------------------------------------------------- /dist/23.63a71ad02d460735b260.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[23,7,55],{"/aIi":function(t,i){t.exports="dist/images/1.18d12255a792809c320cfff34c146e7f.jpeg"},"0Pcb":function(t,i,e){"use strict";const n=function(){const t=window.navigator.userAgent;return window.location.href,function(t){const i={},e=t.indexOf("iPhone")>=0||t.indexOf("iPad")>=0||t.indexOf("iPod")>=0,n=t.indexOf("Android")>0;return i.ios=e,i.android=n,i.mobile=e||n,i.pc=!e&&!n,i}(t)}();i.a=n},Anus:function(t,i,e){"use strict";e.r(i);var n=e("Qb4n"),s=e("UwLk"),a=e("ysz4"),o=e("0Pcb");i.default=class extends n.a{constructor(){super(),this.ctx=this.getContext("2d"),this.scale=1.5}loadImages(){let t=e("/aIi"),i=new Image;i.src=t,i.onload=(()=>{this.image=i,this.loading.stop(),setTimeout(this.drawImage.bind(this),200)})}drawImage(){let{ctx:t,image:i,width:e,height:n}=this;if(i){let s,a,o,h,r=i.width,c=i.height;e>n?(o=(e-(s=(a=n)*r/c))/2,h=0):(o=0,h=(n-(a=(s=e)*c/r))/2),this.areaRect={left:o,top:h,width:s,height:a},t.drawImage(i,o,h,s,a),t.rect(o,h,s,a),t.clip()}}drawZoom(t){let{ctx:i,zoomRadius:e,loading:n,width:s,height:h,image:r,scale:c,areaRect:d}=this;if(t.preventDefault(),!n.isLoading){let n,r;o.a.pc?(n=(t=t).x,r=t.y):(n=t.changedTouches[0].pageX,r=t.changedTouches[0].pageY);let d=Object(a.h)(this.ctx.canvas,n,r);i.clearRect(0,0,s,h),this.drawImage(),i.save(),i.lineWidth=.1*e,i.strokeStyle="#ffffff",i.beginPath(),i.arc(d.x,d.y,e,0,2*Math.PI,!1),i.clip(),i.drawImage(i.canvas,d.x-e,d.y-e,2*e,2*e,d.x-e-(2*e*c-2*e)/2,d.y-e-(2*e*c-2*e)/2,2*e*c,2*e*c),i.stroke(),i.restore()}}bindMouseMove(){this.container.addEventListener(o.a.pc?"mousemove":"touchmove",this.drawZoom.bind(this),!1)}render(t){super.render(t);let{ctx:i,width:e,height:n}=this;this.loading=new s.default(i),this.loading.start(),this.zoomRadius=Math.min(e,n)/8,this.loadImages(),this.bindMouseMove()}}},Qb4n:function(t,i,e){"use strict";var n=e("kZAv");i.a=class{constructor(){this.el=document.createElement("canvas")}initCanvasSize(t,i){this.el.width=t,this.el.height=i,this.width=t,this.height=i}getContext(t,i){return this.el.getContext(t,i)}render(t){this.container=t;let{width:i,height:e}=t.getBoundingClientRect();this.initCanvasSize(i||n.d,e||n.b),this.container.innerHTML="",this.container.appendChild(this.el)}}},UwLk:function(t,i,e){"use strict";e.r(i);i.default=class{constructor(t,i={}){this.ctx=t,this.radius=i.radius||5,this.count=i.count||6,this.duration=i.duration||8,this.margin=i.margin||10,this.color="#f48041",this.index=0,this.show=this.duration,this.point=this.computerPoint(),this.isLoading=!1}computerPoint(){let t=[],{ctx:i,count:e,radius:n,margin:s}=this,a=e*n*2+(e-1)*s,o=(i.canvas.width-a)/2;for(let i=0;i=e&&(this.index=0),this.duration-=1,t.clearRect(0,0,t.canvas.width,t.canvas.height),this.isLoading&&(t.save(),t.fillStyle=i,this.startLoading(),t.restore(),window.requestAnimationFrame(this.animate.bind(this)))}start(){this.isLoading=!0,this.animate()}stop(){let{ctx:t}=this;this.isLoading=!1}}},kZAv:function(t,i,e){"use strict";e.d(i,"d",function(){return n}),e.d(i,"b",function(){return s}),e.d(i,"a",function(){return a}),e.d(i,"c",function(){return o});const n=500,s=500,a=`${e("0Pcb").a.pc?24:16}px sans-serif`,o="https://snayan.github.io/canvas-demo/"}}]); -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-background-sync.prod.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"names":[],"mappings":"","sources":["packages/workbox-background-sync/browser.mjs"],"sourcesContent":["this.workbox=this.workbox||{},this.workbox.backgroundSync=function(e,t){\"use strict\";try{self.workbox.v[\"workbox:background-sync:3.3.0\"]=1}catch(e){}const r=[\"method\",\"referrer\",\"referrerPolicy\",\"mode\",\"credentials\",\"cache\",\"redirect\",\"integrity\",\"keepalive\"];class s{static fromRequest(e){return babelHelpers.asyncToGenerator(function*(){const t={headers:{}};\"GET\"!==e.method&&(t.body=yield e.clone().blob());for(const[r,s]of e.headers.entries())t.headers[r]=s;for(const s of r)void 0!==e[s]&&(t[s]=e[s]);return new s({url:e.url,requestInit:t})})()}constructor({url:e,requestInit:t,timestamp:r=Date.now()}){this.url=e,this.requestInit=t,this.e=r}get timestamp(){return this.e}toObject(){return{url:this.url,timestamp:this.timestamp,requestInit:this.requestInit}}toRequest(){return new Request(this.url,this.requestInit)}clone(){const e=Object.assign({},this.requestInit);return e.headers=Object.assign({},this.requestInit.headers),this.requestInit.body&&(e.body=this.requestInit.body.slice()),new s({url:this.url,timestamp:this.timestamp,requestInit:e})}}const i=\"workbox-background-sync\",n=\"requests\",u=\"queueName\",c=\"workbox-background-sync\",o=10080;class l{constructor(t){this.t=t,this.r=new e.DBWrapper(i,1,{onupgradeneeded:e=>e.target.result.createObjectStore(n,{autoIncrement:!0}).createIndex(u,u,{unique:!1})})}addEntry(e){var t=this;return babelHelpers.asyncToGenerator(function*(){yield t.r.add(n,{queueName:t.t.name,storableRequest:e.toObject()})})()}getAndRemoveOldestEntry(){var e=this;return babelHelpers.asyncToGenerator(function*(){const[t]=yield e.r.getAllMatching(n,{index:u,query:IDBKeyRange.only(e.t.name),count:1,includeKeys:!0});if(t)return yield e.r.delete(n,t.primaryKey),new s(t.value.storableRequest)})()}}const a=new Set;class h{constructor(e,{callbacks:r={},maxRetentionTime:s=o}={}){if(a.has(e))throw new t.WorkboxError(\"duplicate-queue-name\",{name:e});a.add(e),this.s=e,this.i=r,this.n=s,this.u=new l(this),this.c()}get name(){return this.s}addRequest(e){var t=this;return babelHelpers.asyncToGenerator(function*(){const r=yield s.fromRequest(e.clone());yield t.o(\"requestWillEnqueue\",r),yield t.u.addEntry(r),yield t.l()})()}replayRequests(){var e=this;return babelHelpers.asyncToGenerator(function*(){const r=Date.now(),s=[],i=[];let n;for(;n=yield e.u.getAndRemoveOldestEntry();){const t=n.clone(),u=60*e.n*1e3;if(r-n.timestamp>u)continue;yield e.o(\"requestWillReplay\",n);const c={request:n.toRequest()};try{c.response=yield fetch(c.request.clone())}catch(e){c.error=e,i.push(t)}s.push(c)}if(yield e.o(\"queueDidReplay\",s),i.length)throw yield Promise.all(i.map(function(t){return e.u.addEntry(t)})),new t.WorkboxError(\"queue-replay-failed\",{name:e.s,count:i.length})})()}o(e,...t){var r=this;return babelHelpers.asyncToGenerator(function*(){\"function\"==typeof r.i[e]&&(yield r.i[e].apply(null,t))})()}c(){\"sync\"in registration?self.addEventListener(\"sync\",e=>{e.tag===`${c}:${this.s}`&&e.waitUntil(this.replayRequests())}):this.replayRequests()}l(){var e=this;return babelHelpers.asyncToGenerator(function*(){if(\"sync\"in registration)try{yield registration.sync.register(`${c}:${e.s}`)}catch(e){}})()}static get a(){return a}}return Object.freeze({Queue:h,Plugin:class{constructor(...e){this.t=new h(...e),this.fetchDidFail=this.fetchDidFail.bind(this)}fetchDidFail({request:e}){var t=this;return babelHelpers.asyncToGenerator(function*(){yield t.t.addRequest(e)})()}}})}(workbox.core._private,workbox.core._private);\n"],"file":"workbox-background-sync.prod.js"} -------------------------------------------------------------------------------- /example/sh/canvas/imgCanvas.ts: -------------------------------------------------------------------------------- 1 | import Canvas from 'common/canvas'; 2 | 3 | class ImgCanvas extends Canvas { 4 | ctx: CanvasRenderingContext2D; 5 | font: string; 6 | images: HTMLImageElement[]; 7 | index: number; 8 | angle: number; 9 | nextAngle: number; 10 | maxAngle: number; 11 | marginLeft: number; 12 | marginTop: number; 13 | alpha: number; 14 | duration: number; 15 | show: number; 16 | constructor(width: number, height: number, images: HTMLImageElement[]) { 17 | super(); 18 | this.ctx = this.getContext('2d'); 19 | this.images = images; 20 | this.marginLeft = 20; 21 | this.marginTop = Math.floor(this.marginLeft * height / width); 22 | this.maxAngle = 45; 23 | this.angle = this.random(-this.maxAngle, this.maxAngle); 24 | this.nextAngle = this.random(-this.maxAngle, this.maxAngle); 25 | this.index = -1; 26 | this.alpha = 1; 27 | this.duration = 180; 28 | this.show = this.duration; 29 | this.initCanvasSize(width, height); 30 | } 31 | /* 随机数 */ 32 | private random(min, max) { 33 | return Math.floor(Math.random() * (max - min + 1)) + min; 34 | } 35 | /* 旋转坐标 */ 36 | public rotate(angle) { 37 | let { ctx } = this; 38 | ctx.rotate(angle * Math.PI / 180); 39 | } 40 | /* 平移坐标到图片中心 */ 41 | private translate() { 42 | let { ctx, width, height } = this; 43 | ctx.translate(width / 2, height / 2); 44 | } 45 | /* 剪辑图片区域 */ 46 | private clip() { 47 | let { ctx, marginLeft, marginTop, width, height } = this; 48 | ctx.beginPath(); 49 | ctx.rect(marginLeft, marginTop, width - marginLeft * 2, height - marginTop * 2); 50 | ctx.clip(); 51 | } 52 | /* 计算宽高 */ 53 | private computeSize(img: HTMLImageElement) { 54 | let { width, height } = this; 55 | let imgW = img.width; 56 | let imgH = img.height; 57 | let dstW = width; 58 | let dstH = dstW * imgH / imgW; 59 | return { dstW, dstH }; 60 | } 61 | /* 渲染图片 */ 62 | private renderImage() { 63 | let { ctx, width, height, alpha, index, images } = this; 64 | let img = images[index]; 65 | let next = (this.index + 1) % images.length; 66 | let nextImg = images[next]; 67 | let dst = this.computeSize(nextImg); 68 | let dstW = dst.dstW; 69 | let dstH = dst.dstH; 70 | if (nextImg) { 71 | ctx.save(); 72 | this.rotate(this.nextAngle); 73 | ctx.globalAlpha = 1 - alpha; 74 | this.ctx.drawImage(nextImg, -dstW / 2, -dstH / 2, dstW, dstH); 75 | ctx.restore(); 76 | } 77 | if (img) { 78 | ctx.save(); 79 | ctx.globalAlpha = alpha; 80 | dst = this.computeSize(img); 81 | dstW = dst.dstW; 82 | dstH = dst.dstH; 83 | this.rotate(this.angle); 84 | this.ctx.drawImage(img, -dstW / 2, -dstH / 2, dstW, dstH); 85 | ctx.restore(); 86 | } 87 | } 88 | /* 渲染 */ 89 | public render() { 90 | let { ctx, width, height, maxAngle, images } = this; 91 | if (!images.length) { 92 | return this; 93 | } 94 | ctx.clearRect(0, 0, width, height); 95 | ctx.save(); 96 | this.clip(); 97 | this.translate(); 98 | if (this.duration <= 0) { 99 | this.alpha = 1; 100 | this.index += 1; 101 | this.angle = this.nextAngle; 102 | this.nextAngle = this.random(-maxAngle, maxAngle); 103 | this.duration = this.show; 104 | } 105 | if (this.duration < 30) { 106 | this.alpha -= 1 / 30; 107 | } 108 | if (this.index >= this.images.length) { 109 | this.index = 0; 110 | } 111 | this.duration -= 1; 112 | this.renderImage(); 113 | ctx.restore(); 114 | return this; 115 | } 116 | } 117 | 118 | export default ImgCanvas; 119 | -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-cache-expiration.prod.js: -------------------------------------------------------------------------------- 1 | this.workbox=this.workbox||{},this.workbox.expiration=function(e,t,r,n,i){"use strict";try{self.workbox.v["workbox:cache-expiration:3.3.0"]=1}catch(e){}const s="url",a="timestamp";class l{constructor(e){this.e=e,this.t=e,this.r=new t.DBWrapper(this.e,2,{onupgradeneeded:e=>this.n(e)})}n(e){const t=e.target.result;e.oldVersion<2&&t.objectStoreNames.contains("workbox-cache-expiration")&&t.deleteObjectStore("workbox-cache-expiration"),t.createObjectStore(this.t,{keyPath:s}).createIndex(a,a,{unique:!1})}setTimestamp(e,t){var r=this;return babelHelpers.asyncToGenerator(function*(){yield r.r.put(r.t,{[s]:new URL(e,location).href,[a]:t})})()}getAllTimestamps(){var e=this;return babelHelpers.asyncToGenerator(function*(){return yield e.r.getAllMatching(e.t,{index:a})})()}getTimestamp(e){var t=this;return babelHelpers.asyncToGenerator(function*(){return(yield t.r.get(t.t,e)).timestamp})()}deleteUrl(e){var t=this;return babelHelpers.asyncToGenerator(function*(){yield t.r.delete(t.t,new URL(e,location).href)})()}delete(){var e=this;return babelHelpers.asyncToGenerator(function*(){yield e.r.deleteDatabase(),e.r=null})()}}class o{constructor(e,t={}){this.i=!1,this.s=!1,this.a=t.maxEntries,this.l=t.maxAgeSeconds,this.e=e,this.o=new l(e)}expireEntries(){var e=this;return babelHelpers.asyncToGenerator(function*(){if(e.i)return void(e.s=!0);e.i=!0;const t=Date.now(),r=yield e.c(t),n=yield e.u(),i=[...new Set(r.concat(n))];yield Promise.all([e.h(i),e.d(i)]),e.i=!1,e.s&&(e.s=!1,e.expireEntries())})()}c(e){var t=this;return babelHelpers.asyncToGenerator(function*(){if(!t.l)return[];const r=e-1e3*t.l,n=[];return(yield t.o.getAllTimestamps()).forEach(function(e){e.timestampe.a;){const e=r.shift();t.push(e.url)}return t})()}h(e){var t=this;return babelHelpers.asyncToGenerator(function*(){const r=yield caches.open(t.e);for(const t of e)yield r.delete(t)})()}d(e){var t=this;return babelHelpers.asyncToGenerator(function*(){for(const r of e)yield t.o.deleteUrl(r)})()}updateTimestamp(e){var t=this;return babelHelpers.asyncToGenerator(function*(){const r=new URL(e,location);r.hash="",yield t.o.setTimestamp(r.href,Date.now())})()}isURLExpired(e){var t=this;return babelHelpers.asyncToGenerator(function*(){if(!t.l)throw new r.WorkboxError("expired-test-without-max-age",{methodName:"isURLExpired",paramName:"maxAgeSeconds"});const n=new URL(e,location);return n.hash="",(yield t.o.getTimestamp(n.href))this.deleteCacheAndMetadata())}f(e){if(e===n.cacheNames.getRuntimeName())throw new r.WorkboxError("expire-custom-caches-only");let t=this.b.get(e);return t||(t=new o(e,this.p),this.b.set(e,t)),t}cachedResponseWillBeUsed({cacheName:e,cachedResponse:t}){if(!t)return null;let r=this.m(t);return this.f(e).expireEntries(),r?t:null}m(e){if(!this.l)return!0;const t=this.y(e);return null===t||t>=Date.now()-1e3*this.l}y(e){if(!e.headers.has("date"))return null;const t=e.headers.get("date"),r=new Date(t).getTime();return isNaN(r)?null:r}cacheDidUpdate({cacheName:e,request:t}){var r=this;return babelHelpers.asyncToGenerator(function*(){const n=r.f(e);yield n.updateTimestamp(t.url),yield n.expireEntries()})()}deleteCacheAndMetadata(){var e=this;return babelHelpers.asyncToGenerator(function*(){for(const[t,r]of e.b)yield caches.delete(t),yield r.delete();e.b=new Map})()}},e}({},workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private); 2 | 3 | //# sourceMappingURL=workbox-cache-expiration.prod.js.map 4 | -------------------------------------------------------------------------------- /dist/workbox/workbox-v3.3.0/workbox-cache-expiration.prod.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"names":[],"mappings":"","sources":["packages/workbox-cache-expiration/browser.mjs"],"sourcesContent":["this.workbox=this.workbox||{},this.workbox.expiration=function(e,t,r,n,i){\"use strict\";try{self.workbox.v[\"workbox:cache-expiration:3.3.0\"]=1}catch(e){}const s=\"url\",a=\"timestamp\";class l{constructor(e){this.e=e,this.t=e,this.r=new t.DBWrapper(this.e,2,{onupgradeneeded:e=>this.n(e)})}n(e){const t=e.target.result;e.oldVersion<2&&t.objectStoreNames.contains(\"workbox-cache-expiration\")&&t.deleteObjectStore(\"workbox-cache-expiration\"),t.createObjectStore(this.t,{keyPath:s}).createIndex(a,a,{unique:!1})}setTimestamp(e,t){var r=this;return babelHelpers.asyncToGenerator(function*(){yield r.r.put(r.t,{[s]:new URL(e,location).href,[a]:t})})()}getAllTimestamps(){var e=this;return babelHelpers.asyncToGenerator(function*(){return yield e.r.getAllMatching(e.t,{index:a})})()}getTimestamp(e){var t=this;return babelHelpers.asyncToGenerator(function*(){return(yield t.r.get(t.t,e)).timestamp})()}deleteUrl(e){var t=this;return babelHelpers.asyncToGenerator(function*(){yield t.r.delete(t.t,new URL(e,location).href)})()}delete(){var e=this;return babelHelpers.asyncToGenerator(function*(){yield e.r.deleteDatabase(),e.r=null})()}}class o{constructor(e,t={}){this.i=!1,this.s=!1,this.a=t.maxEntries,this.l=t.maxAgeSeconds,this.e=e,this.o=new l(e)}expireEntries(){var e=this;return babelHelpers.asyncToGenerator(function*(){if(e.i)return void(e.s=!0);e.i=!0;const t=Date.now(),r=yield e.c(t),n=yield e.u(),i=[...new Set(r.concat(n))];yield Promise.all([e.h(i),e.d(i)]),e.i=!1,e.s&&(e.s=!1,e.expireEntries())})()}c(e){var t=this;return babelHelpers.asyncToGenerator(function*(){if(!t.l)return[];const r=e-1e3*t.l,n=[];return(yield t.o.getAllTimestamps()).forEach(function(e){e.timestampe.a;){const e=r.shift();t.push(e.url)}return t})()}h(e){var t=this;return babelHelpers.asyncToGenerator(function*(){const r=yield caches.open(t.e);for(const t of e)yield r.delete(t)})()}d(e){var t=this;return babelHelpers.asyncToGenerator(function*(){for(const r of e)yield t.o.deleteUrl(r)})()}updateTimestamp(e){var t=this;return babelHelpers.asyncToGenerator(function*(){const r=new URL(e,location);r.hash=\"\",yield t.o.setTimestamp(r.href,Date.now())})()}isURLExpired(e){var t=this;return babelHelpers.asyncToGenerator(function*(){if(!t.l)throw new r.WorkboxError(\"expired-test-without-max-age\",{methodName:\"isURLExpired\",paramName:\"maxAgeSeconds\"});const n=new URL(e,location);return n.hash=\"\",(yield t.o.getTimestamp(n.href))this.deleteCacheAndMetadata())}f(e){if(e===n.cacheNames.getRuntimeName())throw new r.WorkboxError(\"expire-custom-caches-only\");let t=this.b.get(e);return t||(t=new o(e,this.p),this.b.set(e,t)),t}cachedResponseWillBeUsed({cacheName:e,cachedResponse:t}){if(!t)return null;let r=this.m(t);return this.f(e).expireEntries(),r?t:null}m(e){if(!this.l)return!0;const t=this.y(e);return null===t||t>=Date.now()-1e3*this.l}y(e){if(!e.headers.has(\"date\"))return null;const t=e.headers.get(\"date\"),r=new Date(t).getTime();return isNaN(r)?null:r}cacheDidUpdate({cacheName:e,request:t}){var r=this;return babelHelpers.asyncToGenerator(function*(){const n=r.f(e);yield n.updateTimestamp(t.url),yield n.expireEntries()})()}deleteCacheAndMetadata(){var e=this;return babelHelpers.asyncToGenerator(function*(){for(const[t,r]of e.b)yield caches.delete(t),yield r.delete();e.b=new Map})()}},e}({},workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private);\n"],"file":"workbox-cache-expiration.prod.js"} -------------------------------------------------------------------------------- /common/render/index.scss: -------------------------------------------------------------------------------- 1 | .single { 2 | display: flex; 3 | justify-content: center; 4 | align-items: stretch; 5 | height: 100%; 6 | overflow: hidden; 7 | opacity: 0; 8 | transition: all 0.5s ease-out; 9 | will-change: opacity; 10 | } 11 | 12 | .collect { 13 | margin: 20px 10px; 14 | padding: 0; 15 | display: block; 16 | float: left; 17 | width: calc(25vw - 20px); 18 | height: calc(25vw - 20px); 19 | display: flex; 20 | flex-direction: column-reverse; 21 | justify-content: center; 22 | align-items: center; 23 | } 24 | 25 | .collectMobile{ 26 | width: calc(100vw - 20px); 27 | height: calc(100vw - 20px); 28 | } 29 | 30 | .codes { 31 | flex: 1 1 auto; 32 | width: 50%; 33 | margin: 20px; 34 | padding: 20px; 35 | overflow: hidden; 36 | display: flex; 37 | flex-direction: column; 38 | border: 1px solid royalblue; 39 | border-radius: 10px; 40 | } 41 | 42 | .codesTab { 43 | flex: 0 0 auto; 44 | height: 42px; 45 | display: flex; 46 | align-items: stretch; 47 | overflow: auto; 48 | } 49 | 50 | .otherTab { 51 | padding: 0 10px; 52 | background: rgba($color: #666, $alpha: 0.6); 53 | color: rgba($color: #fff, $alpha: 0.6); 54 | line-height: 42px; 55 | border-right: 1px solid #fff; 56 | cursor: pointer; 57 | &:hover { 58 | background: rgba($color: #666, $alpha: 0.4); 59 | color: rgba($color: #fff, $alpha: 1); 60 | } 61 | } 62 | 63 | .activeTab { 64 | background: #f5f2f0; 65 | color: #3a73d1; 66 | padding: 0 10px; 67 | line-height: 42px; 68 | border-right: 1px solid #fff; 69 | cursor: pointer; 70 | &:hover { 71 | color: #0858db; 72 | } 73 | } 74 | 75 | .codesSection { 76 | display: flex; 77 | flex: 1 1 auto; 78 | overflow: scroll; 79 | background: #f5f2f0; 80 | } 81 | 82 | .otherSection { 83 | display: none; 84 | } 85 | 86 | .activeSection { 87 | display: block; 88 | } 89 | 90 | .result { 91 | flex: 1 1 auto; 92 | margin: 20px; 93 | padding: 20px; 94 | width: 50%; 95 | border: 1px solid royalblue; 96 | border-radius: 10px; 97 | box-sizing: content-box; 98 | } 99 | 100 | .mobileResult { 101 | border: none; 102 | margin: 0; 103 | padding: 0; 104 | border-radius: 0; 105 | display: block; 106 | } 107 | 108 | .collect .result { 109 | margin: 0; 110 | padding: 10px; 111 | width: 100%; 112 | height: 100%; 113 | box-sizing: border-box; 114 | border: 1px solid royalblue; 115 | border-radius: 10px; 116 | } 117 | 118 | .loading { 119 | position: fixed; 120 | top: calc(50% - 16px); 121 | left: calc(50% - 16px); 122 | width: 32px; 123 | height: 32px; 124 | border-radius: 50%; 125 | background: #b3d4fc; 126 | animation: spin 1.8s ease infinite; 127 | &::before, 128 | &::after { 129 | content: ''; 130 | display: block; 131 | position: absolute; 132 | height: inherit; 133 | width: inherit; 134 | background: inherit; 135 | border-radius: inherit; 136 | animation: spin 1.8s ease infinite; 137 | } 138 | &::before { 139 | left: calc(50% - 80px); 140 | background: #07a; 141 | } 142 | &::after { 143 | left: calc(50% + 48px); 144 | background: #690; 145 | } 146 | } 147 | 148 | .mobile { 149 | & > .codes { 150 | display: none; 151 | } 152 | } 153 | 154 | .loaded { 155 | opacity: 1; 156 | } 157 | 158 | .error { 159 | display: flex; 160 | flex: 1; 161 | flex-direction: column; 162 | justify-content: center; 163 | align-items: center; 164 | } 165 | .errorTitle { 166 | color: red; 167 | font-weight: 700; 168 | font-size: 24px; 169 | } 170 | .errorTip { 171 | color: #999; 172 | font-size: 12px; 173 | } 174 | 175 | @keyframes spin { 176 | 0% { 177 | top: calc(50% - 16px); 178 | transform: rotate(0deg); 179 | } 180 | 50% { 181 | top: calc(50% - 80px); 182 | transform: rotate(-180deg); 183 | } 184 | 100% { 185 | top: calc(50% - 16px); 186 | transform: rotate(-360deg); 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /example/zoom/canvas/zoom.ts: -------------------------------------------------------------------------------- 1 | import Canvas from 'common/canvas'; 2 | import Loading from '@/loading'; 3 | import { windowToCanvas } from 'common/util'; 4 | import browser from 'common/browser'; 5 | 6 | interface Rect { 7 | left: number; 8 | top: number; 9 | width: number; 10 | height: number; 11 | } 12 | 13 | class ZoomCanvas extends Canvas { 14 | ctx: CanvasRenderingContext2D; 15 | loading: Loading; 16 | image: HTMLImageElement; 17 | zoomRadius: number; 18 | scale: number; 19 | areaRect: Rect; 20 | constructor() { 21 | super(); 22 | this.ctx = this.getContext('2d'); 23 | this.scale = 1.5; 24 | } 25 | 26 | /* 加载图片 */ 27 | private loadImages() { 28 | let url = require(`../img/1.jpeg`); 29 | let img = new Image(); 30 | img.src = url; 31 | img.onload = () => { 32 | this.image = img; 33 | this.loading.stop(); 34 | setTimeout(this.drawImage.bind(this), 200); 35 | }; 36 | } 37 | 38 | /* 绘制图片 */ 39 | private drawImage() { 40 | let { ctx, image, width, height } = this; 41 | if (image) { 42 | let imgWidth = image.width; 43 | let imgHeight = image.height; 44 | let isHorizontal = width > height; 45 | let drawWidth; 46 | let drawHeight; 47 | let dstX; 48 | let dstY; 49 | if (isHorizontal) { 50 | drawHeight = height; 51 | drawWidth = (drawHeight * imgWidth) / imgHeight; 52 | dstX = (width - drawWidth) / 2; 53 | dstY = 0; 54 | } else { 55 | drawWidth = width; 56 | drawHeight = (drawWidth * imgHeight) / imgWidth; 57 | dstX = 0; 58 | dstY = (height - drawHeight) / 2; 59 | } 60 | this.areaRect = { 61 | left: dstX, 62 | top: dstY, 63 | width: drawWidth, 64 | height: drawHeight, 65 | }; 66 | ctx.drawImage(image, dstX, dstY, drawWidth, drawHeight); 67 | ctx.rect(dstX, dstY, drawWidth, drawHeight); 68 | ctx.clip(); 69 | } 70 | } 71 | 72 | /* 绘制放大镜🔍 */ 73 | private drawZoom(e: MouseEvent | TouchEvent) { 74 | let { ctx, zoomRadius, loading, width, height, image, scale, areaRect } = this; 75 | e.preventDefault(); 76 | if (!loading.isLoading) { 77 | let x; 78 | let y; 79 | if (browser.pc) { 80 | e = e as MouseEvent; 81 | x = e.x; 82 | y = e.y; 83 | } else { 84 | x = (e as TouchEvent).changedTouches[0].pageX; 85 | y = (e as TouchEvent).changedTouches[0].pageY; 86 | } 87 | let center = windowToCanvas(this.ctx.canvas, x, y); 88 | ctx.clearRect(0, 0, width, height); 89 | this.drawImage(); 90 | ctx.save(); 91 | ctx.lineWidth = zoomRadius * 0.1; 92 | ctx.strokeStyle = '#ffffff'; 93 | ctx.beginPath(); 94 | ctx.arc(center.x, center.y, zoomRadius, 0, Math.PI * 2, false); 95 | ctx.clip(); 96 | ctx.drawImage( 97 | ctx.canvas, 98 | center.x - zoomRadius, 99 | center.y - zoomRadius, 100 | zoomRadius * 2, 101 | zoomRadius * 2, 102 | center.x - zoomRadius - (zoomRadius * 2 * scale - zoomRadius * 2) / 2, 103 | center.y - zoomRadius - (zoomRadius * 2 * scale - zoomRadius * 2) / 2, 104 | zoomRadius * 2 * scale, 105 | zoomRadius * 2 * scale, 106 | ); 107 | ctx.stroke(); 108 | ctx.restore(); 109 | } 110 | } 111 | 112 | /* 绑定鼠标移动事件 */ 113 | private bindMouseMove() { 114 | this.container.addEventListener(browser.pc ? 'mousemove' : 'touchmove', this.drawZoom.bind(this), false); 115 | } 116 | 117 | /* 渲染 */ 118 | render(container: HTMLElement) { 119 | super.render(container); 120 | let { ctx, width, height } = this; 121 | this.loading = new Loading(ctx); 122 | this.loading.start(); 123 | this.zoomRadius = Math.min(width, height) / 8; 124 | this.loadImages(); 125 | this.bindMouseMove(); 126 | } 127 | } 128 | 129 | export default ZoomCanvas; 130 | -------------------------------------------------------------------------------- /dist/32.293a725104a70dcfef11.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[32,33],{"0Pcb":function(t,e,i){"use strict";const s=function(){const t=window.navigator.userAgent;return window.location.href,function(t){const e={},i=t.indexOf("iPhone")>=0||t.indexOf("iPad")>=0||t.indexOf("iPod")>=0,s=t.indexOf("Android")>0;return e.ios=i,e.android=s,e.mobile=i||s,e.pc=!i&&!s,e}(t)}();e.a=s},"17XO":function(t,e,i){"use strict";i.r(e);const s=9.81;e.default=class{constructor(t,e,i,{verticalHeight:s=0,pixelPerMiter:r=1,useGravity:n=!1,useRebound:a=!1}={}){this.x=t,this.y=e,this.radius=i,this.offset=0,this.moveSpeed=0,this.currentSpeed=0,this.behaviors=[],this.pixelPerMiter=r,this.useGravity=n,this.useRebound=a,this.verticalHeight=s,this.isStill=!1}setSpeed(t){this.moveSpeed=t,this.currentSpeed=t}addBehavior(t){Array.isArray(t)?this.behaviors=[...this.behaviors,...t]:this.behaviors=[...this.behaviors,t]}update(t){for(let e of this.behaviors)e.call(null,this,t)}render(t){let{x:e,y:i,radius:s,offset:r,pixelPerMiter:n}=this;t.save(),t.translate(e,i+r*n),t.beginPath(),t.arc(0,0,s,0,2*Math.PI,!1),t.fill(),t.stroke(),t.restore()}reset(){this.offset=0,this.currentSpeed=this.moveSpeed}static move(t,e){if(t.isStill)return;let{currentSpeed:i}=t,r=e/1e3;t.useGravity&&(t.currentSpeed+=s*r);let n=t.currentSpeed*r;t.offset+n>t.verticalHeight?t.useRebound?(t.offset=t.verticalHeight,t.currentSpeed=.6*-t.currentSpeed,n*t.pixelPerMiter/r<1&&(t.isStill=!0,t.currentSpeed=0)):(t.isStill=!0,t.currentSpeed=0,t.offset=t.verticalHeight):t.offset+=n}}},Qb4n:function(t,e,i){"use strict";var s=i("kZAv");e.a=class{constructor(){this.el=document.createElement("canvas")}initCanvasSize(t,e){this.el.width=t,this.el.height=e,this.width=t,this.height=e}getContext(t,e){return this.el.getContext(t,e)}render(t){this.container=t;let{width:e,height:i}=t.getBoundingClientRect();this.initCanvasSize(e||s.d,i||s.b),this.container.innerHTML="",this.container.appendChild(this.el)}}},UWGR:function(t,e,i){"use strict";i.r(e),i.d(e,"default",function(){return n});var s=i("Qb4n"),r=i("17XO");class n extends s.a{constructor(){super(),this.ctx=this.getContext("2d"),this.padding=80,this.radius=20,this.isStart=!1}init(){this.fps=0,this.lastFrameTime=0,this.speed=5,this.distance=50;this.height,this.padding;this.distance<=0?this.pixelPerMiter=0:this.pixelPerMiter=(this.height-2*this.padding)/this.distance}createBall(){let{width:t,height:e,padding:i,speed:s,radius:n,pixelPerMiter:a,distance:h}=this;this.ball=new r.default(t/2,i-n,n,{verticalHeight:h,pixelPerMiter:a,useGravity:!0,useRebound:!0}),this.ball.setSpeed(s),this.ball.addBehavior(r.default.move)}createStartButton(){let{padding:t,radius:e}=this,i=document.createElement("button");i.style.position="absolute",i.style.right=2*e*1.4+"px",i.style.top=t-2*e+"px",i.style.width=2*e*1.4+"px",i.style.height=2*e+"px",i.style.textAlign="center",i.style.border="none",i.style.background="green",i.style.color="white",i.style.borderRadius="6px",i.style.zIndex="3",i.innerText="start",this.el.parentElement.style.position="relative",this.el.parentElement.appendChild(i),i.addEventListener("click",this.start.bind(this),!1)}calculateFps(t){let{fps:e,lastFrameTime:i,lastCalculateFpsTime:s}=this;i&&(0===e||t-s>1e3)&&(this.fps=1e3/(t-i),this.lastCalculateFpsTime=t)}draw(){let{ctx:t,width:e,height:i,padding:s}=this;t.strokeStyle="green",t.beginPath(),t.moveTo(s,i-s),t.lineTo(e-s,i-s),t.stroke(),t.fillStyle="orange",t.strokeStyle="red",this.ball.render(t)}update(){this.fps&&this.ball.update(1e3/this.fps)}animate(t){let{width:e,height:i,ctx:s}=this;s.clearRect(0,0,e,i),this.calculateFps(t),this.update(),this.draw(),this.lastFrameTime=t,this.timer=window.requestAnimationFrame(this.animate.bind(this))}start(){window.cancelAnimationFrame(this.timer),this.isStart=!0,this.ball.reset(),this.animate(0)}stop(){this.isStart=!1}render(t){super.render(t),this.init(),this.createBall(),this.createStartButton(),this.draw()}}},kZAv:function(t,e,i){"use strict";i.d(e,"d",function(){return s}),i.d(e,"b",function(){return r}),i.d(e,"a",function(){return n}),i.d(e,"c",function(){return a});const s=500,r=500,n=`${i("0Pcb").a.pc?24:16}px sans-serif`,a="https://snayan.github.io/canvas-demo/"}}]); --------------------------------------------------------------------------------