├── 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/"}}]);
--------------------------------------------------------------------------------