canvas 绘制的网页背景效果

This commit is contained in:
lqs 2025-01-18 09:03:48 +00:00
commit 552a4a05fe
22 changed files with 18381 additions and 0 deletions

28
.babelrc Normal file
View File

@ -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"
]
}
}
}

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
.project
.settings
.idea
node_modules/*
*.lock
*.log

22
LICENSE Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Hust.cc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

124
README-zh.md Normal file
View File

@ -0,0 +1,124 @@
# canvas-nest.js
> 一个基于 html5 canvas 绘制的网页背景效果。
[![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。
- 非常小,只有 2 Kb。
- 非常容易实现,配置简单,即使你不是 web 开发者,也能简单搞定。
- 模块化 & 区域渲染。
## 使用
- 快捷使用
将下面的代码插入到 `<body> 和 </body> 之间`.
```html
<script type="text/javascript" src="dist/canvas-nest.js"></script>
```
强烈建议在 `</body>`标签上方. 例如下面的代码结构:
```html
<html>
<head>
...
</head>
<body>
...
...
<script type="text/javascript" src="dist/canvas-nest.js"></script>
</body>
</html>
```
然后就完成了,打开网页即可看到效果!`请注意不要将代码置于 <head> </head>里面`.
- 模块化区域绘制(定制开发)
完成安装好,可以使用模块化方式 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`
Example:
- 快捷使用
```html
<script type="text/javascript" color="0,0,255" opacity='0.7' zIndex="-2" count="99" src="dist/canvas-nest.js"></script>
```
- 模块化区域绘制(定制开发)
```js
{
color: '0,0,255',
opacity: 0.7,
zIndex: -2,
count: 99,
};
```
**注意: 所有的配置项都有默认值,如果你不知道怎么设置,可以先不设置这些配置项,就使用默认值看看效果也可以的。**
## 相关项目
- [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-nest): vscode 扩展, 在vscode扩展市场中搜索`nest` 即可安装。
## 使用项目
- [A Tool](https://atool.vip): 一个好用的工具集合.
## License
MIT@[hustcc](https://github.com/hustcc).

126
README.md Normal file
View File

@ -0,0 +1,126 @@
# canvas-nest.js
> A nest background of website draw on canvas. [中文 Readme 帮助文档](README-zh.md).
[![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
- 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.
## Install
```sh
# use npm
npm install --save canvas-nest.js
# or use yarn
yarn add canvas-nest.js
```
## Usage
- Script tag
Insert the code below `between <body> and </body>`.
```html
<script src="dist/canvas-nest.js"></script>
```
Strongly suggest to insert before the tag `</body>`, as the following:
```html
<html>
<head>
...
</head>
<body>
...
...
<script src="dist/canvas-nest.js"></script>
</body>
</html>
```
Then ok! `Please do not add the code in the <head> </head>`.
- Modular usage (Area render)
After installation, you can import this as module.
There is only one API, use it as below:
```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
<script type="text/javascript" color="0,0,255" opacity='0.7' zIndex="-2" count="99" src="dist/canvas-nest.js"></script>
```
- Modular usage (Area render)
```js
{
color: '0,0,255',
opacity: 0.7,
zIndex: -2,
count: 99,
};
```
**Note: If the Configuration isn't customized, default values are available as well.**
## Related projects
- [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.
## Used by
- [A Tool](https://atool.vip): a convenient tool box.
## License
MIT@[hustcc](https://github.com/hustcc).

1
dist/canvas-nest.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/canvas-nest.umd.js vendored Normal file

File diff suppressed because one or more lines are too long

30
index.d.ts vendored Normal file
View File

@ -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;
}

69
index.html Normal file
View File

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>canvas-nest.js</title>
<style>
* {
margin: 0;
padding: 0;
}
html, body {
height: 100%;
width: 100%;
}
#github-iframe {
position: fixed;
left: 32px;
top: 32px;
}
#area-render {
position: fixed;
width: 320px;
height: 160px;
right: 4px;
bottom: 4px;
border: dashed 1px #ccc;
}
</style>
</head>
<body>
<div id="github-iframe"></div>
<div id="area-render"></div>
<script type="text/javascript" color="255,0,0" pointColor="255,0,0" opacity='0.7' zIndex="-2" count="100" src="dist/canvas-nest.js"></script>
<script type="text/javascript" src="dist/canvas-nest.umd.js"></script>
<script type="text/javascript">
var cn = new CanvasNest(document.getElementById('area-render'), {
color: '255,0,255',
count: 50,
});
// 下面为其他 js无需关注
function asyncLoad() {
//async load github
var i = document.createElement("iframe");
i.src = "https://ghbtns.com/github-btn.html?user=hustcc&repo=canvas-nest.js&type=star&count=true";
i.scrolling = "no";
i.frameborder = "0";
i.border = "0";
i.setAttribute("frameborder", "0", 0);
i.width = "100px";
i.height = "20px";
document.getElementById("github-iframe").appendChild(i);
}
function loadGitHubBtn() {
if (window.addEventListener) {window.addEventListener("load", asyncLoad, false);}
else if (window.attachEvent) {window.attachEvent("onload", asyncLoad);}
else {window.onload = asyncLoad;}
}
loadGitHubBtn();
</script>
</body>
</html>

178
lib/CanvasNest.js Normal file
View File

@ -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'];

25
lib/iife.js Normal file
View File

@ -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());

18
lib/index.js Normal file
View File

@ -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'];

25
lib/utils.js Normal file
View File

@ -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;
};

17402
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

66
package.json Normal file
View File

@ -0,0 +1,66 @@
{
"name": "canvas-nest.js",
"officialName": "canvas-nest.js",
"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": {
"canvas-nest.js": "^2.0.4",
"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": "https://atool.vip",
"license": "MIT",
"keywords": [
"canvas",
"html5",
"nest"
],
"repository": {
"type": "git",
"url": "https://github.com/hustcc/canvas-nest.js"
},
"bugs": {
"url": "https://github.com/hustcc/canvas-nest.js/issues"
},
"devDependencies": {
"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"
}
}

29
rollup.config.iife.js Normal file
View File

@ -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: [],
};

30
rollup.config.umd.js Normal file
View File

@ -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: [],
};

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

146
src/CanvasNest.js Normal file
View File

@ -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);
}
}

21
src/iife.js Normal file
View File

@ -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());

8
src/index.js Normal file
View File

@ -0,0 +1,8 @@
/**
* Created by hustcc on 18/6/23.
* Contract: i@hust.cc
*/
import CanvasNest from './CanvasNest';
export default CanvasNest;

26
src/utils.js Normal file
View File

@ -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}`;