diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..974597e --- /dev/null +++ b/.babelrc @@ -0,0 +1,28 @@ +{ + "env": { + "rollup": { + "presets": [ + [ + "env", + { + "modules": false + } + ] + ], + "plugins": [ + "transform-class-properties", + "transform-object-rest-spread", + "version" + ] + }, + "babel": { + "presets": ["env"], + "plugins": [ + "transform-class-properties", + "add-module-exports", + "transform-object-rest-spread", + "version" + ] + } + } +} diff --git a/.gitignore b/.gitignore index 3f875d7..1589f73 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .project .settings - +.idea node_modules/* - +*.lock +*.log diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index f2772a8..0000000 --- a/.jshintrc +++ /dev/null @@ -1,13 +0,0 @@ -{ - "quotmark": true, - "boss": true, - "eqnull": true, - "expr": true, - "funcscope": true, - "loopfunc": true, - "smarttabs": true, - "node": true, - "browser": true, - "undef": true, - "unused": true -} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index aacd2fb..0000000 --- a/.travis.yml +++ /dev/null @@ -1,3 +0,0 @@ -language: node_js -node_js: - - "4.4.4" \ No newline at end of file diff --git a/README-zh.md b/README-zh.md index ab83bc3..e968cc7 100644 --- a/README-zh.md +++ b/README-zh.md @@ -1,25 +1,39 @@ # canvas-nest.js -> 一个基于html5 canvas绘制的网页背景效果,非常赞!如果需要 `wordpress插件`,在插件库搜索 `canvas-nest` 或者看看项目 [canvas-nest-for-wp](https://github.com/aTool-org/canvas-nest-for-wp)。 +> 一个基于 html5 canvas 绘制的网页背景效果。 -![travis-ci](https://travis-ci.org/hustcc/canvas-nest.js.svg?branch=master) ![npm](https://img.shields.io/npm/v/canvas-nest.js.svg?style=flat-square) ![npm](https://img.shields.io/npm/l/canvas-nest.js.svg?style=flat-square) +[![npm](https://img.shields.io/badge/demo-online-brightgreen.svg)](https://git.hust.cc/canvas-nest.js) +[![npm](https://img.shields.io/npm/v/canvas-nest.js.svg)](https://www.npmjs.com/package/canvas-nest.js) +[![npm](https://img.shields.io/npm/dm/canvas-nest.js.svg)](https://www.npmjs.com/package/canvas-nest.js) +[![gzip](http://img.badgesize.io/https://unpkg.com/canvas-nest.js/dist/canvas-nest.js?compression=gzip)](https://unpkg.com/canvas-nest.js/dist/canvas-nest.js) +![screenshot](/screenshot.png) + +## 安装 +```sh +# 使用 npm +npm install --save canvas-nest.js + +# 或者使用 yarn +yarn add canvas-nest.js +``` ## 特性 - - 不依赖任何框架或者类库,比如不依赖 jQuery,使用原生的 javascript。 - - 非常小,只有1.6 kb,如果开启 gzip,可以更小。 - - 非常容易实现,配置简单,即使你不是web开发者,也能简单搞定。 + - 不依赖 jQuery,使用原生的 javascript。 + - 非常小,只有 2 Kb。 + - 非常容易实现,配置简单,即使你不是 web 开发者,也能简单搞定。 + - 模块化 & 区域渲染。 ## 使用 -使用非常简单,感觉都没有必要写这一节内容。 + - 快捷使用 将下面的代码插入到 ` 和 之间`. ```html - + ``` 强烈建议在 ``标签上方. 例如下面的代码结构: @@ -32,20 +46,40 @@ ... ... - ... - + ``` -`请注意不要将代码置于 里面`. +然后就完成了,打开网页即可看到效果!`请注意不要将代码置于 里面`. + -然后就完成了,打开网页即可看到效果! + - 模块化区域绘制(定制开发) +完成安装好,可以使用模块化方式 import。 -## 配置和配置项 +并且只有一个 API,使用如下: + +```js +import CanvasNest from 'canvas-nest.js'; + +const config = { + color: '255,0,0', + count: 88, +}; + +// 在 element 地方使用 config 渲染效果 +const cn = new CanvasNest(element, config); + +// destroy +cn.destroy(); +``` + + +## 配置 - **`color`**: 线条颜色, 默认: `'0,0,0'` ;三个数字分别为(R,G,B),注意用,分割 + - **`pointColor`**: 交点颜色, 默认: `'0,0,0'` ;三个数字分别为(R,G,B),注意用,分割 - **`opacity`**: 线条透明度(0~1), 默认: `0.5` - **`count`**: 线条的总数量, 默认: `150` - **`zIndex`**: 背景的z-index属性,css属性用于控制所在层的位置, 默认: `-1` @@ -53,24 +87,38 @@ Example: -``` - + - 快捷使用 + +```html + ``` -这些属性配置在引用js的script标签中,作为它的一个属性值。所有的配置项都有默认值,如果你不知道怎么设置,可以先不设置这些配置项,就使用默认值看看效果也可以的。 + - 模块化区域绘制(定制开发) + +```js +{ + color: '0,0,255', + opacity: 0.7, + zIndex: -2, + count: 99, +}; +``` +**注意: 所有的配置项都有默认值,如果你不知道怎么设置,可以先不设置这些配置项,就使用默认值看看效果也可以的。** -## 示例 -1. [在线工具: https://atool.vip/](https://atool.vip/) +## 相关项目 -如果你使用的了本项目,也可以修改此处文件,并 pr,我会接受的。 + - [canvas-nest-for-wp](https://github.com/aTool-org/canvas-nest-for-wp): WP 插件,在插件市场搜索 `canvas-nest` 即可安装。 + - [vue-canvas-nest](https://github.com/ZYSzys/vue-canvas-nest): VUE 组件包装。 + - [react-canvas-nest](https://github.com/flyerH/react-canvas-nest): React 组件包装。 + - [canvas-nest-for-vscode](https://github.com/AShujiao/vscode-background-cover): vscode 扩展, 在vscode扩展市场中搜索`background-cover` 即可安装。 -![screenshot](https://raw.githubusercontent.com/hustcc/canvas-nest.js/master/screenshot.png) +## 使用项目 + - [A Tool](https://atool.vip): 一个好用的工具集合. -## 其他 -本项目的Javascript文件已经存储在CDN上,可以直接使用,地址为: [http://www.bootcdn.cn/canvas-nest.js/](http://www.bootcdn.cn/canvas-nest.js/),如果你不需要 CDN 或者有自己的 CDN,可以直接下载源码 dist 目录中的 `canvas-nest.min.js`,然后相应的修改使用地址即可。 +## License -有任何的bug或者建议,非常鼓励 issue 和 pr,来者不拒。 +MIT@[hustcc](https://github.com/hustcc). diff --git a/README.md b/README.md index 33486c7..f759848 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,44 @@ # canvas-nest.js -> A nest backgroud of website draw on canvas. [中文Readme帮助文档](https://github.com/hustcc/canvas-nest.js/blob/master/README-zh.md). For `wordpress plugin`, search `canvas-nest` or see [canvas-nest-for-wp](https://github.com/aTool-org/canvas-nest-for-wp). +> A nest background of website draw on canvas. [中文 Readme 帮助文档](README-zh.md). -![travis-ci](https://travis-ci.org/hustcc/canvas-nest.js.svg?branch=master) ![npm](https://img.shields.io/npm/v/canvas-nest.js.svg?style=flat-square) ![npm](https://img.shields.io/npm/l/canvas-nest.js.svg?style=flat-square) +[![npm](https://img.shields.io/badge/demo-online-brightgreen.svg)](https://git.hust.cc/canvas-nest.js) +[![npm](https://img.shields.io/npm/v/canvas-nest.js.svg)](https://www.npmjs.com/package/canvas-nest.js) +[![npm](https://img.shields.io/npm/dm/canvas-nest.js.svg)](https://www.npmjs.com/package/canvas-nest.js) +[![gzip](http://img.badgesize.io/https://unpkg.com/canvas-nest.js/dist/canvas-nest.js?compression=gzip)](https://unpkg.com/canvas-nest.js/dist/canvas-nest.js) +![screenshot](/screenshot.png) +## Feature -## feature + - It does not depend on jQuery and original javascrpit is used. + - Small size, only 2 Kb. + - Easy to implement, simple configuration. + - You do not have to be a web developer to use it. + - Modularized with area rendering. - - do not depend on jQuery or other javascript framework. - - very light, only 1.6 kb. can be smaller after gzip. - - so easy to use, even you are not a web developer. +## Install +```sh +# use npm +npm install --save canvas-nest.js + +# or use yarn +yarn add canvas-nest.js +``` -## usage -so eazy that I do not want write the chapter. +## Usage -insert the code below `between and `. + - Script tag + +Insert the code below `between and `. ```html - + ``` -suggest before the tag ``. like below: +Strongly suggest to insert before the tag ``, as the following: ```html @@ -33,45 +48,79 @@ suggest before the tag ``. like below: ... ... - ... - + ``` +Then ok! `Please do not add the code in the `. -`please do not add the code in the `. -then ok! + - Modular usage (Area render) +After installation, you can import this as module. -## config +There is only one API, use it as below: - - **`color`**: the canvas line color, default: `'0,0,0'` ; the color is (R,G,B) - - **`opacity`**: the opacity of line (0~1), default: `0.5` - - **`count`**: the number of lines, default: `150` - - **`zIndex`**: the index of z space, default: `-1` +```js +import CanvasNest from 'canvas-nest.js'; + +const config = { + color: '255,0,0', + count: 88, +}; + +// Using config rendering effect at 'element'. +const cn = new CanvasNest(element, config); + +// destroy +cn.destroy(); +``` + + +## Configuration + + - **`color`**: color of lines, default: `'0,0,0'`; RGB values: (R,G,B).(note: use ',' to separate.) + - **`pointColor`**: color of points, default: `'0,0,0'`; RGB values: (R,G,B).(note: use ',' to separate.) + - **`opacity`**: the opacity of line (0~1), default: `0.5`. + - **`count`**: the number of lines, default: `99`. + - **`zIndex`**: z-index property of the background, default: `-1`. Example: + - Script tag + ```html - + +``` + + - Modular usage (Area render) + +```js +{ + color: '0,0,255', + opacity: 0.7, + zIndex: -2, + count: 99, +}; ``` -set the config on the script node `as a attribute`. all the config has the default value, you can choose to set any of them. +**Note: If the Configuration isn't customized, default values are available as well.** -## preview +## Related projects -1. [Online Tools: https://atool.vip/](https://atool.vip/) + - [canvas-nest-for-wp](https://github.com/aTool-org/canvas-nest-for-wp): a wordpress plugin, search `canvas-nest` in wordpress store. + - [vue-canvas-nest](https://github.com/ZYSzys/vue-canvas-nest): vue component wrapper. + - [react-canvas-nest](https://github.com/flyerH/react-canvas-nest): react component wrapper. + - [canvas-nest-for-vscode](https://github.com/AShujiao/vscode-nest): a vscode extensions, search `nest` in vscode extensions. -if you has used this project, pls let me know, I can add your website on. +## Used by -![screenshot](https://raw.githubusercontent.com/hustcc/canvas-nest.js/master/screenshot.png) + - [A Tool](https://atool.vip): a convenient tool box. -## other -Project library cdn url: [http://www.bootcdn.cn/canvas-nest.js/](http://www.bootcdn.cn/canvas-nest.js/). +## License -any bug or question, welcome to push request and issue. +MIT@[hustcc](https://github.com/hustcc). diff --git a/dist/canvas-nest.js b/dist/canvas-nest.js index e7bff1b..16f956f 100644 --- a/dist/canvas-nest.js +++ b/dist/canvas-nest.js @@ -1,118 +1 @@ -/** - * Copyright (c) 2016 hustcc - * License: MIT - * Version: v1.0.1 - * GitHub: https://github.com/hustcc/canvas-nest.js -**/ -! function() { - //封装方法,压缩之后减少文件大小 - function get_attribute(node, attr, default_value) { - return node.getAttribute(attr) || default_value; - } - //封装方法,压缩之后减少文件大小 - function get_by_tagname(name) { - return document.getElementsByTagName(name); - } - //获取配置参数 - function get_config_option() { - var scripts = get_by_tagname("script"), - script_len = scripts.length, - script = scripts[script_len - 1]; //当前加载的script - return { - l: script_len, //长度,用于生成id用 - z: get_attribute(script, "zIndex", -1), //z-index - o: get_attribute(script, "opacity", 0.5), //opacity - c: get_attribute(script, "color", "0,0,0"), //color - n: get_attribute(script, "count", 99) //count - }; - } - //设置canvas的高宽 - function set_canvas_size() { - canvas_width = the_canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, - canvas_height = the_canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; - } - - //绘制过程 - function draw_canvas() { - context.clearRect(0, 0, canvas_width, canvas_height); - //随机的线条和当前位置联合数组 - var e, i, d, x_dist, y_dist, dist; //临时节点 - //遍历处理每一个点 - random_points.forEach(function(r, idx) { - r.x += r.xa, - r.y += r.ya, //移动 - r.xa *= r.x > canvas_width || r.x < 0 ? -1 : 1, - r.ya *= r.y > canvas_height || r.y < 0 ? -1 : 1, //碰到边界,反向反弹 - context.fillRect(r.x - 0.5, r.y - 0.5, 1, 1); //绘制一个宽高为1的点 - //从下一个点开始 - for (i = idx + 1; i < all_array.length; i++) { - e = all_array[i]; - // 当前点存在 - if (null !== e.x && null !== e.y) { - x_dist = r.x - e.x; //x轴距离 l - y_dist = r.y - e.y; //y轴距离 n - dist = x_dist * x_dist + y_dist * y_dist; //总距离, m - - dist < e.max && (e === current_point && dist >= e.max / 2 && (r.x -= 0.03 * x_dist, r.y -= 0.03 * y_dist), //靠近的时候加速 - d = (e.max - dist) / e.max, - context.beginPath(), - context.lineWidth = d / 2, - context.strokeStyle = "rgba(" + config.c + "," + (d + 0.2) + ")", - context.moveTo(r.x, r.y), - context.lineTo(e.x, e.y), - context.stroke()); - } - } - }), frame_func(draw_canvas); - } - //创建画布,并添加到body中 - var the_canvas = document.createElement("canvas"), //画布 - config = get_config_option(), //配置 - canvas_id = "c_n" + config.l, //canvas id - context = the_canvas.getContext("2d"), canvas_width, canvas_height, - frame_func = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(func) { - window.setTimeout(func, 1000 / 45); - }, random = Math.random, - current_point = { - x: null, //当前鼠标x - y: null, //当前鼠标y - max: 20000 // 圈半径的平方 - }, - all_array; - the_canvas.id = canvas_id; - the_canvas.style.cssText = "position:fixed;top:0;left:0;z-index:" + config.z + ";opacity:" + config.o; - get_by_tagname("body")[0].appendChild(the_canvas); - - //初始化画布大小 - set_canvas_size(); - window.onresize = set_canvas_size; - //当时鼠标位置存储,离开的时候,释放当前位置信息 - window.onmousemove = function(e) { - e = e || window.event; - current_point.x = e.clientX; - current_point.y = e.clientY; - }, window.onmouseout = function() { - current_point.x = null; - current_point.y = null; - }; - //随机生成config.n条线位置信息 - for (var random_points = [], i = 0; config.n > i; i++) { - var x = random() * canvas_width, //随机位置 - y = random() * canvas_height, - xa = 2 * random() - 1, //随机运动方向 - ya = 2 * random() - 1; - // 随机点 - random_points.push({ - x: x, - y: y, - xa: xa, - ya: ya, - max: 6000 //沾附距离 - }); - } - all_array = random_points.concat([current_point]); - //0.1秒后绘制 - setTimeout(function() { - draw_canvas(); - }, 100); -}(); +!function(){"use strict";function e(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function t(e,t){return e(t={exports:{}},t.exports),t.exports}var n=t(function(e,t){Object.defineProperty(t,"__esModule",{value:!0});var n=1;t.default=function(){return""+n++},e.exports=t.default});e(n);var o=t(function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:30,n=null;return function(){for(var o=this,i=arguments.length,r=Array(i),a=0;an||r.x<0?-1:1,r.ya*=r.y>o||r.y<0?-1:1,t.fillStyle="rgba("+e.c.pointColor+")",t.fillRect(r.x-.5,r.y-.5,1,1),u=f+1;u=s.max/2&&(r.x-=.03*l,r.y-=.03*d),c=(s.max-v)/s.max,t.beginPath(),t.lineWidth=c/2,t.strokeStyle="rgba("+e.c.color+","+(c+.2)+")",t.moveTo(r.x,r.y),t.lineTo(s.x,s.y),t.stroke()))}),this.requestFrame(this.drawCanvas)}},{key:"destroy",value:function(){l(this.el),window.onmousemove=this.onmousemove,window.onmouseout=this.onmouseout,f(this.tid),this.canvas.parentNode.removeChild(this.canvas)}}]),e}();y.version="2.0.4";var w,b;new y(document.body,(w=document.getElementsByTagName("script"),{zIndex:(b=w[w.length-1]).getAttribute("zIndex"),opacity:b.getAttribute("opacity"),color:b.getAttribute("color"),pointColor:b.getAttribute("pointColor"),count:Number(b.getAttribute("count"))||99}))}(); diff --git a/dist/canvas-nest.min.js b/dist/canvas-nest.min.js deleted file mode 100644 index 006aada..0000000 --- a/dist/canvas-nest.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Copyright (c) 2016 hustcc - * License: MIT - * Version: v1.0.1 - * GitHub: https://github.com/hustcc/canvas-nest.js -**/ -!function(){function n(n,e,t){return n.getAttribute(e)||t}function e(n){return document.getElementsByTagName(n)}function t(){var t=e("script"),o=t.length,i=t[o-1];return{l:o,z:n(i,"zIndex",-1),o:n(i,"opacity",.5),c:n(i,"color","0,0,0"),n:n(i,"count",99)}}function o(){a=m.width=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth,c=m.height=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight}function i(){r.clearRect(0,0,a,c);var n,e,t,o,m,l;s.forEach(function(i,x){for(i.x+=i.xa,i.y+=i.ya,i.xa*=i.x>a||i.x<0?-1:1,i.ya*=i.y>c||i.y<0?-1:1,r.fillRect(i.x-.5,i.y-.5,1,1),e=x+1;e=n.max/2&&(i.x-=.03*o,i.y-=.03*m),t=(n.max-l)/n.max,r.beginPath(),r.lineWidth=t/2,r.strokeStyle="rgba("+d.c+","+(t+.2)+")",r.moveTo(i.x,i.y),r.lineTo(n.x,n.y),r.stroke()))}),x(i)}var a,c,u,m=document.createElement("canvas"),d=t(),l="c_n"+d.l,r=m.getContext("2d"),x=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(n){window.setTimeout(n,1e3/45)},w=Math.random,y={x:null,y:null,max:2e4};m.id=l,m.style.cssText="position:fixed;top:0;left:0;z-index:"+d.z+";opacity:"+d.o,e("body")[0].appendChild(m),o(),window.onresize=o,window.onmousemove=function(n){n=n||window.event,y.x=n.clientX,y.y=n.clientY},window.onmouseout=function(){y.x=null,y.y=null};for(var s=[],f=0;d.n>f;f++){var h=w()*a,g=w()*c,v=2*w()-1,p=2*w()-1;s.push({x:h,y:g,xa:v,ya:p,max:6e3})}u=s.concat([y]),setTimeout(function(){i()},100)}(); \ No newline at end of file diff --git a/dist/canvas-nest.umd.js b/dist/canvas-nest.umd.js new file mode 100644 index 0000000..858c06d --- /dev/null +++ b/dist/canvas-nest.umd.js @@ -0,0 +1 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.CanvasNest=t()}(this,function(){"use strict";function e(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function t(e,t){return e(t={exports:{}},t.exports),t.exports}var n=t(function(e,t){Object.defineProperty(t,"__esModule",{value:!0});var n=1;t.default=function(){return""+n++},e.exports=t.default});e(n);var o=t(function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:30,n=null;return function(){for(var o=this,i=arguments.length,r=Array(i),a=0;an||r.x<0?-1:1,r.ya*=r.y>o||r.y<0?-1:1,t.fillStyle="rgba("+e.c.pointColor+")",t.fillRect(r.x-.5,r.y-.5,1,1),u=v+1;u=s.max/2&&(r.x-=.03*l,r.y-=.03*d),c=(s.max-f)/s.max,t.beginPath(),t.lineWidth=c/2,t.strokeStyle="rgba("+e.c.color+","+(c+.2)+")",t.moveTo(r.x,r.y),t.lineTo(s.x,s.y),t.stroke()))}),this.requestFrame(this.drawCanvas)}},{key:"destroy",value:function(){l(this.el),window.onmousemove=this.onmousemove,window.onmouseout=this.onmouseout,v(this.tid),this.canvas.parentNode.removeChild(this.canvas)}}]),e}();return y.version="2.0.4",y}); diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index f106eaa..0000000 --- a/gulpfile.js +++ /dev/null @@ -1,16 +0,0 @@ -const fs = require('fs'); -const gulp = require('gulp'); -const uglify = require('gulp-uglify'); -const rename = require("gulp-rename"); -const injectVersion = require('gulp-inject-version'); - -gulp.task('mini', () => ( - gulp.src('src/canvas-nest.js') - .pipe(injectVersion()) - .pipe(gulp.dest('dist/')) - .pipe(uglify({ - preserveComments: 'license' - })) //uglify - .pipe(rename("canvas-nest.min.js")) - .pipe(gulp.dest('dist/')) -)); \ No newline at end of file diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..d4c7f4a --- /dev/null +++ b/index.d.ts @@ -0,0 +1,30 @@ +declare module 'canvas-nest.js' { + interface configType { + /** + * 线条颜色, 默认: '0,0,0' ;三个数字分别为(R,G,B),注意用,分割 + */ + color?: string; + + /** + * 线条的总数量, 默认: 150 + */ + count?: number; + + /** + * 背景的z-index属性,css属性用于控制所在层的位置, 默认: -1 + */ + zIndex?: number; + + /** + * 线条透明度(0~1), 默认: 0.5 + */ + opacity?: number; + } + + class CanvasNest { + constructor(element: Element, config?: configType) + destroy(): void; + } + + export default CanvasNest; +} \ No newline at end of file diff --git a/index.html b/index.html index ffab0eb..348c560 100644 --- a/index.html +++ b/index.html @@ -4,28 +4,66 @@ canvas-nest.js - + + -
+
+ +
- + + diff --git a/lib/CanvasNest.js b/lib/CanvasNest.js new file mode 100644 index 0000000..37bff66 --- /dev/null +++ b/lib/CanvasNest.js @@ -0,0 +1,178 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; + +var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /** + * Created by hustcc on 18/6/23. + * Contract: i@hust.cc + */ + +var _sizeSensor = require('size-sensor'); + +var _utils = require('./utils'); + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var CanvasNest = function () { + function CanvasNest(el, config) { + var _this = this; + + _classCallCheck(this, CanvasNest); + + this.randomPoints = function () { + return (0, _utils.range)(_this.c.count).map(function () { + return { + x: Math.random() * _this.canvas.width, + y: Math.random() * _this.canvas.height, + xa: 2 * Math.random() - 1, // 随机运动返现 + ya: 2 * Math.random() - 1, + max: 6000 // 沾附距离 + }; + }); + }; + + this.el = el; + + this.c = _extends({ + zIndex: -1, // z-index + opacity: 0.5, // opacity + color: '0,0,0', // color of lines + pointColor: '0,0,0', // color of points + count: 99 }, config); + + this.canvas = this.newCanvas(); + this.context = this.canvas.getContext('2d'); + + this.points = this.randomPoints(); + this.current = { + x: null, // 当前鼠标x + y: null, // 当前鼠标y + max: 20000 // 圈半径的平方 + }; + this.all = this.points.concat([this.current]); + + this.bindEvent(); + + this.requestFrame(this.drawCanvas); + } + + _createClass(CanvasNest, [{ + key: 'bindEvent', + value: function bindEvent() { + var _this2 = this; + + (0, _sizeSensor.bind)(this.el, function () { + _this2.canvas.width = _this2.el.clientWidth; + _this2.canvas.height = _this2.el.clientHeight; + }); + + this.onmousemove = window.onmousemove; + window.onmousemove = function (e) { + _this2.current.x = e.clientX - _this2.el.offsetLeft + document.scrollingElement.scrollLeft; // 当存在横向滚动条时,x坐标再往右移动滚动条拉动的距离 + _this2.current.y = e.clientY - _this2.el.offsetTop + document.scrollingElement.scrollTop; // 当存在纵向滚动条时,y坐标再往下移动滚动条拉动的距离 + _this2.onmousemove && _this2.onmousemove(e); + }; + + this.onmouseout = window.onmouseout; + window.onmouseout = function () { + _this2.current.x = null; + _this2.current.y = null; + _this2.onmouseout && _this2.onmouseout(); + }; + } + }, { + key: 'newCanvas', + value: function newCanvas() { + if (getComputedStyle(this.el).position === 'static') { + this.el.style.position = 'relative'; + } + var canvas = document.createElement('canvas'); // 画布 + canvas.style.cssText = (0, _utils.canvasStyle)(this.c); + + canvas.width = this.el.clientWidth; + canvas.height = this.el.clientHeight; + + this.el.appendChild(canvas); + return canvas; + } + }, { + key: 'requestFrame', + value: function requestFrame(func) { + var _this3 = this; + + this.tid = (0, _utils.requestAnimationFrame)(function () { + return func.call(_this3); + }); + } + }, { + key: 'drawCanvas', + value: function drawCanvas() { + var _this4 = this; + + var context = this.context; + var width = this.canvas.width; + var height = this.canvas.height; + var current = this.current; + var points = this.points; + var all = this.all; + + context.clearRect(0, 0, width, height); + // 随机的线条和当前位置联合数组 + var e = void 0, + i = void 0, + d = void 0, + x_dist = void 0, + y_dist = void 0, + dist = void 0; // 临时节点 + // 遍历处理每一个点 + points.forEach(function (r, idx) { + r.x += r.xa; + r.y += r.ya; // 移动 + r.xa *= r.x > width || r.x < 0 ? -1 : 1; + r.ya *= r.y > height || r.y < 0 ? -1 : 1; // 碰到边界,反向反弹 + context.fillStyle = 'rgba(' + _this4.c.pointColor + ')'; + context.fillRect(r.x - 0.5, r.y - 0.5, 1, 1); // 绘制一个宽高为1的点 + // 从下一个点开始 + for (i = idx + 1; i < all.length; i++) { + e = all[i]; + // 当前点存在 + if (null !== e.x && null !== e.y) { + x_dist = r.x - e.x; // x轴距离 l + y_dist = r.y - e.y; // y轴距离 n + dist = x_dist * x_dist + y_dist * y_dist; // 总距离, m + + dist < e.max && (e === current && dist >= e.max / 2 && (r.x -= 0.03 * x_dist, r.y -= 0.03 * y_dist), // 靠近的时候加速 + d = (e.max - dist) / e.max, context.beginPath(), context.lineWidth = d / 2, context.strokeStyle = 'rgba(' + _this4.c.color + ',' + (d + 0.2) + ')', context.moveTo(r.x, r.y), context.lineTo(e.x, e.y), context.stroke()); + } + } + }); + this.requestFrame(this.drawCanvas); + } + }, { + key: 'destroy', + value: function destroy() { + // 清除事件 + (0, _sizeSensor.clear)(this.el); + + // mouse 事件清除 + window.onmousemove = this.onmousemove; // 回滚方法 + window.onmouseout = this.onmouseout; + + // 删除轮询 + (0, _utils.cancelAnimationFrame)(this.tid); + + // 删除 dom + this.canvas.parentNode.removeChild(this.canvas); + } + }]); + + return CanvasNest; +}(); + +CanvasNest.version = '2.0.4'; +exports.default = CanvasNest; +module.exports = exports['default']; \ No newline at end of file diff --git a/lib/iife.js b/lib/iife.js new file mode 100644 index 0000000..2b933cc --- /dev/null +++ b/lib/iife.js @@ -0,0 +1,25 @@ +'use strict'; + +var _CanvasNest = require('./CanvasNest'); + +var _CanvasNest2 = _interopRequireDefault(_CanvasNest); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var getScriptConfig = function getScriptConfig() { + var scripts = document.getElementsByTagName('script'); + var len = scripts.length; + var script = scripts[len - 1]; // 当前加载的script + return { + zIndex: script.getAttribute('zIndex'), + opacity: script.getAttribute('opacity'), + color: script.getAttribute('color'), + pointColor: script.getAttribute('pointColor'), + count: Number(script.getAttribute('count')) || 99 + }; +}; /** + * Created by hustcc on 18/6/23. + * Contract: i@hust.cc + */ + +new _CanvasNest2.default(document.body, getScriptConfig()); \ No newline at end of file diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..fbcaf1b --- /dev/null +++ b/lib/index.js @@ -0,0 +1,18 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _CanvasNest = require('./CanvasNest'); + +var _CanvasNest2 = _interopRequireDefault(_CanvasNest); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = _CanvasNest2.default; /** + * Created by hustcc on 18/6/23. + * Contract: i@hust.cc + */ + +module.exports = exports['default']; \ No newline at end of file diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 0000000..2dedd78 --- /dev/null +++ b/lib/utils.js @@ -0,0 +1,25 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +/** + * Created by hustcc on 18/6/23. + * Contract: i@hust.cc + */ + +var requestAnimationFrame = exports.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || window.oRequestAnimationFrame || function (func) { + return window.setTimeout(func, 1000 / 60); +}; + +var cancelAnimationFrame = exports.cancelAnimationFrame = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.msCancelAnimationFrame || window.oCancelAnimationFrame || window.clearTimeout; + +var range = exports.range = function range(n) { + return new Array(n).fill(0).map(function (e, idx) { + return idx; + }); +}; + +var canvasStyle = exports.canvasStyle = function canvasStyle(config) { + return "display:block;position:absolute;top:0;left:0;height:100%;width:100%;overflow:hidden;pointer-events:none;z-index:" + config.zIndex + ";opacity:" + config.opacity; +}; \ No newline at end of file diff --git a/package.json b/package.json index 4849913..d3ddaad 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,42 @@ { "name": "canvas-nest.js", "officialName": "canvas-nest.js", - "version": "1.0.1", + "version": "2.0.4", + "main": "lib/index.js", "summary": "A nest backgroud of website draw on canvas use javascript, do not depends on jQuery.", "description": "A nest backgroud of website draw on canvas use javascript, do not depends on jQuery.", + "scripts": { + "test": "npm run size", + "size": "size-limit", + "build:lib": "rimraf ./lib && cross-env NODE_ENV=babel babel src -d lib", + "build:umd": "cross-env NODE_ENV=rollup rollup -c rollup.config.umd.js", + "build:iife": "cross-env NODE_ENV=rollup rollup -c rollup.config.iife.js", + "build": "npm run build:umd && npm run build:iife && npm run build:lib && npm run test" + }, + "dependencies": { + "size-sensor": "^0.2.0" + }, + "size-limit": [ + { + "limit": "2.5 KB", + "path": "dist/canvas-nest.umd.js" + }, + { + "limit": "2.5 KB", + "path": "dist/canvas-nest.js" + } + ], "author": { "name": "hustcc", "url": "https://github.com/hustcc" }, - "homepage": "http://www.atool.org", + "homepage": "https://atool.vip", "license": "MIT", "keywords": [ "canvas", "html5", "nest" ], - "main": "dist/canvas-nest.min.js", "repository": { "type": "git", "url": "https://github.com/hustcc/canvas-nest.js" @@ -24,17 +45,21 @@ "url": "https://github.com/hustcc/canvas-nest.js/issues" }, "devDependencies": { - "gulp": "^3.9.0", - "gulp-uglify": "^1.5.3", - "jshint": "^2.9.2", - "gulp-rename": "^1.2.2", - "gulp-inject-version": "^1.0.1" - }, - "scripts": { - "lint": "jshint src/canvas-nest.js", - "test": "npm run lint", - "build": "gulp mini && npm run test" - }, - "dependencies": { + "babel-cli": "^6.26.0", + "babel-plugin-add-module-exports": "^0.2.1", + "babel-plugin-transform-class-properties": "^6.24.1", + "babel-plugin-transform-object-rest-spread": "^6.26.0", + "babel-plugin-version": "^0.2.1", + "babel-preset-env": "^1.6.1", + "cross-env": "^5.1.3", + "jest": "^24.9.0", + "jest-electron": "^0.1.6", + "rimraf": "^2.6.2", + "rollup": "^0.58.1", + "rollup-plugin-babel": "^3.0.4", + "rollup-plugin-commonjs": "^9.1.3", + "rollup-plugin-node-resolve": "^3.3.0", + "rollup-plugin-uglify": "^3.0.0", + "size-limit": "^0.18.0" } -} \ No newline at end of file +} diff --git a/rollup.config.iife.js b/rollup.config.iife.js new file mode 100644 index 0000000..699fce1 --- /dev/null +++ b/rollup.config.iife.js @@ -0,0 +1,29 @@ +/** + * Created by hustcc on 18/6/23. + * Contract: i@hust.cc + */ + +import uglify from 'rollup-plugin-uglify'; +import babel from 'rollup-plugin-babel'; +import resolve from 'rollup-plugin-node-resolve'; +import commonjs from 'rollup-plugin-commonjs'; + +export default { + input: 'src/iife.js', + output: { + file: 'dist/canvas-nest.js', + format: 'iife', + }, + plugins: [ + resolve(), + babel({ + exclude: 'node_modules/**', + }), + commonjs(), + uglify({ + output: { comments: false }, + compress: { warnings: false } + }), + ], + external: [], +}; diff --git a/rollup.config.umd.js b/rollup.config.umd.js new file mode 100644 index 0000000..ad79cfe --- /dev/null +++ b/rollup.config.umd.js @@ -0,0 +1,30 @@ +/** + * Created by hustcc on 18/6/23. + * Contract: i@hust.cc + */ + +import uglify from 'rollup-plugin-uglify'; +import babel from 'rollup-plugin-babel'; +import resolve from 'rollup-plugin-node-resolve'; +import commonjs from 'rollup-plugin-commonjs'; + +export default { + input: 'src/index.js', + output: { + file: 'dist/canvas-nest.umd.js', + name: 'CanvasNest', + format: 'umd', + }, + plugins: [ + resolve(), + babel({ + exclude: 'node_modules/**', + }), + commonjs(), + uglify({ + output: { comments: false }, + compress: { warnings: false } + }), + ], + external: [], +}; diff --git a/screenshot.png b/screenshot.png index f2263a9..e558f61 100644 Binary files a/screenshot.png and b/screenshot.png differ diff --git a/src/CanvasNest.js b/src/CanvasNest.js new file mode 100644 index 0000000..7b086fc --- /dev/null +++ b/src/CanvasNest.js @@ -0,0 +1,146 @@ +/** + * Created by hustcc on 18/6/23. + * Contract: i@hust.cc + */ + +import { bind, clear } from 'size-sensor'; +import { requestAnimationFrame, cancelAnimationFrame, range, canvasStyle } from './utils'; + +export default class CanvasNest { + + static version = __VERSION__; + + constructor(el, config) { + this.el = el; + + this.c = { + zIndex: -1, // z-index + opacity: 0.5, // opacity + color: '0,0,0', // color of lines + pointColor: '0,0,0', // color of points + count: 99, // count + ...config, + }; + + this.canvas = this.newCanvas(); + this.context = this.canvas.getContext('2d'); + + this.points = this.randomPoints(); + this.current = { + x: null, // 当前鼠标x + y: null, // 当前鼠标y + max: 20000 // 圈半径的平方 + }; + this.all = this.points.concat([this.current]); + + this.bindEvent(); + + this.requestFrame(this.drawCanvas); + } + + bindEvent() { + bind(this.el, () => { + this.canvas.width = this.el.clientWidth; + this.canvas.height = this.el.clientHeight; + }); + + this.onmousemove = window.onmousemove; + window.onmousemove = e => { + this.current.x = e.clientX - this.el.offsetLeft + document.scrollingElement.scrollLeft; // 当存在横向滚动条时,x坐标再往右移动滚动条拉动的距离 + this.current.y = e.clientY - this.el.offsetTop + document.scrollingElement.scrollTop; // 当存在纵向滚动条时,y坐标再往下移动滚动条拉动的距离 + this.onmousemove && this.onmousemove(e); + }; + + this.onmouseout = window.onmouseout; + window.onmouseout = () => { + this.current.x = null; + this.current.y = null; + this.onmouseout && this.onmouseout(); + }; + } + + randomPoints = () => { + return range(this.c.count).map(() => ({ + x: Math.random() * this.canvas.width, + y: Math.random() * this.canvas.height, + xa: 2 * Math.random() - 1, // 随机运动返现 + ya: 2 * Math.random() - 1, + max: 6000 // 沾附距离 + })); + }; + + newCanvas() { + if (getComputedStyle(this.el).position === 'static') { + this.el.style.position = 'relative' + } + const canvas = document.createElement('canvas'); // 画布 + canvas.style.cssText = canvasStyle(this.c); + + canvas.width = this.el.clientWidth; + canvas.height = this.el.clientHeight; + + this.el.appendChild(canvas); + return canvas; + } + + requestFrame(func) { + this.tid = requestAnimationFrame(() => func.call(this)); + } + + drawCanvas() { + const context = this.context; + const width = this.canvas.width; + const height = this.canvas.height; + const current = this.current; + const points = this.points; + const all = this.all; + + context.clearRect(0, 0, width, height); + // 随机的线条和当前位置联合数组 + let e, i, d, x_dist, y_dist, dist; // 临时节点 + // 遍历处理每一个点 + points.forEach((r, idx) => { + r.x += r.xa; + r.y += r.ya; // 移动 + r.xa *= r.x > width || r.x < 0 ? -1 : 1; + r.ya *= r.y > height || r.y < 0 ? -1 : 1; // 碰到边界,反向反弹 + context.fillStyle = `rgba(${this.c.pointColor})`; + context.fillRect(r.x - 0.5, r.y - 0.5, 1, 1); // 绘制一个宽高为1的点 + // 从下一个点开始 + for (i = idx + 1; i < all.length; i ++) { + e = all[i]; + // 当前点存在 + if (null !== e.x && null !== e.y) { + x_dist = r.x - e.x; // x轴距离 l + y_dist = r.y - e.y; // y轴距离 n + dist = x_dist * x_dist + y_dist * y_dist; // 总距离, m + + dist < e.max && (e === current && dist >= e.max / 2 && (r.x -= 0.03 * x_dist, r.y -= 0.03 * y_dist), // 靠近的时候加速 + d = (e.max - dist) / e.max, + context.beginPath(), + context.lineWidth = d / 2, + context.strokeStyle = `rgba(${this.c.color},${d + 0.2})`, + context.moveTo(r.x, r.y), + context.lineTo(e.x, e.y), + context.stroke()); + } + } + }); + this.requestFrame(this.drawCanvas); + } + + destroy() { + // 清除事件 + clear(this.el); + + // mouse 事件清除 + window.onmousemove = this.onmousemove; // 回滚方法 + window.onmouseout = this.onmouseout; + + // 删除轮询 + cancelAnimationFrame(this.tid); + + // 删除 dom + this.canvas.parentNode.removeChild(this.canvas); + } +} diff --git a/src/canvas-nest.js b/src/canvas-nest.js deleted file mode 100644 index 88f859a..0000000 --- a/src/canvas-nest.js +++ /dev/null @@ -1,118 +0,0 @@ -/** - * Copyright (c) 2016 hustcc - * License: MIT - * Version: %%GULP_INJECT_VERSION%% - * GitHub: https://github.com/hustcc/canvas-nest.js -**/ -! function() { - //封装方法,压缩之后减少文件大小 - function get_attribute(node, attr, default_value) { - return node.getAttribute(attr) || default_value; - } - //封装方法,压缩之后减少文件大小 - function get_by_tagname(name) { - return document.getElementsByTagName(name); - } - //获取配置参数 - function get_config_option() { - var scripts = get_by_tagname("script"), - script_len = scripts.length, - script = scripts[script_len - 1]; //当前加载的script - return { - l: script_len, //长度,用于生成id用 - z: get_attribute(script, "zIndex", -1), //z-index - o: get_attribute(script, "opacity", 0.5), //opacity - c: get_attribute(script, "color", "0,0,0"), //color - n: get_attribute(script, "count", 99) //count - }; - } - //设置canvas的高宽 - function set_canvas_size() { - canvas_width = the_canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, - canvas_height = the_canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; - } - - //绘制过程 - function draw_canvas() { - context.clearRect(0, 0, canvas_width, canvas_height); - //随机的线条和当前位置联合数组 - var e, i, d, x_dist, y_dist, dist; //临时节点 - //遍历处理每一个点 - random_points.forEach(function(r, idx) { - r.x += r.xa, - r.y += r.ya, //移动 - r.xa *= r.x > canvas_width || r.x < 0 ? -1 : 1, - r.ya *= r.y > canvas_height || r.y < 0 ? -1 : 1, //碰到边界,反向反弹 - context.fillRect(r.x - 0.5, r.y - 0.5, 1, 1); //绘制一个宽高为1的点 - //从下一个点开始 - for (i = idx + 1; i < all_array.length; i++) { - e = all_array[i]; - // 当前点存在 - if (null !== e.x && null !== e.y) { - x_dist = r.x - e.x; //x轴距离 l - y_dist = r.y - e.y; //y轴距离 n - dist = x_dist * x_dist + y_dist * y_dist; //总距离, m - - dist < e.max && (e === current_point && dist >= e.max / 2 && (r.x -= 0.03 * x_dist, r.y -= 0.03 * y_dist), //靠近的时候加速 - d = (e.max - dist) / e.max, - context.beginPath(), - context.lineWidth = d / 2, - context.strokeStyle = "rgba(" + config.c + "," + (d + 0.2) + ")", - context.moveTo(r.x, r.y), - context.lineTo(e.x, e.y), - context.stroke()); - } - } - }), frame_func(draw_canvas); - } - //创建画布,并添加到body中 - var the_canvas = document.createElement("canvas"), //画布 - config = get_config_option(), //配置 - canvas_id = "c_n" + config.l, //canvas id - context = the_canvas.getContext("2d"), canvas_width, canvas_height, - frame_func = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(func) { - window.setTimeout(func, 1000 / 60); - }, random = Math.random, - current_point = { - x: null, //当前鼠标x - y: null, //当前鼠标y - max: 20000 // 圈半径的平方 - }, - all_array; - the_canvas.id = canvas_id; - the_canvas.style.cssText = "position:fixed;top:0;left:0;z-index:" + config.z + ";opacity:" + config.o; - get_by_tagname("body")[0].appendChild(the_canvas); - - //初始化画布大小 - set_canvas_size(); - window.onresize = set_canvas_size; - //当时鼠标位置存储,离开的时候,释放当前位置信息 - window.onmousemove = function(e) { - e = e || window.event; - current_point.x = e.clientX; - current_point.y = e.clientY; - }, window.onmouseout = function() { - current_point.x = null; - current_point.y = null; - }; - //随机生成config.n条线位置信息 - for (var random_points = [], i = 0; config.n > i; i++) { - var x = random() * canvas_width, //随机位置 - y = random() * canvas_height, - xa = 2 * random() - 1, //随机运动方向 - ya = 2 * random() - 1; - // 随机点 - random_points.push({ - x: x, - y: y, - xa: xa, - ya: ya, - max: 6000 //沾附距离 - }); - } - all_array = random_points.concat([current_point]); - //0.1秒后绘制 - setTimeout(function() { - frame_func(draw_canvas); - }, 100); -}(); diff --git a/src/iife.js b/src/iife.js new file mode 100644 index 0000000..0411003 --- /dev/null +++ b/src/iife.js @@ -0,0 +1,21 @@ +/** + * Created by hustcc on 18/6/23. + * Contract: i@hust.cc + */ + +import CanvasNest from './CanvasNest'; + +const getScriptConfig = () => { + const scripts = document.getElementsByTagName('script'); + const len = scripts.length; + const script = scripts[len - 1]; // 当前加载的script + return { + zIndex: script.getAttribute('zIndex'), + opacity: script.getAttribute('opacity'), + color: script.getAttribute('color'), + pointColor: script.getAttribute('pointColor'), + count: Number(script.getAttribute('count')) || 99, + }; +}; + +new CanvasNest(document.body, getScriptConfig()); diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..c604ed1 --- /dev/null +++ b/src/index.js @@ -0,0 +1,8 @@ +/** + * Created by hustcc on 18/6/23. + * Contract: i@hust.cc + */ + +import CanvasNest from './CanvasNest'; + +export default CanvasNest; diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..756fb53 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,26 @@ +/** + * Created by hustcc on 18/6/23. + * Contract: i@hust.cc + */ + +export const requestAnimationFrame = window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.msRequestAnimationFrame || + window.oRequestAnimationFrame || + function(func) { + return window.setTimeout(func, 1000 / 60); + }; + +export const cancelAnimationFrame = window.cancelAnimationFrame || + window.webkitCancelAnimationFrame || + window.mozCancelAnimationFrame || + window.msCancelAnimationFrame || + window.oCancelAnimationFrame || + window.clearTimeout; + +export const range = n => + new Array(n).fill(0).map((e, idx) => idx); + +export const canvasStyle = config => + `display:block;position:absolute;top:0;left:0;height:100%;width:100%;overflow:hidden;pointer-events:none;z-index:${config.zIndex};opacity:${config.opacity}`;