├── .eslintrc ├── .gitignore ├── README.CN.md ├── README.md ├── asset ├── cax-matter.png ├── cax-wegame.png ├── cax0712.png ├── demo.jpg ├── draw.png ├── getting-start.png ├── hot.png ├── qq.png ├── ss1.png ├── ss3.png ├── wegame.jpg ├── wegame.png ├── wx.png └── xqbl.png ├── change-log.md ├── index.html ├── packages ├── cax-weapp │ ├── app.js │ ├── app.json │ ├── app.wxss │ ├── cax │ │ ├── cax.js │ │ ├── cax.json │ │ ├── cax.wxml │ │ ├── cax.wxss │ │ └── index.js │ ├── images │ │ └── wx.png │ ├── index │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss │ └── project.config.json ├── cax-wegame │ ├── audio │ │ ├── bgm.mp3 │ │ ├── boom.mp3 │ │ └── bullet.mp3 │ ├── game.js │ ├── game.json │ ├── images │ │ ├── Common.png │ │ ├── bg.jpg │ │ ├── bullet.png │ │ ├── enemy.png │ │ ├── explosion1.png │ │ ├── explosion10.png │ │ ├── explosion11.png │ │ ├── explosion12.png │ │ ├── explosion13.png │ │ ├── explosion14.png │ │ ├── explosion15.png │ │ ├── explosion16.png │ │ ├── explosion17.png │ │ ├── explosion18.png │ │ ├── explosion19.png │ │ ├── explosion2.png │ │ ├── explosion3.png │ │ ├── explosion4.png │ │ ├── explosion5.png │ │ ├── explosion6.png │ │ ├── explosion7.png │ │ ├── explosion8.png │ │ ├── explosion9.png │ │ └── hero.png │ ├── js │ │ ├── background.js │ │ ├── bullet.js │ │ ├── enemy-group.js │ │ ├── enemy.js │ │ ├── libs │ │ │ └── cax.js │ │ ├── music.js │ │ └── player.js │ └── project.config.json ├── cax │ ├── .babelrc │ ├── .eslintignore │ ├── README.md │ ├── asset │ │ ├── cax-wegame.png │ │ ├── cax0712.png │ │ ├── demo.jpg │ │ ├── getting-start.png │ │ ├── qq.png │ │ ├── wegame.png │ │ └── wx.png │ ├── change-log.md │ ├── dist │ │ ├── cax.js │ │ └── cax.min.js │ ├── examples │ │ ├── button │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ ├── main.js │ │ │ ├── mario-sheet.png │ │ │ └── wepay.png │ │ ├── cache │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ ├── main.js │ │ │ ├── mario-sheet.png │ │ │ └── wepay.png │ │ ├── caching │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ ├── main.js │ │ │ ├── mario-sheet.png │ │ │ └── wepay.png │ │ ├── clip-transform │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ ├── main.js │ │ │ └── wepay.png │ │ ├── clip-transition │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ ├── main.js │ │ │ ├── pay.png │ │ │ └── wepay.png │ │ ├── clip │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ ├── main.js │ │ │ └── wepay-diy.jpg │ │ ├── composite-operation │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ ├── main.js │ │ │ └── wepay-diy.jpg │ │ ├── filter │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ ├── main.js │ │ │ ├── wegame.test.js │ │ │ └── wepay-diy.jpg │ │ ├── getting-start │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ ├── main.js │ │ │ └── wepay-diy.jpg │ │ ├── graphics │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ └── main.js │ │ ├── group-clip │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ ├── main.js │ │ │ └── wepay-diy.jpg │ │ ├── matter │ │ │ ├── img │ │ │ │ ├── basketball.png │ │ │ │ └── box.jpg │ │ │ ├── index.html │ │ │ └── matter.js │ │ ├── path │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ └── main.js │ │ ├── pie │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ └── main.js │ │ ├── simple │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ ├── main.js │ │ │ ├── mario-sheet.png │ │ │ └── wepay.png │ │ ├── sprite │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ ├── main.js │ │ │ └── mario-sheet.png │ │ ├── to-animate │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ ├── main.js │ │ │ └── wepay-diy.jpg │ │ ├── to-shape │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ └── main.js │ │ ├── to │ │ │ ├── bundler.js │ │ │ ├── index.html │ │ │ ├── main.js │ │ │ └── wepay-diy.jpg │ │ └── vision │ │ │ ├── bundler.js │ │ │ ├── hero-m.png │ │ │ ├── index.html │ │ │ └── main.js │ ├── package.json │ ├── src │ │ ├── common │ │ │ ├── animate.js │ │ │ ├── raf-interval.js │ │ │ ├── to.js │ │ │ ├── tween.js │ │ │ └── util.js │ │ ├── index.js │ │ └── render │ │ │ ├── base │ │ │ ├── a2c.js │ │ │ ├── arc-to-bezier.js │ │ │ ├── event-dispatcher.js │ │ │ ├── event.js │ │ │ ├── matrix2d.js │ │ │ ├── path-parser.js │ │ │ ├── stage-propagation-tag.js │ │ │ └── uid.js │ │ │ ├── display │ │ │ ├── bitmap.js │ │ │ ├── display-object.js │ │ │ ├── element │ │ │ │ └── button.js │ │ │ ├── graphics.js │ │ │ ├── group.js │ │ │ ├── shape │ │ │ │ ├── arrow-path.js │ │ │ │ ├── circle.js │ │ │ │ ├── ellipse.js │ │ │ │ ├── equilateral-polygon.js │ │ │ │ ├── path.js │ │ │ │ ├── polygon.js │ │ │ │ ├── rect.js │ │ │ │ ├── rounded-rect.js │ │ │ │ ├── sector.js │ │ │ │ └── shape.js │ │ │ ├── sprite.js │ │ │ ├── stage.js │ │ │ ├── text.js │ │ │ ├── we-stage.js │ │ │ └── wegame-canvas.js │ │ │ ├── filter │ │ │ ├── README.md │ │ │ ├── blur.js │ │ │ ├── brightness.js │ │ │ ├── colorize.js │ │ │ ├── contrast.js │ │ │ ├── create-image-data.js │ │ │ ├── gamma.js │ │ │ ├── grayscale.js │ │ │ ├── index.js │ │ │ ├── invert.js │ │ │ ├── sepia.js │ │ │ └── threshold.js │ │ │ └── render │ │ │ ├── canvas-render.js │ │ │ ├── hit-render.js │ │ │ ├── render.js │ │ │ ├── renderer.js │ │ │ └── wx-hit-render.js │ └── webpack.config.js └── to │ ├── README.EN.md │ ├── README.md │ ├── dist │ ├── to.js │ └── to.min.js │ ├── examples │ ├── animate │ │ ├── index.html │ │ └── wepay-diy.jpg │ ├── simple │ │ ├── bundler.js │ │ ├── index.html │ │ ├── main.js │ │ └── wepay-diy.jpg │ ├── swing │ │ ├── index.html │ │ └── wepay-diy.jpg │ └── to │ │ ├── index.html │ │ └── wepay-diy.jpg │ ├── package.json │ ├── src │ ├── animate.js │ ├── index.js │ ├── raf-interval.js │ ├── to.js │ └── tween.js │ └── webpack.config.js └── tutorial └── cax-matter.md /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "standard", 3 | "rules": { 4 | "one-var": 0, 5 | "no-mixed-operators": 0, 6 | "standard/no-callback-literal": 0, 7 | "new-cap": 0 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /*/*/node_modules 3 | /packages/node_modules 4 | .DS_Store 5 | packages/.DS_Store 6 | /packages/*/test 7 | -------------------------------------------------------------------------------- /asset/cax-matter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/asset/cax-matter.png -------------------------------------------------------------------------------- /asset/cax-wegame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/asset/cax-wegame.png -------------------------------------------------------------------------------- /asset/cax0712.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/asset/cax0712.png -------------------------------------------------------------------------------- /asset/demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/asset/demo.jpg -------------------------------------------------------------------------------- /asset/draw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/asset/draw.png -------------------------------------------------------------------------------- /asset/getting-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/asset/getting-start.png -------------------------------------------------------------------------------- /asset/hot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/asset/hot.png -------------------------------------------------------------------------------- /asset/qq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/asset/qq.png -------------------------------------------------------------------------------- /asset/ss1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/asset/ss1.png -------------------------------------------------------------------------------- /asset/ss3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/asset/ss3.png -------------------------------------------------------------------------------- /asset/wegame.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/asset/wegame.jpg -------------------------------------------------------------------------------- /asset/wegame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/asset/wegame.png -------------------------------------------------------------------------------- /asset/wx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/asset/wx.png -------------------------------------------------------------------------------- /asset/xqbl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/asset/xqbl.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | -------------------------------------------------------------------------------- /packages/cax-weapp/app.js: -------------------------------------------------------------------------------- 1 | App({ 2 | onLaunch: function () { 3 | 4 | } 5 | }) 6 | -------------------------------------------------------------------------------- /packages/cax-weapp/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "index/index" 4 | ], 5 | "window": { 6 | "backgroundTextStyle": "light", 7 | "navigationBarBackgroundColor": "#fff", 8 | "navigationBarTitleText": "WeChat", 9 | "navigationBarTextStyle": "black" 10 | } 11 | } -------------------------------------------------------------------------------- /packages/cax-weapp/app.wxss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-weapp/app.wxss -------------------------------------------------------------------------------- /packages/cax-weapp/cax/cax.js: -------------------------------------------------------------------------------- 1 | import cax from './index' 2 | 3 | Component({ 4 | /** 5 | * 组件的属性列表 6 | */ 7 | properties: { 8 | 9 | option: { 10 | type: Object 11 | } 12 | }, 13 | 14 | /** 15 | * 组件的初始数据 16 | */ 17 | data: { 18 | width: 0, 19 | height: 0, 20 | id: 'caxCanvas' + cax.caxCanvasId++, 21 | index: cax.caxCanvasId - 1 22 | }, 23 | 24 | /** 25 | * 组件的方法列表 26 | */ 27 | methods: { 28 | 29 | getCaxCanvasId: function () { 30 | return this.data.id 31 | }, 32 | 33 | touchStart: function (evt) { 34 | this.stage.touchStartHandler(evt) 35 | this.stage.touchStart && this.stage.touchStart(evt) 36 | }, 37 | 38 | touchMove: function (evt) { 39 | this.stage.touchMoveHandler(evt) 40 | this.stage.touchMove && this.stage.touchMove(evt) 41 | }, 42 | 43 | touchEnd: function (evt) { 44 | this.stage.touchEndHandler(evt) 45 | this.stage.touchEnd && this.stage.touchEnd(evt) 46 | } 47 | 48 | } 49 | }) 50 | -------------------------------------------------------------------------------- /packages/cax-weapp/cax/cax.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /packages/cax-weapp/cax/cax.wxml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/cax-weapp/cax/cax.wxss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-weapp/cax/cax.wxss -------------------------------------------------------------------------------- /packages/cax-weapp/images/wx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-weapp/images/wx.png -------------------------------------------------------------------------------- /packages/cax-weapp/index/index.js: -------------------------------------------------------------------------------- 1 | import cax from '../cax/index' 2 | 3 | Page({ 4 | onLoad: function (options) { 5 | const info = wx.getSystemInfoSync() 6 | const stage = new cax.Stage(info.windowWidth, info.windowHeight / 2, 'myCanvas', this) 7 | 8 | const rect = new cax.Rect(100, 100, { 9 | fillStyle: 'black' 10 | }) 11 | 12 | rect.originX = 50 13 | rect.originY = 50 14 | rect.x = 100 15 | rect.y = 100 16 | rect.rotation = 30 17 | 18 | rect.on('touchstart', () => { 19 | console.log('rect touchstart') 20 | }) 21 | 22 | rect.on('touchmove', () => { 23 | console.log('rect touchmove') 24 | }) 25 | 26 | rect.on('touchend', () => { 27 | console.log('rect touchend') 28 | }) 29 | 30 | rect.on('tap', () => { 31 | console.log('rect tap') 32 | }) 33 | 34 | 35 | stage.add(rect) 36 | 37 | const button = new cax.Button({ width: 100, height: 40, text: "I am button!" }) 38 | button.y = 170 39 | button.x = 20 40 | stage.add(button) 41 | 42 | 43 | 44 | 45 | const bitmap = new cax.Bitmap('/images/wx.png') 46 | 47 | 48 | 49 | bitmap.on('tap', () => { 50 | console.log('bitmap tap') 51 | }) 52 | 53 | stage.add(bitmap) 54 | 55 | 56 | const sprite = new cax.Sprite({ 57 | framerate: 7, 58 | imgs: ['https://r.photo.store.qq.com/psb?/V137Nysk1nVBJS/09YJstVgoLEi0niIWFcOJCyGmkyDaYLq.tlpDE62Zdc!/r/dDMBAAAAAAAA'], 59 | frames: [ 60 | // x, y, width, height, originX, originY ,imageIndex 61 | [0, 0, 32, 32], 62 | [32 * 1, 0, 32, 32], 63 | [32 * 2, 0, 32, 32], 64 | [32 * 3, 0, 32, 32], 65 | [32 * 4, 0, 32, 32], 66 | [32 * 5, 0, 32, 32], 67 | [32 * 6, 0, 32, 32], 68 | [32 * 7, 0, 32, 32], 69 | [32 * 8, 0, 32, 32], 70 | [32 * 9, 0, 32, 32], 71 | [32 * 10, 0, 32, 32], 72 | [32 * 11, 0, 32, 32], 73 | [32 * 12, 0, 32, 32], 74 | [32 * 13, 0, 32, 32], 75 | [32 * 14, 0, 32, 32] 76 | ], 77 | animations: { 78 | walk: { 79 | frames: [0, 1] 80 | }, 81 | happy: { 82 | frames: [11, 12, 13, 14] 83 | }, 84 | win: { 85 | frames: [7, 8, 9, 10] 86 | } 87 | }, 88 | currentAnimation: 'walk', 89 | animationEnd: function () { 90 | } 91 | }) 92 | 93 | sprite.x = 100 94 | sprite.y = 100 95 | stage.add(sprite) 96 | 97 | 98 | 99 | const stage2 = new cax.Stage(info.windowWidth, info.windowHeight / 2, 'myCanvas2', this) 100 | 101 | const button2 = new cax.Button({ width: 100, height: 40, text: "I am in stage2!" }) 102 | button2.y = 170 103 | button2.x = 20 104 | stage2.add(button2) 105 | const bitmap2 = new cax.Bitmap('/images/wx.png') 106 | bitmap2.y=100 107 | stage2.add(bitmap2) 108 | 109 | cax.To.get(rect).to().x(200, 2000, cax.easing.elasticInOut).start() 110 | 111 | 112 | 113 | 114 | setInterval(function () { 115 | rect.rotation++ 116 | stage.update() 117 | stage2.update() 118 | }, 16) 119 | 120 | } 121 | }) 122 | -------------------------------------------------------------------------------- /packages/cax-weapp/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": { 3 | "cax":"../cax/cax" 4 | } 5 | } -------------------------------------------------------------------------------- /packages/cax-weapp/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /packages/cax-weapp/index/index.wxss: -------------------------------------------------------------------------------- 1 | .container{ 2 | height:1000px; 3 | } -------------------------------------------------------------------------------- /packages/cax-weapp/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件。", 3 | "setting": { 4 | "urlCheck": true, 5 | "es6": true, 6 | "postcss": true, 7 | "minified": true, 8 | "newFeature": true 9 | }, 10 | "compileType": "miniprogram", 11 | "libVersion": "1.9.94", 12 | "appid": "wxdf970566455966b0", 13 | "projectname": "cax-weapp", 14 | "condition": { 15 | "search": { 16 | "current": -1, 17 | "list": [] 18 | }, 19 | "conversation": { 20 | "current": -1, 21 | "list": [] 22 | }, 23 | "plugin": { 24 | "current": -1, 25 | "list": [] 26 | }, 27 | "game": { 28 | "currentL": -1, 29 | "list": [] 30 | }, 31 | "miniprogram": { 32 | "current": -1, 33 | "list": [] 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /packages/cax-wegame/audio/bgm.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/audio/bgm.mp3 -------------------------------------------------------------------------------- /packages/cax-wegame/audio/boom.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/audio/boom.mp3 -------------------------------------------------------------------------------- /packages/cax-wegame/audio/bullet.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/audio/bullet.mp3 -------------------------------------------------------------------------------- /packages/cax-wegame/game.js: -------------------------------------------------------------------------------- 1 | import cax from './js/libs/cax' 2 | 3 | import Background from './js/background' 4 | import Player from './js/player' 5 | import EnemyGroup from './js/enemy-group' 6 | import Music from './js/music' 7 | 8 | const bg = new Background() 9 | const player = new Player() 10 | const stage = new cax.Stage() 11 | const enemyGroup = new EnemyGroup() 12 | const music = new Music() 13 | const info = wx.getSystemInfoSync() 14 | const screenHeight = info.windowHeight 15 | 16 | stage.add(bg, enemyGroup, player) 17 | 18 | stage.add(player.bulletGroup) 19 | 20 | let touchX = null 21 | let touchY = null 22 | 23 | wx.onTouchStart(function (e) { 24 | touchX = e.touches[0].clientX 25 | touchY = e.touches[0].clientY 26 | }) 27 | 28 | wx.onTouchMove(function (e) { 29 | touchX = e.touches[0].clientX 30 | touchY = e.touches[0].clientY 31 | }) 32 | 33 | function update () { 34 | stage.update() 35 | bg.update() 36 | 37 | player.update() 38 | if (touchX !== null) { 39 | player.x = touchX 40 | player.y = touchY 41 | } 42 | enemyGroup.update() 43 | 44 | enemyGroup.children.forEach(enemy => { 45 | player.bulletGroup.children.forEach(bullet => { 46 | if (bullet.isCollideWith(enemy)) { 47 | bullet.visible = false 48 | enemy.explode() 49 | music.playExplosion() 50 | } 51 | }) 52 | }) 53 | 54 | requestAnimationFrame(update) 55 | } 56 | 57 | update() 58 | 59 | 60 | const text = new cax.Text('powered by cax', { 61 | font: '20px Arial', 62 | color: '#42B035', 63 | baseline: 'top' 64 | }) 65 | text.y = screenHeight - 30 66 | text.x = 4 67 | text.alpha = 0.6 68 | stage.add(text) 69 | 70 | cax.To.get(text).to().x(100, 2000, cax.easing.elasticInOut).start() -------------------------------------------------------------------------------- /packages/cax-wegame/game.json: -------------------------------------------------------------------------------- 1 | { 2 | "deviceOrientation": "portrait" 3 | } 4 | -------------------------------------------------------------------------------- /packages/cax-wegame/images/Common.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/Common.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/bg.jpg -------------------------------------------------------------------------------- /packages/cax-wegame/images/bullet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/bullet.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/enemy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/enemy.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion1.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion10.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion11.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion12.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion13.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion13.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion14.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion14.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion15.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion16.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion17.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion17.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion18.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion19.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion19.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion2.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion3.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion4.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion5.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion6.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion7.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion8.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/explosion9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/explosion9.png -------------------------------------------------------------------------------- /packages/cax-wegame/images/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax-wegame/images/hero.png -------------------------------------------------------------------------------- /packages/cax-wegame/js/background.js: -------------------------------------------------------------------------------- 1 | import cax from './libs/cax' 2 | 3 | const info = wx.getSystemInfoSync() 4 | const screenWidth = info.windowWidth 5 | const screenHeight = info.windowHeight 6 | 7 | const BG_IMG_SRC = 'images/bg.jpg' 8 | const BG_WIDTH = 512 9 | const BG_HEIGHT = 512 10 | 11 | export default class BackGround extends cax.Group { 12 | constructor () { 13 | super() 14 | 15 | this.bgUp = new cax.Bitmap(BG_IMG_SRC) 16 | this.bgDown = new cax.Bitmap(BG_IMG_SRC) 17 | 18 | this.bgDown.y = screenHeight * -1 19 | this.bgUp.y = -1 20 | 21 | this.bgDown.scaleX = this.bgUp.scaleX = screenWidth / BG_WIDTH 22 | this.bgDown.scaleY = this.bgUp.scaleY = screenHeight / BG_HEIGHT 23 | 24 | this.add(this.bgUp, this.bgDown) 25 | } 26 | 27 | update () { 28 | this.bgDown.y += 2 29 | this.bgUp.y += 2 30 | 31 | if (this.bgUp.y >= screenHeight) { 32 | this.bgUp.y = this.bgDown.y - screenHeight 33 | } 34 | 35 | if (this.bgDown.y >= screenHeight) { 36 | this.bgDown.y = this.bgUp.y - screenHeight 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/cax-wegame/js/bullet.js: -------------------------------------------------------------------------------- 1 | import cax from './libs/cax' 2 | 3 | const BULLET_IMG_SRC = 'images/bullet.png' 4 | const IMG_WIDTH = 62 5 | const IMG_HEIGHT = 108 6 | 7 | export default class Bullet extends cax.Group { 8 | constructor () { 9 | super() 10 | this.bitmap = new cax.Bitmap(BULLET_IMG_SRC) 11 | this.bitmap.originX = IMG_WIDTH / 2 12 | this.bitmap.originY = IMG_HEIGHT / 2 13 | this.add(this.bitmap) 14 | this.scaleX = this.scaleY = 0.3 15 | this.speed = 5 16 | 17 | this.width = IMG_WIDTH / 2 18 | this.height = IMG_WIDTH / 2 19 | } 20 | 21 | // 每一帧更新子弹位置 22 | update () { 23 | this.y -= this.speed 24 | // 超出屏幕外回收自身 25 | if (this.y < -200) { 26 | this.destroy() 27 | } 28 | } 29 | 30 | isCollideWith (sp) { 31 | if (this.visible && !sp.exploded) { 32 | let spX = sp.x 33 | let spY = sp.y 34 | 35 | return !!(spX >= this.x - this.width / 2 && 36 | spX <= this.x + this.width / 2 && 37 | spY >= this.y - this.height / 2 && 38 | spY <= this.y + this.height / 2) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/cax-wegame/js/enemy-group.js: -------------------------------------------------------------------------------- 1 | import cax from './libs/cax' 2 | import Enemy from './enemy' 3 | 4 | const info = wx.getSystemInfoSync() 5 | const screenWidth = info.windowWidth 6 | 7 | function rnd (start, end) { 8 | return Math.floor(Math.random() * (end - start) + start) 9 | } 10 | 11 | export default class EnemyGroup extends cax.Group { 12 | constructor () { 13 | super() 14 | this.preGenerateTime = Date.now() 15 | } 16 | 17 | generate () { 18 | const e = new Enemy() 19 | e.x = rnd(0, screenWidth) 20 | e.y = -60 21 | this.add(e) 22 | } 23 | 24 | update () { 25 | this.currentTime = Date.now() 26 | if (this.currentTime - this.preGenerateTime > 1000) { 27 | this.generate() 28 | 29 | this.preGenerateTime = this.currentTime 30 | } 31 | 32 | this.children.forEach(child => { 33 | child.update() 34 | }) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/cax-wegame/js/enemy.js: -------------------------------------------------------------------------------- 1 | import cax from './libs/cax' 2 | 3 | const ENEMY_IMG_SRC = 'images/enemy.png' 4 | 5 | const IMG_WIDTH = 120 6 | const IMG_HEIGHT = 79 7 | 8 | const info = wx.getSystemInfoSync() 9 | const screenHeight = info.windowHeight 10 | 11 | export default class Enemy extends cax.Group { 12 | constructor () { 13 | super() 14 | this.bitmap = new cax.Bitmap(ENEMY_IMG_SRC) 15 | this.bitmap.originX = IMG_WIDTH / 2 16 | this.bitmap.originY = IMG_HEIGHT / 2 17 | this.add(this.bitmap) 18 | 19 | this.scaleX = this.scaleY = 0.5 20 | this.speed = 1 21 | 22 | this.width = IMG_WIDTH / 2 23 | this.height = IMG_WIDTH / 2 24 | 25 | this.spriteOption = { 26 | framerate: 20, 27 | imgs: [ 28 | 'images/explosion1.png', 29 | 'images/explosion2.png', 30 | 'images/explosion3.png', 31 | 'images/explosion4.png', 32 | 'images/explosion5.png', 33 | 'images/explosion6.png', 34 | 'images/explosion7.png', 35 | 'images/explosion8.png', 36 | 'images/explosion9.png', 37 | 'images/explosion10.png', 38 | 'images/explosion11.png', 39 | 'images/explosion12.png', 40 | 'images/explosion13.png', 41 | 'images/explosion14.png', 42 | 'images/explosion15.png', 43 | 'images/explosion16.png', 44 | 'images/explosion17.png', 45 | 'images/explosion18.png', 46 | 'images/explosion19.png' 47 | ], 48 | frames: [ 49 | // x, y, width, height, originX, originY ,imageIndex 50 | [0, 0, 64, 48, 0, 0, 0], 51 | [0, 0, 64, 48, 0, 0, 1], 52 | [0, 0, 64, 48, 0, 0, 2], 53 | [0, 0, 64, 48, 0, 0, 3], 54 | [0, 0, 64, 48, 0, 0, 4], 55 | [0, 0, 64, 48, 0, 0, 5], 56 | [0, 0, 64, 48, 0, 0, 6], 57 | [0, 0, 64, 48, 0, 0, 7], 58 | [0, 0, 64, 48, 0, 0, 8], 59 | [0, 0, 64, 48, 0, 0, 9], 60 | [0, 0, 64, 48, 0, 0, 10], 61 | [0, 0, 64, 48, 0, 0, 11], 62 | [0, 0, 64, 48, 0, 0, 12], 63 | [0, 0, 64, 48, 0, 0, 13], 64 | [0, 0, 64, 48, 0, 0, 14], 65 | [0, 0, 64, 48, 0, 0, 15], 66 | [0, 0, 64, 48, 0, 0, 16], 67 | [0, 0, 64, 48, 0, 0, 17], 68 | [0, 0, 64, 48, 0, 0, 18] 69 | ], 70 | animations: { 71 | explode: { 72 | frames: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18] 73 | } 74 | }, 75 | currentAnimation: 'explode', 76 | animationEnd: () => { 77 | this.destroy() 78 | } 79 | } 80 | } 81 | 82 | explode () { 83 | this.bitmap.visible = false 84 | this.exploded = true 85 | const es = new cax.Sprite(this.spriteOption) 86 | es.fixed = true 87 | es.x = this.x - 32 88 | es.y = this.y - 24 89 | this.es = es 90 | this.add(es) 91 | } 92 | 93 | update () { 94 | if(this.es){ 95 | this.es.y += this.speed * 2 96 | } 97 | this.y += this.speed 98 | if (this.y > screenHeight) { 99 | this.destroy() 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /packages/cax-wegame/js/music.js: -------------------------------------------------------------------------------- 1 | let instance 2 | 3 | /** 4 | * 统一的音效管理器 5 | */ 6 | export default class Music { 7 | constructor () { 8 | if (instance) { return instance } 9 | 10 | instance = this 11 | 12 | this.bgmAudio = wx.createInnerAudioContext() 13 | this.bgmAudio.loop = true 14 | this.bgmAudio.src = 'audio/bgm.mp3' 15 | 16 | this.shootAudio = wx.createInnerAudioContext() 17 | this.shootAudio.src = 'audio/bullet.mp3' 18 | 19 | this.boomAudio = wx.createInnerAudioContext() 20 | this.boomAudio.src = 'audio/boom.mp3' 21 | 22 | this.playBgm() 23 | } 24 | 25 | playBgm () { 26 | this.bgmAudio.play() 27 | } 28 | 29 | playShoot () { 30 | // this.shootAudio.currentTime = 0 31 | this.shootAudio.play() 32 | } 33 | 34 | playExplosion () { 35 | // this.boomAudio.currentTime = 0 36 | this.boomAudio.play() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/cax-wegame/js/player.js: -------------------------------------------------------------------------------- 1 | import cax from './libs/cax' 2 | import Bullet from './bullet' 3 | import Music from './music' 4 | 5 | const info = wx.getSystemInfoSync() 6 | const screenWidth = info.windowWidth 7 | const screenHeight = info.windowHeight 8 | 9 | // 玩家相关常量设置 10 | const PLAYER_IMG_SRC = 'images/hero.png' 11 | const IMG_WIDTH = 186 12 | const IMG_HEIGHT = 130 13 | 14 | export default class Player extends cax.Group { 15 | constructor (ctx) { 16 | super() 17 | this.music = new Music() 18 | this.bitmap = new cax.Bitmap(PLAYER_IMG_SRC) 19 | this.bitmap.originX = IMG_WIDTH / 2 20 | this.bitmap.originY = IMG_HEIGHT / 2 21 | 22 | this.add(this.bitmap) 23 | this.x = screenWidth / 2 24 | this.y = screenHeight - 80 25 | 26 | this.scaleX = this.scaleY = 0.5 27 | 28 | this.preShootTime = Date.now() 29 | this.bulletGroup = new cax.Group() 30 | } 31 | 32 | update () { 33 | this.currentTime = Date.now() 34 | if (this.currentTime - this.preShootTime > 200) { 35 | this.shoot() 36 | this.preShootTime = this.currentTime 37 | } 38 | 39 | this.bulletGroup.children.forEach(bullet => { 40 | bullet.update() 41 | }) 42 | } 43 | 44 | shoot () { 45 | let bullet = new Bullet() 46 | bullet.x = this.x 47 | bullet.y = this.y - 30 48 | this.music.playShoot() 49 | this.bulletGroup.add(bullet) 50 | } 51 | 52 | isCollideWith (sp) { 53 | let spX = sp.x + sp.width / 2 54 | let spY = sp.y + sp.height / 2 55 | 56 | return !!(spX >= this.x && 57 | spX <= this.x + this.width && 58 | spY >= this.y && 59 | spY <= this.y + this.height) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /packages/cax-wegame/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件。", 3 | "setting": { 4 | "urlCheck": true, 5 | "es6": true, 6 | "postcss": true, 7 | "minified": true, 8 | "newFeature": true 9 | }, 10 | "compileType": "game", 11 | "libVersion": "game", 12 | "appid": "wx5d552c03ad3810b9", 13 | "projectname": "cax-wegame", 14 | "condition": { 15 | "search": { 16 | "current": -1, 17 | "list": [] 18 | }, 19 | "conversation": { 20 | "current": -1, 21 | "list": [] 22 | }, 23 | "game": { 24 | "currentL": -1, 25 | "list": [] 26 | }, 27 | "miniprogram": { 28 | "current": -1, 29 | "list": [] 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /packages/cax/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "transform-class-properties" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/cax/.eslintignore: -------------------------------------------------------------------------------- 1 | 2 | dist 3 | node_modules 4 | 5 | example/hyperscript/bundler.js 6 | example/life-cycle/bundler.js 7 | example/nest/bundler.js 8 | example/pagination/bundler.js 9 | example/perfs 10 | example/plugin/bundler.js 11 | example/ref/bundler.js 12 | example/simple/bundler.js 13 | example/slot/bundler.js 14 | example/todo/bundler.js 15 | example/tree/bundler.js 16 | 17 | ../cax-weapp/cax/index.js 18 | ../cax-wegame/js/libs/cax.js -------------------------------------------------------------------------------- /packages/cax/asset/cax-wegame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/asset/cax-wegame.png -------------------------------------------------------------------------------- /packages/cax/asset/cax0712.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/asset/cax0712.png -------------------------------------------------------------------------------- /packages/cax/asset/demo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/asset/demo.jpg -------------------------------------------------------------------------------- /packages/cax/asset/getting-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/asset/getting-start.png -------------------------------------------------------------------------------- /packages/cax/asset/qq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/asset/qq.png -------------------------------------------------------------------------------- /packages/cax/asset/wegame.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/asset/wegame.png -------------------------------------------------------------------------------- /packages/cax/asset/wx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/asset/wx.png -------------------------------------------------------------------------------- /packages/cax/examples/button/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cax Simple Demo 7 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /packages/cax/examples/button/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | 3 | 4 | const stage = new cax.Stage(300, 400, 'body') 5 | 6 | const button = new cax.Button({ 7 | width: 100, 8 | height: 40, 9 | // textX:8, 10 | text: "sfsdf Me!", 11 | //autoHeight: true 12 | }) 13 | button.x =100 14 | button.y =200 15 | stage.add(button) 16 | 17 | cax.setInterval(() => { 18 | stage.update() 19 | }, 16) -------------------------------------------------------------------------------- /packages/cax/examples/button/mario-sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/button/mario-sheet.png -------------------------------------------------------------------------------- /packages/cax/examples/button/wepay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/button/wepay.png -------------------------------------------------------------------------------- /packages/cax/examples/cache/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Cax Cache Demo 8 | 25 | 26 | 27 | 28 |
29 |
30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /packages/cax/examples/cache/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | 3 | 4 | 5 | const stage = new cax.Stage(600, 400, '#canvasCtn') 6 | 7 | const radius = 50 8 | const rings = 40 9 | 10 | const colors = ["#828b20", "#b0ac31", "#cbc53d", "#fad779", "#f9e4ad", "#faf2db", "#563512", "#9b4a0b", "#d36600", "#fe8a00", "#f9a71f"] 11 | 12 | for (let i = 0; i < 200; i++) { 13 | 14 | const shape = new cax.Graphics() 15 | for (var j = rings; j > 0; j--) { 16 | shape.beginPath().fillStyle(colors[Math.random() * colors.length | 0]).arc(0,0,radius * j / rings,0,Math.PI*2).fill() 17 | } 18 | shape.x = Math.random() * 600 19 | shape.y = Math.random() * 400 20 | shape.velX = Math.random() * 10 - 5 21 | shape.velY = Math.random() * 10 - 5 22 | 23 | 24 | stage.add(shape); 25 | } 26 | 27 | 28 | 29 | 30 | cax.tick(function () { 31 | 32 | var w = 600 + radius * 2; 33 | var h = 400 + radius * 2; 34 | 35 | for (var i = 0; i < 200; i++) { 36 | var shape = stage.children[i]; 37 | shape.x = (shape.x + radius + shape.velX + w) % w - radius; 38 | shape.y = (shape.y + radius + shape.velY + h) % h - radius; 39 | } 40 | 41 | stage.update(); 42 | }) 43 | 44 | 45 | 46 | let tag = true 47 | 48 | document.querySelector('#toggleBtn').addEventListener('click', () => { 49 | 50 | for (var i = 0; i < 200; i++) { 51 | var shape = stage.children[i]; 52 | if (tag) { 53 | shape.cache(-radius, -radius, radius * 2, radius * 2) 54 | } else { 55 | shape.uncache() 56 | } 57 | } 58 | 59 | tag =!tag 60 | 61 | }) -------------------------------------------------------------------------------- /packages/cax/examples/cache/mario-sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/cache/mario-sheet.png -------------------------------------------------------------------------------- /packages/cax/examples/cache/wepay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/cache/wepay.png -------------------------------------------------------------------------------- /packages/cax/examples/caching/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Cax Simple Demo 8 | 25 | 26 | 27 | 28 |
29 |
30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /packages/cax/examples/caching/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | 3 | 4 | const stage = new cax.Stage(300, 400, '#canvasCtn') 5 | 6 | const circle = new cax.Circle(40, { fillStyle: 'black' }) 7 | 8 | circle.x = 200 9 | circle.y = 250 10 | circle.rotation = 15 11 | circle.cache(0, 0, 40, 40, 1) 12 | 13 | 14 | 15 | 16 | const text = new cax.Text("abc", { 17 | font: '60px Arial' 18 | }) 19 | 20 | text.x = 100 21 | text.y = 100 22 | //text.scaleX = 0.5 23 | text.cache(0, 0, 80, 60) 24 | stage.add(text,circle) 25 | 26 | stage.update() 27 | 28 | setInterval(()=>{ 29 | stage.update() 30 | },16) 31 | 32 | const gt = new cax.Text("Group Cache", { 33 | font: '20px Arial' 34 | }) 35 | const group = new cax.Group() 36 | 37 | group.x =130 38 | group.y =30 39 | 40 | const rect = new cax.Rect(140,40, { fillStyle: 'red' }) 41 | 42 | group.cache(-20,0,100,20 ,1) 43 | 44 | group.add(rect, gt) 45 | stage.add(group) 46 | stage.update() 47 | 48 | 49 | group.cursor = 'move' 50 | 51 | group.on('drag',(evt)=>{ 52 | evt.target.x +=evt.dx 53 | evt.target.y+=evt.dy 54 | }) 55 | text.cursor = 'move' 56 | circle.cursor = 'pointer' 57 | 58 | 59 | let tag = false 60 | 61 | document.querySelector('#toggleBtn').addEventListener('click', () => { 62 | group[(tag ? 'cache' : 'uncache')](-20,0,100,20 ,1) 63 | text[(tag ? 'cache' : 'uncache')](0, 0, 80, 60) 64 | circle[(tag ? 'cache' : 'uncache')](0, 0, 40, 40, 1) 65 | tag =!tag 66 | stage.update() 67 | }) 68 | 69 | // cax.setInterval(function(){ 70 | // stage.update() 71 | // },16) -------------------------------------------------------------------------------- /packages/cax/examples/caching/mario-sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/caching/mario-sheet.png -------------------------------------------------------------------------------- /packages/cax/examples/caching/wepay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/caching/wepay.png -------------------------------------------------------------------------------- /packages/cax/examples/clip-transform/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cax Clip Demo 7 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
32 |
Click The Canvas
33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /packages/cax/examples/clip-transform/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | 3 | const w = 576 4 | const h = 360 5 | const r = 65 6 | const stage = new cax.Stage(w, h, '#canvasCtn') 7 | const bitmap = new cax.Bitmap('./wepay.png', () => { 8 | stage.update() 9 | }) 10 | 11 | 12 | const clipPath = new cax.Graphics() 13 | clipPath.x = 40 + Math.random() * 200 14 | clipPath.y = 40 + Math.random() * 200 15 | clipPath.arc(0, 0, r, 0, Math.PI * 2) 16 | bitmap.clip(clipPath) 17 | 18 | stage.add(bitmap) 19 | 20 | let tag = true 21 | 22 | stage.on('click', (evt) => { 23 | const rt = 576 / (window.innerWidth>800?800:window.innerWidth) 24 | clipPath.x = evt.stageX * rt 25 | clipPath.y = evt.stageY * rt 26 | }) 27 | 28 | let speedX = 1, 29 | speedY = 1 30 | 31 | cax.setInterval(function () { 32 | 33 | clipPath.x += speedX 34 | clipPath.y += speedY 35 | if (clipPath.y > h - r) { 36 | clipPath.y = h - r 37 | speedY *= -1 38 | } else if (clipPath.y < r) { 39 | clipPath.y = r 40 | speedY *= -1 41 | } 42 | 43 | if (clipPath.x > w - r) { 44 | clipPath.x = w - r 45 | speedX *= -1 46 | } else if (clipPath.x < r) { 47 | clipPath.x = r 48 | speedX *= -1 49 | } 50 | 51 | stage.update() 52 | }, 15) -------------------------------------------------------------------------------- /packages/cax/examples/clip-transform/wepay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/clip-transform/wepay.png -------------------------------------------------------------------------------- /packages/cax/examples/clip-transition/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cax Clip Demo 7 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
32 |
Click The Canvas
33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /packages/cax/examples/clip-transition/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | 3 | const w = 576 4 | const h = 360 5 | const r = 700 6 | const stage = new cax.Stage(w, h, '#canvasCtn') 7 | const group = new cax.Group() 8 | 9 | cax.loadImgs({ 10 | imgs:['./wepay.png','./pay.png'], 11 | progress:function(a,b,c,d){ 12 | console.log(a,b,c,d) 13 | }, 14 | complete:function(imgs){ 15 | 16 | 17 | const bitmap = new cax.Bitmap(imgs[0]) 18 | const payBmp = new cax.Bitmap(imgs[1]) 19 | 20 | const clipPath = new cax.Graphics() 21 | clipPath.x = 280 22 | clipPath.y = 180 23 | clipPath.arc(0, 0, r, 0, Math.PI * 2) 24 | group.clip(clipPath) 25 | bitmap.visible = false 26 | group.add(bitmap, payBmp) 27 | stage.add(group) 28 | 29 | 30 | stage.on('click', (evt) => { 31 | const rt = 576 / (window.innerWidth > 800 ? 800 : window.innerWidth) 32 | clipPath.x = evt.stageX * rt 33 | clipPath.y = evt.stageY * rt 34 | }) 35 | 36 | let flag = false 37 | 38 | cax.To.get(clipPath) 39 | .to().scaleY(0.0001, 1000).scaleX(0.0001, 1000) 40 | .end(()=>{ 41 | bitmap.visible = !flag 42 | payBmp.visible = flag 43 | flag = !flag 44 | }) 45 | .wait(100) 46 | .to().scaleY(1, 1000).scaleX(1, 1000) 47 | .wait(1900) 48 | .cycle().start() 49 | 50 | 51 | cax.setInterval(function () { 52 | stage.update() 53 | }, 15) 54 | } 55 | }) 56 | -------------------------------------------------------------------------------- /packages/cax/examples/clip-transition/pay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/clip-transition/pay.png -------------------------------------------------------------------------------- /packages/cax/examples/clip-transition/wepay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/clip-transition/wepay.png -------------------------------------------------------------------------------- /packages/cax/examples/clip/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cax Clip Demo 7 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 | 31 |
32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /packages/cax/examples/clip/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | const stage = new cax.Stage(260, 200, '#canvasCtn') 3 | 4 | cax.loadImg({ 5 | img:'./wepay-diy.jpg', 6 | complete:function(img){ 7 | 8 | const bitmap = new cax.Bitmap(img) 9 | 10 | bitmap.x = 130 11 | bitmap.y = 100 12 | bitmap.originX = 40 13 | bitmap.originY = 40 14 | bitmap.cursor = 'pointer' 15 | bitmap.on('click', () => { 16 | alert('微信支付') 17 | }) 18 | 19 | bitmap.on('drag',(evt)=>{ 20 | evt.target.x+=evt.dx 21 | evt.target.y+=evt.dy 22 | }) 23 | 24 | 25 | 26 | cax.setInterval(()=>{ 27 | stage.update() 28 | },16) 29 | 30 | const clipPath = new cax.Graphics() 31 | clipPath.x = 40 32 | clipPath.y = 40 33 | clipPath.arc(0, 0, 25, 0, Math.PI * 2) 34 | bitmap.clip(clipPath) 35 | 36 | stage.add(bitmap) 37 | 38 | let tag = true 39 | 40 | document.querySelector('#toggleBtn').addEventListener('click', () => { 41 | bitmap.clip(tag ? null : clipPath) 42 | tag =!tag 43 | stage.update() 44 | }) 45 | } 46 | }) -------------------------------------------------------------------------------- /packages/cax/examples/clip/wepay-diy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/clip/wepay-diy.jpg -------------------------------------------------------------------------------- /packages/cax/examples/composite-operation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cax Composite Operation Demo 7 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 | 31 |
32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /packages/cax/examples/composite-operation/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | const stage = new cax.Stage(260, 200, '#canvasCtn') 3 | const group = new cax.Group() 4 | group.x = 90 5 | group.y = 60 6 | const bitmap = new cax.Bitmap('./wepay-diy.jpg', () => { 7 | group.cache(0, 0, 100, 100, 1) 8 | stage.update() 9 | }) 10 | 11 | 12 | group.cursor = 'pointer' 13 | group.on('click', () => { 14 | alert('微信支付') 15 | }) 16 | 17 | group.on('drag', (evt) => { 18 | evt.target.x += evt.dx 19 | evt.target.y += evt.dy 20 | }) 21 | const bg = new cax.Rect(11200, 1180, { fillStyle: '#DE5347' }) 22 | //bg.cursor = 'default' 23 | 24 | const rect = new cax.Rect(80, 20, { fillStyle: 'black' }) 25 | rect.compositeOperation = 'source-atop' 26 | 27 | 28 | group.add(bitmap, rect) 29 | 30 | stage.add(bg, group) 31 | 32 | cax.tick(() => { 33 | stage.update() 34 | }) 35 | 36 | let tag = true 37 | 38 | document.querySelector('#toggleBtn').addEventListener('click', () => { 39 | 40 | if (tag) { 41 | 42 | group.uncache() 43 | } else { 44 | group.cache(0, 0, 100, 100) 45 | } 46 | 47 | 48 | tag = !tag 49 | 50 | }) -------------------------------------------------------------------------------- /packages/cax/examples/composite-operation/wepay-diy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/composite-operation/wepay-diy.jpg -------------------------------------------------------------------------------- /packages/cax/examples/filter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Cax Filter Demo 8 | 25 | 26 | 27 | 28 |
29 |
30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /packages/cax/examples/filter/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | 3 | 4 | const stage = new cax.Stage(300, 400, '#canvasCtn') 5 | 6 | cax.loadImg({ 7 | img: './wepay-diy.jpg', 8 | complete: (img) => { 9 | const bitmap = new cax.Bitmap(img) 10 | bitmap.x = 20 11 | bitmap.y = 30 12 | stage.add(bitmap) 13 | 14 | 15 | const bitmapA = bitmap.clone() 16 | bitmapA.x = 20 17 | bitmapA.y = 110 18 | stage.add(bitmapA) 19 | 20 | const bitmapB = bitmapA.clone() 21 | bitmapB.x = 110 22 | stage.add(bitmapB) 23 | 24 | const bitmapC = bitmapA.clone() 25 | bitmapC.x = 200 26 | stage.add(bitmapC) 27 | 28 | const bitmapD = bitmapA.clone() 29 | bitmapD.x = 200 30 | bitmapD.y = 30 31 | stage.add(bitmapD) 32 | 33 | const bitmapE = bitmapA.clone() 34 | bitmapE.x = 110 35 | bitmapE.y = 30 36 | stage.add(bitmapE) 37 | 38 | const bitmapF = bitmapA.clone() 39 | bitmapF.x = 200 40 | bitmapF.y = 190 41 | stage.add(bitmapF) 42 | 43 | const bitmapG = bitmapA.clone() 44 | bitmapG.x = 20 45 | bitmapG.y = 190 46 | stage.add(bitmapG) 47 | 48 | const bitmapH = bitmapA.clone() 49 | bitmapH.x = 110 50 | bitmapH.y = 190 51 | stage.add(bitmapH) 52 | 53 | const bitmapI = bitmapA.clone() 54 | bitmapI.x = 110 55 | bitmapI.y = 270 56 | stage.add(bitmapI) 57 | 58 | const bitmapJ = bitmapA.clone() 59 | bitmapJ.x = 20 60 | bitmapJ.y = 270 61 | stage.add(bitmapJ) 62 | 63 | const bitmapK = bitmapA.clone() 64 | bitmapK.x = 200 65 | bitmapK.y = 270 66 | stage.add(bitmapK) 67 | 68 | 69 | filter() 70 | 71 | let tag = true 72 | document.querySelector('#toggleBtn').addEventListener('click', function () { 73 | if (tag) { 74 | unfilter() 75 | } else { 76 | filter() 77 | } 78 | tag = !tag 79 | }) 80 | 81 | function unfilter() { 82 | bitmapA.unfilter() 83 | bitmapB.unfilter() 84 | bitmapC.unfilter() 85 | bitmapD.unfilter() 86 | bitmapE.unfilter() 87 | bitmapF.unfilter() 88 | bitmapG.unfilter() 89 | bitmapH.unfilter() 90 | bitmapI.unfilter() 91 | bitmapJ.unfilter() 92 | bitmapK.unfilter() 93 | } 94 | 95 | function filter() { 96 | bitmapA.filter('invert(1)', { x: 0, y: 0, width: 80, height: 80 }) 97 | bitmapB.filter('brightness(1.3)', { x: 0, y: 0, width: 80, height: 80 }) 98 | bitmapC.filter('blur(15px)', { x: 0, y: 0, width: 80, height: 80 }) 99 | bitmapD.filter('contrast(1.3)', { x: 0, y: 0, width: 80, height: 80 }) 100 | bitmapE.filter('brightness(0.5)', { x: 0, y: 0, width: 80, height: 80 }) 101 | bitmapF.filter('contrast(0.3)', { x: 0, y: 0, width: 80, height: 80 }) 102 | bitmapG.filter('grayscale(1)', { x: 0, y: 0, width: 80, height: 80 }) 103 | bitmapH.filter('sepia(1)', { x: 0, y: 0, width: 80, height: 80 }) 104 | bitmapI.filter('threshold(168)', { x: 0, y: 0, width: 80, height: 80 }) 105 | bitmapJ.filter('gamma(10)', { x: 0, y: 0, width: 80, height: 80 }) 106 | bitmapK.filter({ 107 | type: 'colorize', 108 | color: '#FF0000', 109 | amount: 0.6 110 | }, { x: 0, y: 0, width: 80, height: 80 }) 111 | } 112 | 113 | cax.tick(() => { 114 | stage.update() 115 | }) 116 | 117 | } 118 | }) 119 | 120 | 121 | // const circle = new cax.Circle(40, { fillStyle: 'red' }) 122 | 123 | 124 | 125 | // circle.filter('brightness(150%)', { x: -40, y: -40, width: 80, height: 80 }) 126 | 127 | // circle.x = 140 128 | // circle.y = 40 129 | // circle.scaleX = 0.5 130 | // circle.rotation = 30 131 | 132 | // circle.cursor = 'pointer' -------------------------------------------------------------------------------- /packages/cax/examples/filter/wegame.test.js: -------------------------------------------------------------------------------- 1 | import cax from './js/libs/cax' 2 | 3 | 4 | const stage = new cax.Stage() 5 | 6 | const bitmap = new cax.Bitmap('images/wepay-diy.jpg') 7 | bitmap.x = 20 8 | bitmap.y = 30 9 | stage.add(bitmap) 10 | 11 | 12 | const bitmapA = bitmap.clone() 13 | bitmapA.x = 20 14 | bitmapA.y = 110 15 | stage.add(bitmapA) 16 | 17 | const bitmapB = bitmapA.clone() 18 | bitmapB.x = 110 19 | stage.add(bitmapB) 20 | 21 | const bitmapC = bitmapA.clone() 22 | bitmapC.x = 200 23 | stage.add(bitmapC) 24 | 25 | const bitmapD = bitmapA.clone() 26 | bitmapD.x = 200 27 | bitmapD.y = 30 28 | stage.add(bitmapD) 29 | 30 | const bitmapE = bitmapA.clone() 31 | bitmapE.x = 110 32 | bitmapE.y = 30 33 | stage.add(bitmapE) 34 | 35 | const bitmapF = bitmapA.clone() 36 | bitmapF.x = 200 37 | bitmapF.y = 190 38 | stage.add(bitmapF) 39 | 40 | const bitmapG = bitmapA.clone() 41 | bitmapG.x = 20 42 | bitmapG.y = 190 43 | stage.add(bitmapG) 44 | 45 | const bitmapH = bitmapA.clone() 46 | bitmapH.x = 110 47 | bitmapH.y = 190 48 | stage.add(bitmapH) 49 | 50 | const bitmapI = bitmapA.clone() 51 | bitmapI.x = 110 52 | bitmapI.y = 270 53 | stage.add(bitmapI) 54 | 55 | const bitmapJ = bitmapA.clone() 56 | bitmapJ.x = 20 57 | bitmapJ.y = 270 58 | stage.add(bitmapJ) 59 | 60 | const bitmapK = bitmapA.clone() 61 | bitmapK.x = 200 62 | bitmapK.y = 270 63 | stage.add(bitmapK) 64 | 65 | 66 | filter() 67 | 68 | 69 | 70 | function unfilter(){ 71 | bitmapA.unfilter() 72 | bitmapB.unfilter() 73 | bitmapC.unfilter() 74 | bitmapD.unfilter() 75 | bitmapE.unfilter() 76 | bitmapF.unfilter() 77 | bitmapG.unfilter() 78 | bitmapH.unfilter() 79 | bitmapI.unfilter() 80 | bitmapJ.unfilter() 81 | bitmapK.unfilter() 82 | } 83 | 84 | function filter(){ 85 | bitmapA.filter('invert(1)', { x: 0, y: 0, width: 80, height: 80 }) 86 | bitmapB.filter('brightness(1.1)', { x: 0, y: 0, width: 80, height: 80 }) 87 | bitmapC.filter('blur(15px)', { x: 0, y: 0, width: 80, height: 80 }) 88 | bitmapD.filter('contrast(1.3)', { x: 0, y: 0, width: 80, height: 80 }) 89 | bitmapE.filter('brightness(0.5)', { x: 0, y: 0, width: 80, height: 80 }) 90 | bitmapF.filter('contrast(0.3)', { x: 0, y: 0, width: 80, height: 80 }) 91 | bitmapG.filter('grayscale(1)', { x: 0, y: 0, width: 80, height: 80 }) 92 | bitmapH.filter('sepia(1)', { x: 0, y: 0, width: 80, height: 80 }) 93 | bitmapI.filter('threshold(168)', { x: 0, y: 0, width: 80, height: 80 }) 94 | bitmapJ.filter('gamma(10)', { x: 0, y: 0, width: 80, height: 80 }) 95 | bitmapK.filter({ 96 | type:'colorize', 97 | color:'#FF0000', 98 | amount: 0.6 99 | }, { x: 0, y: 0, width: 80, height: 80 }) 100 | } 101 | 102 | cax.tick(() => { 103 | stage.update() 104 | }) 105 | 106 | setTimeout(function(){ 107 | unfilter() 108 | },2000) 109 | 110 | setTimeout(function(){ 111 | filter() 112 | },4000) -------------------------------------------------------------------------------- /packages/cax/examples/filter/wepay-diy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/filter/wepay-diy.jpg -------------------------------------------------------------------------------- /packages/cax/examples/getting-start/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cax Simple Demo 7 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /packages/cax/examples/getting-start/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | 3 | const stage = new cax.Stage(200, 200, 'body') 4 | 5 | cax.loadImgs({ 6 | imgs: ['./wepay-diy.jpg'], 7 | complete: (imgs) => { 8 | const img = imgs[0] 9 | const bitmap = new cax.Bitmap(img) 10 | 11 | bitmap.x = stage.width / 2 12 | bitmap.y = stage.height / 2 13 | bitmap.rotation = -10 14 | bitmap.originX = img.width / 2 15 | bitmap.originY = img.height / 2 16 | bitmap.filter('blur(10px)') 17 | 18 | stage.add(bitmap) 19 | stage.update() 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /packages/cax/examples/getting-start/wepay-diy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/getting-start/wepay-diy.jpg -------------------------------------------------------------------------------- /packages/cax/examples/graphics/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Cax Graphics Demo 8 | 25 | 26 | 27 | 28 |
29 |
30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /packages/cax/examples/graphics/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | 3 | const stage = new cax.Stage(300, 400, '#canvasCtn') 4 | 5 | const ball = new cax.Graphics() 6 | 7 | ball.beginPath() 8 | .arc(0, 0, 140, 0, Math.PI * 2) 9 | .closePath() 10 | .fillStyle('#f4862c').fill() 11 | .strokeStyle("#046ab4").lineWidth(8).stroke() 12 | .lineWidth(6) 13 | .beginPath().moveTo(298 - 377, 506 - 391).bezierCurveTo(236 - 377, 396 - 391, 302 - 377, 272 - 391, 407 - 377, 254 - 391).stroke() 14 | .beginPath().moveTo(328 - 377, 258 - 391).bezierCurveTo(360 - 377, 294 - 391, 451 - 377, 272 - 391, 503 - 377, 332 - 391).stroke() 15 | .beginPath().moveTo(282 - 377, 288 - 391).bezierCurveTo(391 - 377, 292 - 391, 481 - 377, 400 - 391, 488 - 377, 474 - 391).stroke() 16 | .beginPath().moveTo(242 - 377, 352 - 391).bezierCurveTo(352 - 377, 244 - 391, 319 - 377, 423 - 391, 409 - 377, 527 - 391).stroke(); 17 | 18 | ball.x = 150 19 | ball.y = 200 20 | ball.scaleX = ball.scaleY = 0.4 21 | 22 | stage.add(ball) 23 | 24 | ball.on('drag', (evt) => { 25 | evt.target.x += evt.dx 26 | evt.target.y += evt.dy 27 | evt.preventDefault() 28 | }) 29 | 30 | ball.cursor = 'move' 31 | 32 | document.querySelector('#addScaleBtn').addEventListener('click', () => { 33 | ball.scaleX += 0.1 34 | ball.scaleY += 0.1 35 | }) 36 | 37 | document.querySelector('#subScaleBtn').addEventListener('click', () => { 38 | 39 | ball.scaleX -= 0.1 40 | ball.scaleY -= 0.1 41 | 42 | if (ball.scaleX < 0.1) { 43 | ball.scaleX = ball.scaleY = 0.1 44 | } 45 | }) 46 | 47 | cax.tick(stage.update.bind(stage)) -------------------------------------------------------------------------------- /packages/cax/examples/group-clip/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cax Clip Demo 7 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 | 31 |
32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /packages/cax/examples/group-clip/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | const stage = new cax.Stage(260, 200, '#canvasCtn') 3 | const group = new cax.Group() 4 | const bitmap = new cax.Bitmap('./wepay-diy.jpg', () => { 5 | stage.update() 6 | }) 7 | 8 | group.x = 130 9 | group.y = 100 10 | bitmap.originX = 40 11 | bitmap.originY = 40 12 | bitmap.cursor = 'pointer' 13 | bitmap.on('click', () => { 14 | alert('微信支付') 15 | }) 16 | 17 | const clipPath = new cax.Graphics() 18 | clipPath.x = 0 19 | clipPath.y = 0 20 | clipPath.arc(0, 0, 25, 0, Math.PI * 2) 21 | 22 | const text = new cax.Text('Hello Cax Clip!') 23 | text.x = -30 24 | group.add(bitmap, text) 25 | 26 | group.clip(clipPath) 27 | stage.add(group) 28 | group.cursor = 'move' 29 | group.on('drag',(evt)=>{ 30 | evt.target.x+=evt.dx 31 | evt.target.y+=evt.dy 32 | }) 33 | let tag = true 34 | group.on('click',(evt)=>{ 35 | console.log(1) 36 | }) 37 | 38 | cax.setInterval(()=>{ 39 | stage.update() 40 | },16) 41 | 42 | document.querySelector('#toggleBtn').addEventListener('click', () => { 43 | group.clip(tag ? null : clipPath) 44 | tag = !tag 45 | stage.update() 46 | }) -------------------------------------------------------------------------------- /packages/cax/examples/group-clip/wepay-diy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/group-clip/wepay-diy.jpg -------------------------------------------------------------------------------- /packages/cax/examples/matter/img/basketball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/matter/img/basketball.png -------------------------------------------------------------------------------- /packages/cax/examples/matter/img/box.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/matter/img/box.jpg -------------------------------------------------------------------------------- /packages/cax/examples/matter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cax + Matter-js 7 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /packages/cax/examples/path/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cax Simple Demo 7 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /packages/cax/examples/path/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | 3 | const stage = new cax.Stage(300, 400, 'body') 4 | // const path = new cax.Path('M4.645,45.577c-0.017-0.383-0.029-0.767-0.029-1.154c0-13.997,11.387-25.385,25.385-25.385 s25.385,11.387,25.385,25.385c0,0.387-0.012,0.771-0.029,1.154h4.616C59.985,45.193,60,44.81,60,44.423c0-16.569-13.431-30-30-30 s-30,13.431-30,30c0,0.387,0.015,0.77,0.029,1.154H4.645z',{ 5 | // strokeStyle:'black', 6 | // // fillStyle:'black' 7 | // }) 8 | 9 | const path = new cax.Path('M10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80',{ 10 | strokeStyle:'black', 11 | // fillStyle:'black' 12 | }) 13 | 14 | //path.x = 100 15 | stage.add(path) 16 | stage.update() 17 | -------------------------------------------------------------------------------- /packages/cax/examples/pie/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cax Pie Chart Demo 7 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /packages/cax/examples/simple/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cax Simple Demo 7 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /packages/cax/examples/simple/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | 3 | const stage = new cax.Stage(300, 400, 'body') 4 | 5 | const bitmap = new cax.Bitmap('./wepay.png') 6 | bitmap.rect = [0, 0, 170, 140] 7 | bitmap.x = 60 8 | bitmap.y = 60 9 | bitmap.cursor = 'pointer' 10 | bitmap.on('click', () => { 11 | alert('wepay') 12 | }) 13 | 14 | 15 | const group = new cax.Group() 16 | const rr = new cax.RoundedRect(100, 40, 2, { fillStyle: '#42B035', strokeStyle: '#42B035', lineWidth: 4 }) 17 | const text = new cax.Text('Drag Me!', { 18 | color: 'white', 19 | font: '20px Arial' 20 | }) 21 | text.x = 50 - text.getWidth() / 2 22 | text.y = 40 / 2 - 10 23 | group.add(rr, text) 24 | group.cursor = 'move' 25 | group.on('drag', (evt) => { 26 | group.x += evt.dx 27 | group.y += evt.dy 28 | evt.preventDefault() 29 | }) 30 | group.x=100 31 | group.y=250 32 | 33 | const caxText = new cax.Text('Hello Cax!', { 34 | color: '#42B035', 35 | font: '30px Arial' 36 | }) 37 | caxText.shadow = { 38 | color: '#42B035', 39 | offsetX: -5, 40 | offsetY: 5, 41 | blur: 10 42 | } 43 | caxText.x = 150 - caxText.getWidth() / 2 44 | caxText.y = 200 45 | caxText.on('drag', (evt) => { 46 | evt.target.x += evt.dx 47 | evt.target.y += evt.dy 48 | evt.preventDefault() 49 | }) 50 | caxText.cursor = 'move' 51 | 52 | stage.add(group, bitmap, caxText) 53 | 54 | cax.tick(() => { 55 | stage.update() 56 | }) 57 | 58 | 59 | // bitmap.on('touchstart', () => { 60 | // console.log('touchstart') 61 | // }) 62 | 63 | // bitmap.on('tap', () => { 64 | // console.log('tap') 65 | // }) 66 | 67 | 68 | // bitmap.on('touchmove', () => { 69 | // console.log('touchmove') 70 | // }) 71 | 72 | // bitmap.on('drag', () => { 73 | // console.log('dragging') 74 | // }) 75 | 76 | // bitmap.on('touchend', () => { 77 | // console.log('touchend') 78 | // }) 79 | 80 | 81 | // const ap = new cax.ArrowPath([{ x: 100, y: 200 }, { x: 100, y: 300 }]) 82 | // stage.add(ap) 83 | 84 | // const ap2 = new cax.ArrowPath([{ x: 100, y: 200 }, { x: 200, y: 200 }]) 85 | // stage.add(ap2) 86 | 87 | 88 | 89 | // const ap3 = new cax.ArrowPath([{ x: 100, y: 200 }, { x: 0, y: 200 }]) 90 | // stage.add(ap3) 91 | 92 | 93 | // const ap4 = new cax.ArrowPath([{ x: 100, y: 200 }, { x: 100, y: 100 }]) 94 | // stage.add(ap4) -------------------------------------------------------------------------------- /packages/cax/examples/simple/mario-sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/simple/mario-sheet.png -------------------------------------------------------------------------------- /packages/cax/examples/simple/wepay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/simple/wepay.png -------------------------------------------------------------------------------- /packages/cax/examples/sprite/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cax Simple Demo 7 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /packages/cax/examples/sprite/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | 3 | 4 | const stage = new cax.Stage(300, 400, 'body') 5 | 6 | const sprite = new cax.Sprite({ 7 | framerate: 7, 8 | imgs: ['./mario-sheet.png'], 9 | frames: [ 10 | // x, y, width, height, originX, originY ,imageIndex 11 | [0, 0, 32, 32], 12 | [32 * 1, 0, 32, 32], 13 | [32 * 2, 0, 32, 32], 14 | [32 * 3, 0, 32, 32], 15 | [32 * 4, 0, 32, 32], 16 | [32 * 5, 0, 32, 32], 17 | [32 * 6, 0, 32, 32], 18 | [32 * 7, 0, 32, 32], 19 | [32 * 8, 0, 32, 32], 20 | [32 * 9, 0, 32, 32], 21 | [32 * 10, 0, 32, 32], 22 | [32 * 11, 0, 32, 32], 23 | [32 * 12, 0, 32, 32], 24 | [32 * 13, 0, 32, 32], 25 | [32 * 14, 0, 32, 32] 26 | ], 27 | animations: { 28 | walk: { 29 | frames: [0, 1] 30 | }, 31 | happy: { 32 | frames: [5, 6, 7, 8, 9] 33 | }, 34 | win: { 35 | frames: [12] 36 | } 37 | }, 38 | playOnce: false, 39 | currentAnimation: "walk", 40 | animationEnd: function () { 41 | 42 | } 43 | }); 44 | stage.add(sprite) 45 | 46 | cax.setInterval(() => { 47 | 48 | sprite.x += 0.8 49 | stage.update() 50 | }, 16) -------------------------------------------------------------------------------- /packages/cax/examples/sprite/mario-sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/sprite/mario-sheet.png -------------------------------------------------------------------------------- /packages/cax/examples/to-animate/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cax Motion Demo 7 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /packages/cax/examples/to-animate/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | 3 | const stage = new cax.Stage(300, 400, 'body') 4 | const bitmap = new cax.Bitmap('./wepay-diy.jpg',()=>{ 5 | cax.To.get(bitmap).animate('rubber').start() 6 | }) 7 | 8 | bitmap.x = 150 9 | bitmap.y = 200 10 | bitmap.scaleX = 0.6 11 | bitmap.scaleY = 0.6 12 | bitmap.originX = 40 13 | bitmap.originY = 40 14 | bitmap.cursor = 'pointer' 15 | bitmap.on('click', () => { 16 | alert('微信支付') 17 | }) 18 | 19 | stage.add(bitmap) 20 | 21 | 22 | cax.setInterval(() => { 23 | stage.update() 24 | }, 16) -------------------------------------------------------------------------------- /packages/cax/examples/to-animate/wepay-diy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/to-animate/wepay-diy.jpg -------------------------------------------------------------------------------- /packages/cax/examples/to-shape/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cax Motion Demo 7 | 23 | 24 | 25 |
26 |
27 | 28 |
29 |
Click AnyWhere to Tween
30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /packages/cax/examples/to-shape/main.js: -------------------------------------------------------------------------------- 1 | 2 | import cax from '../../src/index.js' 3 | 4 | 5 | const stage = new cax.Stage(300, 400, '#canvasCtn'); 6 | 7 | for (var i = 0; i < 25; i++) { 8 | var circle = new cax.Circle((i + 1) * 4, { 9 | lineWidth: 15, 10 | strokeStyle: '#113355' 11 | }); 12 | 13 | circle.alpha = 1 - i * 0.02; 14 | circle.x = Math.random() * 300; 15 | circle.y = Math.random() * 400; 16 | circle.compositeOperation = "lighter"; 17 | 18 | cax.To.get(circle).to({ x: 150, y: 200 }, (0.5 + i * 0.04) * 1500, cax.easing.bounceOut).start() 19 | stage.add(circle); 20 | } 21 | 22 | 23 | stage.on('click', function (evt) { 24 | stage.children.forEach((child, index) => { 25 | cax.To.get(child).to({ x: evt.stageX, y: evt.stageY }, (0.5 + index * 0.04) * 1500, cax.easing.bounceOut).start() 26 | }) 27 | }) 28 | 29 | cax.tick(function () { 30 | stage.update() 31 | }) -------------------------------------------------------------------------------- /packages/cax/examples/to/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Cax Motion Demo 7 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /packages/cax/examples/to/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | 3 | const stage = new cax.Stage(300, 400, 'body') 4 | const bitmap = new cax.Bitmap('./wepay-diy.jpg') 5 | 6 | bitmap.x = 200 7 | bitmap.y = -200 8 | bitmap.scaleX = 0.6 9 | bitmap.scaleY = 0.6 10 | bitmap.originX = 40 11 | bitmap.originY = 40 12 | bitmap.cursor = 'pointer' 13 | bitmap.on('click', () => { 14 | alert('微信支付') 15 | }) 16 | 17 | 18 | stage.add(bitmap) 19 | 20 | 21 | const easing = cax.To.easing.elasticInOut 22 | 23 | cax.To.get(bitmap) 24 | .to({ y: 340, rotation: 240 }, 2000, easing) 25 | .begin(() => { 26 | console.log("Task one has began!") 27 | }) 28 | .progress(() => { 29 | console.log("Task one is progressing!") 30 | }) 31 | .end(() => { 32 | console.log("Task one has completed!") 33 | }) 34 | .wait(500) 35 | .to() 36 | .rotation(0, 1400, easing) 37 | .begin(() => { 38 | console.log("Task two has began!") 39 | }) 40 | .progress(() => { 41 | console.log("Task two is progressing!") 42 | }) 43 | .end(() => { 44 | console.log("Task two has completed!") 45 | }) 46 | .wait(500) 47 | .to() 48 | .scaleX(1, 1400, easing) 49 | .scaleY(1, 1400, easing) 50 | .begin(() => { 51 | console.log("Task three has began!") 52 | }) 53 | .progress(() => { 54 | console.log("Task three is progressing!") 55 | }) 56 | .end(() => { 57 | console.log("Task three has completed!") 58 | }) 59 | .wait(500) 60 | .to({ x: 160, y: 200 }, 1000, easing) 61 | .rotation(360, 1000, easing) 62 | .begin(() => { 63 | console.log("Task four has began!") 64 | }) 65 | .progress(() => { 66 | console.log("Task four is progressing!") 67 | }) 68 | .end(() => { 69 | console.log("Task four has completed!") 70 | }) 71 | .start(); 72 | 73 | 74 | 75 | cax.setInterval(() => { 76 | stage.update() 77 | }, 16) -------------------------------------------------------------------------------- /packages/cax/examples/to/wepay-diy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/to/wepay-diy.jpg -------------------------------------------------------------------------------- /packages/cax/examples/vision/hero-m.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/cax/examples/vision/hero-m.png -------------------------------------------------------------------------------- /packages/cax/examples/vision/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Cax Vision Demo 8 | 25 | 26 | 27 | 28 |
29 |
30 |
31 | 32 | 33 | 34 |
35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /packages/cax/examples/vision/main.js: -------------------------------------------------------------------------------- 1 | import cax from '../../src/index.js' 2 | import Bitmap from '../../src/render/display/bitmap.js'; 3 | 4 | 5 | const stage = new cax.Stage(300, 400, '#canvasCtn') 6 | let filter = false 7 | 8 | class Player extends cax.Group { 9 | constructor() { 10 | super() 11 | 12 | this.sprite = new cax.Sprite({ 13 | 14 | framerate: 5, 15 | imgs: ['./hero-m.png'], 16 | frames: [ 17 | // x, y, width, height, originX, originY ,imageIndex 18 | [64, 64, 64, 64], 19 | [128, 64, 64, 64], 20 | [192, 64, 64, 64], 21 | [256, 64, 64, 64], 22 | [320, 64, 64, 64], 23 | [384, 64, 64, 64], 24 | [448, 64, 64, 64], 25 | 26 | [0, 192, 64, 64], 27 | [64, 192, 64, 64], 28 | [128, 192, 64, 64], 29 | [192, 192, 64, 64], 30 | [256, 192, 64, 64], 31 | [320, 192, 64, 64], 32 | [384, 192, 64, 64], 33 | [448, 192, 64, 64], 34 | [448, 192, 64, 64] 35 | ], 36 | animations: { 37 | walk: { 38 | frames: [0, 1, 2, 3, 4, 5, 6], 39 | next: "run", 40 | speed: 2, 41 | loop: false 42 | }, 43 | happy: { 44 | frames: [11, 12, 13, 14] 45 | }, 46 | win: { 47 | frames: [7, 8, 9, 10] 48 | } 49 | }, 50 | currentAnimation: "walk" 51 | }) 52 | 53 | this.sprite.originX = 32 54 | this.sprite.originY = 32 55 | this.visionGroup = new cax.Group() 56 | this.visionGroup.fixed = true 57 | this.add(this.visionGroup, this.sprite) 58 | this.directionRight = false 59 | this.preTime = Date.now() 60 | } 61 | 62 | update() { 63 | if(!this.sprite.visible){ 64 | this.sprite.updateFrame() 65 | } 66 | this.x += (this.directionRight ? 1 : -1) 67 | if (Date.now() - this.preTime > 50) { 68 | this.addVision() 69 | this.preTime = Date.now() 70 | } 71 | if (this.x < -20) { 72 | this.x = 310 73 | } 74 | 75 | if (this.x > 310) { 76 | this.x = -19 77 | } 78 | 79 | 80 | } 81 | 82 | addVision() { 83 | if(this.sprite.rect){ 84 | const vision = new Bitmap('./hero-m.png') 85 | vision.rect = this.sprite.rect.slice(0) 86 | if(filter){ 87 | vision.compositeOperation = 'lighter' 88 | vision.filter({ 89 | type:'colorize', 90 | color:'#ff4725', 91 | amount: 1 92 | },) 93 | } 94 | vision.scaleX = this.scaleX 95 | vision.originX = 32 96 | vision.originY = 32 97 | vision.alpha = 0.5 98 | vision.x = this.x 99 | vision.y = this.y 100 | this.visionGroup.add(vision) 101 | 102 | cax.To.get(vision).to({ alpha: 0 }, 1500).end((obj) => { 103 | obj.destroy() 104 | }).start() 105 | } 106 | } 107 | 108 | } 109 | 110 | const player = new Player() 111 | stage.add(player) 112 | 113 | player.x = 200 114 | player.y = 200 115 | 116 | cax.setInterval(() => { 117 | player.update() 118 | stage.update() 119 | }, 16) 120 | 121 | 122 | let tag = false 123 | 124 | document.querySelector('#toggleBtn').addEventListener('click', () => { 125 | player.sprite.visible = tag 126 | tag =!tag 127 | stage.update() 128 | }) 129 | 130 | 131 | document.querySelector('#toggleFilterBtn').addEventListener('click', () => { 132 | filter = !filter 133 | }) 134 | 135 | document.querySelector('#toggleDirectionBtn').addEventListener('click', () => { 136 | player.directionRight = !player.directionRight 137 | player.scaleX *= -1 138 | }) 139 | -------------------------------------------------------------------------------- /packages/cax/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cax", 3 | "version": "1.3.6", 4 | "description": "小程序、小游戏和 Web 通用 Canvas 渲染引擎", 5 | "main": "dist/cax.js", 6 | "scripts": { 7 | "lint": "eslint src", 8 | "fix": "eslint src --fix", 9 | "fixwegame": "eslint ../cax-wegame --fix", 10 | "fixweapp": "eslint ../cax-weapp --fix", 11 | "lint:example": "eslint example --fix", 12 | "to-animate": "webpack -w", 13 | "pie": "webpack -w", 14 | "clip": "webpack -w", 15 | "graphics": "webpack -w", 16 | "sprite": "webpack -w", 17 | "group-clip": "webpack -w", 18 | "clip-transform": "webpack -w", 19 | "filter": "webpack -w", 20 | "getting-start": "webpack -w", 21 | "vision": "webpack -w", 22 | "to-shape": "webpack -w", 23 | "clip-transition": "webpack -w", 24 | "composite-operation": "webpack -w", 25 | "cache": "webpack -w", 26 | "caching": "webpack -w", 27 | "to": "webpack -w", 28 | "simple": "webpack -w", 29 | "build": "webpack", 30 | "build-min": "webpack", 31 | "test": "karma start test/karma.conf.js" 32 | }, 33 | "devDependencies": { 34 | "eslint": "^4.3.0", 35 | "eslint-config-standard": "^10.2.1", 36 | "eslint-plugin-import": "^2.7.0", 37 | "eslint-plugin-node": "^5.1.1", 38 | "eslint-plugin-promise": "^3.5.0", 39 | "eslint-plugin-standard": "^3.0.1", 40 | "babel-core": "^6.26.0", 41 | "babel-loader": "^7.1.4", 42 | "babel-plugin-transform-class-properties": "^6.24.1", 43 | "babel-plugin-transform-react-jsx": "^6.24.1", 44 | "babel-preset-env": "^1.6.1", 45 | "chai": "^4.1.2", 46 | "jasmine-core": "^2.5.2", 47 | "karma": "^1.3.0", 48 | "karma-babel-preprocessor": "^7.0.0", 49 | "karma-chai-sinon": "^0.1.5", 50 | "karma-chrome-launcher": "^2.0.0", 51 | "karma-coverage": "^1.0.0", 52 | "karma-jasmine": "^1.1.0", 53 | "karma-mocha": "^1.1.1", 54 | "karma-mocha-reporter": "^2.0.4", 55 | "karma-sauce-launcher": "^1.1.0", 56 | "karma-sinon": "^1.0.5", 57 | "karma-source-map-support": "^1.2.0", 58 | "karma-sourcemap-loader": "^0.3.6", 59 | "karma-webpack": "^2.0.4", 60 | "mocha": "^5.0.4", 61 | "node-libs-browser": "^0.5.3", 62 | "sinon": "^4.5.0", 63 | "sinon-chai": "^3.0.0", 64 | "webpack": "^3.4.1" 65 | }, 66 | "repository": { 67 | "type": "git", 68 | "url": "git+https://github.com/dntzhang/cax.git" 69 | }, 70 | "keywords": [ 71 | "canvas", 72 | "web", 73 | "weapp" 74 | ], 75 | "devEngines": { 76 | "node": "6.x || 7.x || 8.x", 77 | "npm": "3.x || 4.x || 5.x" 78 | }, 79 | "author": "dntzhang", 80 | "license": "MIT", 81 | "bugs": { 82 | "url": "https://github.com/dntzhang/cax/issues/new" 83 | }, 84 | "homepage": "http://dntzhang.github.io/cax" 85 | } -------------------------------------------------------------------------------- /packages/cax/src/common/animate.js: -------------------------------------------------------------------------------- 1 | import To from './to' 2 | 3 | To.extend('rubber', [['to', ['scaleX', { 4 | '0': 1.25, 5 | '1': 300 6 | }], ['scaleY', { 7 | '0': 0.75, 8 | '1': 300 9 | }]], ['to', ['scaleX', { 10 | '0': 0.75, 11 | '1': 100 12 | }], ['scaleY', { 13 | '0': 1.25, 14 | '1': 100 15 | }]], ['to', ['scaleX', { 16 | '0': 1.15, 17 | '1': 100 18 | }], ['scaleY', { 19 | '0': 0.85, 20 | '1': 100 21 | }]], ['to', ['scaleX', { 22 | '0': 0.95, 23 | '1': 150 24 | }], ['scaleY', { 25 | '0': 1.05, 26 | '1': 150 27 | }]], ['to', ['scaleX', { 28 | '0': 1.05, 29 | '1': 100 30 | }], ['scaleY', { 31 | '0': 0.95, 32 | '1': 100 33 | }]], ['to', ['scaleX', { 34 | '0': 1, 35 | '1': 250 36 | }], ['scaleY', { 37 | '0': 1, 38 | '1': 250 39 | }]]]) 40 | 41 | To.extend('bounceIn', [['to', ['scaleX', { 42 | '0': 0, 43 | '1': 0 44 | }], ['scaleY', { 45 | '0': 0, 46 | '1': 0 47 | }]], ['to', ['scaleX', { 48 | '0': 1.35, 49 | '1': 200 50 | }], ['scaleY', { 51 | '0': 1.35, 52 | '1': 200 53 | }]], ['to', ['scaleX', { 54 | '0': 0.9, 55 | '1': 100 56 | }], ['scaleY', { 57 | '0': 0.9, 58 | '1': 100 59 | }]], ['to', ['scaleX', { 60 | '0': 1.1, 61 | '1': 100 62 | }], ['scaleY', { 63 | '0': 1.1, 64 | '1': 100 65 | }]], ['to', ['scaleX', { 66 | '0': 0.95, 67 | '1': 100 68 | }], ['scaleY', { 69 | '0': 0.95, 70 | '1': 100 71 | }]], ['to', ['scaleX', { 72 | '0': 1, 73 | '1': 100 74 | }], ['scaleY', { 75 | '0': 1, 76 | '1': 100 77 | }]]]) 78 | 79 | To.extend('flipInX', [['to', ['rotateX', { 80 | '0': -90, 81 | '1': 0 82 | }]], ['to', ['rotateX', { 83 | '0': 20, 84 | '1': 300 85 | }]], ['to', ['rotateX', { 86 | '0': -20, 87 | '1': 300 88 | }]], ['to', ['rotateX', { 89 | '0': 10, 90 | '1': 300 91 | }]], ['to', ['rotateX', { 92 | '0': -5, 93 | '1': 300 94 | }]], ['to', ['rotateX', { 95 | '0': 0, 96 | '1': 300 97 | }]]]) 98 | 99 | To.extend('zoomOut', [['to', ['scaleX', { 100 | '0': 0, 101 | '1': 400 102 | }], ['scaleY', { 103 | '0': 0, 104 | '1': 400 105 | }]]]) 106 | -------------------------------------------------------------------------------- /packages/cax/src/common/raf-interval.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * raf-interval v0.3.0 By dntzhang 3 | * Github: https://github.com/dntzhang/raf-interval 4 | * MIT Licensed. 5 | */ 6 | 7 | if (!Date.now) { 8 | Date.now = function now () { 9 | return new Date().getTime() 10 | } 11 | } 12 | 13 | let queue = [], 14 | id = -1, 15 | ticking = false, 16 | tickId = null, 17 | now = Date.now, 18 | lastTime = 0, 19 | vendors = ['ms', 'moz', 'webkit', 'o'], 20 | x = 0, 21 | isWeapp = typeof wx !== 'undefined' && typeof Page !== 'undefined', 22 | isWegame = typeof wx !== 'undefined' && typeof Page === 'undefined', 23 | isBrowser = typeof window !== 'undefined' 24 | 25 | let raf = isBrowser ? window.requestAnimationFrame : null 26 | let caf = isBrowser ? window.cancelAnimationFrame : null 27 | 28 | function mockRaf (callback, element) { 29 | let currTime = now() 30 | let timeToCall = Math.max(0, 16 - (currTime - lastTime)) 31 | let id = setTimeout(function () { 32 | callback(currTime + timeToCall) 33 | }, timeToCall) 34 | lastTime = currTime + timeToCall 35 | return id 36 | } 37 | 38 | function mockCaf (id) { 39 | clearTimeout(id) 40 | } 41 | 42 | if (isBrowser) { 43 | window.setRafInterval = setRafInterval 44 | window.clearRafInterval = clearRafInterval 45 | 46 | for (; x < vendors.length && !window.requestAnimationFrame; ++x) { 47 | window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'] 48 | window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || 49 | window[vendors[x] + 'CancelRequestAnimationFrame'] 50 | } 51 | 52 | if (!raf) { 53 | raf = mockRaf 54 | caf = mockCaf 55 | window.requestAnimationFrame = raf 56 | window.cancelAnimationFrame = caf 57 | } 58 | } else if (isWeapp) { 59 | raf = mockRaf 60 | caf = mockCaf 61 | } else if (isWegame) { 62 | raf = requestAnimationFrame 63 | caf = cancelAnimationFrame 64 | } 65 | 66 | export function setRafInterval (fn, interval) { 67 | id++ 68 | queue.push({ id: id, fn: fn, interval: interval, lastTime: now() }) 69 | if (!ticking) { 70 | let tick = function () { 71 | tickId = raf(tick) 72 | each(queue, function (item) { 73 | if (item.interval < 17 || now() - item.lastTime >= item.interval) { 74 | item.fn() 75 | item.lastTime = now() 76 | } 77 | }) 78 | } 79 | ticking = true 80 | tick() 81 | } 82 | return id 83 | } 84 | 85 | export function clearRafInterval (id) { 86 | let i = 0, 87 | len = queue.length 88 | 89 | for (; i < len; i++) { 90 | if (id === queue[i].id) { 91 | queue.splice(i, 1) 92 | break 93 | } 94 | } 95 | 96 | if (queue.length === 0) { 97 | caf(tickId) 98 | ticking = false 99 | } 100 | } 101 | 102 | function each (arr, fn) { 103 | if (Array.prototype.forEach) { 104 | arr.forEach(fn) 105 | } else { 106 | let i = 0, 107 | len = arr.length 108 | for (; i < len; i++) { 109 | fn(arr[i], i) 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /packages/cax/src/common/util.js: -------------------------------------------------------------------------------- 1 | export function getImageInWx (img, callback) { 2 | if ((img.indexOf('https://') === -1 && img.indexOf('http://') === -1) || img.indexOf('http://tmp/') === 0) { 3 | wx.getImageInfo({ 4 | src: img, 5 | success: (info) => { 6 | callback({ 7 | img: img, 8 | width: info.width, 9 | height: info.height 10 | }) 11 | } 12 | }) 13 | } else { 14 | wx.downloadFile({ 15 | url: img, 16 | success: (res) => { 17 | if (res.statusCode === 200) { 18 | wx.getImageInfo({ 19 | src: res.tempFilePath, 20 | success: (info) => { 21 | callback({ 22 | img: res.tempFilePath, 23 | width: info.width, 24 | height: info.height 25 | }) 26 | } 27 | }) 28 | } 29 | } 30 | }) 31 | } 32 | } 33 | 34 | function getGlobal () { 35 | if (typeof global !== 'object' || !global || global.Math !== Math || global.Array !== Array) { 36 | if (typeof self !== 'undefined') { 37 | return self 38 | } else if (typeof window !== 'undefined') { 39 | return window 40 | } else if (typeof global !== 'undefined') { 41 | return global 42 | } 43 | return (function () { 44 | return this 45 | })() 46 | } 47 | return global 48 | } 49 | 50 | const root = getGlobal() 51 | 52 | export default{ 53 | getImageInWx, 54 | root, 55 | isWeapp: typeof wx !== 'undefined' && typeof Page !== 'undefined', 56 | isWegame: typeof wx !== 'undefined' && typeof Page === 'undefined' 57 | } 58 | -------------------------------------------------------------------------------- /packages/cax/src/index.js: -------------------------------------------------------------------------------- 1 | import TWEEN from './common/tween' 2 | import To from './common/to' 3 | import './common/animate' 4 | 5 | import Stage from './render/display/stage' 6 | import WeStage from './render/display/we-stage' 7 | import Graphics from './render/display/graphics' 8 | import Bitmap from './render/display/bitmap' 9 | import Text from './render/display/text' 10 | import Group from './render/display/group' 11 | import Sprite from './render/display/sprite' 12 | import Shape from './render/display/shape/shape' 13 | 14 | import RoundedRect from './render/display/shape/rounded-rect' 15 | import ArrowPath from './render/display/shape/arrow-path' 16 | import Ellipse from './render/display/shape/ellipse' 17 | import Path from './render/display/shape/path' 18 | 19 | import Button from './render/display/element/button' 20 | 21 | import Rect from './render/display/shape/rect' 22 | import Circle from './render/display/shape/circle' 23 | import Polygon from './render/display/shape/polygon' 24 | import EquilateralPolygon from './render/display/shape/equilateral-polygon' 25 | 26 | import {setRafInterval, clearRafInterval} from './common/raf-interval' 27 | 28 | To.easing = { 29 | linear: TWEEN.Easing.Linear.None 30 | } 31 | 32 | const cax = { 33 | easing: { 34 | linear: TWEEN.Easing.Linear.None 35 | }, 36 | util: { 37 | randomInt: (min, max) => { 38 | return min + Math.floor(Math.random() * (max - min + 1)) 39 | } 40 | }, 41 | 42 | Stage, 43 | WeStage, 44 | Graphics, 45 | Bitmap, 46 | Text, 47 | Group, 48 | Sprite, 49 | Shape, 50 | 51 | ArrowPath, 52 | Ellipse, 53 | Path, 54 | 55 | Button, 56 | 57 | RoundedRect, 58 | Rect, 59 | Circle, 60 | Polygon, 61 | EquilateralPolygon, 62 | 63 | setInterval: setRafInterval, 64 | clearInterval: clearRafInterval, 65 | tick: function (fn) { 66 | return setRafInterval(fn, 16) 67 | }, 68 | untick: function (tickId) { 69 | clearRafInterval(tickId) 70 | }, 71 | 72 | caxCanvasId: 0, 73 | TWEEN, 74 | To 75 | }; 76 | 77 | ['Quadratic', 78 | 'Cubic', 79 | 'Quartic', 80 | 'Quintic', 81 | 'Sinusoidal', 82 | 'Exponential', 83 | 'Circular', 84 | 'Elastic', 85 | 'Back', 86 | 'Bounce'].forEach(item => { 87 | const itemLower = item.toLowerCase() 88 | cax.easing[itemLower + 'In'] = TWEEN.Easing[item].In 89 | cax.easing[itemLower + 'Out'] = TWEEN.Easing[item].Out 90 | cax.easing[itemLower + 'InOut'] = TWEEN.Easing[item].InOut 91 | 92 | To.easing[itemLower + 'In'] = TWEEN.Easing[item].In 93 | To.easing[itemLower + 'Out'] = TWEEN.Easing[item].Out 94 | To.easing[itemLower + 'InOut'] = TWEEN.Easing[item].InOut 95 | }) 96 | 97 | const isWegame = typeof wx !== 'undefined' && typeof Page === 'undefined' 98 | 99 | cax.loadImg = function (option) { 100 | const img = isWegame ? wx.createImage() : new Image() 101 | img.onload = function () { 102 | option.complete(this) 103 | } 104 | img.src = option.img 105 | } 106 | 107 | cax.loadImgs = function (option) { 108 | const result = [] 109 | let loaded = 0 110 | const len = option.imgs.length 111 | option.imgs.forEach((src, index) => { 112 | const img = isWegame ? wx.createImage() : new Image() 113 | img.onload = (function (i, img) { 114 | return function () { 115 | result[i] = img 116 | loaded++ 117 | option.progress && option.progress(loaded / len, loaded, i, img, result) 118 | if (loaded === len) { 119 | option.complete && option.complete(result) 120 | } 121 | } 122 | })(index, img) 123 | img.src = src 124 | }) 125 | } 126 | 127 | module.exports = cax 128 | -------------------------------------------------------------------------------- /packages/cax/src/render/base/a2c.js: -------------------------------------------------------------------------------- 1 | // https://src.chromium.org/viewvc/blink/trunk/Source/core/svg/SVGPathParser.cpp?revision=195686#l225 2 | // https://github.com/adobe-webplatform/Snap.svg/blob/master/src/path.js#L752 3 | 4 | const math = Math 5 | const PI = math.PI 6 | const abs = math.abs 7 | 8 | function cacher (fn) { 9 | const cache = {} 10 | return function () { 11 | const key = [...arguments].join('-') 12 | if (cache.hasOwnProperty(key)) return cache[key] 13 | const result = fn.apply(null, arguments) 14 | cache[key] = result 15 | return result 16 | } 17 | } 18 | 19 | function a2c (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { 20 | // for more information of where this math came from visit: 21 | // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes 22 | var _120 = PI * 120 / 180, 23 | rad = PI / 180 * (+angle || 0), 24 | res = [], 25 | xy, 26 | rotate = cacher(function (x, y, rad) { 27 | var X = x * math.cos(rad) - y * math.sin(rad), 28 | Y = x * math.sin(rad) + y * math.cos(rad) 29 | return { x: X, y: Y } 30 | }) 31 | if (!rx || !ry) { 32 | return [x1, y1, x2, y2, x2, y2] 33 | } 34 | if (!recursive) { 35 | xy = rotate(x1, y1, -rad) 36 | x1 = xy.x 37 | y1 = xy.y 38 | xy = rotate(x2, y2, -rad) 39 | x2 = xy.x 40 | y2 = xy.y 41 | var cos = math.cos(PI / 180 * angle), 42 | sin = math.sin(PI / 180 * angle), 43 | x = (x1 - x2) / 2, 44 | y = (y1 - y2) / 2 45 | var h = x * x / (rx * rx) + y * y / (ry * ry) 46 | if (h > 1) { 47 | h = math.sqrt(h) 48 | rx = h * rx 49 | ry = h * ry 50 | } 51 | var rx2 = rx * rx, 52 | ry2 = ry * ry, 53 | k = (large_arc_flag == sweep_flag ? -1 : 1) * 54 | math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), 55 | cx = k * rx * y / ry + (x1 + x2) / 2, 56 | cy = k * -ry * x / rx + (y1 + y2) / 2, 57 | f1 = math.asin(((y1 - cy) / ry).toFixed(9)), 58 | f2 = math.asin(((y2 - cy) / ry).toFixed(9)) 59 | 60 | f1 = x1 < cx ? PI - f1 : f1 61 | f2 = x2 < cx ? PI - f2 : f2 62 | f1 < 0 && (f1 = PI * 2 + f1) 63 | f2 < 0 && (f2 = PI * 2 + f2) 64 | if (sweep_flag && f1 > f2) { 65 | f1 = f1 - PI * 2 66 | } 67 | if (!sweep_flag && f2 > f1) { 68 | f2 = f2 - PI * 2 69 | } 70 | } else { 71 | f1 = recursive[0] 72 | f2 = recursive[1] 73 | cx = recursive[2] 74 | cy = recursive[3] 75 | } 76 | var df = f2 - f1 77 | if (abs(df) > _120) { 78 | var f2old = f2, 79 | x2old = x2, 80 | y2old = y2 81 | f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1) 82 | x2 = cx + rx * math.cos(f2) 83 | y2 = cy + ry * math.sin(f2) 84 | res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]) 85 | } 86 | df = f2 - f1 87 | var c1 = math.cos(f1), 88 | s1 = math.sin(f1), 89 | c2 = math.cos(f2), 90 | s2 = math.sin(f2), 91 | t = math.tan(df / 4), 92 | hx = 4 / 3 * rx * t, 93 | hy = 4 / 3 * ry * t, 94 | m1 = [x1, y1], 95 | m2 = [x1 + hx * s1, y1 - hy * c1], 96 | m3 = [x2 + hx * s2, y2 - hy * c2], 97 | m4 = [x2, y2] 98 | m2[0] = 2 * m1[0] - m2[0] 99 | m2[1] = 2 * m1[1] - m2[1] 100 | if (recursive) { 101 | return [m2, m3, m4].concat(res) 102 | } else { 103 | res = [m2, m3, m4].concat(res).join().split(',') 104 | var newres = [] 105 | for (var i = 0, ii = res.length; i < ii; i++) { 106 | newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x 107 | } 108 | return newres 109 | } 110 | } 111 | 112 | export default a2c 113 | -------------------------------------------------------------------------------- /packages/cax/src/render/base/arc-to-bezier.js: -------------------------------------------------------------------------------- 1 | // https://github.com/colinmeinke/svg-arc-to-cubic-bezier 2 | 3 | const TAU = Math.PI * 2 4 | 5 | const mapToEllipse = ({ x, y }, rx, ry, cosphi, sinphi, centerx, centery) => { 6 | x *= rx 7 | y *= ry 8 | 9 | const xp = cosphi * x - sinphi * y 10 | const yp = sinphi * x + cosphi * y 11 | 12 | return { 13 | x: xp + centerx, 14 | y: yp + centery 15 | } 16 | } 17 | 18 | const approxUnitArc = (ang1, ang2) => { 19 | const a = 4 / 3 * Math.tan(ang2 / 4) 20 | 21 | const x1 = Math.cos(ang1) 22 | const y1 = Math.sin(ang1) 23 | const x2 = Math.cos(ang1 + ang2) 24 | const y2 = Math.sin(ang1 + ang2) 25 | 26 | return [ 27 | { 28 | x: x1 - y1 * a, 29 | y: y1 + x1 * a 30 | }, 31 | { 32 | x: x2 + y2 * a, 33 | y: y2 - x2 * a 34 | }, 35 | { 36 | x: x2, 37 | y: y2 38 | } 39 | ] 40 | } 41 | 42 | const vectorAngle = (ux, uy, vx, vy) => { 43 | const sign = (ux * vy - uy * vx < 0) ? -1 : 1 44 | const umag = Math.sqrt(ux * ux + uy * uy) 45 | const vmag = Math.sqrt(ux * ux + uy * uy) 46 | const dot = ux * vx + uy * vy 47 | 48 | let div = dot / (umag * vmag) 49 | 50 | if (div > 1) { 51 | div = 1 52 | } 53 | 54 | if (div < -1) { 55 | div = -1 56 | } 57 | 58 | return sign * Math.acos(div) 59 | } 60 | 61 | const getArcCenter = ( 62 | px, 63 | py, 64 | cx, 65 | cy, 66 | rx, 67 | ry, 68 | largeArcFlag, 69 | sweepFlag, 70 | sinphi, 71 | cosphi, 72 | pxp, 73 | pyp 74 | ) => { 75 | const rxsq = Math.pow(rx, 2) 76 | const rysq = Math.pow(ry, 2) 77 | const pxpsq = Math.pow(pxp, 2) 78 | const pypsq = Math.pow(pyp, 2) 79 | 80 | let radicant = (rxsq * rysq) - (rxsq * pypsq) - (rysq * pxpsq) 81 | 82 | if (radicant < 0) { 83 | radicant = 0 84 | } 85 | 86 | radicant /= (rxsq * pypsq) + (rysq * pxpsq) 87 | radicant = Math.sqrt(radicant) * (largeArcFlag === sweepFlag ? -1 : 1) 88 | 89 | const centerxp = radicant * rx / ry * pyp 90 | const centeryp = radicant * -ry / rx * pxp 91 | 92 | const centerx = cosphi * centerxp - sinphi * centeryp + (px + cx) / 2 93 | const centery = sinphi * centerxp + cosphi * centeryp + (py + cy) / 2 94 | 95 | const vx1 = (pxp - centerxp) / rx 96 | const vy1 = (pyp - centeryp) / ry 97 | const vx2 = (-pxp - centerxp) / rx 98 | const vy2 = (-pyp - centeryp) / ry 99 | 100 | let ang1 = vectorAngle(1, 0, vx1, vy1) 101 | let ang2 = vectorAngle(vx1, vy1, vx2, vy2) 102 | 103 | if (sweepFlag === 0 && ang2 > 0) { 104 | ang2 -= TAU 105 | } 106 | 107 | if (sweepFlag === 1 && ang2 < 0) { 108 | ang2 += TAU 109 | } 110 | 111 | return [ centerx, centery, ang1, ang2 ] 112 | } 113 | 114 | const arcToBezier = ({ 115 | px, 116 | py, 117 | cx, 118 | cy, 119 | rx, 120 | ry, 121 | xAxisRotation = 0, 122 | largeArcFlag = 0, 123 | sweepFlag = 0 124 | }) => { 125 | const curves = [] 126 | 127 | if (rx === 0 || ry === 0) { 128 | return [] 129 | } 130 | 131 | const sinphi = Math.sin(xAxisRotation * TAU / 360) 132 | const cosphi = Math.cos(xAxisRotation * TAU / 360) 133 | 134 | const pxp = cosphi * (px - cx) / 2 + sinphi * (py - cy) / 2 135 | const pyp = -sinphi * (px - cx) / 2 + cosphi * (py - cy) / 2 136 | 137 | if (pxp === 0 && pyp === 0) { 138 | return [] 139 | } 140 | 141 | rx = Math.abs(rx) 142 | ry = Math.abs(ry) 143 | 144 | const lambda = 145 | Math.pow(pxp, 2) / Math.pow(rx, 2) + 146 | Math.pow(pyp, 2) / Math.pow(ry, 2) 147 | 148 | if (lambda > 1) { 149 | rx *= Math.sqrt(lambda) 150 | ry *= Math.sqrt(lambda) 151 | } 152 | 153 | let [ centerx, centery, ang1, ang2 ] = getArcCenter( 154 | px, 155 | py, 156 | cx, 157 | cy, 158 | rx, 159 | ry, 160 | largeArcFlag, 161 | sweepFlag, 162 | sinphi, 163 | cosphi, 164 | pxp, 165 | pyp 166 | ) 167 | 168 | const segments = Math.max(Math.ceil(Math.abs(ang2) / (TAU / 4)), 1) 169 | 170 | ang2 /= segments 171 | 172 | for (let i = 0; i < segments; i++) { 173 | curves.push(approxUnitArc(ang1, ang2)) 174 | ang1 += ang2 175 | } 176 | 177 | return curves.map(curve => { 178 | const { x: x1, y: y1 } = mapToEllipse(curve[ 0 ], rx, ry, cosphi, sinphi, centerx, centery) 179 | const { x: x2, y: y2 } = mapToEllipse(curve[ 1 ], rx, ry, cosphi, sinphi, centerx, centery) 180 | const { x, y } = mapToEllipse(curve[ 2 ], rx, ry, cosphi, sinphi, centerx, centery) 181 | 182 | return { x1, y1, x2, y2, x, y } 183 | }) 184 | } 185 | 186 | export default arcToBezier 187 | -------------------------------------------------------------------------------- /packages/cax/src/render/base/event-dispatcher.js: -------------------------------------------------------------------------------- 1 | import option from './stage-propagation-tag' 2 | 3 | class EventDispatcher { 4 | constructor () { 5 | this._listeners = null 6 | this._captureListeners = null 7 | } 8 | 9 | addEventListener (type, listener, useCapture) { 10 | var listeners 11 | if (useCapture) { 12 | listeners = this._captureListeners = this._captureListeners || {} 13 | } else { 14 | listeners = this._listeners = this._listeners || {} 15 | } 16 | var arr = listeners[type] 17 | if (arr) { this.removeEventListener(type, listener, useCapture) } 18 | arr = listeners[type] // remove may have deleted the array 19 | if (!arr) { listeners[type] = [listener] } else { arr.push(listener) } 20 | return listener 21 | } 22 | 23 | removeEventListener (type, listener, useCapture) { 24 | var listeners = useCapture ? this._captureListeners : this._listeners 25 | if (!listeners) { return } 26 | var arr = listeners[type] 27 | if (!arr) { return } 28 | 29 | arr.every((item, index) => { 30 | if (item === listener) { 31 | arr.splice(index, 1) 32 | return false 33 | } 34 | return true 35 | }) 36 | } 37 | 38 | on (type, listener, useCapture) { 39 | this.addEventListener(type, listener, useCapture) 40 | } 41 | 42 | off (type, listener, useCapture) { 43 | this.removeEventListener(type, listener, useCapture) 44 | } 45 | 46 | dispatchEvent (evt) { 47 | option.stagePropagationStopped[evt.type] = false 48 | 49 | var top = this, list = [top] 50 | while (top.parent) { list.push(top = top.parent) } 51 | var i, l = list.length 52 | 53 | // capture & atTarget 54 | for (i = l - 1; i >= 0 && !evt.propagationStopped; i--) { 55 | list[i]._dispatchEvent(evt, 0) 56 | } 57 | // bubbling 58 | for (i = 0; i < l && !evt.propagationStopped; i++) { 59 | list[i]._dispatchEvent(evt, 1) 60 | } 61 | } 62 | 63 | _dispatchEvent (evt, type) { 64 | evt.target = this 65 | if (this._captureListeners && type === 0) { 66 | let cls = this._captureListeners[evt.type] 67 | cls && cls.forEach(fn => { 68 | fn.call(this, evt) 69 | }) 70 | } 71 | 72 | if (this._listeners && type === 1) { 73 | let ls = this._listeners[evt.type] 74 | ls && ls.forEach(fn => { 75 | fn.call(this, evt) 76 | }) 77 | } 78 | } 79 | } 80 | 81 | export default EventDispatcher 82 | -------------------------------------------------------------------------------- /packages/cax/src/render/base/event.js: -------------------------------------------------------------------------------- 1 | import option from './stage-propagation-tag' 2 | 3 | class Event { 4 | constructor () { 5 | this.propagationStopped = false 6 | this.stageX = null 7 | this.stageY = null 8 | this.pureEvent = null 9 | } 10 | 11 | stopPropagation () { 12 | option.stagePropagationStopped[this.type] = true 13 | this.propagationStopped = true 14 | } 15 | 16 | preventDefault () { 17 | this.pureEvent.preventDefault() 18 | } 19 | } 20 | 21 | export default Event 22 | -------------------------------------------------------------------------------- /packages/cax/src/render/base/matrix2d.js: -------------------------------------------------------------------------------- 1 | 2 | const DEG_TO_RAD = 0.017453292519943295 3 | const PI_2 = Math.PI * 2 4 | 5 | class Matrix2D { 6 | constructor (a, b, c, d, tx, ty) { 7 | this.a = a == null ? 1 : a 8 | this.b = b || 0 9 | this.c = c || 0 10 | this.d = d == null ? 1 : d 11 | this.tx = tx || 0 12 | this.ty = ty || 0 13 | return this 14 | } 15 | 16 | identity () { 17 | this.a = this.d = 1 18 | this.b = this.c = this.tx = this.ty = 0 19 | return this 20 | } 21 | 22 | appendTransform (x, y, scaleX, scaleY, rotation, skewX, skewY, originX, originY) { 23 | if (rotation % 360) { 24 | var r = rotation * DEG_TO_RAD 25 | var cos = Math.cos(r) 26 | var sin = Math.sin(r) 27 | } else { 28 | cos = 1 29 | sin = 0 30 | } 31 | if (skewX || skewY) { 32 | skewX *= DEG_TO_RAD 33 | skewY *= DEG_TO_RAD 34 | this.append(Math.cos(skewY), Math.sin(skewY), -Math.sin(skewX), Math.cos(skewX), x, y) 35 | this.append(cos * scaleX, sin * scaleX, -sin * scaleY, cos * scaleY, 0, 0) 36 | } else { 37 | this.append(cos * scaleX, sin * scaleX, -sin * scaleY, cos * scaleY, x, y) 38 | } 39 | if (originX || originY) { 40 | this.tx -= originX * this.a + originY * this.c 41 | this.ty -= originX * this.b + originY * this.d 42 | } 43 | return this 44 | } 45 | 46 | append (a, b, c, d, tx, ty) { 47 | var a1 = this.a 48 | var b1 = this.b 49 | var c1 = this.c 50 | var d1 = this.d 51 | this.a = a * a1 + b * c1 52 | this.b = a * b1 + b * d1 53 | this.c = c * a1 + d * c1 54 | this.d = c * b1 + d * d1 55 | this.tx = tx * a1 + ty * c1 + this.tx 56 | this.ty = tx * b1 + ty * d1 + this.ty 57 | return this 58 | } 59 | 60 | initialize (a, b, c, d, tx, ty) { 61 | this.a = a 62 | this.b = b 63 | this.c = c 64 | this.d = d 65 | this.tx = tx 66 | this.ty = ty 67 | return this 68 | } 69 | 70 | setValues (a, b, c, d, tx, ty) { 71 | this.a = a == null ? 1 : a 72 | this.b = b || 0 73 | this.c = c || 0 74 | this.d = d == null ? 1 : d 75 | this.tx = tx || 0 76 | this.ty = ty || 0 77 | return this 78 | } 79 | 80 | invert () { 81 | let a1 = this.a 82 | let b1 = this.b 83 | let c1 = this.c 84 | let d1 = this.d 85 | let tx1 = this.tx 86 | let n = a1 * d1 - b1 * c1 87 | 88 | this.a = d1 / n 89 | this.b = -b1 / n 90 | this.c = -c1 / n 91 | this.d = a1 / n 92 | this.tx = (c1 * this.ty - d1 * tx1) / n 93 | this.ty = -(a1 * this.ty - b1 * tx1) / n 94 | return this 95 | }; 96 | 97 | copy (matrix) { 98 | return this.setValues(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty) 99 | } 100 | } 101 | 102 | Matrix2D.decompose = function (a, b, c, d, tx, ty, transform) { 103 | const skewX = -Math.atan2(-c, d) 104 | const skewY = Math.atan2(b, a) 105 | 106 | const delta = Math.abs(skewX + skewY) 107 | 108 | if (delta < 0.00001 || Math.abs(PI_2 - delta) < 0.00001) { 109 | transform.rotation = skewY 110 | 111 | if (a < 0 && d >= 0) { 112 | transform.rotation += (transform.rotation <= 0) ? Math.PI : -Math.PI 113 | } 114 | 115 | transform.skewX = transform.skewY = 0 116 | } else { 117 | transform.rotation = 0 118 | transform.skewX = skewX 119 | transform.skewY = skewY 120 | } 121 | 122 | // next set scale 123 | transform.scaleX = Math.sqrt((a * a) + (b * b)) 124 | transform.scaleY = Math.sqrt((c * c) + (d * d)) 125 | 126 | // next set position 127 | transform.x = tx 128 | transform.y = ty 129 | } 130 | 131 | export default Matrix2D 132 | -------------------------------------------------------------------------------- /packages/cax/src/render/base/path-parser.js: -------------------------------------------------------------------------------- 1 | // https://github.com/jkroso/parse-svg-path/blob/master/index.js 2 | /** 3 | * expected argument lengths 4 | * @type {Object} 5 | */ 6 | 7 | var length = {a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0} 8 | 9 | /** 10 | * segment pattern 11 | * @type {RegExp} 12 | */ 13 | 14 | var segment = /([astvzqmhlc])([^astvzqmhlc]*)/ig 15 | 16 | /** 17 | * parse an svg path data string. Generates an Array 18 | * of commands where each command is an Array of the 19 | * form `[command, arg1, arg2, ...]` 20 | * 21 | * @param {String} path 22 | * @return {Array} 23 | */ 24 | 25 | function parse (path) { 26 | var data = [] 27 | path.replace(segment, function (_, command, args) { 28 | var type = command.toLowerCase() 29 | args = parseValues(args) 30 | 31 | // overloaded moveTo 32 | if (type === 'm' && args.length > 2) { 33 | data.push([command].concat(args.splice(0, 2))) 34 | type = 'l' 35 | command = command === 'm' ? 'l' : 'L' 36 | } 37 | 38 | while (true) { 39 | if (args.length === length[type]) { 40 | args.unshift(command) 41 | return data.push(args) 42 | } 43 | if (args.length < length[type]) throw new Error('malformed path data') 44 | data.push([command].concat(args.splice(0, length[type]))) 45 | } 46 | }) 47 | return data 48 | } 49 | 50 | var number = /-?[0-9]*\.?[0-9]+(?:e[-+]?\d+)?/ig 51 | 52 | function parseValues (args) { 53 | var numbers = args.match(number) 54 | return numbers ? numbers.map(Number) : [] 55 | } 56 | 57 | export default parse 58 | -------------------------------------------------------------------------------- /packages/cax/src/render/base/stage-propagation-tag.js: -------------------------------------------------------------------------------- 1 | export default { 2 | stagePropagationStopped: {} 3 | } 4 | -------------------------------------------------------------------------------- /packages/cax/src/render/base/uid.js: -------------------------------------------------------------------------------- 1 | var UID = {} 2 | 3 | UID._nextID = 0 4 | 5 | UID.get = function () { 6 | return UID._nextID++ 7 | } 8 | 9 | export default UID 10 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/bitmap.js: -------------------------------------------------------------------------------- 1 | import DisplayObject from './display-object.js' 2 | import util from '../../common/util' 3 | 4 | class Bitmap extends DisplayObject { 5 | constructor (img, onLoad) { 6 | super() 7 | if (typeof img === 'string') { 8 | if (Bitmap.cache[img]) { 9 | if (util.isWeapp) { 10 | this.img = Bitmap.cache[img].img 11 | this.rect = [0, 0, Bitmap.cache[img].width, Bitmap.cache[img].height] 12 | this.width = this.rect[2] 13 | this.height = this.rect[3] 14 | } else { 15 | this.img = Bitmap.cache[img] 16 | this.rect = [0, 0, this.img.width, this.img.height] 17 | this.width = this.img.width 18 | this.height = this.img.height 19 | } 20 | onLoad && onLoad.call(this) 21 | } else if (util.isWeapp) { 22 | util.getImageInWx(img, (result) => { 23 | this.img = result.img 24 | if (!this.rect) { 25 | this.rect = [0, 0, result.width, result.height] 26 | } 27 | this.width = result.width 28 | this.height = result.height 29 | onLoad && onLoad.call(this) 30 | Bitmap.cache[img] = result 31 | }) 32 | } else { 33 | this.img = util.isWegame ? wx.createImage() : new window.Image() 34 | 35 | this.img.onload = () => { 36 | if (!this.rect) { 37 | this.rect = [0, 0, this.img.width, this.img.height] 38 | } 39 | this.width = this.img.width 40 | this.height = this.img.height 41 | onLoad && onLoad.call(this) 42 | Bitmap.cache[img] = this.img 43 | } 44 | this.img.src = img 45 | } 46 | } else { 47 | this.img = img 48 | this.rect = [0, 0, img.width, img.height] 49 | this.width = img.width 50 | this.height = img.height 51 | Bitmap.cache[img.src] = img 52 | } 53 | } 54 | 55 | clone () { 56 | // 复制完img宽度0??所以直接传字符串 57 | const bitmap = new Bitmap(typeof this.img === 'string' ? this.img : this.img.src) 58 | bitmap.x = this.x 59 | bitmap.y = this.y 60 | bitmap.scaleX = this.scaleX 61 | bitmap.scaleY = this.scaleY 62 | bitmap.rotation = this.rotation 63 | bitmap.skewX = this.skewX 64 | bitmap.skewY = this.skewY 65 | bitmap.originX = this.originX 66 | bitmap.originY = this.originY 67 | bitmap.width = this.width 68 | bitmap.height = this.height 69 | bitmap.cursor = this.cursor 70 | 71 | return bitmap 72 | } 73 | } 74 | 75 | Bitmap.cache = { 76 | 77 | } 78 | 79 | export default Bitmap 80 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/element/button.js: -------------------------------------------------------------------------------- 1 | import Group from '../group' 2 | import Text from '../text' 3 | import RoundedRect from '../shape/rounded-rect' 4 | import Bitmap from '../bitmap' 5 | 6 | /* 7 | Options 8 | font: 9 | text: 10 | textColor: 11 | image: [path, width, height] 12 | bgColor: 13 | bgImage: [path, width, height] 14 | borderRadius: 15 | borderColor: 16 | */ 17 | 18 | class Button extends Group { 19 | constructor (option) { 20 | super() 21 | this.width = option.width 22 | this.height = option.height 23 | this.x = option.x 24 | this.y = option.y 25 | 26 | let textHeight = 0 27 | var textGroup 28 | 29 | if (option.text) { 30 | textGroup = new Group() 31 | this.text = new Text(option.text, { 32 | font: option.font, 33 | color: option.color 34 | }) 35 | const textWidth = this.text.getWidth() 36 | 37 | if (textWidth > option.width) { 38 | const step = Math.round(option.text.length * (option.width) / textWidth / 2) 39 | 40 | const textList = this.stringSplit(option.text, step) 41 | const lineHeight = option.lineHeight || 12 42 | textHeight = textList.length * lineHeight + 6 43 | 44 | textList.forEach((text, index) => { 45 | this.text = new Text(text, { 46 | font: option.font, 47 | color: option.color 48 | }) 49 | 50 | this.text.x = option.width / 2 - this.text.getWidth() / 2 * this.text.scaleX + (option.textX || 0) 51 | this.text.y = Math.max(textHeight, option.height) / 2 - 10 + 5 * this.text.scaleY + (option.textY || 0) + index * 12 - textHeight / 2 + lineHeight / 2 52 | textGroup.add(this.text) 53 | }) 54 | } else { 55 | this.text.x = option.width / 2 - this.text.getWidth() / 2 * this.text.scaleX + (option.textX || 0) 56 | this.text.y = option.height / 2 - 10 + 5 * this.text.scaleY + (option.textY || 0) 57 | textGroup.add(this.text) 58 | } 59 | } 60 | 61 | if (option.bgImage) { 62 | var ratio = option.ratio || 1 63 | let bitmap = new Bitmap(option.bgImage[0]) 64 | bitmap.scaleX = ratio 65 | bitmap.scaleY = ratio 66 | bitmap.width = option.bgImage[1] 67 | bitmap.height = option.bgImage[2] 68 | bitmap.x = (this.width - bitmap.width) / 2 69 | bitmap.y = (this.height - bitmap.height) / 2 70 | this.add(bitmap) 71 | } else if (option.bgColor || option.borderColor) { 72 | this.roundedRect = new RoundedRect(option.width, option.autoHeight ? Math.max(textHeight, option.height) : option.height, option.borderRadius, { 73 | strokeStyle: option.borderColor || 'black', 74 | fillStyle: option.bgColor || '#F5F5F5' 75 | }) 76 | this.add(this.roundedRect) 77 | } 78 | 79 | if (option.image) { 80 | var ratio = option.ratio || 1 81 | let bitmap = new Bitmap(option.image[0]) 82 | bitmap.scaleX = ratio 83 | bitmap.scaleY = ratio 84 | bitmap.width = option.image[1] 85 | bitmap.height = option.image[2] 86 | bitmap.x = (this.width - bitmap.width) / 2 87 | bitmap.y = (this.height - bitmap.height) / 2 88 | this.add(bitmap) 89 | } 90 | 91 | if (textGroup) { 92 | this.add(textGroup) 93 | } 94 | } 95 | 96 | stringSplit (str, len) { 97 | let arr = [], 98 | offset = 0, 99 | char_length = 0 100 | for (let i = 0; i < str.length; i++) { 101 | let son_str = str.charAt(i) 102 | encodeURI(son_str).length > 2 ? char_length += 1 : char_length += 0.5 103 | if (char_length >= len || (char_length < len && i === str.length - 1)) { 104 | let sub_len = char_length == len ? i + 1 : i 105 | arr.push(str.substr(offset, sub_len - offset + ((char_length < len && i === str.length - 1) ? 1 : 0))) 106 | offset = i + 1 107 | char_length = 0 108 | } 109 | } 110 | return arr 111 | } 112 | } 113 | 114 | export default Button 115 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/graphics.js: -------------------------------------------------------------------------------- 1 | import DisplayObject from './display-object.js' 2 | 3 | const assMap = { 4 | fillStyle: true, 5 | strokeStyle: true, 6 | lineWidth: true, 7 | lineCap: true, 8 | lineDashOffset: true, 9 | lineJoin: true, 10 | miterLimit: true 11 | } 12 | 13 | class Graphics extends DisplayObject { 14 | constructor () { 15 | super() 16 | this.cmds = [] 17 | this.currentGradient = null 18 | } 19 | 20 | clearRect () { 21 | this.cmds.push(['clearRect', arguments]) 22 | return this 23 | } 24 | 25 | rect () { 26 | this.cmds.push(['rect', arguments]) 27 | return this 28 | } 29 | 30 | clear () { 31 | this.cmds.length = 0 32 | return this 33 | } 34 | 35 | setLineDash () { 36 | this.cmds.push(['setLineDash', arguments]) 37 | return this 38 | } 39 | 40 | strokeRect () { 41 | this.cmds.push(['strokeRect', arguments]) 42 | return this 43 | } 44 | 45 | fillRect () { 46 | this.cmds.push(['fillRect', arguments]) 47 | return this 48 | } 49 | 50 | beginPath () { 51 | this.cmds.push(['beginPath', arguments]) 52 | return this 53 | } 54 | 55 | arc () { 56 | this.cmds.push(['arc', arguments]) 57 | return this 58 | } 59 | 60 | closePath () { 61 | this.cmds.push(['closePath', arguments]) 62 | return this 63 | } 64 | 65 | fillStyle () { 66 | this.cmds.push(['fillStyle', arguments]) 67 | return this 68 | } 69 | 70 | fill () { 71 | this.cmds.push(['fill', arguments]) 72 | return this 73 | } 74 | 75 | strokeStyle () { 76 | this.cmds.push(['strokeStyle', arguments]) 77 | return this 78 | } 79 | 80 | lineWidth () { 81 | this.cmds.push(['lineWidth', arguments]) 82 | return this 83 | } 84 | 85 | lineCap () { 86 | this.cmds.push(['lineCap', arguments]) 87 | return this 88 | } 89 | 90 | lineDashOffset () { 91 | this.cmds.push(['lineDashOffset', arguments]) 92 | return this 93 | } 94 | 95 | lineJoin () { 96 | this.cmds.push(['lineJoin', arguments]) 97 | return this 98 | } 99 | 100 | miterLimit () { 101 | this.cmds.push(['miterLimit', arguments]) 102 | return this 103 | } 104 | 105 | stroke () { 106 | this.cmds.push(['stroke', arguments]) 107 | return this 108 | } 109 | 110 | moveTo () { 111 | this.cmds.push(['moveTo', arguments]) 112 | return this 113 | } 114 | 115 | lineTo () { 116 | this.cmds.push(['lineTo', arguments]) 117 | return this 118 | } 119 | 120 | bezierCurveTo () { 121 | this.cmds.push(['bezierCurveTo', arguments]) 122 | return this 123 | } 124 | 125 | quadraticCurveTo () { 126 | this.cmds.push(['quadraticCurveTo', arguments]) 127 | return this 128 | } 129 | 130 | createRadialGradient () { 131 | this.cmds.push(['createRadialGradient', arguments]) 132 | return this 133 | } 134 | 135 | createLinearGradient () { 136 | this.cmds.push(['createLinearGradient', arguments]) 137 | return this 138 | } 139 | 140 | addColorStop () { 141 | this.cmds.push(['addColorStop', arguments]) 142 | return this 143 | } 144 | 145 | fillGradient () { 146 | this.cmds.push(['fillGradient']) 147 | return this 148 | } 149 | 150 | arcTo () { 151 | this.cmds.push(['arcTo', arguments]) 152 | return this 153 | } 154 | 155 | render (ctx) { 156 | this.cmds.forEach(cmd => { 157 | const methodName = cmd[0] 158 | if (assMap[methodName]) { 159 | ctx[methodName] = cmd[1][0] 160 | } else if (methodName === 'addColorStop') { 161 | this.currentGradient && this.currentGradient.addColorStop(cmd[1][0], cmd[1][1]) 162 | } else if (methodName === 'fillGradient') { 163 | ctx.fillStyle = this.currentGradient 164 | } else { 165 | let result = ctx[methodName].apply(ctx, Array.prototype.slice.call(cmd[1])) 166 | if (methodName === 'createRadialGradient' || methodName === 'createLinearGradient') { 167 | this.currentGradient = result 168 | } 169 | } 170 | }) 171 | } 172 | } 173 | 174 | export default Graphics 175 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/group.js: -------------------------------------------------------------------------------- 1 | import DisplayObject from './display-object.js' 2 | 3 | class Group extends DisplayObject { 4 | constructor (data) { 5 | super(data) 6 | this.children = [] 7 | } 8 | 9 | add (child) { 10 | const len = arguments.length 11 | 12 | for (let i = 0; i < len; i++) { 13 | const c = arguments[i] 14 | const parent = c.parent 15 | if (parent) { 16 | parent.removeChildAt(parent.children.indexOf(c)) 17 | } 18 | this.children.push(c) 19 | c.parent = this 20 | } 21 | } 22 | 23 | addChildAt (child, index) { 24 | var par = child.parent 25 | par && par.removeChildAt(par.children.indexOf(child)) 26 | child.parent = this 27 | this.children.splice(index, 0, child) 28 | } 29 | 30 | removeChildAt (index) { 31 | var child = this.children[index] 32 | if (child) { child.parent = null } 33 | this.children.splice(index, 1) 34 | } 35 | 36 | replace (current, pre) { 37 | const index = pre.parent.children.indexOf(pre) 38 | this.removeChildAt(index) 39 | this.addChildAt(current, index) 40 | } 41 | 42 | remove (child) { 43 | const len = arguments.length 44 | let cLen = this.children.length 45 | 46 | for (let i = 0; i < len; i++) { 47 | for (let j = 0; j < cLen; j++) { 48 | if (child.id === this.children[j].id) { 49 | child.parent = null 50 | this.children.splice(j, 1) 51 | j-- 52 | cLen-- 53 | } 54 | } 55 | } 56 | } 57 | 58 | empty () { 59 | this.children.forEach(child => { 60 | child.parent = null 61 | }) 62 | this.children.length = 0 63 | } 64 | 65 | destroy () { 66 | this.empty() 67 | // Stage does not have a parent 68 | this.parent && super.destroy() 69 | } 70 | } 71 | 72 | export default Group 73 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/shape/arrow-path.js: -------------------------------------------------------------------------------- 1 | import Shape from './shape' 2 | 3 | class ArrowPath extends Shape { 4 | constructor (path, option) { 5 | super() 6 | 7 | this.path = path 8 | this.option = Object.assign({ 9 | strokeStyle: 'black', 10 | lineWidth: 1, 11 | headSize: 10 12 | }, option) 13 | } 14 | 15 | draw () { 16 | const path = this.path 17 | this.beginPath() 18 | const len = path.length 19 | if (len === 2) { 20 | this.drawArrow(path[0].x, path[0].y, path[1].x, path[1].y, 30) 21 | } else { 22 | this.moveTo(path[0].x, path[0].y) 23 | for (let i = 1; i < len - 1; i++) { 24 | this.lineTo(path[i].x, path[i].y) 25 | } 26 | this.drawArrow(path[len - 2].x, path[len - 2].y, path[len - 1].x, path[len - 1].y, 30) 27 | } 28 | 29 | this.stroke() 30 | } 31 | 32 | drawArrow (fromX, fromY, toX, toY, theta) { 33 | let angle = Math.atan2(fromY - toY, fromX - toX) * 180 / Math.PI, 34 | angle1 = (angle + theta) * Math.PI / 180, 35 | angle2 = (angle - theta) * Math.PI / 180, 36 | hs = this.option.headSize, 37 | topX = hs * Math.cos(angle1), 38 | topY = hs * Math.sin(angle1), 39 | botX = hs * Math.cos(angle2), 40 | botY = hs * Math.sin(angle2) 41 | 42 | let arrowX = fromX - topX, 43 | arrowY = fromY - topY 44 | 45 | this.moveTo(arrowX, arrowY) 46 | this.moveTo(fromX, fromY) 47 | this.lineTo(toX, toY) 48 | arrowX = toX + topX 49 | arrowY = toY + topY 50 | this.moveTo(arrowX, arrowY) 51 | this.lineTo(toX, toY) 52 | arrowX = toX + botX 53 | arrowY = toY + botY 54 | this.lineTo(arrowX, arrowY) 55 | this.strokeStyle(this.option.strokeStyle) 56 | this.lineWidth(this.option.lineWidth) 57 | } 58 | } 59 | 60 | export default ArrowPath 61 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/shape/circle.js: -------------------------------------------------------------------------------- 1 | import Shape from './shape' 2 | 3 | class Circle extends Shape { 4 | constructor (r, option) { 5 | super() 6 | this.option = option || {} 7 | this.r = r 8 | 9 | this._dp = Math.PI * 2 10 | } 11 | 12 | draw () { 13 | this.beginPath() 14 | this.arc(0, 0, this.r, 0, this._dp, false) 15 | 16 | if (this.option.strokeStyle) { 17 | if (this.option.lineWidth !== undefined) { 18 | this.lineWidth(this.option.lineWidth) 19 | } 20 | this.strokeStyle(this.option.strokeStyle) 21 | this.stroke() 22 | } 23 | 24 | if (this.option.fillStyle) { 25 | this.fillStyle(this.option.fillStyle) 26 | this.fill() 27 | } 28 | } 29 | } 30 | 31 | export default Circle 32 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/shape/ellipse.js: -------------------------------------------------------------------------------- 1 | 2 | import Shape from './shape' 3 | 4 | class Ellipse extends Shape { 5 | constructor (width, height, option) { 6 | super() 7 | this.option = option || {} 8 | this.width = width 9 | this.height = height 10 | } 11 | 12 | draw () { 13 | const w = this.width 14 | const h = this.height 15 | const k = 0.5522848 16 | const ox = (w / 2) * k 17 | const oy = (h / 2) * k 18 | const xe = w 19 | const ye = h 20 | const xm = w / 2 21 | const ym = h / 2 22 | 23 | this.beginPath() 24 | this.moveTo(0, ym) 25 | this.bezierCurveTo(0, ym - oy, xm - ox, 0, xm, 0) 26 | this.bezierCurveTo(xm + ox, 0, xe, ym - oy, xe, ym) 27 | this.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye) 28 | this.bezierCurveTo(xm - ox, ye, 0, ym + oy, 0, ym) 29 | 30 | if (this.option.strokeStyle) { 31 | if (this.option.lineWidth !== undefined) { 32 | this.lineWidth(this.option.lineWidth) 33 | } 34 | this.strokeStyle(this.option.strokeStyle) 35 | this.stroke() 36 | } 37 | 38 | if (this.option.fillStyle) { 39 | this.fillStyle(this.option.fillStyle) 40 | this.fill() 41 | } 42 | } 43 | } 44 | 45 | export default Ellipse 46 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/shape/equilateral-polygon.js: -------------------------------------------------------------------------------- 1 | import Shape from './shape' 2 | 3 | class EquilateralPolygon extends Shape { 4 | constructor (num, r, options) { 5 | super() 6 | 7 | this.num = num 8 | this.r = r 9 | this.options = options || {} 10 | 11 | this.vertex = [] 12 | this.initVertex() 13 | } 14 | 15 | initVertex () { 16 | this.vertex.length = [] 17 | const num = this.num 18 | const r = this.r 19 | let i, startX, startY, newX, newY 20 | 21 | if (num % 2 === 0) { 22 | startX = r * Math.cos(2 * Math.PI * 0 / num) 23 | startY = r * Math.sin(2 * Math.PI * 0 / num) 24 | 25 | this.vertex.push([startX, startY]) 26 | for (i = 1; i < num; i++) { 27 | newX = r * Math.cos(2 * Math.PI * i / num) 28 | newY = r * Math.sin(2 * Math.PI * i / num) 29 | 30 | this.vertex.push([newX, newY]) 31 | } 32 | } else { 33 | startX = r * Math.cos(2 * Math.PI * 0 / num - Math.PI / 2) 34 | startY = r * Math.sin(2 * Math.PI * 0 / num - Math.PI / 2) 35 | 36 | this.vertex.push([startX, startY]) 37 | for (i = 1; i < num; i++) { 38 | newX = r * Math.cos(2 * Math.PI * i / num - Math.PI / 2) 39 | newY = r * Math.sin(2 * Math.PI * i / num - Math.PI / 2) 40 | 41 | this.vertex.push([newX, newY]) 42 | } 43 | } 44 | } 45 | 46 | draw () { 47 | this.beginPath() 48 | 49 | this.moveTo(this.vertex[0][0], this.vertex[0][1]) 50 | 51 | for (let i = 1, len = this.vertex.length; i < len; i++) { 52 | this.lineTo(this.vertex[i][0], this.vertex[i][1]) 53 | } 54 | this.closePath() 55 | 56 | if (this.options.fillStyle) { 57 | this.fillStyle(this.options.fillStyle) 58 | this.fill() 59 | } 60 | 61 | if (this.options.strokeStyle) { 62 | this.strokeStyle(this.options.strokeStyle) 63 | if (typeof this.options.lineWidth === 'number') { 64 | this.lineWidth(this.options.lineWidth) 65 | } 66 | this.stroke() 67 | } 68 | } 69 | } 70 | 71 | export default EquilateralPolygon 72 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/shape/polygon.js: -------------------------------------------------------------------------------- 1 | import Shape from './shape' 2 | 3 | class Polygon extends Shape { 4 | constructor (vertex, options) { 5 | super() 6 | 7 | this.vertex = vertex || [] 8 | this.options = options || {} 9 | this.strokeColor = this.options.strokeColor 10 | this.fillColor = this.options.fillColor 11 | } 12 | 13 | draw () { 14 | this.clear().beginPath() 15 | this.strokeStyle(this.strokeColor) 16 | this.moveTo(this.vertex[0][0], this.vertex[0][1]) 17 | 18 | for (let i = 1, len = this.vertex.length; i < len; i++) { 19 | this.lineTo(this.vertex[i][0], this.vertex[i][1]) 20 | } 21 | this.closePath() 22 | // 路径闭合 23 | // if (this.options.strokeStyle) { 24 | // this.strokeStyle = strokeStyle; 25 | // this.lineWidth(this.options.width); 26 | // this.lineJoin('round'); 27 | // this.stroke(); 28 | // } 29 | if (this.strokeColor) { 30 | this.strokeStyle(this.strokeColor) 31 | this.stroke() 32 | } 33 | if (this.fillColor) { 34 | this.fillStyle(this.fillColor) 35 | this.fill() 36 | } 37 | } 38 | } 39 | 40 | export default Polygon 41 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/shape/rect.js: -------------------------------------------------------------------------------- 1 | import Shape from './shape' 2 | 3 | class Rect extends Shape { 4 | constructor(width, height, option) { 5 | super() 6 | 7 | this.width = width 8 | this.height = height 9 | this.option = option || {} 10 | } 11 | 12 | draw() { 13 | if (this.option.fillStyle) { 14 | this.fillStyle(this.option.fillStyle) 15 | this.fillRect(0, 0, this.width, this.height) 16 | } 17 | 18 | if (this.option.strokeStyle) { 19 | this.strokeStyle(this.option.strokeStyle) 20 | if (typeof this.option.lineWidth === 'number') { 21 | this.lineWidth(this.option.lineWidth) 22 | } 23 | this.strokeRect(0, 0, this.width, this.height) 24 | } 25 | } 26 | 27 | clone() { 28 | return new Rect(this.width, this.height, { 29 | fillStyle: this.option.fillStyle, 30 | strokeStyle: this.option.strokeStyle, 31 | lineWidth: this.option.lineWidth 32 | }) 33 | } 34 | } 35 | 36 | export default Rect 37 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/shape/rounded-rect.js: -------------------------------------------------------------------------------- 1 | import Shape from './shape' 2 | 3 | class RoundedRect extends Shape { 4 | constructor (width, height, r, option) { 5 | super() 6 | this.option = Object.assign({ 7 | lineWidth: 1, 8 | lt: true, 9 | rt: true, 10 | lb: true, 11 | rb: true 12 | }, option) 13 | this.r = r || 0 14 | this.width = width 15 | this.height = height 16 | } 17 | 18 | draw () { 19 | const width = this.width, 20 | height = this.height, 21 | r = this.r 22 | 23 | const ax = r, 24 | ay = 0, 25 | bx = width, 26 | by = 0, 27 | cx = width, 28 | cy = height, 29 | dx = 0, 30 | dy = height, 31 | ex = 0, 32 | ey = 0 33 | 34 | this.beginPath() 35 | 36 | this.moveTo(ax, ay) 37 | if (this.option.rt) { 38 | this.arcTo(bx, by, cx, cy, r) 39 | } else { 40 | this.lineTo(bx, by) 41 | } 42 | 43 | if (this.option.rb) { 44 | this.arcTo(cx, cy, dx, dy, r) 45 | } else { 46 | this.lineTo(cx, cy) 47 | } 48 | 49 | if (this.option.lb) { 50 | this.arcTo(dx, dy, ex, ey, r) 51 | } else { 52 | this.lineTo(dx, dy) 53 | } 54 | 55 | if (this.option.lt) { 56 | this.arcTo(ex, ey, ax, ay, r) 57 | } else { 58 | this.lineTo(ex, ey) 59 | } 60 | 61 | if (this.option.fillStyle) { 62 | this.closePath() 63 | this.fillStyle(this.option.fillStyle) 64 | this.fill() 65 | } 66 | 67 | if (this.option.strokeStyle) { 68 | this.lineWidth(this.option.lineWidth) 69 | this.strokeStyle(this.option.strokeStyle) 70 | this.stroke() 71 | } 72 | } 73 | } 74 | 75 | export default RoundedRect 76 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/shape/sector.js: -------------------------------------------------------------------------------- 1 | import Shape from './shape' 2 | 3 | class Sector extends Shape { 4 | constructor (r, from, to, option) { 5 | super() 6 | 7 | this.option = option || {} 8 | this.r = r 9 | this.from = from 10 | this.to = to 11 | } 12 | 13 | draw () { 14 | this.beginPath() 15 | .moveTo(0, 0) 16 | .arc(0, 0, this.r, this.from, this.to) 17 | .closePath() 18 | .fillStyle(this.option.fillStyle) 19 | .fill() 20 | .strokeStyle(this.option.strokeStyle) 21 | .lineWidth(this.option.lineWidth) 22 | .stroke() 23 | } 24 | } 25 | 26 | export default Sector 27 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/shape/shape.js: -------------------------------------------------------------------------------- 1 | import Graphics from '../graphics' 2 | 3 | class Shape extends Graphics { 4 | // constructor() { 5 | // super() 6 | // } 7 | 8 | draw () { 9 | 10 | } 11 | 12 | render (ctx) { 13 | this.clear() 14 | this.draw() 15 | super.render(ctx) 16 | } 17 | } 18 | 19 | export default Shape 20 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/sprite.js: -------------------------------------------------------------------------------- 1 | import DisplayObject from './display-object' 2 | import util from '../../common/util' 3 | import Bitmap from './bitmap' 4 | 5 | class Sprite extends DisplayObject { 6 | constructor (option) { 7 | super() 8 | this.option = option 9 | const len = this.option.imgs.length 10 | let count = 0 11 | const firstImg = this.option.imgs[0] 12 | this.imgMap = {} 13 | 14 | if (util.isWeapp) { 15 | this.option.imgs.forEach(img => { 16 | util.getImageInWx(img, (result) => { 17 | this.imgMap[img] = result.img 18 | count++ 19 | if (count === len) { 20 | this.img = this.imgMap[firstImg] 21 | this.rect = [0, 0, 0, 0] 22 | } 23 | }) 24 | } 25 | ) 26 | } else { 27 | if (typeof firstImg === 'string') { 28 | const len = this.option.imgs.length 29 | let loadedCount = 0 30 | this.option.imgs.forEach(src => { 31 | if (Bitmap.cache[src]) { 32 | this.imgMap[src] = Bitmap.cache[src] 33 | loadedCount++ 34 | if (loadedCount === len) { 35 | this.img = this.imgMap[firstImg] 36 | this.rect = [0, 0, 0, 0] 37 | } 38 | } else { 39 | const img = util.isWegame ? wx.createImage() : new window.Image() 40 | img.onload = () => { 41 | this.imgMap[src] = img 42 | loadedCount++ 43 | if (loadedCount === len) { 44 | this.img = this.imgMap[firstImg] 45 | this.rect = [0, 0, 0, 0] 46 | } 47 | Bitmap.cache[src] = img 48 | } 49 | img.src = src 50 | } 51 | }) 52 | } else if (firstImg instanceof Bitmap) { 53 | this.rect = [0, 0, 0, 0] 54 | this.img = firstImg.img 55 | } else { 56 | this.rect = [0, 0, 0, 0] 57 | this.img = firstImg 58 | } 59 | } 60 | 61 | this.x = option.x || 0 62 | this.y = option.y || 0 63 | this.currentFrameIndex = 0 64 | this.animationFrameIndex = 0 65 | this.currentAnimation = option.currentAnimation || null 66 | 67 | this.interval = 1e3 / option.framerate 68 | 69 | this.paused = false 70 | this.animationEnd = option.animationEnd || function () {} 71 | if (this.currentAnimation) { 72 | if (option.playOnce) { 73 | this.gotoAndPlayOnce(this.currentAnimation) 74 | } else { 75 | this.gotoAndPlay(this.currentAnimation) 76 | } 77 | } 78 | } 79 | 80 | play () { 81 | this.paused = false 82 | } 83 | 84 | pause () { 85 | this.paused = true 86 | } 87 | 88 | reset () { 89 | this.currentFrameIndex = 0 90 | this.animationFrameIndex = 0 91 | } 92 | 93 | updateFrame () { 94 | if (!this.paused) { 95 | let opt = this.option 96 | this.dt = Date.now() - this.startTime 97 | let frames = opt.animations[this.currentAnimation].frames 98 | const len = frames.length 99 | const index = Math.floor(this.dt / this.interval % len) 100 | this.rect = opt.frames[ frames[ index ] ] 101 | const rectLen = this.rect.length 102 | 103 | rectLen > 4 && (this.originX = this.rect[2] * this.rect[4]) 104 | rectLen > 5 && (this.originY = this.rect[3] * this.rect[5]) 105 | if (rectLen > 6) { 106 | const img = this.option.imgs[this.rect[6]] 107 | this.img = typeof img === 'string' ? this.imgMap[img] : img 108 | } 109 | 110 | if (index === len - 1 && (!this.endTime || Date.now() - this.endTime > this.interval)) { 111 | this.endTime = Date.now() 112 | this.animationEnd() 113 | if (this._willDestroy) { 114 | this.destroy() 115 | } 116 | } 117 | } 118 | } 119 | 120 | gotoAndPlay (animation) { 121 | this.paused = false 122 | this.reset() 123 | this.currentAnimation = animation 124 | this.startTime = Date.now() 125 | } 126 | 127 | gotoAndStop (animation) { 128 | this.reset() 129 | this.paused = true 130 | this.currentAnimation = animation 131 | var opt = this.option 132 | var frames = opt.animations[this.currentAnimation].frames 133 | this.rect = opt.frames[frames[this.animationFrameIndex]] 134 | const rect = this.rect 135 | this.width = rect[2] 136 | this.height = rect[3] 137 | const rectLen = rect.length 138 | rectLen > 4 && (this.originX = rect[2] * rect[4]) 139 | rectLen > 5 && (this.originY = rect[3] * rect[5]) 140 | if (rectLen > 6) { 141 | const img = this.option.imgs[rect[6]] 142 | this.img = typeof img === 'string' ? this.imgMap[img] : img 143 | } 144 | } 145 | 146 | gotoAndPlayOnce (animation) { 147 | this.gotoAndPlay(animation) 148 | this._willDestroy = true 149 | } 150 | } 151 | 152 | export default Sprite 153 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/text.js: -------------------------------------------------------------------------------- 1 | import DisplayObject from './display-object' 2 | import util from '../../common/util' 3 | 4 | let measureCtx 5 | 6 | if (util.isWeapp) { 7 | measureCtx = wx.createCanvasContext('measure0') 8 | } else if (typeof document !== 'undefined') { 9 | measureCtx = document.createElement('canvas').getContext('2d') 10 | } 11 | 12 | class Text extends DisplayObject { 13 | constructor (text, option) { 14 | super() 15 | 16 | this.text = text 17 | option = option || {} 18 | this.font = option.font || '10px sans-serif' 19 | this.fontSize = option.fontSize || 10 20 | this.textAlign = option.textAlign || 'left' 21 | this.baseline = option.baseline || 'top' 22 | // color 待废弃 23 | this.fillStyle = option.fillStyle || option.color 24 | this.lineWidth = option.lineWidth || 1 25 | this.strokeStyle = option.strokeStyle 26 | } 27 | 28 | getWidth () { 29 | if (!measureCtx) { 30 | if (util.isWegame) { 31 | measureCtx = wx.createCanvas().getContext('2d') 32 | } 33 | } 34 | 35 | if (this.font) { 36 | measureCtx.font = this.font 37 | } 38 | return measureCtx.measureText(this.text).width 39 | } 40 | } 41 | 42 | export default Text 43 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/we-stage.js: -------------------------------------------------------------------------------- 1 | import Group from './group.js' 2 | import Renderer from '../render/renderer.js' 3 | import WxHitRender from '../render/wx-hit-render.js' 4 | import Event from '../base/event.js' 5 | 6 | class WeStage extends Group { 7 | constructor (width, height, id, page) { 8 | super() 9 | 10 | const component = page.selectComponent('#' + id) 11 | component.setData({ 12 | width, 13 | height 14 | }) 15 | component.stage = this 16 | const canvasId = component.getCaxCanvasId() 17 | 18 | const ctx = wx.createCanvasContext(canvasId, component) 19 | const hitCtx = wx.createCanvasContext(canvasId + 'Hit', component) 20 | this.renderer = new Renderer(ctx, width, height) 21 | this._hitRender = new WxHitRender(hitCtx, component, canvasId) 22 | this._overObject = null 23 | this.ctx = ctx 24 | this.hitAABB = true 25 | this.width = width 26 | this.height = height 27 | } 28 | 29 | touchStartHandler (evt) { 30 | const p1 = evt.changedTouches[0] 31 | 32 | evt.stageX = Math.round(p1.x * this.scaleX) 33 | evt.stageY = Math.round(p1.y * this.scaleY) 34 | 35 | this._getObjectUnderPoint(evt, (obj) => { 36 | this.willDragObject = obj 37 | this._mouseDownX = evt.stageX 38 | this._mouseDownY = evt.stageY 39 | this.preStageX = evt.stageX 40 | this.preStageY = evt.stageY 41 | }) 42 | } 43 | 44 | touchMoveHandler (evt) { 45 | const p1 = evt.changedTouches[0] 46 | 47 | evt.stageX = Math.round(p1.x * this.scaleX) 48 | evt.stageY = Math.round(p1.y * this.scaleY) 49 | 50 | this._getObjectUnderPoint(evt, (obj) => { 51 | let mockEvt = new Event() 52 | mockEvt.stageX = evt.stageX 53 | mockEvt.stageY = evt.stageY 54 | mockEvt.pureEvent = evt 55 | 56 | if (this.willDragObject) { 57 | mockEvt.type = 'drag' 58 | mockEvt.dx = mockEvt.stageX - this.preStageX 59 | mockEvt.dy = mockEvt.stageY - this.preStageY 60 | this.preStageX = mockEvt.stageX 61 | this.preStageY = mockEvt.stageY 62 | this.willDragObject.dispatchEvent(mockEvt) 63 | } 64 | 65 | if (obj) { 66 | if (this._overObject === null) { 67 | this._overObject = obj 68 | } else { 69 | if (obj.id !== this._overObject.id) { 70 | this._overObject = obj 71 | } else { 72 | mockEvt.type = 'touchmove' 73 | obj.dispatchEvent(mockEvt) 74 | } 75 | } 76 | } else if (this._overObject) { 77 | this._overObject = null 78 | } 79 | }) 80 | } 81 | 82 | touchEndHandler (evt) { 83 | const p1 = evt.changedTouches[0] 84 | 85 | evt.stageX = Math.round(p1.x * this.scaleX) 86 | evt.stageY = Math.round(p1.y * this.scaleY) 87 | 88 | let mockEvt = new Event() 89 | mockEvt.stageX = evt.stageX 90 | mockEvt.stageY = evt.stageY 91 | 92 | mockEvt.pureEvent = evt 93 | 94 | this._getObjectUnderPoint(evt, (obj) => { 95 | this._mouseUpX = evt.stageX 96 | this._mouseUpY = evt.stageY 97 | 98 | this.willDragObject = null 99 | this.preStageX = null 100 | this.preStageY = null 101 | 102 | if (obj && Math.abs(this._mouseDownX - this._mouseUpX) < 30 && Math.abs(this._mouseDownY - this._mouseUpY) < 30) { 103 | mockEvt.type = 'tap' 104 | obj.dispatchEvent(mockEvt) 105 | } 106 | }) 107 | } 108 | 109 | _handleMouseOut (evt) { 110 | this.dispatchEvent({ 111 | pureEvent: evt, 112 | type: 'mouseout', 113 | stageX: evt.stageX, 114 | stageY: evt.stageY 115 | }) 116 | } 117 | 118 | _getObjectUnderPoint (evt, cb) { 119 | const list = this.renderer.getHitRenderList(this) 120 | if (this.hitAABB) { 121 | return this._hitRender.hitAABB(list, evt, cb) 122 | } else { 123 | this._hitRender.clear() 124 | this._hitRender.hit(list, evt, cb, list.length - 1) 125 | } 126 | } 127 | 128 | on (type, cb) { 129 | switch (type) { 130 | case 'touchstart': 131 | this.touchStart = cb 132 | break 133 | case 'touchmove': 134 | this.touchMove = cb 135 | break 136 | case 'touchend': 137 | this.touchEnd = cb 138 | break 139 | } 140 | } 141 | 142 | update () { 143 | this.renderer.update(this) 144 | } 145 | } 146 | 147 | export default WeStage 148 | -------------------------------------------------------------------------------- /packages/cax/src/render/display/wegame-canvas.js: -------------------------------------------------------------------------------- 1 | let wegameCanvas = null 2 | if (typeof wx !== 'undefined') { 3 | // 在开放数据域的环境下,用`wx.getSharedCanvas`创建canvas 4 | if (wx.getSharedCanvas) { 5 | wegameCanvas = wx.getSharedCanvas() 6 | } else if (wx.createCanvas) { 7 | wegameCanvas = wx.createCanvas() 8 | } 9 | } 10 | 11 | export default wegameCanvas 12 | -------------------------------------------------------------------------------- /packages/cax/src/render/filter/README.md: -------------------------------------------------------------------------------- 1 | ## Interface design reference 2 | 3 | * https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/filter 4 | * http://www.runoob.com/cssref/css3-pr-filter.html 5 | * https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function 6 | 7 | ## Usage 8 | 9 | ``` js 10 | const bitmap = new cax.Bitmap(img) 11 | bitmap.filter('brightness(0.5)') 12 | 13 | //or filter rect of bitmap 14 | //bitmap.filter('brightness(0.5)'), { x: 0, y: 0, width: 80, height: 80 } 15 | ``` 16 | 17 | ## Todo 18 | 19 | horizontalFlip 和 verticalFlip 来制作镜像 spritesheet 20 | 21 | ``` js 22 | new cax.Sprite({ 23 | imgs:[bitmap.flipX()] 24 | }) 25 | 26 | //bitmap.flipX() 27 | //flipX return的就是 this.cacheCanvas 28 | //bitmap.filpY() 29 | ``` 30 | -------------------------------------------------------------------------------- /packages/cax/src/render/filter/blur.js: -------------------------------------------------------------------------------- 1 | import { createImageData } from './create-image-data' 2 | 3 | export function blur (pixels, diameter) { 4 | diameter = Math.abs(diameter) 5 | if (diameter <= 1) return pixels 6 | var radius = diameter / 2 7 | var len = Math.ceil(diameter) + (1 - (Math.ceil(diameter) % 2)) 8 | var weights = new Float32Array(len) 9 | var rho = (radius + 0.5) / 3 10 | var rhoSq = rho * rho 11 | var gaussianFactor = 1 / Math.sqrt(2 * Math.PI * rhoSq) 12 | var rhoFactor = -1 / (2 * rho * rho) 13 | var wsum = 0 14 | var middle = Math.floor(len / 2) 15 | for (var i = 0; i < len; i++) { 16 | var x = i - middle 17 | var gx = gaussianFactor * Math.exp(x * x * rhoFactor) 18 | weights[i] = gx 19 | wsum += gx 20 | } 21 | for (var i = 0; i < weights.length; i++) { 22 | weights[i] /= wsum 23 | } 24 | return separableConvolve(pixels, weights, weights, false) 25 | } 26 | 27 | function separableConvolve (pixels, horizWeights, vertWeights, opaque) { 28 | return horizontalConvolve( 29 | verticalConvolve(pixels, vertWeights, opaque), 30 | horizWeights, opaque 31 | ) 32 | } 33 | 34 | function horizontalConvolve (pixels, weightsVector, opaque) { 35 | var side = weightsVector.length 36 | var halfSide = Math.floor(side / 2) 37 | 38 | var src = pixels.data 39 | var sw = pixels.width 40 | var sh = pixels.height 41 | 42 | var w = sw 43 | var h = sh 44 | var output = createImageData(w, h) 45 | var dst = output.data 46 | 47 | var alphaFac = opaque ? 1 : 0 48 | 49 | for (var y = 0; y < h; y++) { 50 | for (var x = 0; x < w; x++) { 51 | var sy = y 52 | var sx = x 53 | var dstOff = (y * w + x) * 4 54 | var r = 0, g = 0, b = 0, a = 0 55 | for (var cx = 0; cx < side; cx++) { 56 | var scy = sy 57 | var scx = Math.min(sw - 1, Math.max(0, sx + cx - halfSide)) 58 | var srcOff = (scy * sw + scx) * 4 59 | var wt = weightsVector[cx] 60 | r += src[srcOff] * wt 61 | g += src[srcOff + 1] * wt 62 | b += src[srcOff + 2] * wt 63 | a += src[srcOff + 3] * wt 64 | } 65 | dst[dstOff] = r 66 | dst[dstOff + 1] = g 67 | dst[dstOff + 2] = b 68 | dst[dstOff + 3] = a + alphaFac * (255 - a) 69 | } 70 | } 71 | return output 72 | } 73 | 74 | function verticalConvolve (pixels, weightsVector, opaque) { 75 | var side = weightsVector.length 76 | var halfSide = Math.floor(side / 2) 77 | 78 | var src = pixels.data 79 | var sw = pixels.width 80 | var sh = pixels.height 81 | 82 | var w = sw 83 | var h = sh 84 | var output = createImageData(w, h) 85 | var dst = output.data 86 | 87 | var alphaFac = opaque ? 1 : 0 88 | 89 | for (var y = 0; y < h; y++) { 90 | for (var x = 0; x < w; x++) { 91 | var sy = y 92 | var sx = x 93 | var dstOff = (y * w + x) * 4 94 | var r = 0, g = 0, b = 0, a = 0 95 | for (var cy = 0; cy < side; cy++) { 96 | var scy = Math.min(sh - 1, Math.max(0, sy + cy - halfSide)) 97 | var scx = sx 98 | var srcOff = (scy * sw + scx) * 4 99 | var wt = weightsVector[cy] 100 | r += src[srcOff] * wt 101 | g += src[srcOff + 1] * wt 102 | b += src[srcOff + 2] * wt 103 | a += src[srcOff + 3] * wt 104 | } 105 | dst[dstOff] = r 106 | dst[dstOff + 1] = g 107 | dst[dstOff + 2] = b 108 | dst[dstOff + 3] = a + alphaFac * (255 - a) 109 | } 110 | } 111 | return output 112 | }; 113 | -------------------------------------------------------------------------------- /packages/cax/src/render/filter/brightness.js: -------------------------------------------------------------------------------- 1 | export function brightness (pixels, adjustment) { 2 | const data = pixels.data 3 | const length = data.length 4 | for (let i = 0; i < length; i += 4) { 5 | data[i] += adjustment 6 | data[i + 1] += adjustment 7 | data[i + 2] += adjustment 8 | } 9 | return pixels 10 | } 11 | -------------------------------------------------------------------------------- /packages/cax/src/render/filter/colorize.js: -------------------------------------------------------------------------------- 1 | export function colorize (pixels, option) { 2 | const data = pixels.data 3 | const length = data.length 4 | const hex = (option.color.charAt(0) === '#') ? option.color.substr(1) : option.color 5 | const colorRGB = { 6 | r: parseInt(hex.substr(0, 2), 16), 7 | g: parseInt(hex.substr(2, 2), 16), 8 | b: parseInt(hex.substr(4, 2), 16) 9 | } 10 | 11 | for (let i = 0; i < length; i += 4) { 12 | data[i] -= (data[i] - colorRGB.r) * (option.amount) 13 | data[i + 1] -= (data[i + 1] - colorRGB.g) * (option.amount) 14 | data[i + 2] -= (data[i + 2] - colorRGB.b) * (option.amount) 15 | } 16 | 17 | return pixels 18 | }; 19 | -------------------------------------------------------------------------------- /packages/cax/src/render/filter/contrast.js: -------------------------------------------------------------------------------- 1 | export function contrast (pixels, contrast) { 2 | const data = pixels.data 3 | const length = data.length 4 | const factor = (259 * (contrast + 255)) / (255 * (259 - contrast)) 5 | 6 | for (let i = 0; i < length; i += 4) { 7 | data[i] = factor * (data[i] - 128) + 128 8 | data[i + 1] = factor * (data[i + 1] - 128) + 128 9 | data[i + 2] = factor * (data[i + 2] - 128) + 128 10 | } 11 | 12 | return pixels 13 | }; 14 | -------------------------------------------------------------------------------- /packages/cax/src/render/filter/create-image-data.js: -------------------------------------------------------------------------------- 1 | let tmpCtx = null 2 | 3 | if (typeof document !== 'undefined') { 4 | tmpCtx = document.createElement('canvas').getContext('2d') 5 | } else if (typeof wx !== 'undefined' && wx.createCanvas) { 6 | tmpCtx = wx.createCanvas().getContext('2d') 7 | } 8 | 9 | export function createImageData (w, h) { 10 | return tmpCtx.createImageData(w, h) 11 | } 12 | -------------------------------------------------------------------------------- /packages/cax/src/render/filter/gamma.js: -------------------------------------------------------------------------------- 1 | export function gamma (pixels, adjustment) { 2 | const data = pixels.data 3 | const length = data.length 4 | for (let i = 0; i < length; i += 4) { 5 | data[i] = Math.pow(data[i] / 255, adjustment) * 255 6 | data[i + 1] = Math.pow(data[i + 1] / 255, adjustment) * 255 7 | data[i + 2] = Math.pow(data[i + 2] / 255, adjustment) * 255 8 | } 9 | return pixels 10 | }; 11 | -------------------------------------------------------------------------------- /packages/cax/src/render/filter/grayscale.js: -------------------------------------------------------------------------------- 1 | export function grayscale (pixels, adjustment) { 2 | const data = pixels.data 3 | const length = data.length 4 | for (let i = 0; i < length; i += 4) { 5 | let r = data[i] 6 | let g = data[i + 1] 7 | let b = data[i + 2] 8 | 9 | // CIE luminance for the RGB 10 | // The human eye is bad at seeing red and blue, so we de-emphasize them. 11 | let v = 0.2126 * r + 0.7152 * g + 0.0722 * b 12 | data[i] = r + (v - r) * adjustment 13 | data[i + 1] = g + (v - g) * adjustment 14 | data[i + 2] = b + (v - b) * adjustment 15 | } 16 | return pixels 17 | }; 18 | -------------------------------------------------------------------------------- /packages/cax/src/render/filter/index.js: -------------------------------------------------------------------------------- 1 | 2 | import { invert } from './invert' 3 | import { blur } from './blur' 4 | import { brightness } from './brightness' 5 | import { contrast } from './contrast' 6 | import { grayscale } from './grayscale' 7 | import { sepia } from './sepia' 8 | import { threshold } from './threshold' 9 | import { gamma } from './gamma' 10 | import { colorize } from './colorize' 11 | 12 | export function filter (pixels, name) { 13 | if (typeof name === 'string') { 14 | let type = name.split('(')[0] 15 | let num = getNumber(name) 16 | switch (type) { 17 | case 'invert': 18 | return invert(pixels, num) 19 | case 'brightness': 20 | return brightness(pixels, -255 + num * 255) 21 | case 'blur': 22 | return blur(pixels, num) 23 | case 'contrast': 24 | return contrast(pixels, -255 + num * 255) 25 | case 'grayscale': 26 | return grayscale(pixels, num) 27 | case 'sepia': 28 | return sepia(pixels, num) 29 | case 'threshold': 30 | return threshold(pixels, num) 31 | case 'gamma': 32 | return gamma(pixels, num) 33 | } 34 | } else { 35 | switch (name.type) { 36 | case 'colorize': 37 | return colorize(pixels, name) 38 | } 39 | } 40 | } 41 | 42 | function getNumber (str) { 43 | str = str.replace(/(invert)|(brightness)|(blur)|(contrast)|(grayscale)|(sepia)|(threshold)|(gamma)?\(/g, '').replace(')', '') 44 | if (str.indexOf('%') !== -1) { 45 | return Number(str.replace('%', '')) / 100 46 | } else if (str.indexOf('px') !== -1) { 47 | return Number(str.replace('px', '')) 48 | } else { 49 | return Number(str) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/cax/src/render/filter/invert.js: -------------------------------------------------------------------------------- 1 | 2 | export function invert (pixels, ratio) { 3 | const d = pixels.data 4 | ratio = ratio === undefined ? 1 : ratio 5 | for (var i = 0; i < d.length; i += 4) { 6 | d[i] = d[i] + ratio * (255 - 2 * d[i]) 7 | d[i + 1] = d[i + 1] + ratio * (255 - 2 * d[i + 1]) 8 | d[i + 2] = d[i + 2] + ratio * (255 - 2 * d[i + 2]) 9 | } 10 | return pixels 11 | } 12 | -------------------------------------------------------------------------------- /packages/cax/src/render/filter/sepia.js: -------------------------------------------------------------------------------- 1 | export function sepia (pixels, adjustment) { 2 | const data = pixels.data 3 | const length = data.length 4 | for (let i = 0; i < length; i += 4) { 5 | const r = data[i] 6 | const g = data[i + 1] 7 | const b = data[i + 2] 8 | 9 | const sr = (r * 0.393) + (g * 0.769) + (b * 0.189) 10 | const sg = (r * 0.349) + (g * 0.686) + (b * 0.168) 11 | const sb = (r * 0.272) + (g * 0.534) + (b * 0.131) 12 | 13 | data[i] = r + (sr - r) * adjustment 14 | data[i + 1] = g + (sg - g) * adjustment 15 | data[i + 2] = b + (sb - b) * adjustment 16 | } 17 | 18 | return pixels 19 | }; 20 | -------------------------------------------------------------------------------- /packages/cax/src/render/filter/threshold.js: -------------------------------------------------------------------------------- 1 | export function threshold (pixels, threshold) { 2 | const data = pixels.data 3 | const length = data.length 4 | for (let i = 0; i < length; i += 4) { 5 | const r = data[i] 6 | const g = data[i + 1] 7 | const b = data[i + 2] 8 | const v = (0.2126 * r + 0.7152 * g + 0.0722 * b >= threshold) ? 255 : 0 9 | data[i] = data[i + 1] = data[i + 2] = v 10 | } 11 | return pixels 12 | }; 13 | -------------------------------------------------------------------------------- /packages/cax/src/render/render/render.js: -------------------------------------------------------------------------------- 1 | class Render { 2 | render () { 3 | 4 | } 5 | 6 | renderGraphics () { 7 | 8 | } 9 | 10 | clear () { 11 | 12 | } 13 | } 14 | 15 | export default Render 16 | -------------------------------------------------------------------------------- /packages/cax/src/render/render/renderer.js: -------------------------------------------------------------------------------- 1 | import CanvasRender from '../render/canvas-render' 2 | import Group from '../display/group.js' 3 | 4 | class Renderer { 5 | constructor (canvasOrContext, width, height) { 6 | this.renderList = [] 7 | if (arguments.length === 3) { 8 | this.renderer = new CanvasRender(canvasOrContext, width, height) 9 | this.width = width 10 | this.height = height 11 | } else { 12 | this.renderer = new CanvasRender(canvasOrContext) 13 | this.width = canvasOrContext.width 14 | this.height = canvasOrContext.height 15 | } 16 | this.ctx = this.renderer.ctx 17 | } 18 | 19 | update (stage) { 20 | this.renderer.clear(this.ctx, this.width, this.height) 21 | this.renderer.render(this.ctx, stage) 22 | this.ctx.draw && this.ctx.draw() 23 | } 24 | 25 | getHitRenderList (stage) { 26 | const objs = this.renderList 27 | objs.length = 0 28 | this.computeMatrix(stage) 29 | return objs 30 | } 31 | 32 | computeMatrix (stage) { 33 | for (var i = 0, len = stage.children.length; i < len; i++) { 34 | this._computeMatrix(stage.children[i]) 35 | } 36 | } 37 | 38 | initComplex (o) { 39 | o.complexCompositeOperation = this._getCompositeOperation(o) 40 | o.complexAlpha = this._getAlpha(o, 1) 41 | } 42 | 43 | _computeMatrix (o, mtx) { 44 | if (!o.isVisible()) { 45 | return 46 | } 47 | if (mtx && !o.fixed) { 48 | o._matrix.initialize(mtx.a, mtx.b, mtx.c, mtx.d, mtx.tx, mtx.ty) 49 | } else { 50 | o._matrix.initialize(1, 0, 0, 1, 0, 0) 51 | } 52 | 53 | o._matrix.appendTransform(o.x, o.y, o.scaleX, o.scaleY, o.rotation, o.skewX, o.skewY, o.originX, o.originY) 54 | 55 | if (o instanceof Group) { 56 | var list = o.children, 57 | len = list.length, 58 | i = 0 59 | for (; i < len; i++) { 60 | this._computeMatrix(list[i], o._matrix) 61 | } 62 | } else { 63 | // if (o instanceof Graphics) { 64 | // this.renderList.push(o) 65 | // this.initComplex(o) 66 | // } else { 67 | o.initAABB() 68 | // if (this.isInStage(o)) { 69 | this.renderList.push(o) 70 | this.initComplex(o) 71 | // } 72 | // } 73 | } 74 | } 75 | 76 | _getCompositeOperation (o) { 77 | if (o.compositeOperation) return o.compositeOperation 78 | if (o.parent) return this._getCompositeOperation(o.parent) 79 | } 80 | 81 | _getAlpha (o, alpha) { 82 | var result = o.alpha * alpha 83 | if (o.parent) { 84 | return this._getAlpha(o.parent, result) 85 | } 86 | return result 87 | } 88 | 89 | isInStage (o) { 90 | return this.collisionBetweenAABB(o.AABB, this.stage.AABB) 91 | } 92 | 93 | collisionBetweenAABB (AABB1, AABB2) { 94 | var maxX = AABB1[0] + AABB1[2] 95 | if (maxX < AABB2[0]) return false 96 | var minX = AABB1[0] 97 | if (minX > AABB2[0] + AABB2[2]) return false 98 | var maxY = AABB1[1] + AABB1[3] 99 | if (maxY < AABB2[1]) return false 100 | var minY = AABB1[1] 101 | if (minY > AABB2[1] + AABB2[3]) return false 102 | return true 103 | } 104 | } 105 | 106 | export default Renderer 107 | -------------------------------------------------------------------------------- /packages/cax/src/render/render/wx-hit-render.js: -------------------------------------------------------------------------------- 1 | 2 | import Graphics from '../display/graphics.js' 3 | import Render from './render.js' 4 | import Event from '../base/event.js' 5 | import Sprite from '../display/sprite.js' 6 | import Bitmap from '../display/bitmap.js' 7 | import Text from '../display/text.js' 8 | 9 | class WxHitRender extends Render { 10 | constructor (ctx, component, canvasId) { 11 | super() 12 | 13 | this.ctx = ctx 14 | this._isWeapp = true 15 | this._component = component 16 | this._hitCanvasId = canvasId + 'Hit' 17 | 18 | this.disableEvents = ['mouseover', 'mouseout', 'mousemove', 'touchmove'] 19 | } 20 | 21 | clear () { 22 | this.ctx.clearRect(0, 0, 2, 2) 23 | } 24 | 25 | hitAABB (list, evt, cb) { 26 | const len = list.length 27 | for (let i = len - 1; i >= 0; i--) { 28 | let o = list[i] 29 | 30 | if (o.AABB && this.checkPointInAABB(evt.stageX, evt.stageY, o.AABB)) { 31 | this._dispatchEvent(o, evt) 32 | cb(o) 33 | return o 34 | } 35 | } 36 | } 37 | 38 | checkPointInAABB (x, y, AABB) { 39 | let minX = AABB[0] 40 | if (x < minX) return false 41 | let minY = AABB[1] 42 | if (y < minY) return false 43 | let maxX = minX + AABB[2] 44 | if (x > maxX) return false 45 | let maxY = minY + AABB[3] 46 | if (y > maxY) return false 47 | return true 48 | } 49 | 50 | hit (list, evt, cb, current) { 51 | const ctx = this.ctx 52 | const obj = list[current] 53 | const mtx = obj._hitMatrix.initialize(1, 0, 0, 1, 0, 0) 54 | ctx.save() 55 | mtx.appendTransform(obj.x - evt.stageX, obj.y - evt.stageY, obj.scaleX, obj.scaleY, obj.rotation, obj.skewX, obj.skewY, obj.originX, obj.originY) 56 | ctx.globalCompositeOperation = obj.complexCompositeOperation 57 | ctx.globalAlpha = obj.complexAlpha 58 | ctx.setTransform(mtx.a, mtx.b, mtx.c, mtx.d, mtx.tx, mtx.ty) 59 | if (obj instanceof Graphics) { 60 | obj.render(ctx) 61 | } else if (obj instanceof Sprite && obj.rect) { 62 | obj.updateFrame() 63 | const rect = obj.rect 64 | ctx.drawImage(obj.img, rect[0], rect[1], rect[2], rect[3], 0, 0, rect[2], rect[3]) 65 | } else if (obj instanceof Bitmap && obj.rect) { 66 | const bRect = obj.rect 67 | ctx.drawImage(obj.img, bRect[0], bRect[1], bRect[2], bRect[3], 0, 0, bRect[2], bRect[3]) 68 | } else if (obj instanceof Text) { 69 | ctx.font = obj.font 70 | ctx.fillStyle = obj.color 71 | ctx.textAlign = obj.textAlign 72 | ctx.fillText(obj.text, 0, 0) 73 | } 74 | ctx.restore() 75 | current-- 76 | ctx.draw(false, () => { 77 | wx.canvasGetImageData({ 78 | canvasId: this._hitCanvasId, 79 | x: 0, 80 | y: 0, 81 | width: 1, 82 | height: 1, 83 | success: (res) => { 84 | if (res.data[3] > 1) { 85 | this._dispatchEvent(obj, evt) 86 | cb(obj) 87 | } else { 88 | if (current > -1) { this.hit(list, evt, cb, current) } 89 | } 90 | } 91 | }, this._component) 92 | }) 93 | } 94 | 95 | _dispatchEvent (obj, evt) { 96 | if (this.disableEvents.indexOf(evt.type) !== -1) return 97 | let mockEvt = new Event() 98 | mockEvt.stageX = evt.stageX 99 | mockEvt.stageY = evt.stageY 100 | mockEvt.pureEvent = evt 101 | mockEvt.type = evt.type 102 | obj.dispatchEvent(mockEvt) 103 | } 104 | } 105 | 106 | export default WxHitRender 107 | -------------------------------------------------------------------------------- /packages/cax/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var packageJSON = require('./package.json'); 4 | /** 5 | * Env 6 | * Get npm lifecycle event to identify the environment 7 | */ 8 | var ENV = process.env.npm_lifecycle_event; 9 | 10 | var config = { 11 | entry: './examples/todo/main.js', 12 | output: { 13 | // path: __dirname, 14 | path: './examples/todo/', 15 | filename: 'bundler.js' 16 | }, 17 | module: { 18 | loaders: [ 19 | { 20 | loader: 'babel-loader', 21 | test: /\.js$/, 22 | query: { 23 | presets: 'env', 24 | "plugins": [ 25 | "transform-class-properties", 26 | ["transform-react-jsx", { 27 | "pragma": "Cax.h" 28 | }] 29 | ] 30 | }, 31 | 32 | } 33 | ] 34 | }, 35 | plugins: [ 36 | // Avoid publishing files when compilation fails 37 | new webpack.NoEmitOnErrorsPlugin() 38 | ], 39 | stats: { 40 | // Nice colored output 41 | colors: true 42 | }, 43 | // Create Sourcemaps for the bundle 44 | // devtool: 'source-map', 45 | }; 46 | 47 | if (ENV === 'build' || ENV === 'build-min') { 48 | config = { 49 | entry: { 50 | 'cax': './src/index.js' 51 | }, 52 | output: { 53 | // path: __dirname, 54 | path: path.resolve(__dirname, './dist/'), 55 | library: 'cax', 56 | libraryTarget: 'umd', 57 | filename: '[name].js' 58 | //umdNamedDefine: true 59 | }, 60 | module: { 61 | loaders: [ 62 | { 63 | loader: 'babel-loader', 64 | test: path.join(__dirname, 'src'), 65 | query: { 66 | presets: 'env' 67 | }, 68 | } 69 | ] 70 | }, 71 | plugins: [ 72 | // Avoid publishing files when compilation fails 73 | new webpack.BannerPlugin(" cax v" + packageJSON.version + "\r\n By https://github.com/dntzhang \r\n Github: https://github.com/dntzhang/cax\r\n MIT Licensed."), 74 | new webpack.NoEmitOnErrorsPlugin() 75 | ], 76 | stats: { 77 | // Nice colored output 78 | colors: true 79 | }, 80 | // Create Sourcemaps for the bundle 81 | // devtool: 'source-map', 82 | }; 83 | 84 | if (ENV === 'build-min') { 85 | config.plugins.push(new webpack.optimize.UglifyJsPlugin({ 86 | compress: { 87 | warnings: false, 88 | screw_ie8: false 89 | }, 90 | mangle: { 91 | screw_ie8: false 92 | }, 93 | output: { screw_ie8: false } 94 | })); 95 | config.entry = { 96 | 'cax.min': './src/index.js' 97 | }; 98 | } 99 | } else if (ENV === 'todomvc') { 100 | config.entry = './' + ENV + '/js/main.js'; 101 | config.output.path = './' + ENV + '/'; 102 | } else { 103 | config.entry = path.resolve(__dirname, './examples/' + ENV + '/main.js'); 104 | config.output.path = path.resolve(__dirname, './examples/' + ENV + '/'); 105 | } 106 | 107 | 108 | //console.log(ENV); 109 | 110 | module.exports = config; 111 | -------------------------------------------------------------------------------- /packages/to/README.EN.md: -------------------------------------------------------------------------------- 1 | English | [简体中文](./README.md) 2 | 3 | # to2to [![](https://img.shields.io/npm/v/to2to.svg)](https://www.npmjs.com/package/to2to) 4 | 5 | > Simple and lightweight javascript animation engine 6 | 7 | * [Simple DEMO](http://dntzhang.github.io/cax/packages/to/examples/simple/) 8 | * [Animation DEMO](https://dntzhang.github.io/cax/packages/to/examples/to/) 9 | * [To + Shape](https://dntzhang.github.io/cax/packages/cax/examples/to-shape/) 10 | * [Animate DEMO](https://dntzhang.github.io/cax/packages/cax/examples/to-animate/) 11 | * [Swing DEMO](https://dntzhang.github.io/cax/packages/to/examples/swing/) 12 | 13 | ## Features 14 | 15 | * Simple API and lightweight 16 | * Support cycle movement 17 | * Support parallel and serial motion 18 | * Can be used in all environments (Canvas, DOM, WebGL, SVG, Object..) 19 | * Support weapp, wegame and browsers with the same simple API 20 | 21 | ## Getting Started 22 | 23 | Get to2to through npm or cdn: 24 | 25 | ``` bash 26 | npm i to2to 27 | ``` 28 | 29 | * [https://unpkg.com/to2to@latest/dist/to.min.js](https://unpkg.com/to2to@latest/dist/to.min.js) 30 | * [https://unpkg.com/to2to@latest/dist/to.js](https://unpkg.com/to2to@latest/dist/to.js) 31 | 32 | Usage: 33 | 34 | ``` js 35 | import To from 'to2to' 36 | 37 | const ele = document.querySelector('#animateEle') 38 | 39 | To.get({ rotate: 0, x: 0, y: 0 }) 40 | .to({ rotate: 720, x: 200, y: 200 }, 1600, To.easing.elasticInOut) 41 | .progress(function () { 42 | ele.style.transform = `translate(${this.x}px, ${this.y}px) rotate(${this.rotate}deg)` 43 | }) 44 | .start() 45 | ``` 46 | 47 | ## Using to2to in cax 48 | 49 | Cax has built-in to capability to write motion effects in a continuous way. 50 | 51 | ``` js 52 | const easing = cax.To.easing.elasticInOut 53 | 54 | cax.To.get(bitmap) 55 | .to({ y: 340, rotation: 240 }, 2000, easing) 56 | .begin(() => { 57 | console.log("Task one has began!") 58 | }) 59 | .progress(() => { 60 | console.log("Task one is progressing!") 61 | }) 62 | .end(() => { 63 | console.log("Task one has completed!") 64 | }) 65 | .wait(500) 66 | .to() 67 | .rotation(0, 1400, easing) 68 | .begin(() => { 69 | console.log("Task two has began!") 70 | }) 71 | .progress(() => { 72 | console.log("Task two is progressing!") 73 | }) 74 | .end(() => { 75 | console.log("Task two has completed!") 76 | }) 77 | .start(); 78 | ``` 79 | 80 | * `to` and `to` are parallel 81 | * `to` and `wait` are serial 82 | * The serial between `to` and `to` is serial with the next `to` and `to` 83 | 84 | Of course, `set` can also be used to support the movement of arbitrary attributes, such as: 85 | 86 | ``` js 87 | .set('y', 240, 2000, cax.easing.elasticInOut) 88 | ``` 89 | 90 | Equate to: 91 | 92 | ``` js 93 | .y(240, 2000, cax.easing.elasticInOut) 94 | ``` 95 | 96 | If you want circular motion, you can use the `cycle` method: 97 | 98 | ``` js 99 | cax.To.get(bitmap) 100 | .to() 101 | .y(340, 2000, cax.easing.elasticInOut) 102 | .to 103 | .y(0, 2000, cax.easing.elasticInOut) 104 | .cycle() 105 | .start() 106 | ``` 107 | 108 | [Motion Demo](http://dntzhang.github.io/cax/packages/cax/examples/to/) 109 | 110 | 111 | ## Custom animation 112 | 113 | You can use custom animation through the `animate` method: 114 | 115 | ``` js 116 | const stage = new cax.Stage(300, 400, 'body') 117 | const bitmap = new cax.Bitmap('./wepay-diy.jpg', function () { 118 | var eio = To.easing.elasticInOut 119 | To.get(bitmap).animate('rubber').start() 120 | }) 121 | 122 | bitmap.x = 150 123 | bitmap.y = 200 124 | bitmap.originX = 40 125 | bitmap.originY = 40 126 | stage.add(bitmap) 127 | 128 | cax.setInterval(() => { 129 | stage.update() 130 | }, 16) 131 | ``` 132 | 133 | to2to has a few custom animations built in: 134 | 135 | * rubber 136 | * bounceIn 137 | * flipInX 138 | * zoomOut 139 | 140 | ## Extend custom animation 141 | 142 | Built in is not enough to use? do-it-yourselfery! 143 | 144 | For example, `customAnimation` is implemented through the following: 145 | 146 | ``` js 147 | To.extend('customAnimation', [['to', ['scaleX', { 148 | '0': 0, 149 | '1': 400, 150 | '2': To.easing.elasticInOut 151 | }], ['scaleY', { 152 | '0': 0, 153 | '1': 400 154 | }]]]) 155 | ``` 156 | 157 | An index of 2 easing can be transmitted or transmitted without representing a linear uniform change. 158 | 159 | Using the defined custom animation: 160 | 161 | ```js 162 | To.get(obj).animate('customAnimation').start() 163 | ``` 164 | 165 | # Who is using cax? 166 | 167 | ![Tencent Wechat](../../asset/wx.png) ![Tencent QQ](../../asset/qq.png) 168 | 169 | ## License 170 | 171 | MIT 172 | -------------------------------------------------------------------------------- /packages/to/README.md: -------------------------------------------------------------------------------- 1 | 简体中文 | [English](./README.EN.md) 2 | 3 | # to2to [![](https://img.shields.io/npm/v/to2to.svg)](https://www.npmjs.com/package/to2to) 4 | 5 | > 简单轻量的 Javascript 运动引擎 6 | 7 | * [Simple DEMO](http://dntzhang.github.io/cax/packages/to/examples/simple/) 8 | * [Animation DEMO](https://dntzhang.github.io/cax/packages/to/examples/to/) 9 | * [To + Shape](https://dntzhang.github.io/cax/packages/cax/examples/to-shape/) 10 | * [Animate DEMO](https://dntzhang.github.io/cax/packages/cax/examples/to-animate/) 11 | * [Swing DEMO](https://dntzhang.github.io/cax/packages/to/examples/swing/) 12 | 13 | to2to 中文念 '兔兔兔',作为 cax 内置的运动套件独立出一个package ,因为它本身可以和平台环境运动对象无关。既可运动 dom,也可运动 cax 内置对象,也可运动对象字面量。众所周知,运动需要循环的 tick 去不断执行偏移函数,小程序,小游戏和web各浏览器的 相应的 API 还是有差异,to2to 抹平了这些差异,让你使用同样的api可以在不同环境畅快运动。 14 | 15 | ## 特性 16 | 17 | * 超轻量级的代码体积 18 | * 支持周期运动 19 | * 支持并行与串行运动 20 | * 运动一切(Canvas、DOM、WebGL、SVG、Object..) 21 | * 支持小程序、小游戏以及 Web 浏览器用相同简介的 API 运动 22 | 23 | ## 一分钟入门 to2to 使用 24 | 25 | 通过 npm 安装或者 cdn 下载下来在 HTML 引用该脚本: 26 | 27 | ``` bash 28 | npm i to2to 29 | ``` 30 | 31 | * [https://unpkg.com/to2to@latest/dist/to.min.js](https://unpkg.com/to2to@latest/dist/to.min.js) 32 | * [https://unpkg.com/to2to@latest/dist/to.js](https://unpkg.com/to2to@latest/dist/to.js) 33 | 34 | 使用: 35 | 36 | ``` js 37 | import To from 'to2to' 38 | 39 | const ele = document.querySelector('#animateEle') 40 | 41 | To.get({ rotate: 0, x: 0, y: 0 }) 42 | .to({ rotate: 720, x: 200, y: 200 }, 1600, To.easing.elasticInOut) 43 | .progress(function () { 44 | ele.style.transform = `translate(${this.x}px, ${this.y}px) rotate(${this.rotate}deg)` 45 | }) 46 | .start() 47 | ``` 48 | 49 | ## 在 cax 中使用 to2to 50 | 51 | cax 内置了 to 的能力以连缀的方式写运动效果: 52 | 53 | ``` js 54 | const easing = cax.To.easing.elasticInOut 55 | 56 | cax.To.get(bitmap) 57 | .to({ y: 340, rotation: 240 }, 2000, easing) 58 | .begin(() => { 59 | console.log("Task one has began!") 60 | }) 61 | .progress(() => { 62 | console.log("Task one is progressing!") 63 | }) 64 | .end(() => { 65 | console.log("Task one has completed!") 66 | }) 67 | .wait(500) 68 | .to() 69 | .rotation(0, 1400, easing) 70 | .begin(() => { 71 | console.log("Task two has began!") 72 | }) 73 | .progress(() => { 74 | console.log("Task two is progressing!") 75 | }) 76 | .end(() => { 77 | console.log("Task two has completed!") 78 | }) 79 | .start(); 80 | ``` 81 | 82 | * `to` 和 `to` 之间的是并行 83 | * `to` 和 `wait` 之前的是串行 84 | * `to` 和 `to` 之间的 与 下一个 `to` 和 `to` 之间的是串行 85 | 86 | 有点绕,但是很直观,慢慢体会。 87 | 88 | 如果想要循环播放的话可以使用 `cycle` 方法: 89 | 90 | ``` js 91 | cax.To.get(bitmap) 92 | .to() 93 | .y(340, 2000, cax.easing.elasticInOut) 94 | .to 95 | .y(0, 2000, cax.easing.elasticInOut) 96 | .cycle() 97 | .start() 98 | ``` 99 | 100 | [运动演示地址](http://dntzhang.github.io/cax/packages/cax/examples/to/) 101 | 102 | ## 自定义动画 103 | 104 | 通过 `animate` 方法可以使用自定义的动画: 105 | 106 | ``` js 107 | const stage = new cax.Stage(300, 400, 'body') 108 | const bitmap = new cax.Bitmap('./wepay-diy.jpg', function () { 109 | var eio = To.easing.elasticInOut 110 | To.get(bitmap).animate('rubber').start() 111 | }) 112 | 113 | bitmap.x = 150 114 | bitmap.y = 200 115 | bitmap.originX = 40 116 | bitmap.originY = 40 117 | stage.add(bitmap) 118 | 119 | cax.setInterval(() => { 120 | stage.update() 121 | }, 16) 122 | ``` 123 | 124 | to2to 内置了少数几个自定义动画 125 | 126 | * rubber 127 | * bounceIn 128 | * flipInX 129 | * zoomOut 130 | 131 | ## 扩展自定义动画 132 | 133 | 内置的不够用?自己动手丰衣足食: 134 | 135 | 比如 `customAnimation` 就是通过下面实现的: 136 | 137 | ``` js 138 | To.extend('customAnimation', [['to', ['scaleX', { 139 | '0': 0, 140 | '1': 400, 141 | '2': To.easing.elasticInOut 142 | }], ['scaleY', { 143 | '0': 0, 144 | '1': 400 145 | }]]]) 146 | ``` 147 | 148 | 索引为 2 的 easing 可以传可不传,不传代表线性匀速变化。 149 | 150 | 使用刚刚定义的自定义动画: 151 | 152 | ```js 153 | To.get(obj).animate('customAnimation').start() 154 | ``` 155 | 156 | ## 谁在使用? 157 | 158 | ![Tencent Wechat](../../asset/wx.png) ![Tencent QQ](../../asset/qq.png) 159 | 160 | ## License 161 | 162 | MIT 163 | -------------------------------------------------------------------------------- /packages/to/examples/animate/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Cax Motion Demo 8 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /packages/to/examples/animate/wepay-diy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/to/examples/animate/wepay-diy.jpg -------------------------------------------------------------------------------- /packages/to/examples/simple/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | To Simple Demo 7 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /packages/to/examples/simple/main.js: -------------------------------------------------------------------------------- 1 | import To from '../../src/index.js' 2 | 3 | const ele = document.querySelector('#animateEle') 4 | 5 | ele.onload = function(){ 6 | 7 | To.get({ rotate: 0, x: 0, y: 0 }) 8 | .to({ rotate: 720, x: 200, y: 200 }, 1600, To.easing.elasticInOut) 9 | .progress(function () { 10 | ele.style.transform = `translate(${this.x}px, ${this.y}px) rotate(${this.rotate}deg)` 11 | }) 12 | .start() 13 | } 14 | 15 | ele.src = ele.src -------------------------------------------------------------------------------- /packages/to/examples/simple/wepay-diy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/to/examples/simple/wepay-diy.jpg -------------------------------------------------------------------------------- /packages/to/examples/swing/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Cax Motion Demo 8 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /packages/to/examples/swing/wepay-diy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/to/examples/swing/wepay-diy.jpg -------------------------------------------------------------------------------- /packages/to/examples/to/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Cax Motion Demo 8 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /packages/to/examples/to/wepay-diy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dntzhang/cax/f52df2b6822447b6c35d2efb6a50c1b6a86b1e54/packages/to/examples/to/wepay-diy.jpg -------------------------------------------------------------------------------- /packages/to/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "to2to", 3 | "version": "1.0.4", 4 | "description": "Simple and lightweight javascript animation engine - 小程序、小游戏和 Web 通用运动引擎", 5 | "main": "dist/to.js", 6 | "scripts": { 7 | "lint": "eslint src", 8 | "fix": "eslint src --fix", 9 | "fixwegame": "eslint ../cax-wegame --fix", 10 | "fixweapp": "eslint ../cax-weapp --fix", 11 | "lint:example": "eslint example --fix", 12 | "nest": "webpack -w", 13 | "clip": "webpack -w", 14 | "clip-transform": "webpack -w", 15 | "map": "webpack -w", 16 | "dag": "webpack -w", 17 | "clip-transform-to": "webpack -w", 18 | "cache": "webpack -w", 19 | "bar-x": "webpack -w", 20 | "bar": "webpack -w", 21 | "to": "webpack -w", 22 | "rect": "webpack -w", 23 | "radar": "webpack -w", 24 | "line": "webpack -w", 25 | "lines": "webpack -w", 26 | "circle": "webpack -w", 27 | "doughnut": "webpack -w", 28 | "cylinder": "webpack -w", 29 | "simple": "webpack -w", 30 | "scoped-style": "webpack -w", 31 | "on": "webpack -w", 32 | "render-to-string": "webpack -w", 33 | "newly-added": "webpack -w", 34 | "undo": "webpack -w", 35 | "slot": "webpack -w", 36 | "plugin": "webpack -w", 37 | "todo": "webpack -w", 38 | "ref": "webpack -w", 39 | "tree": "webpack -w", 40 | "perfs": "webpack -w", 41 | "life-cycle": "webpack -w", 42 | "pagination": "webpack -w", 43 | "build": "webpack", 44 | "hyperscript": "webpack -w", 45 | "select": "webpack -w", 46 | "build-min": "webpack", 47 | "test": "karma start test/karma.conf.js" 48 | }, 49 | "devDependencies": { 50 | "eslint": "^4.3.0", 51 | "eslint-config-standard": "^10.2.1", 52 | "eslint-plugin-import": "^2.7.0", 53 | "eslint-plugin-node": "^5.1.1", 54 | "eslint-plugin-promise": "^3.5.0", 55 | "eslint-plugin-standard": "^3.0.1", 56 | "babel-core": "^6.26.0", 57 | "babel-loader": "^7.1.4", 58 | "babel-plugin-transform-class-properties": "^6.24.1", 59 | "babel-plugin-transform-react-jsx": "^6.24.1", 60 | "babel-preset-env": "^1.6.1", 61 | "chai": "^4.1.2", 62 | "jasmine-core": "^2.5.2", 63 | "karma": "^1.3.0", 64 | "karma-babel-preprocessor": "^7.0.0", 65 | "karma-chai-sinon": "^0.1.5", 66 | "karma-chrome-launcher": "^2.0.0", 67 | "karma-coverage": "^1.0.0", 68 | "karma-jasmine": "^1.1.0", 69 | "karma-mocha": "^1.1.1", 70 | "karma-mocha-reporter": "^2.0.4", 71 | "karma-sauce-launcher": "^1.1.0", 72 | "karma-sinon": "^1.0.5", 73 | "karma-source-map-support": "^1.2.0", 74 | "karma-sourcemap-loader": "^0.3.6", 75 | "karma-webpack": "^2.0.4", 76 | "mocha": "^5.0.4", 77 | "node-libs-browser": "^0.5.3", 78 | "sinon": "^4.5.0", 79 | "sinon-chai": "^3.0.0", 80 | "webpack": "^3.4.1" 81 | }, 82 | "repository": { 83 | "type": "git", 84 | "url": "git+https://github.com/dntzhang/cax.git" 85 | }, 86 | "keywords": [ 87 | "canvas", 88 | "web", 89 | "weapp" 90 | ], 91 | "devEngines": { 92 | "node": "6.x || 7.x || 8.x", 93 | "npm": "3.x || 4.x || 5.x" 94 | }, 95 | "author": "dntzhang", 96 | "license": "MIT", 97 | "bugs": { 98 | "url": "https://github.com/dntzhang/cax/issues/new" 99 | }, 100 | "homepage": "http://dntzhang.github.io/cax" 101 | } 102 | -------------------------------------------------------------------------------- /packages/to/src/animate.js: -------------------------------------------------------------------------------- 1 | import To from './to' 2 | 3 | To.extend('rubber', [['to', ['scaleX', { 4 | '0': 1.25, 5 | '1': 300 6 | }], ['scaleY', { 7 | '0': 0.75, 8 | '1': 300 9 | }]], ['to', ['scaleX', { 10 | '0': 0.75, 11 | '1': 100 12 | }], ['scaleY', { 13 | '0': 1.25, 14 | '1': 100 15 | }]], ['to', ['scaleX', { 16 | '0': 1.15, 17 | '1': 100 18 | }], ['scaleY', { 19 | '0': 0.85, 20 | '1': 100 21 | }]], ['to', ['scaleX', { 22 | '0': 0.95, 23 | '1': 150 24 | }], ['scaleY', { 25 | '0': 1.05, 26 | '1': 150 27 | }]], ['to', ['scaleX', { 28 | '0': 1.05, 29 | '1': 100 30 | }], ['scaleY', { 31 | '0': 0.95, 32 | '1': 100 33 | }]], ['to', ['scaleX', { 34 | '0': 1, 35 | '1': 250 36 | }], ['scaleY', { 37 | '0': 1, 38 | '1': 250 39 | }]]]) 40 | 41 | 42 | To.extend('bounceIn', [['to', ['scaleX', { 43 | '0': 0, 44 | '1': 0 45 | }], ['scaleY', { 46 | '0': 0, 47 | '1': 0 48 | }]], ['to', ['scaleX', { 49 | '0': 1.35, 50 | '1': 200 51 | }], ['scaleY', { 52 | '0': 1.35, 53 | '1': 200 54 | }]], ['to', ['scaleX', { 55 | '0': 0.9, 56 | '1': 100 57 | }], ['scaleY', { 58 | '0': 0.9, 59 | '1': 100 60 | }]], ['to', ['scaleX', { 61 | '0': 1.1, 62 | '1': 100 63 | }], ['scaleY', { 64 | '0': 1.1, 65 | '1': 100 66 | }]], ['to', ['scaleX', { 67 | '0': 0.95, 68 | '1': 100 69 | }], ['scaleY', { 70 | '0': 0.95, 71 | '1': 100 72 | }]], ['to', ['scaleX', { 73 | '0': 1, 74 | '1': 100 75 | }], ['scaleY', { 76 | '0': 1, 77 | '1': 100 78 | }]]]) 79 | 80 | To.extend('flipInX', [['to', ['rotateX', { 81 | '0': -90, 82 | '1': 0 83 | }]], ['to', ['rotateX', { 84 | '0': 20, 85 | '1': 300 86 | }]], ['to', ['rotateX', { 87 | '0': -20, 88 | '1': 300 89 | }]], ['to', ['rotateX', { 90 | '0': 10, 91 | '1': 300 92 | }]], ['to', ['rotateX', { 93 | '0': -5, 94 | '1': 300 95 | }]], ['to', ['rotateX', { 96 | '0': 0, 97 | '1': 300 98 | }]]]) 99 | 100 | 101 | To.extend('zoomOut', [['to', ['scaleX', { 102 | '0': 0, 103 | '1': 400 104 | }], ['scaleY', { 105 | '0': 0, 106 | '1': 400 107 | }]]]) -------------------------------------------------------------------------------- /packages/to/src/index.js: -------------------------------------------------------------------------------- 1 | import To from './to' 2 | import './animate' 3 | import TWEEN from './tween' 4 | 5 | To.easing = { 6 | linear: TWEEN.Easing.Linear.None 7 | }; 8 | 9 | ['Quadratic', 10 | 'Cubic', 11 | 'Quartic', 12 | 'Quintic', 13 | 'Sinusoidal', 14 | 'Exponential', 15 | 'Circular', 16 | 'Elastic', 17 | 'Back', 18 | 'Bounce'].forEach(item => { 19 | const itemLower = item.toLowerCase() 20 | To.easing[itemLower + 'In'] = TWEEN.Easing[item].In 21 | To.easing[itemLower + 'Out'] = TWEEN.Easing[item].Out 22 | To.easing[itemLower + 'InOut'] = TWEEN.Easing[item].InOut 23 | }) 24 | 25 | 26 | module.exports = To -------------------------------------------------------------------------------- /packages/to/src/raf-interval.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * raf-interval v0.3.0 By dntzhang 3 | * Github: https://github.com/dntzhang/raf-interval 4 | * MIT Licensed. 5 | */ 6 | 7 | if (!Date.now) { 8 | Date.now = function now () { 9 | return new Date().getTime() 10 | } 11 | } 12 | 13 | let queue = [], 14 | id = -1, 15 | ticking = false, 16 | tickId = null, 17 | now = Date.now, 18 | lastTime = 0, 19 | vendors = ['ms', 'moz', 'webkit', 'o'], 20 | x = 0, 21 | isWeapp = typeof wx !== 'undefined' && typeof Page !== 'undefined', 22 | isWegame = typeof wx !== 'undefined' && typeof Page === 'undefined', 23 | isBrowser = typeof window !== 'undefined' 24 | 25 | let raf = isBrowser ? window.requestAnimationFrame : null 26 | let caf = isBrowser ? window.cancelAnimationFrame : null 27 | 28 | function mockRaf (callback, element) { 29 | let currTime = now() 30 | let timeToCall = Math.max(0, 16 - (currTime - lastTime)) 31 | let id = setTimeout(function () { 32 | callback(currTime + timeToCall) 33 | }, timeToCall) 34 | lastTime = currTime + timeToCall 35 | return id 36 | } 37 | 38 | function mockCaf (id) { 39 | clearTimeout(id) 40 | } 41 | 42 | if (isBrowser) { 43 | window.setRafInterval = setRafInterval 44 | window.clearRafInterval = clearRafInterval 45 | 46 | for (; x < vendors.length && !window.requestAnimationFrame; ++x) { 47 | window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'] 48 | window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || 49 | window[vendors[x] + 'CancelRequestAnimationFrame'] 50 | } 51 | 52 | if (!raf) { 53 | raf = mockRaf 54 | caf = mockCaf 55 | window.requestAnimationFrame = raf 56 | window.cancelAnimationFrame = caf 57 | } 58 | } else if (isWeapp) { 59 | raf = mockRaf 60 | caf = mockCaf 61 | } else if (isWegame) { 62 | raf = requestAnimationFrame 63 | caf = cancelAnimationFrame 64 | } 65 | 66 | export function setRafInterval (fn, interval) { 67 | id++ 68 | queue.push({ id: id, fn: fn, interval: interval, lastTime: now() }) 69 | if (!ticking) { 70 | let tick = function () { 71 | tickId = raf(tick) 72 | each(queue, function (item) { 73 | if (item.interval < 17 || now() - item.lastTime >= item.interval) { 74 | item.fn() 75 | item.lastTime = now() 76 | } 77 | }) 78 | } 79 | ticking = true 80 | tick() 81 | } 82 | return id 83 | } 84 | 85 | export function clearRafInterval (id) { 86 | let i = 0, 87 | len = queue.length 88 | 89 | for (; i < len; i++) { 90 | if (id === queue[i].id) { 91 | queue.splice(i, 1) 92 | break 93 | } 94 | } 95 | 96 | if (queue.length === 0) { 97 | caf(tickId) 98 | ticking = false 99 | } 100 | } 101 | 102 | function each (arr, fn) { 103 | if (Array.prototype.forEach) { 104 | arr.forEach(fn) 105 | } else { 106 | let i = 0, 107 | len = arr.length 108 | for (; i < len; i++) { 109 | fn(arr[i], i) 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /packages/to/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var packageJSON = require('./package.json'); 4 | /** 5 | * Env 6 | * Get npm lifecycle event to identify the environment 7 | */ 8 | var ENV = process.env.npm_lifecycle_event; 9 | 10 | var config = { 11 | entry: '', 12 | output: { 13 | // path: __dirname, 14 | path: '', 15 | filename: 'bundler.js' 16 | }, 17 | module: { 18 | loaders: [ 19 | { 20 | loader: 'babel-loader', 21 | test: /\.js$/, 22 | query: { 23 | presets: 'env', 24 | "plugins": [ 25 | "transform-class-properties" 26 | ] 27 | }, 28 | 29 | } 30 | ] 31 | }, 32 | plugins: [ 33 | // Avoid publishing files when compilation fails 34 | new webpack.NoEmitOnErrorsPlugin() 35 | ], 36 | stats: { 37 | // Nice colored output 38 | colors: true 39 | }, 40 | // Create Sourcemaps for the bundle 41 | // devtool: 'source-map', 42 | }; 43 | 44 | if(ENV === 'build'||ENV === 'build-min'){ 45 | config = { 46 | entry: { 47 | 'to': './src/index.js' 48 | }, 49 | output: { 50 | // path: __dirname, 51 | path: path.resolve(__dirname,'./dist/'), 52 | library:'To', 53 | libraryTarget: 'umd', 54 | filename: '[name].js' 55 | //umdNamedDefine: true 56 | }, 57 | module: { 58 | loaders: [ 59 | { 60 | loader: 'babel-loader', 61 | test: path.join(__dirname, 'src'), 62 | query: { 63 | presets: 'env' 64 | }, 65 | } 66 | ] 67 | }, 68 | plugins: [ 69 | // Avoid publishing files when compilation fails 70 | new webpack.BannerPlugin(" to2to v"+packageJSON.version+" \r\n By https://github.com/dntzhang \r\n Github: https://github.com/dntzhang/cax\r\n MIT Licensed."), 71 | new webpack.NoEmitOnErrorsPlugin() 72 | ], 73 | stats: { 74 | // Nice colored output 75 | colors: true 76 | }, 77 | // Create Sourcemaps for the bundle 78 | // devtool: 'source-map', 79 | }; 80 | 81 | if(ENV === 'build-min'){ 82 | config.plugins.push(new webpack.optimize.UglifyJsPlugin({ 83 | compress: { 84 | warnings: false, 85 | screw_ie8 : false 86 | }, 87 | mangle: { 88 | screw_ie8: false 89 | }, 90 | output: { screw_ie8: false } 91 | })); 92 | config.entry = { 93 | 'to.min': './src/index.js' 94 | }; 95 | } 96 | }else{ 97 | config.entry = path.resolve(__dirname,'./examples/' + ENV + '/main.js'); 98 | config.output.path = path.resolve(__dirname,'./examples/' + ENV + '/'); 99 | } 100 | 101 | 102 | //console.log(ENV); 103 | 104 | module.exports = config; 105 | -------------------------------------------------------------------------------- /tutorial/cax-matter.md: -------------------------------------------------------------------------------- 1 | # Cax + Matter-js 物理引擎结合使用 2 | 3 | 最初试过 box2dweb 与 [cax框架](https://github.com/dntzhang/cax) 结合使用,发现 box2dweb 的代码会导致 webpack 编译出的 cax 包模块执行顺序乱套。 4 | box2dweb 貌似也没有官方文档和维护地址,所以弃坑转战 Matter-js。 5 | 6 | Matter-js 是 Github 上最流行的 Web 2D 物理引擎,主要有如下特性: 7 | 8 | * 支持刚体、混合体、复合体 9 | * 支持凹凸多边形刚体 10 | * 支持刚体间约束条件 11 | * 内置睡眠与静止身体 12 | * 物理模拟时间加快变慢 13 | * 移动兼容(触摸事件和PC鼠标事件响应) 14 | * 物理性质(质量、面积、密度、动量守恒、摩擦阻力、重力、弹性或非碰撞检测以及恢复等) 15 | 16 | ## 开始结合 Cax 和 Matter-js 17 | 18 | ### 引入 js 19 | 20 | 先在 HTML 引入 matter-js 和 cax, 你可以通过 npm 或 cdn 获取 js: 21 | 22 | * [https://unpkg.com/matter-js](https://unpkg.com/matter-js) 23 | * [https://unpkg.com/cax](https://unpkg.com/cax) 24 | 25 | ### 准备工作 26 | 27 | 页面添加 Canvas 28 | 29 | ``` html 30 | 31 | ``` 32 | 33 | 提前声明好变量: 34 | 35 | ``` js 36 | var Engine = Matter.Engine, 37 | Render = Matter.Render, 38 | World = Matter.World, 39 | Bodies = Matter.Bodies, 40 | Composites = Matter.Composites, 41 | Body = Matter.Body, 42 | Constraint = Matter.Constraint, 43 | MouseConstraint = Matter.MouseConstraint, 44 | Common = Matter.Common, 45 | Events = Matter.Events, 46 | Composite = Matter.Composite 47 | ``` 48 | 49 | ### 创建刚体 50 | 51 | ```js 52 | Bodies.rectangle(100, 49, 800, 44, { isStatic: true }) 53 | ``` 54 | 55 | * 前四个参数分别代表 x y width height。需要注意的是 x 和 y 是矩形中心的坐标 56 | * `isStatic` 为 true 的话代表是静止刚体,不传或者传 false 为可运动刚体。 57 | 58 | ### 创建四面墙并添加到世界 59 | 60 | ```js 61 | // 创建引擎 62 | var engine = Engine.create(); 63 | 64 | // 创建四面墙壁墙壁并添加到世界 65 | var offset = 10; 66 | World.add(engine.world, [ 67 | Bodies.rectangle(400, 600 - offset, 800, offset * 2, { isStatic: true }), 68 | Bodies.rectangle(400, offset, 800, offset * 2, { isStatic: true }), 69 | Bodies.rectangle(offset, 300, offset * 2, 600, { isStatic: true }), 70 | Bodies.rectangle(800 - offset, 300, offset * 2, 600, { isStatic: true }), 71 | ]); 72 | ``` 73 | 74 | ### 创建物体并添加到世界 75 | 76 | ``` js 77 | var stack = Composites.stack(20, 20, 6, 4, 0, 0, function (x, y) { 78 | if (Common.random() > 0.5) { 79 | return Bodies.rectangle(x, y, 64, 64, { 80 | bitmap: new cax.Bitmap("img/box.jpg") 81 | }); 82 | } else { 83 | return Bodies.circle(x, y, 46, { 84 | desity: 0.0005, 85 | frictionAir: 0.06, 86 | friction: 0.01, 87 | bitmap: new cax.Bitmap("img/basketball.png"), 88 | 89 | }); 90 | } 91 | }); 92 | 93 | World.add(engine.world, stack); 94 | ``` 95 | 96 | 通过`Composites.stack(xx, yy, columns, rows, columnGap, rowGap, callback)`可以用来创建物体堆。 97 | 参数xx,yy分别为物体堆中第一个物体的x和y坐标,columns和 rows分别为所要创建的物体堆的列数和行数,columnGap和rowGap分别为物体与物体之间的列间隙和行间隙,最后,由var body = callback(x, y, column, row, lastBody, i); 可以看出callback为生成的具体物体的方法。 98 | 99 | 看以看到,创建的时候挂在 bitmap 上去用户后续的渲染。 100 | 101 | ### 发动引擎 102 | 103 | ```js 104 | Engine.run(engine) 105 | ``` 106 | ### 初始化渲染墙壁和物体 107 | 108 | ```js 109 | var bodies = Composite.allBodies(engine.world); 110 | 111 | for (var i = 0; i < bodies.length; i += 1) { 112 | var obj = bodies[i] 113 | if (obj.bitmap) { 114 | obj.bitmap.x = obj.position.x 115 | obj.bitmap.y = obj.position.y 116 | if (obj.label === 'Circle Body') { 117 | obj.bitmap.scaleX = obj.bitmap.scaleY = 92 / 128 118 | obj.bitmap.originX = 64 119 | obj.bitmap.originY = 64 120 | obj.bitmap.rotation = obj.angle * 180 / Math.PI 121 | } else { 122 | obj.bitmap.scaleX = obj.bitmap.scaleY = 64 / 200 123 | obj.bitmap.originX = 100 124 | obj.bitmap.originY = 100 125 | obj.bitmap.rotation = obj.angle * 180 / Math.PI 126 | } 127 | stage.add(obj.bitmap) 128 | } 129 | } 130 | 131 | //墙壁 132 | var topRect = new cax.Rect(800, 20, { fillStyle: '#2CB044' }) 133 | stage.add(topRect) 134 | var bottomRect = new cax.Rect(800, 20, { fillStyle: '#2CB044' }) 135 | bottomRect.y = 600 - 20 136 | stage.add(bottomRect) 137 | var leftTop = new cax.Rect(20, 600, { fillStyle: '#2CB044' }) 138 | stage.add(leftTop) 139 | var rightRect = new cax.Rect(20, 600, { fillStyle: '#2CB044' }) 140 | rightRect.x = 800 - 20 141 | stage.add(rightRect) 142 | ``` 143 | 144 | * 通过 `Composite.allBodies` 可以拿到所以刚体 145 | * 通过设置 bitmap 的 scaleX 和 scaleY 可以使 刚体大小和纹理大小对应起来 146 | 147 | ### 更新渲染舞台 148 | 149 | ```js 150 | cax.setInterval(function () { 151 | var bodies = Composite.allBodies(engine.world); 152 | for (var i = 0; i < bodies.length; i += 1) { 153 | var obj = bodies[i] 154 | if (obj.bitmap) { 155 | obj.bitmap.x = obj.position.x 156 | obj.bitmap.y = obj.position.y 157 | obj.bitmap.rotation = obj.angle * 180 / Math.PI 158 | } 159 | } 160 | 161 | stage.update() 162 | }, 16) 163 | ``` 164 | 165 | ### 添加 Matter-js 内置 Debug Canvas 166 | 167 | ```js 168 | var render = Render.create({ 169 | element: document.body, 170 | engine: engine, 171 | options: { 172 | wireframes: false 173 | } 174 | }); 175 | var renderOptions = render.options; 176 | 177 | renderOptions.wireframes = true; 178 | Render.run(render); 179 | ``` 180 | 181 | 最终效果: 182 | 183 | ![](../asset/cax-matter.png) 184 | 185 | [【→ 在线演示】](https://dntzhang.github.io/cax/packages/cax/examples/matter/) 186 | --------------------------------------------------------------------------------