├── .babelrc ├── .eslintrc.json ├── .gitignore ├── LICENSE ├── README.md ├── benchmark.md ├── build ├── README.template.md ├── es5.config.js └── es6.config.js ├── dist ├── weRender.es6.js ├── weRender.js └── weRender.min.js ├── examples ├── circle-actions.html ├── circle-clone.html ├── circle-composite.html ├── circle-zoom.html ├── index.html ├── lib │ ├── weRender.min.js │ └── weScroll.min.js └── path │ ├── index.html │ ├── money.png │ ├── seat.draw.js │ ├── seat.svg │ ├── seatCanvas.js │ └── smile.png ├── package.json └── src ├── index.js ├── weCanvas.js └── weStage.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["latest", { 4 | "es2015": { 5 | "modules": false 6 | } 7 | }] 8 | ], 9 | "plugins": ["external-helpers", "transform-class-properties"] 10 | } -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "react-app" 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/* 2 | .DS_Store 3 | .idea 4 | yarn.lock -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 henryluki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # weRender 2 | Simple, light-weight, Canvas library for 2D rendering 3 | 4 | 5 | # Features 6 | 7 | - `Chain` API 8 | 9 | - Drawing `actions` reusable 10 | 11 | - Same methods as CanvasRenderingContext2D 12 | 13 | # Install 14 | 15 | ```shell 16 | npm install we-render 17 | ``` 18 | 19 | # Usage 20 | 21 | - **ES6 module** 22 | 23 | ```javascript 24 | 25 | import { WeCanvas, WeStage } from 'we-render' 26 | 27 | const child = new WeCanvas() 28 | .setSize(100, 100) 29 | .scale(2, 2) 30 | .fillStyle("red") // different here 31 | .fillRect(0, 0, 10, 10) 32 | 33 | const stage = new WeStage() 34 | 35 | stage.addChid(child) 36 | stage.update() 37 | 38 | ``` 39 | 40 | - **In browser** 41 | 42 | ```html 43 | 44 | 45 | 65 | 66 | ``` 67 | 68 | # Examples 69 | 70 | See examples: 71 | `npm run static` 72 | 73 | * simple 74 | 75 | * clone 76 | 77 | * reuse actions 78 | 79 | * composite 80 | 81 | * zoom 82 | 83 | # Scripts 84 | 85 | Usefull Scripts for improving efficiency. 86 | 87 | **`SVG` to `Canvas`** 88 | 89 | See: https://github.com/weiying-shenzhen/svgToCanvas 90 | 91 | Examples: 92 | 93 | See examples under directory`examples/path` 94 | 95 | # API reference 96 | 97 | ## Modules 98 | 99 |
weRender: Simple Canvas library for easy usage
102 |WeCanvas: Easy canvas api for using, support useing chain
110 |methods
Property
of CanvasRenderingContext2D
here is method
draw()
WeStage: Canvas manager for WeCanvas
118 |Object
| option settions for instance |
158 |
159 |
160 |
161 | ### weCanvas.setSize(width, height)
162 | set canvas size
163 |
164 | **Kind**: instance method of [WeCanvas](#WeCanvas)
165 |
166 | | Param | Type | Description |
167 | | --- | --- | --- |
168 | | width | Number
| canvas width |
169 | | height | Number
| canvas height |
170 |
171 |
172 |
173 | ### weCanvas.setStyle(width, height)
174 | set canvas style, only width and height
175 |
176 | **Kind**: instance method of [WeCanvas](#WeCanvas)
177 |
178 | | Param | Type | Description |
179 | | --- | --- | --- |
180 | | width | String
| canvas style width |
181 | | height | String
| canvas style height |
182 |
183 |
184 |
185 | ### weCanvas.setCoordinate(x, y)
186 | set coordinate of stage
187 |
188 | **Kind**: instance method of [WeCanvas](#WeCanvas)
189 |
190 | | Param | Type | Default | Description |
191 | | --- | --- | --- | --- |
192 | | x | Number
| 0
| horizontal axis |
193 | | y | Number
| 0
| vertical axis |
194 |
195 |
196 |
197 | ### weCanvas.setScale(scale)
198 | set init scale
199 |
200 | **Kind**: instance method of [WeCanvas](#WeCanvas)
201 |
202 | | Param | Type | Description |
203 | | --- | --- | --- |
204 | | scale | Number
| scale ratio |
205 |
206 |
207 |
208 | ### weCanvas.clear()
209 | clear canvas
210 |
211 | **Kind**: instance method of [WeCanvas](#WeCanvas)
212 |
213 |
214 | ### weCanvas.getActions()
215 | get actions for context drawing
216 |
217 | **Kind**: instance method of [WeCanvas](#WeCanvas)
218 |
219 |
220 | ### weCanvas.setActions(actions)
221 | set actions
222 |
223 | **Kind**: instance method of [WeCanvas](#WeCanvas)
224 |
225 | | Param | Type | Description |
226 | | --- | --- | --- |
227 | | actions | Array
| actions for context drawing |
228 |
229 |
230 |
231 | ### weCanvas.draw()
232 | run actions, draw canvas
233 |
234 | **Kind**: instance method of [WeCanvas](#WeCanvas)
235 |
236 |
237 | ### weCanvas.cache(ifCache)
238 | set cache, default: true
239 |
240 | **Kind**: instance method of [WeCanvas](#WeCanvas)
241 |
242 | | Param | Type | Default | Description |
243 | | --- | --- | --- | --- |
244 | | ifCache | Boolean
| true
| if set cache |
245 |
246 |
247 |
248 | ## WeStage
249 | WeStage: Canvas manager for WeCanvas
250 |
251 | **Kind**: global class
252 |
253 | * [WeStage](#WeStage)
254 | * [new WeStage(canvas, options)](#new_WeStage_new)
255 | * [.setSize(width, height)](#WeStage+setSize)
256 | * [.setStyle(width, height)](#WeStage+setStyle)
257 | * [.destory()](#WeStage+destory)
258 | * [.clear()](#WeStage+clear)
259 | * [.addChild(child)](#WeStage+addChild)
260 | * [.translate(x, y, reset)](#WeStage+translate)
261 | * [.update()](#WeStage+update)
262 |
263 |
264 |
265 | ### new WeStage(canvas, options)
266 | create a WeStage instance
267 |
268 |
269 | | Param | Type | Description |
270 | | --- | --- | --- |
271 | | canvas | Canvas
| a Canvas element related to the dom |
272 | | options | Object
| stage settings |
273 |
274 |
275 |
276 | ### weStage.setSize(width, height)
277 | set stage size
278 |
279 | **Kind**: instance method of [WeStage](#WeStage)
280 |
281 | | Param | Type | Description |
282 | | --- | --- | --- |
283 | | width | Number
| stage width |
284 | | height | Number
| stage height |
285 |
286 |
287 |
288 | ### weStage.setStyle(width, height)
289 | set stage style
290 |
291 | **Kind**: instance method of [WeStage](#WeStage)
292 |
293 | | Param | Type | Description |
294 | | --- | --- | --- |
295 | | width | String
| stage style width |
296 | | height | String
| stage style height |
297 |
298 |
299 |
300 | ### weStage.destory()
301 | destrory stage
302 |
303 | **Kind**: instance method of [WeStage](#WeStage)
304 |
305 |
306 | ### weStage.clear()
307 | clear canvas
308 |
309 | **Kind**: instance method of [WeStage](#WeStage)
310 |
311 |
312 | ### weStage.addChild(child)
313 | add child to the stage
314 |
315 | **Kind**: instance method of [WeStage](#WeStage)
316 |
317 | | Param | Type | Description |
318 | | --- | --- | --- |
319 | | child | [WeCanvas](#WeCanvas)
\| Object
| WeCanvas instance or Object cotains Canvas |
320 |
321 |
322 |
323 | ### weStage.translate(x, y, reset)
324 | translate stage, move coordinate
325 |
326 | **Kind**: instance method of [WeStage](#WeStage)
327 |
328 | | Param | Type | Default | Description |
329 | | --- | --- | --- | --- |
330 | | x | Number
| 0
| offset x |
331 | | y | Number
| 0
| offset y |
332 | | reset | Boolean
| false
| should reset after update |
333 |
334 |
335 |
336 | ### weStage.update()
337 | update stage, draw child on canvas
338 | **run this method, all child canvas will draw**
339 |
340 | **Kind**: instance method of [WeStage](#WeStage)
341 |
342 | *docs autogenerated via [jsdoc2md](https://github.com/jsdoc2md/jsdoc-to-markdown)*
343 |
--------------------------------------------------------------------------------
/benchmark.md:
--------------------------------------------------------------------------------
1 | 有无同等屏幕大小的离屏 canvas 性能测试
2 | ----------
3 |
4 | 对例子 (`circle-zoom`) 使用 `timeit` 打点记时工具,记录了 `WeStage` 有无 `_offscreenCanvas`(离屏缓冲)情况的重绘时间
5 |
6 | ### 数据
7 |
8 | - **`Android`**
9 |
10 | - 无: `key:withoutOffscreen:times.length:1630:average:4.108588957055215`
11 | - 有: `key:offscreen:times.length:1227:average:12.859005704971475`
12 |
13 | - **`IOS`**
14 |
15 | - 无: `key:withoutOffscreen:times.length:1215:average:5.57283950617284`
16 | - 有: `key:offscreen:times.length:1385:average:5.624548736462094`
17 |
18 | - **`Chrome`**
19 |
20 | - 无: `key:withoutOffscreen:times.length:1024:average:0.8701171875`
21 | - 有: `key:offscreen:times.length:1020:average:1.607843137254902`
22 |
23 | ### 统计
24 | | 类别 |有 | 无 |
25 | | --- | --- | --- |
26 | | `Android` | 平均:`12.86ms`| 平均:`4.1ms` |
27 | | `IOS` | 平均:`5.62ms` | 平均:`5.57ms` |
28 | | `Chrome` | 平均:`1.61ms` | 平均:`0.87ms`|
29 |
30 | ### 结论
31 |
32 | 对于 `Android`而言,没有离屏 Canvas 性能提升明显;对`IOS`而言,两者基本没有差别;对`Chrome`而言,差距不大。总体而言,同等大小的离屏 Canvas 缓冲没必要存在。
--------------------------------------------------------------------------------
/build/README.template.md:
--------------------------------------------------------------------------------
1 | # weRender
2 | Simple, light-weight, Canvas library for easy usage
3 |
4 |
5 | # Features
6 |
7 | - `Chain` API
8 |
9 | - Drawing `actions` reusable
10 |
11 | - Same methods as CanvasRenderingContext2D
12 |
13 | # Usage
14 |
15 | - **ES6 module**
16 |
17 | ```javascript
18 |
19 | import { WeCanvas, WeRender } from 'weRender'
20 |
21 | const child = new WeCanvas()
22 | .setSize(100, 100)
23 | .scale(2, 2)
24 | .fillStyle("red") // different here
25 | .fillRect(0, 0, 10, 10)
26 |
27 | const stage = new WeStage()
28 |
29 | stage.addChid(child)
30 | stage.update()
31 |
32 | ```
33 |
34 | - **In browser**
35 |
36 | ```html
37 |
38 |
39 |
59 |
60 | ```
61 |
62 | # Examples
63 |
64 | See examples:
65 | `npm run static`
66 |
67 | * simple
68 |
69 | * clone
70 |
71 | * reuse actions
72 |
73 | * composite
74 |
75 | * zoom
76 |
77 | # Scripts
78 |
79 | Usefull Scripts, see:
80 |
81 | * scripts
82 |
83 | # API reference
84 |
85 | {{>main}}
86 |
87 | *docs autogenerated via [jsdoc2md](https://github.com/jsdoc2md/jsdoc-to-markdown)*
88 |
--------------------------------------------------------------------------------
/build/es5.config.js:
--------------------------------------------------------------------------------
1 | import resolve from 'rollup-plugin-node-resolve';
2 | import babel from 'rollup-plugin-babel';
3 | import eslint from 'rollup-plugin-eslint';
4 | import uglify from 'rollup-plugin-uglify';
5 |
6 | const isProduction = process.env.NODE_ENV === 'production'
7 |
8 | export default {
9 | entry: 'src/index.js',
10 | moduleName: "weRender",
11 | format: 'umd',
12 | plugins: [
13 | resolve(),
14 | babel({
15 | exclude: 'node_modules/**'
16 | }),
17 | eslint({
18 | exclude: [
19 | 'src/styles/**'
20 | ]
21 | }),
22 | ( isProduction && uglify())
23 | ],
24 | dest: isProduction ? 'dist/weRender.min.js' : 'dist/weRender.js'
25 | };
--------------------------------------------------------------------------------
/build/es6.config.js:
--------------------------------------------------------------------------------
1 | import eslint from 'rollup-plugin-eslint';
2 | import babel from 'rollup-plugin-babel';
3 |
4 | export default {
5 | entry: 'src/index.js',
6 | format: 'cjs',
7 | plugins: [
8 | eslint({
9 | exclude: [
10 | 'src/styles/**'
11 | ]
12 | }),
13 | babel({
14 | babelrc: false,
15 | plugins: ["external-helpers", "transform-class-properties"],
16 | })
17 | ],
18 | dest: 'dist/weRender.es6.js'
19 | };
20 |
--------------------------------------------------------------------------------
/dist/weRender.es6.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, '__esModule', { value: true });
4 |
5 | /**
6 | * WeCanvas: Easy canvas api for using, support useing chain
7 | *
8 | * - Directly use CanvasRenderingContext2D` methods`
9 | * - `Property` of `CanvasRenderingContext2D` here is `method`
10 | * - Won't really drawing Canvas until run `draw()`
11 | *
12 | */
13 | class WeCanvas {
14 | static generatorMethod() {
15 | WeCanvas.hasGeneratored = true;
16 |
17 | const retangles = ["clearRect", "fillRect", "strokeRect"];
18 | const text = ["fillText", "strokeText", "measureText"];
19 | const lineStyles = ["lineWidth", "lineCap", "lineJoin"];
20 | const textStyles = ["font", "textAlgin", "textBaseline", "direction"];
21 | const fillStrokeStyles = ["fillStyle", "strokeStyle"];
22 | const paths = ["beginPath", "closePath", "moveTo", "lineTo", "bezierCurveTo", "quadraticCurveTo", "arc", "arcTo", "rect"];
23 | const pathsDrawing = ["fill", "stroke"];
24 | const transformations = ["rotate", "scale", "translate", "transform", "resetTransform"];
25 | const images = ["drawImage"];
26 | const pixel = ["createImageData", "getImageData", "putImageData"];
27 | const state = ["save", "restore"];
28 | const shadow = ['shadowColor', 'shadowBlur'];
29 | const _methods = [].concat(retangles, text, lineStyles, textStyles, fillStrokeStyles, paths, pathsDrawing, transformations, images, pixel, state, shadow);
30 | return _methods;
31 | }
32 | /**
33 | * create a WeCanvas instance
34 | *
35 | * @param {Object} options - option settions for instance
36 | */
37 | constructor(options) {
38 | this._rendered = false;
39 | this._init(options);
40 | this.width = this.canvas.width;
41 | this.height = this.canvas.height;
42 | }
43 | /**
44 | * init
45 | *
46 | * @private
47 | * @param {Canvas} options.canvas - canvas element
48 | * @param {Array} options.actions - context drawing actions
49 | * @param {Number} options.width - canvas witdh
50 | * @param {Number} options.height - canvas height
51 | * @param {Number} options.x - horizontal axis
52 | * @param {Number} options.y - vertical axis
53 | * @param {Array} options.methods - methods for context
54 | */
55 | _init({
56 | canvas,
57 | actions,
58 | width,
59 | height,
60 | x,
61 | y,
62 | methods = []
63 | } = {}) {
64 | this.canvas = canvas || document.createElement('canvas');
65 | this._ctx = this.canvas.getContext('2d');
66 | this._initMethods(WeCanvas.hasGeneratored ? methods : WeCanvas.generatorMethod().concat(methods));
67 | this.setSize(width, height);
68 | this.setCoordinate(x, y);
69 | this.setActions(actions);
70 | }
71 | /**
72 | * reduce context methods that need to be bind
73 | *
74 | * @private
75 | * @param {Array} methods - context methods
76 | */
77 | _initMethods(methods = []) {
78 | methods.reduce((hash, method) => {
79 | if (!this[method]) {
80 | this._proxy(method);
81 | hash[method] = true;
82 | }
83 | return hash;
84 | }, {});
85 | }
86 | /**
87 | * bind context method or property to this instance
88 | *
89 | * @private
90 | * @param {String} method - context method or property
91 | */
92 | _proxy(method) {
93 | const prop = this._ctx[method];
94 | if (prop === undefined) return;
95 | WeCanvas.prototype[method] = function (...args) {
96 | this._actions.push([Object.prototype.toString.call(prop) === "[object Function]" ? "method" : "property", method, args]);
97 | return this;
98 | };
99 | }
100 | /**
101 | * set canvas size
102 | *
103 | * @param {Number} width - canvas width
104 | * @param {Number} height - canvas height
105 | */
106 | setSize(width, height) {
107 | if (width && width !== this.width) {
108 | this.canvas.width = width;
109 | this.width = width;
110 | }
111 | if (height && height !== this.height) {
112 | this.canvas.height = height;
113 | this.height = height;
114 | }
115 | return this;
116 | }
117 | /**
118 | * set canvas style, only width and height
119 | *
120 | * @param {String} width - canvas style width
121 | * @param {String} height - canvas style height
122 | */
123 | setStyle(width, height) {
124 | if (width) {
125 | this.canvas.style.width = width;
126 | }
127 | if (height) {
128 | this.canvas.style.height = height;
129 | }
130 | return this;
131 | }
132 | /**
133 | * set coordinate of stage
134 | *
135 | * @param {Number} x - horizontal axis
136 | * @param {Number} y - vertical axis
137 | */
138 | setCoordinate(x = 0, y = 0) {
139 | this.x = x;
140 | this.y = y;
141 | return this;
142 | }
143 | /**
144 | * set init scale
145 | *
146 | * @param {Number} scale - scale ratio
147 | */
148 | setScale(scale) {
149 | this._ctx.scale(scale, scale);
150 | }
151 | /**
152 | * clear canvas
153 | */
154 | clear() {
155 | this._ctx.clearRect(0, 0, this.width, this.height);
156 | this.setActions([]);
157 | }
158 | /**
159 | * get actions for context drawing
160 | */
161 | getActions() {
162 | return this._actions;
163 | }
164 | /**
165 | * set actions
166 | *
167 | * @param {Array} actions - actions for context drawing
168 | */
169 | setActions(actions = []) {
170 | if (Array.isArray(actions)) {
171 | this._actions = actions;
172 | }
173 | }
174 | /**
175 | * run actions, draw canvas
176 | */
177 | draw() {
178 | const shouldRender = (!this._rendered ? true : !this._cache) && !!this._actions.length;
179 | if (!shouldRender) return;
180 |
181 | this._actions.forEach(([type, method, args]) => {
182 | const params = Array.prototype.slice.call(args);
183 |
184 | if (type === "method") {
185 | this._ctx[method].apply(this._ctx, params);
186 | } else {
187 | this._ctx[method] = params[0];
188 | }
189 | });
190 | if (!this._rendered) {
191 | this._rendered = true;
192 | }
193 | return this;
194 | }
195 | /**
196 | * set cache, default: true
197 | *
198 | * @param {Boolean} ifCache - if set cache
199 | */
200 | cache(ifCache = true) {
201 | if (typeof ifCache === "boolean") {
202 | this._cache = ifCache;
203 | }
204 | return this;
205 | }
206 | }
207 |
208 | WeCanvas.hasGeneratored = false;
209 |
210 | /**
211 | * WeStage: Canvas manager for WeCanvas
212 | *
213 | */
214 | class WeStage {
215 | /**
216 | * create a WeStage instance
217 | *
218 | * @param {Canvas} canvas - a Canvas element related to the dom
219 | * @param {Object} options - stage settings
220 | */
221 | constructor(canvas, options = {}) {
222 | this._canvas = new WeCanvas({
223 | canvas
224 | }).cache(false);
225 | this._children = [];
226 | this._updating = false;
227 | this._initOptions(options);
228 | }
229 | /**
230 | * init options for settings
231 | *
232 | * @private
233 | * @param {Boolean} options.clear - auto clear stage
234 | * @param {Number} options.ratio - zoom down level when draw child Canvas
235 | */
236 | _initOptions({
237 | clear = true,
238 | ratio = 1
239 | }) {
240 | if (typeof clear === "boolean") {
241 | this._clear = clear;
242 | }
243 | if (typeof ratio === "number") {
244 | this._ratio = ratio;
245 | }
246 | }
247 | /**
248 | * set stage size
249 | *
250 | * @param {Number} width - stage width
251 | * @param {Number} height - stage height
252 | */
253 | setSize(width, height) {
254 | this._canvas.setSize(width, height);
255 | this._canvas.setScale(this._ratio);
256 | }
257 | /**
258 | * set stage style
259 | *
260 | * @param {String} width - stage style width
261 | * @param {String} height - stage style height
262 | */
263 | setStyle(width, height) {
264 | this._canvas.setStyle(width, height);
265 | }
266 | /**
267 | * destrory stage
268 | */
269 | destory() {
270 | this._canvas = null;
271 | this._children.length = 0;
272 | }
273 | /**
274 | * clear canvas
275 | */
276 | clear() {
277 | this._canvas.clear();
278 | }
279 |
280 | /**
281 | * add child to the stage
282 | *
283 | * @param {WeCanvas|Object} child - WeCanvas instance or Object cotains Canvas
284 | */
285 | addChild(child) {
286 | if (child instanceof WeCanvas || child.canvas.getContext('2d')) {
287 | this._children.push(child);
288 | }
289 | }
290 | /**
291 | * translate stage, move coordinate
292 | *
293 | * @param {Number} x - offset x
294 | * @param {Number} y - offset y
295 | * @param {Boolean} reset - should reset after update
296 | */
297 | translate(x = 0, y = 0, reset = false) {
298 | if (typeof x === "number" && typeof y === "number") {
299 | this._coordinate = {
300 | x,
301 | y
302 | };
303 | }
304 | if (typeof reset === "boolean") {
305 | this._translateReset = reset;
306 | }
307 | }
308 | /**
309 | * update stage, draw child on canvas
310 | * **run this method, all child canvas will draw**
311 | */
312 | update() {
313 | if (!this._children.length || this._updating) return;
314 | this._updating = true;
315 | if (this._clear) {
316 | this.clear();
317 | }
318 | this._translateStage();
319 | this._drawChildren();
320 | this._resetCoordinate();
321 | this._updateStage();
322 | this._updating = false;
323 | this._children = [];
324 | }
325 | /**
326 | * translate stage
327 | * @private
328 | */
329 | _translateStage() {
330 | if (this._coordinate) {
331 | const {
332 | x,
333 | y
334 | } = this._coordinate;
335 | this._canvas.translate(x, y);
336 | }
337 | }
338 | /**
339 | * reset coordinate
340 | * @private
341 | */
342 | _resetCoordinate() {
343 | if (this._translateReset) {
344 | const {
345 | x,
346 | y
347 | } = this._coordinate;
348 | this._canvas.translate(-x, -y);
349 | this._coordinate = null;
350 | }
351 | }
352 | /**
353 | * draw children
354 | * @private
355 | */
356 | _drawChildren() {
357 | this._children.forEach(child => {
358 | if (child instanceof WeCanvas) {
359 | this._drawChild(child);
360 | } else {
361 | this._drawChildCanvas(child);
362 | }
363 | });
364 | }
365 | /**
366 | * draw child, which is a instance of WeCanvas
367 | *
368 | * @private
369 | * @param {WeCanvas} child - a WeCanvas instance
370 | */
371 | _drawChild(child) {
372 | const {
373 | canvas,
374 | x,
375 | y,
376 | width,
377 | height
378 | } = child;
379 | child.draw();
380 | this._canvas.drawImage(canvas, x, y, width / this._ratio, height / this._ratio);
381 | }
382 | /**
383 | * draw child, which is a raw Canvas element
384 | *
385 | * @private
386 | * @param {Number} options.x - horizontal axis
387 | * @param {Number} options.y - vertical axis
388 | * @param {Canvas} options.canvas - Canvas
389 | */
390 | _drawChildCanvas({
391 | x = 0,
392 | y = 0,
393 | canvas
394 | }) {
395 | this._canvas.drawImage(canvas, x, y, canvas.width / this._ratio, canvas.height / this._ratio);
396 | }
397 | /**
398 | * draw dom canvas
399 | * @private
400 | */
401 | _updateStage() {
402 | this._canvas.draw();
403 | }
404 | }
405 |
406 | exports.WeCanvas = WeCanvas;
407 | exports.WeStage = WeStage;
408 |
--------------------------------------------------------------------------------
/dist/weRender.js:
--------------------------------------------------------------------------------
1 | (function (global, factory) {
2 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3 | typeof define === 'function' && define.amd ? define(['exports'], factory) :
4 | (factory((global.weRender = global.weRender || {})));
5 | }(this, (function (exports) { 'use strict';
6 |
7 | var classCallCheck = function (instance, Constructor) {
8 | if (!(instance instanceof Constructor)) {
9 | throw new TypeError("Cannot call a class as a function");
10 | }
11 | };
12 |
13 | var createClass = function () {
14 | function defineProperties(target, props) {
15 | for (var i = 0; i < props.length; i++) {
16 | var descriptor = props[i];
17 | descriptor.enumerable = descriptor.enumerable || false;
18 | descriptor.configurable = true;
19 | if ("value" in descriptor) descriptor.writable = true;
20 | Object.defineProperty(target, descriptor.key, descriptor);
21 | }
22 | }
23 |
24 | return function (Constructor, protoProps, staticProps) {
25 | if (protoProps) defineProperties(Constructor.prototype, protoProps);
26 | if (staticProps) defineProperties(Constructor, staticProps);
27 | return Constructor;
28 | };
29 | }();
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | var slicedToArray = function () {
58 | function sliceIterator(arr, i) {
59 | var _arr = [];
60 | var _n = true;
61 | var _d = false;
62 | var _e = undefined;
63 |
64 | try {
65 | for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
66 | _arr.push(_s.value);
67 |
68 | if (i && _arr.length === i) break;
69 | }
70 | } catch (err) {
71 | _d = true;
72 | _e = err;
73 | } finally {
74 | try {
75 | if (!_n && _i["return"]) _i["return"]();
76 | } finally {
77 | if (_d) throw _e;
78 | }
79 | }
80 |
81 | return _arr;
82 | }
83 |
84 | return function (arr, i) {
85 | if (Array.isArray(arr)) {
86 | return arr;
87 | } else if (Symbol.iterator in Object(arr)) {
88 | return sliceIterator(arr, i);
89 | } else {
90 | throw new TypeError("Invalid attempt to destructure non-iterable instance");
91 | }
92 | };
93 | }();
94 |
95 | /**
96 | * WeCanvas: Easy canvas api for using, support useing chain
97 | *
98 | * - Directly use CanvasRenderingContext2D` methods`
99 | * - `Property` of `CanvasRenderingContext2D` here is `method`
100 | * - Won't really drawing Canvas until run `draw()`
101 | *
102 | */
103 | var WeCanvas = function () {
104 | createClass(WeCanvas, null, [{
105 | key: "generatorMethod",
106 | value: function generatorMethod() {
107 | WeCanvas.hasGeneratored = true;
108 |
109 | var retangles = ["clearRect", "fillRect", "strokeRect"];
110 | var text = ["fillText", "strokeText", "measureText"];
111 | var lineStyles = ["lineWidth", "lineCap", "lineJoin"];
112 | var textStyles = ["font", "textAlgin", "textBaseline", "direction"];
113 | var fillStrokeStyles = ["fillStyle", "strokeStyle"];
114 | var paths = ["beginPath", "closePath", "moveTo", "lineTo", "bezierCurveTo", "quadraticCurveTo", "arc", "arcTo", "rect"];
115 | var pathsDrawing = ["fill", "stroke"];
116 | var transformations = ["rotate", "scale", "translate", "transform", "resetTransform"];
117 | var images = ["drawImage"];
118 | var pixel = ["createImageData", "getImageData", "putImageData"];
119 | var state = ["save", "restore"];
120 | var shadow = ['shadowColor', 'shadowBlur'];
121 | var _methods = [].concat(retangles, text, lineStyles, textStyles, fillStrokeStyles, paths, pathsDrawing, transformations, images, pixel, state, shadow);
122 | return _methods;
123 | }
124 | /**
125 | * create a WeCanvas instance
126 | *
127 | * @param {Object} options - option settions for instance
128 | */
129 |
130 | }]);
131 |
132 | function WeCanvas(options) {
133 | classCallCheck(this, WeCanvas);
134 |
135 | this._rendered = false;
136 | this._init(options);
137 | this.width = this.canvas.width;
138 | this.height = this.canvas.height;
139 | }
140 | /**
141 | * init
142 | *
143 | * @private
144 | * @param {Canvas} options.canvas - canvas element
145 | * @param {Array} options.actions - context drawing actions
146 | * @param {Number} options.width - canvas witdh
147 | * @param {Number} options.height - canvas height
148 | * @param {Number} options.x - horizontal axis
149 | * @param {Number} options.y - vertical axis
150 | * @param {Array} options.methods - methods for context
151 | */
152 |
153 |
154 | createClass(WeCanvas, [{
155 | key: "_init",
156 | value: function _init() {
157 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
158 | canvas = _ref.canvas,
159 | actions = _ref.actions,
160 | width = _ref.width,
161 | height = _ref.height,
162 | x = _ref.x,
163 | y = _ref.y,
164 | _ref$methods = _ref.methods,
165 | methods = _ref$methods === undefined ? [] : _ref$methods;
166 |
167 | this.canvas = canvas || document.createElement('canvas');
168 | this._ctx = this.canvas.getContext('2d');
169 | this._initMethods(WeCanvas.hasGeneratored ? methods : WeCanvas.generatorMethod().concat(methods));
170 | this.setSize(width, height);
171 | this.setCoordinate(x, y);
172 | this.setActions(actions);
173 | }
174 | /**
175 | * reduce context methods that need to be bind
176 | *
177 | * @private
178 | * @param {Array} methods - context methods
179 | */
180 |
181 | }, {
182 | key: "_initMethods",
183 | value: function _initMethods() {
184 | var _this = this;
185 |
186 | var methods = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
187 |
188 | methods.reduce(function (hash, method) {
189 | if (!_this[method]) {
190 | _this._proxy(method);
191 | hash[method] = true;
192 | }
193 | return hash;
194 | }, {});
195 | }
196 | /**
197 | * bind context method or property to this instance
198 | *
199 | * @private
200 | * @param {String} method - context method or property
201 | */
202 |
203 | }, {
204 | key: "_proxy",
205 | value: function _proxy(method) {
206 | var prop = this._ctx[method];
207 | if (prop === undefined) return;
208 | WeCanvas.prototype[method] = function () {
209 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
210 | args[_key] = arguments[_key];
211 | }
212 |
213 | this._actions.push([Object.prototype.toString.call(prop) === "[object Function]" ? "method" : "property", method, args]);
214 | return this;
215 | };
216 | }
217 | /**
218 | * set canvas size
219 | *
220 | * @param {Number} width - canvas width
221 | * @param {Number} height - canvas height
222 | */
223 |
224 | }, {
225 | key: "setSize",
226 | value: function setSize(width, height) {
227 | if (width && width !== this.width) {
228 | this.canvas.width = width;
229 | this.width = width;
230 | }
231 | if (height && height !== this.height) {
232 | this.canvas.height = height;
233 | this.height = height;
234 | }
235 | return this;
236 | }
237 | /**
238 | * set canvas style, only width and height
239 | *
240 | * @param {String} width - canvas style width
241 | * @param {String} height - canvas style height
242 | */
243 |
244 | }, {
245 | key: "setStyle",
246 | value: function setStyle(width, height) {
247 | if (width) {
248 | this.canvas.style.width = width;
249 | }
250 | if (height) {
251 | this.canvas.style.height = height;
252 | }
253 | return this;
254 | }
255 | /**
256 | * set coordinate of stage
257 | *
258 | * @param {Number} x - horizontal axis
259 | * @param {Number} y - vertical axis
260 | */
261 |
262 | }, {
263 | key: "setCoordinate",
264 | value: function setCoordinate() {
265 | var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
266 | var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
267 |
268 | this.x = x;
269 | this.y = y;
270 | return this;
271 | }
272 | /**
273 | * set init scale
274 | *
275 | * @param {Number} scale - scale ratio
276 | */
277 |
278 | }, {
279 | key: "setScale",
280 | value: function setScale(scale) {
281 | this._ctx.scale(scale, scale);
282 | }
283 | /**
284 | * clear canvas
285 | */
286 |
287 | }, {
288 | key: "clear",
289 | value: function clear() {
290 | this._ctx.clearRect(0, 0, this.width, this.height);
291 | this.setActions([]);
292 | }
293 | /**
294 | * get actions for context drawing
295 | */
296 |
297 | }, {
298 | key: "getActions",
299 | value: function getActions() {
300 | return this._actions;
301 | }
302 | /**
303 | * set actions
304 | *
305 | * @param {Array} actions - actions for context drawing
306 | */
307 |
308 | }, {
309 | key: "setActions",
310 | value: function setActions() {
311 | var actions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
312 |
313 | if (Array.isArray(actions)) {
314 | this._actions = actions;
315 | }
316 | }
317 | /**
318 | * run actions, draw canvas
319 | */
320 |
321 | }, {
322 | key: "draw",
323 | value: function draw() {
324 | var _this2 = this;
325 |
326 | var shouldRender = (!this._rendered ? true : !this._cache) && !!this._actions.length;
327 | if (!shouldRender) return;
328 |
329 | this._actions.forEach(function (_ref2) {
330 | var _ref3 = slicedToArray(_ref2, 3),
331 | type = _ref3[0],
332 | method = _ref3[1],
333 | args = _ref3[2];
334 |
335 | var params = Array.prototype.slice.call(args);
336 |
337 | if (type === "method") {
338 | _this2._ctx[method].apply(_this2._ctx, params);
339 | } else {
340 | _this2._ctx[method] = params[0];
341 | }
342 | });
343 | if (!this._rendered) {
344 | this._rendered = true;
345 | }
346 | return this;
347 | }
348 | /**
349 | * set cache, default: true
350 | *
351 | * @param {Boolean} ifCache - if set cache
352 | */
353 |
354 | }, {
355 | key: "cache",
356 | value: function cache() {
357 | var ifCache = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
358 |
359 | if (typeof ifCache === "boolean") {
360 | this._cache = ifCache;
361 | }
362 | return this;
363 | }
364 | }]);
365 | return WeCanvas;
366 | }();
367 |
368 | WeCanvas.hasGeneratored = false;
369 |
370 | /**
371 | * WeStage: Canvas manager for WeCanvas
372 | *
373 | */
374 |
375 | var WeStage = function () {
376 | /**
377 | * create a WeStage instance
378 | *
379 | * @param {Canvas} canvas - a Canvas element related to the dom
380 | * @param {Object} options - stage settings
381 | */
382 | function WeStage(canvas) {
383 | var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
384 | classCallCheck(this, WeStage);
385 |
386 | this._canvas = new WeCanvas({
387 | canvas: canvas
388 | }).cache(false);
389 | this._children = [];
390 | this._updating = false;
391 | this._initOptions(options);
392 | }
393 | /**
394 | * init options for settings
395 | *
396 | * @private
397 | * @param {Boolean} options.clear - auto clear stage
398 | * @param {Number} options.ratio - zoom down level when draw child Canvas
399 | */
400 |
401 |
402 | createClass(WeStage, [{
403 | key: "_initOptions",
404 | value: function _initOptions(_ref) {
405 | var _ref$clear = _ref.clear,
406 | clear = _ref$clear === undefined ? true : _ref$clear,
407 | _ref$ratio = _ref.ratio,
408 | ratio = _ref$ratio === undefined ? 1 : _ref$ratio;
409 |
410 | if (typeof clear === "boolean") {
411 | this._clear = clear;
412 | }
413 | if (typeof ratio === "number") {
414 | this._ratio = ratio;
415 | }
416 | }
417 | /**
418 | * set stage size
419 | *
420 | * @param {Number} width - stage width
421 | * @param {Number} height - stage height
422 | */
423 |
424 | }, {
425 | key: "setSize",
426 | value: function setSize(width, height) {
427 | this._canvas.setSize(width, height);
428 | this._canvas.setScale(this._ratio);
429 | }
430 | /**
431 | * set stage style
432 | *
433 | * @param {String} width - stage style width
434 | * @param {String} height - stage style height
435 | */
436 |
437 | }, {
438 | key: "setStyle",
439 | value: function setStyle(width, height) {
440 | this._canvas.setStyle(width, height);
441 | }
442 | /**
443 | * destrory stage
444 | */
445 |
446 | }, {
447 | key: "destory",
448 | value: function destory() {
449 | this._canvas = null;
450 | this._children.length = 0;
451 | }
452 | /**
453 | * clear canvas
454 | */
455 |
456 | }, {
457 | key: "clear",
458 | value: function clear() {
459 | this._canvas.clear();
460 | }
461 |
462 | /**
463 | * add child to the stage
464 | *
465 | * @param {WeCanvas|Object} child - WeCanvas instance or Object cotains Canvas
466 | */
467 |
468 | }, {
469 | key: "addChild",
470 | value: function addChild(child) {
471 | if (child instanceof WeCanvas || child.canvas.getContext('2d')) {
472 | this._children.push(child);
473 | }
474 | }
475 | /**
476 | * translate stage, move coordinate
477 | *
478 | * @param {Number} x - offset x
479 | * @param {Number} y - offset y
480 | * @param {Boolean} reset - should reset after update
481 | */
482 |
483 | }, {
484 | key: "translate",
485 | value: function translate() {
486 | var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
487 | var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
488 | var reset = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
489 |
490 | if (typeof x === "number" && typeof y === "number") {
491 | this._coordinate = {
492 | x: x,
493 | y: y
494 | };
495 | }
496 | if (typeof reset === "boolean") {
497 | this._translateReset = reset;
498 | }
499 | }
500 | /**
501 | * update stage, draw child on canvas
502 | * **run this method, all child canvas will draw**
503 | */
504 |
505 | }, {
506 | key: "update",
507 | value: function update() {
508 | if (!this._children.length || this._updating) return;
509 | this._updating = true;
510 | if (this._clear) {
511 | this.clear();
512 | }
513 | this._translateStage();
514 | this._drawChildren();
515 | this._resetCoordinate();
516 | this._updateStage();
517 | this._updating = false;
518 | this._children = [];
519 | }
520 | /**
521 | * translate stage
522 | * @private
523 | */
524 |
525 | }, {
526 | key: "_translateStage",
527 | value: function _translateStage() {
528 | if (this._coordinate) {
529 | var _coordinate = this._coordinate,
530 | x = _coordinate.x,
531 | y = _coordinate.y;
532 |
533 | this._canvas.translate(x, y);
534 | }
535 | }
536 | /**
537 | * reset coordinate
538 | * @private
539 | */
540 |
541 | }, {
542 | key: "_resetCoordinate",
543 | value: function _resetCoordinate() {
544 | if (this._translateReset) {
545 | var _coordinate2 = this._coordinate,
546 | x = _coordinate2.x,
547 | y = _coordinate2.y;
548 |
549 | this._canvas.translate(-x, -y);
550 | this._coordinate = null;
551 | }
552 | }
553 | /**
554 | * draw children
555 | * @private
556 | */
557 |
558 | }, {
559 | key: "_drawChildren",
560 | value: function _drawChildren() {
561 | var _this = this;
562 |
563 | this._children.forEach(function (child) {
564 | if (child instanceof WeCanvas) {
565 | _this._drawChild(child);
566 | } else {
567 | _this._drawChildCanvas(child);
568 | }
569 | });
570 | }
571 | /**
572 | * draw child, which is a instance of WeCanvas
573 | *
574 | * @private
575 | * @param {WeCanvas} child - a WeCanvas instance
576 | */
577 |
578 | }, {
579 | key: "_drawChild",
580 | value: function _drawChild(child) {
581 | var canvas = child.canvas,
582 | x = child.x,
583 | y = child.y,
584 | width = child.width,
585 | height = child.height;
586 |
587 | child.draw();
588 | this._canvas.drawImage(canvas, x, y, width / this._ratio, height / this._ratio);
589 | }
590 | /**
591 | * draw child, which is a raw Canvas element
592 | *
593 | * @private
594 | * @param {Number} options.x - horizontal axis
595 | * @param {Number} options.y - vertical axis
596 | * @param {Canvas} options.canvas - Canvas
597 | */
598 |
599 | }, {
600 | key: "_drawChildCanvas",
601 | value: function _drawChildCanvas(_ref2) {
602 | var _ref2$x = _ref2.x,
603 | x = _ref2$x === undefined ? 0 : _ref2$x,
604 | _ref2$y = _ref2.y,
605 | y = _ref2$y === undefined ? 0 : _ref2$y,
606 | canvas = _ref2.canvas;
607 |
608 | this._canvas.drawImage(canvas, x, y, canvas.width / this._ratio, canvas.height / this._ratio);
609 | }
610 | /**
611 | * draw dom canvas
612 | * @private
613 | */
614 |
615 | }, {
616 | key: "_updateStage",
617 | value: function _updateStage() {
618 | this._canvas.draw();
619 | }
620 | }]);
621 | return WeStage;
622 | }();
623 |
624 | exports.WeCanvas = WeCanvas;
625 | exports.WeStage = WeStage;
626 |
627 | Object.defineProperty(exports, '__esModule', { value: true });
628 |
629 | })));
630 |
--------------------------------------------------------------------------------
/dist/weRender.min.js:
--------------------------------------------------------------------------------
1 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(t.weRender=t.weRender||{})}(this,function(t){"use strict";var e=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},i=function(){function t(t,e){for(var i=0;iother examples:
24 |