├── example ├── .gitignore ├── .babelrc ├── .eslintrc ├── .editorconfig ├── src │ ├── index.html │ └── app.js ├── webpack.config.js └── package.json ├── .gitignore ├── .babelrc ├── .eslintrc ├── .editorconfig ├── src ├── particle-line │ ├── color.js │ ├── dot.js │ └── index.js └── index.js ├── package.json ├── README.md └── lib ├── particle-line ├── color.js ├── dot.js └── index.js └── index.js /example/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | *.log 4 | package-lock.json -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | *.log 4 | package-lock.json 5 | yarn 6 | yarn.lock -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react"], 3 | "plugins": ["@babel/plugin-proposal-class-properties"] 4 | } -------------------------------------------------------------------------------- /example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env", "@babel/preset-react"], 3 | "plugins": ["@babel/plugin-proposal-class-properties"] 4 | } -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "browser": true, 5 | "node": true, 6 | "es6": true, 7 | "jest": true 8 | }, 9 | "extends": "airbnb", 10 | "rules": { 11 | "no-unused-vars": 0, 12 | "react/require-default-props": 0 13 | } 14 | } -------------------------------------------------------------------------------- /example/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "browser": true, 5 | "node": true, 6 | "es6": true, 7 | "jest": true 8 | }, 9 | "extends": "airbnb", 10 | "rules": { 11 | "no-unused-vars": 0, 12 | "react/require-default-props": 0 13 | } 14 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # Unix-style newlines with a newline ending every file 5 | [*] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | charset = utf-8 9 | 10 | # Indentation override for all files 11 | [*] 12 | indent_style = space 13 | indent_size = 2 14 | trim_trailing_whitespace: true -------------------------------------------------------------------------------- /example/.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # Unix-style newlines with a newline ending every file 5 | [*] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | charset = utf-8 9 | 10 | # Indentation override for all files 11 | [*] 12 | indent_style = space 13 | indent_size = 2 14 | trim_trailing_whitespace: true -------------------------------------------------------------------------------- /example/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 基于 React 的线性粒子背景 8 | 9 | 10 |
11 | 12 | -------------------------------------------------------------------------------- /example/src/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import styled from 'styled-components' 4 | import ReactParticleLine from 'react-particle-line' 5 | 6 | const Home = styled.div` 7 | height: 100vh; 8 | `; 9 | 10 | const App = () => 11 | render(, document.getElementById('root')) -------------------------------------------------------------------------------- /src/particle-line/color.js: -------------------------------------------------------------------------------- 1 | export default class Color { 2 | constructor (min) { 3 | this.min = min || 0 4 | this._init(this.min) 5 | } 6 | 7 | _init (min) { 8 | this.r = this.colorValue(min) 9 | this.g = this.colorValue(min) 10 | this.b = this.colorValue(min) 11 | this.style = this.createColorStyle(this.r, this.g, this.b) 12 | } 13 | 14 | colorValue (min) { 15 | return Math.floor(Math.random() * 255 + min) 16 | } 17 | 18 | createColorStyle (r, g, b) { 19 | return `rgba(${r}, ${g}, ${b}, .8)` 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/particle-line/dot.js: -------------------------------------------------------------------------------- 1 | import Color from './color' 2 | 3 | export default class Dot { 4 | constructor (ctx, canvasWidth, canvasHeight, x, y) { 5 | this.ctx = ctx 6 | this.x = x || Math.random() * canvasWidth 7 | this.y = y || Math.random() * canvasHeight 8 | this._init() 9 | } 10 | 11 | _init () { 12 | this.vx = -0.5 + Math.random() 13 | this.vy = -0.5 + Math.random() 14 | this.radius = Math.random() * 3 15 | this.color = new Color() 16 | } 17 | 18 | draw () { 19 | this.ctx.beginPath() 20 | this.ctx.fillStyle = this.color.style 21 | this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false) 22 | this.ctx.fill() 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require('path'); 2 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 3 | 4 | module.exports = { 5 | entry: resolve(__dirname, "./src/app.js"), 6 | output: { 7 | path: resolve(__dirname, "./dist"), 8 | filename: "bundle.js" 9 | }, 10 | module: { 11 | rules: [{ 12 | test: /\.(js|jsx)$/, 13 | use: "babel-loader", 14 | exclude: /node_modules/ 15 | }] 16 | }, 17 | plugins: [ 18 | new HtmlWebpackPlugin({ 19 | template: resolve(__dirname, './src/index.html'), 20 | // filename: "./index.html" 21 | }) 22 | ], 23 | resolve: { 24 | extensions: ['*', '.js', '.jsx', '.json'], 25 | }, 26 | devServer: { 27 | port: 3001 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-particle-line", 3 | "version": "0.1.0", 4 | "description": "基于 React 的线性粒子背景", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --open development", 8 | "build": "webpack --mode production", 9 | "deploy": "gh-pages -d example/dist", 10 | "publish-demo": "npm run build && npm run deploy" 11 | }, 12 | "author": "hzzly", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "@babel/cli": "^7.4.3", 16 | "@babel/core": "^7.4.3", 17 | "@babel/plugin-proposal-class-properties": "^7.4.0", 18 | "@babel/preset-env": "^7.4.3", 19 | "@babel/preset-react": "^7.0.0", 20 | "babel-loader": "^8.0.5", 21 | "html-webpack-plugin": "^3.2.0", 22 | "webpack": "^4.30.0", 23 | "webpack-cli": "^3.3.1", 24 | "webpack-dev-server": "^3.3.1" 25 | }, 26 | "dependencies": { 27 | "prop-types": "^15.7.2", 28 | "react": "^16.8.6", 29 | "react-dom": "^16.8.6", 30 | "styled-components": "^4.3.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-particle-line", 3 | "version": "0.1.9", 4 | "description": "基于 React 的线性粒子背景", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "compile": "rimraf lib && babel src --out-dir lib" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/hzzly/react-particle-line.git" 12 | }, 13 | "author": "hzzly", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/hzzly/react-particle-line/issues" 17 | }, 18 | 19 | "keywords": [ 20 | "react", 21 | "particle-line", 22 | "react-particle-line" 23 | ], 24 | "files": [ 25 | "lib/" 26 | ], 27 | "homepage": "https://github.com/hzzly/react-particle-line#readme", 28 | "dependencies": { 29 | "react": "^16.8.6", 30 | "prop-types": "^15.7.2", 31 | "styled-components": "^4.2.0" 32 | }, 33 | "peerDependencies": { 34 | "react": "^16.8.6", 35 | "prop-types": "^15.7.2" 36 | }, 37 | "devDependencies": { 38 | "@babel/cli": "^7.4.3", 39 | "@babel/core": "^7.4.3", 40 | "@babel/plugin-proposal-class-properties": "^7.4.0", 41 | "@babel/preset-env": "^7.4.3", 42 | "@babel/preset-react": "^7.0.0", 43 | "babel-loader": "^8.0.5", 44 | "rimraf": "^2.6.3" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## react-particle-line 2 | 3 | ![NPM version](https://img.shields.io/npm/v/react-particle-line.svg) 4 | ![MIT Licence](https://img.shields.io/npm/l/react-particle-line.svg) 5 | 6 | ### How to use 7 | ``` 8 | npm install react-particle-line --save 9 | ``` 10 | 11 | ### Examples 12 | ```javascript 13 | import React from 'react'; 14 | import ReactParticleLine from 'react-particle-line'; 15 | 16 | const Example = () => ( 17 | 18 | {/* ... */} 19 | 20 | ); 21 | 22 | export default Example; 23 | ``` 24 | 25 | ```javascript 26 | import React from 'react'; 27 | import ReactParticleLine from 'react-particle-line'; 28 | 29 | const Example = () => ( 30 | 36 | {/* ... */} 37 | 38 | ); 39 | 40 | export default Example; 41 | ``` 42 | 43 | ### Props 44 | 45 | | Prop | Type | Default | Description | 46 | | ------- | ----- | :------: | ----------- | 47 | | lineWidth | Number | 0.3 | connect line width | 48 | | dotsNumber | Number | 100 | dot number | 49 | | dotsDistance | Number | 100 | far as points to connect | 50 | | hoverEffect | Boolean | true | mouse hover events | 51 | 52 | ### License 53 | 54 | MIT 55 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import styled from 'styled-components'; 4 | import ParticleLine from './particle-line'; 5 | 6 | const ParticleLineWraper = styled.div` 7 | position: relative; 8 | width: 100%; 9 | height: 100%; 10 | `; 11 | const ChildWraper = styled.div` 12 | z-index: 1; 13 | `; 14 | const CanvasWraper = styled.canvas.attrs({ 15 | id: 'react-particle-line-canvas', 16 | })` 17 | position: absolute; 18 | top: 0; 19 | left: 0; 20 | width: 100%; 21 | height: 100%; 22 | `; 23 | 24 | export default class ReactParticleLine extends Component { 25 | static propTypes = { 26 | lineWidth: PropTypes.number, 27 | dotsNumber: PropTypes.number, 28 | dotsDistance: PropTypes.number, 29 | hoverEffect: PropTypes.bool, 30 | }; 31 | 32 | static defaultProps = { 33 | lineWidth: 0.3, 34 | dotsNumber: 100, 35 | dotsDistance: 100, 36 | hoverEffect: true, 37 | }; 38 | 39 | componentDidMount() { 40 | const { lineWidth, dotsNumber, dotsDistance, hoverEffect } = this.props; 41 | 42 | new ParticleLine('#react-particle-line-canvas', { 43 | lineWidth, 44 | dotsNumber, 45 | dotsDistance, 46 | hoverEffect, 47 | }) 48 | } 49 | 50 | render() { 51 | return ( 52 | 53 | {this.props.children} 54 | 55 | 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/particle-line/color.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports["default"] = void 0; 7 | 8 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 9 | 10 | 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); } } 11 | 12 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 13 | 14 | var Color = 15 | /*#__PURE__*/ 16 | function () { 17 | function Color(min) { 18 | _classCallCheck(this, Color); 19 | 20 | this.min = min || 0; 21 | 22 | this._init(this.min); 23 | } 24 | 25 | _createClass(Color, [{ 26 | key: "_init", 27 | value: function _init(min) { 28 | this.r = this.colorValue(min); 29 | this.g = this.colorValue(min); 30 | this.b = this.colorValue(min); 31 | this.style = this.createColorStyle(this.r, this.g, this.b); 32 | } 33 | }, { 34 | key: "colorValue", 35 | value: function colorValue(min) { 36 | return Math.floor(Math.random() * 255 + min); 37 | } 38 | }, { 39 | key: "createColorStyle", 40 | value: function createColorStyle(r, g, b) { 41 | return "rgba(".concat(r, ", ").concat(g, ", ").concat(b, ", .8)"); 42 | } 43 | }]); 44 | 45 | return Color; 46 | }(); 47 | 48 | exports["default"] = Color; -------------------------------------------------------------------------------- /lib/particle-line/dot.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports["default"] = void 0; 7 | 8 | var _color = _interopRequireDefault(require("./color")); 9 | 10 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 11 | 12 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 13 | 14 | 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); } } 15 | 16 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 17 | 18 | var Dot = 19 | /*#__PURE__*/ 20 | function () { 21 | function Dot(ctx, canvasWidth, canvasHeight, x, y) { 22 | _classCallCheck(this, Dot); 23 | 24 | this.ctx = ctx; 25 | this.x = x || Math.random() * canvasWidth; 26 | this.y = y || Math.random() * canvasHeight; 27 | 28 | this._init(); 29 | } 30 | 31 | _createClass(Dot, [{ 32 | key: "_init", 33 | value: function _init() { 34 | this.vx = -0.5 + Math.random(); 35 | this.vy = -0.5 + Math.random(); 36 | this.radius = Math.random() * 3; 37 | this.color = new _color["default"](); 38 | } 39 | }, { 40 | key: "draw", 41 | value: function draw() { 42 | this.ctx.beginPath(); 43 | this.ctx.fillStyle = this.color.style; 44 | this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false); 45 | this.ctx.fill(); 46 | } 47 | }]); 48 | 49 | return Dot; 50 | }(); 51 | 52 | exports["default"] = Dot; -------------------------------------------------------------------------------- /src/particle-line/index.js: -------------------------------------------------------------------------------- 1 | import Color from './color' 2 | import Dot from './dot' 3 | 4 | const minWidth = 1200 5 | const minHeight = 700 6 | 7 | export default class ParticleLine { 8 | constructor (tagId, options) { 9 | this.tagId = tagId 10 | this.options = options 11 | this.init() 12 | } 13 | 14 | init () { 15 | const canvas = document.querySelector(this.tagId) 16 | const ctx = canvas.getContext('2d') 17 | canvas.width = document.body.clientWidth > minWidth ? document.body.clientWidth : minWidth 18 | canvas.height = document.body.clientHeight > minHeight ? document.body.clientHeight : minHeight 19 | ctx.lineWidth = (this.options && this.options.lineWidth) || 0.3 20 | ctx.strokeStyle = (new Color(150)).style 21 | this.dots = { 22 | nb: (this.options && this.options.dotsNumber) || 100, 23 | distance: (this.options && this.options.dotsDistance) || 100, 24 | array: [] 25 | } 26 | this.canvas = canvas 27 | this.ctx = ctx 28 | this.color = new Color() 29 | this.createDots(this.ctx, this.canvas.width, this.canvas.height) 30 | this.animateDots() 31 | this.hoverEffect() 32 | } 33 | 34 | hoverEffect () { 35 | if (this.options && this.options.hoverEffect) { 36 | this.canvas.addEventListener('mousemove', e => { 37 | if (this.dots.array.length > this.dots.nb) { 38 | this.dots.array.pop() 39 | } 40 | this.dots.array.push(new Dot(this.ctx, this.canvas.width, this.canvas.height, e.pageX, e.pageY)) 41 | }) 42 | } 43 | } 44 | 45 | resize () { 46 | const width = document.body.clientWidth > minWidth ? document.body.clientWidth : minWidth 47 | const height = document.body.clientHeight > minHeight ? document.body.clientHeight : minHeight 48 | this.canvas.width = width 49 | this.canvas.height = height 50 | this.createDots(this.ctx, width, height) 51 | } 52 | 53 | mixComponents (comp1, weight1, comp2, weight2) { 54 | return (comp1 * weight1 + comp2 * weight2) / (weight1 + weight2) 55 | } 56 | 57 | averageColorStyles (dot1, dot2) { 58 | const color1 = dot1.color 59 | const color2 = dot2.color 60 | const r = this.mixComponents(color1.r, dot1.radius, color2.r, dot2.radius) 61 | const g = this.mixComponents(color1.g, dot1.radius, color2.g, dot2.radius) 62 | const b = this.mixComponents(color1.b, dot1.radius, color2.b, dot2.radius) 63 | return this.color.createColorStyle(Math.floor(r), Math.floor(g), Math.floor(b)) 64 | } 65 | 66 | createDots (ctx, canvasWidth, canvasHeight) { 67 | this.dots.array = [] 68 | for (let i = 0; i < this.dots.nb; i++) { 69 | this.dots.array.push(new Dot(ctx, canvasWidth, canvasHeight)) 70 | } 71 | } 72 | 73 | moveDots () { 74 | for (let i = 0; i < this.dots.nb; i++) { 75 | const dot = this.dots.array[i] 76 | if (dot.y < 0 || dot.y > this.canvas.height) { 77 | dot.vx = dot.vx // eslint-disable-line 78 | dot.vy = -dot.vy 79 | } else if (dot.x < 0 || dot.x > this.canvas.width) { 80 | dot.vx = -dot.vx 81 | dot.vy = dot.vy // eslint-disable-line 82 | } 83 | dot.x += dot.vx 84 | dot.y += dot.vy 85 | } 86 | } 87 | 88 | connectDots () { 89 | for (let i = 0; i < this.dots.array.length; i++) { 90 | for (let j = 0; j < this.dots.array.length; j++) { 91 | const iDot = this.dots.array[i] 92 | const jDot = this.dots.array[j] 93 | if ((iDot.x - jDot.x) < this.dots.distance && (iDot.y - jDot.y) < this.dots.distance && (iDot.x - jDot.x) > -this.dots.distance && (iDot.y - jDot.y) > -this.dots.distance) { 94 | this.ctx.beginPath() 95 | this.ctx.strokeStyle = this.averageColorStyles(iDot, jDot) 96 | this.ctx.moveTo(iDot.x, iDot.y) 97 | this.ctx.lineTo(jDot.x, jDot.y) 98 | this.ctx.stroke() 99 | this.ctx.closePath() 100 | } 101 | } 102 | } 103 | } 104 | 105 | drawDots () { 106 | for (let i = 0; i < this.dots.array.length; i++) { 107 | const dot = this.dots.array[i] 108 | dot.draw() 109 | } 110 | } 111 | 112 | animateDots () { 113 | this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) 114 | this.drawDots() 115 | this.connectDots() 116 | this.moveDots() 117 | requestAnimationFrame(this.animateDots.bind(this)) 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /lib/particle-line/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports["default"] = void 0; 7 | 8 | var _color = _interopRequireDefault(require("./color")); 9 | 10 | var _dot = _interopRequireDefault(require("./dot")); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 13 | 14 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 15 | 16 | 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); } } 17 | 18 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 19 | 20 | var minWidth = 1200; 21 | var minHeight = 700; 22 | 23 | var ParticleLine = 24 | /*#__PURE__*/ 25 | function () { 26 | function ParticleLine(tagId, options) { 27 | _classCallCheck(this, ParticleLine); 28 | 29 | this.tagId = tagId; 30 | this.options = options; 31 | this.init(); 32 | } 33 | 34 | _createClass(ParticleLine, [{ 35 | key: "init", 36 | value: function init() { 37 | var canvas = document.querySelector(this.tagId); 38 | var ctx = canvas.getContext('2d'); 39 | canvas.width = document.body.clientWidth > minWidth ? document.body.clientWidth : minWidth; 40 | canvas.height = document.body.clientHeight > minHeight ? document.body.clientHeight : minHeight; 41 | ctx.lineWidth = this.options && this.options.lineWidth || 0.3; 42 | ctx.strokeStyle = new _color["default"](150).style; 43 | this.dots = { 44 | nb: this.options && this.options.dotsNumber || 100, 45 | distance: this.options && this.options.dotsDistance || 100, 46 | array: [] 47 | }; 48 | this.canvas = canvas; 49 | this.ctx = ctx; 50 | this.color = new _color["default"](); 51 | this.createDots(this.ctx, this.canvas.width, this.canvas.height); 52 | this.animateDots(); 53 | this.hoverEffect(); 54 | } 55 | }, { 56 | key: "hoverEffect", 57 | value: function hoverEffect() { 58 | var _this = this; 59 | 60 | if (this.options && this.options.hoverEffect) { 61 | this.canvas.addEventListener('mousemove', function (e) { 62 | if (_this.dots.array.length > _this.dots.nb) { 63 | _this.dots.array.pop(); 64 | } 65 | 66 | _this.dots.array.push(new _dot["default"](_this.ctx, _this.canvas.width, _this.canvas.height, e.pageX, e.pageY)); 67 | }); 68 | } 69 | } 70 | }, { 71 | key: "resize", 72 | value: function resize() { 73 | var width = document.body.clientWidth > minWidth ? document.body.clientWidth : minWidth; 74 | var height = document.body.clientHeight > minHeight ? document.body.clientHeight : minHeight; 75 | this.canvas.width = width; 76 | this.canvas.height = height; 77 | this.createDots(this.ctx, width, height); 78 | } 79 | }, { 80 | key: "mixComponents", 81 | value: function mixComponents(comp1, weight1, comp2, weight2) { 82 | return (comp1 * weight1 + comp2 * weight2) / (weight1 + weight2); 83 | } 84 | }, { 85 | key: "averageColorStyles", 86 | value: function averageColorStyles(dot1, dot2) { 87 | var color1 = dot1.color; 88 | var color2 = dot2.color; 89 | var r = this.mixComponents(color1.r, dot1.radius, color2.r, dot2.radius); 90 | var g = this.mixComponents(color1.g, dot1.radius, color2.g, dot2.radius); 91 | var b = this.mixComponents(color1.b, dot1.radius, color2.b, dot2.radius); 92 | return this.color.createColorStyle(Math.floor(r), Math.floor(g), Math.floor(b)); 93 | } 94 | }, { 95 | key: "createDots", 96 | value: function createDots(ctx, canvasWidth, canvasHeight) { 97 | this.dots.array = []; 98 | 99 | for (var i = 0; i < this.dots.nb; i++) { 100 | this.dots.array.push(new _dot["default"](ctx, canvasWidth, canvasHeight)); 101 | } 102 | } 103 | }, { 104 | key: "moveDots", 105 | value: function moveDots() { 106 | for (var i = 0; i < this.dots.nb; i++) { 107 | var dot = this.dots.array[i]; 108 | 109 | if (dot.y < 0 || dot.y > this.canvas.height) { 110 | dot.vx = dot.vx; // eslint-disable-line 111 | 112 | dot.vy = -dot.vy; 113 | } else if (dot.x < 0 || dot.x > this.canvas.width) { 114 | dot.vx = -dot.vx; 115 | dot.vy = dot.vy; // eslint-disable-line 116 | } 117 | 118 | dot.x += dot.vx; 119 | dot.y += dot.vy; 120 | } 121 | } 122 | }, { 123 | key: "connectDots", 124 | value: function connectDots() { 125 | for (var i = 0; i < this.dots.array.length; i++) { 126 | for (var j = 0; j < this.dots.array.length; j++) { 127 | var iDot = this.dots.array[i]; 128 | var jDot = this.dots.array[j]; 129 | 130 | if (iDot.x - jDot.x < this.dots.distance && iDot.y - jDot.y < this.dots.distance && iDot.x - jDot.x > -this.dots.distance && iDot.y - jDot.y > -this.dots.distance) { 131 | this.ctx.beginPath(); 132 | this.ctx.strokeStyle = this.averageColorStyles(iDot, jDot); 133 | this.ctx.moveTo(iDot.x, iDot.y); 134 | this.ctx.lineTo(jDot.x, jDot.y); 135 | this.ctx.stroke(); 136 | this.ctx.closePath(); 137 | } 138 | } 139 | } 140 | } 141 | }, { 142 | key: "drawDots", 143 | value: function drawDots() { 144 | for (var i = 0; i < this.dots.array.length; i++) { 145 | var dot = this.dots.array[i]; 146 | dot.draw(); 147 | } 148 | } 149 | }, { 150 | key: "animateDots", 151 | value: function animateDots() { 152 | this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); 153 | this.drawDots(); 154 | this.connectDots(); 155 | this.moveDots(); 156 | requestAnimationFrame(this.animateDots.bind(this)); 157 | } 158 | }]); 159 | 160 | return ParticleLine; 161 | }(); 162 | 163 | exports["default"] = ParticleLine; -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports["default"] = void 0; 7 | 8 | var _react = _interopRequireWildcard(require("react")); 9 | 10 | var _propTypes = _interopRequireDefault(require("prop-types")); 11 | 12 | var _styledComponents = _interopRequireDefault(require("styled-components")); 13 | 14 | var _particleLine = _interopRequireDefault(require("./particle-line")); 15 | 16 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } 17 | 18 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj["default"] = obj; return newObj; } } 19 | 20 | function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 21 | 22 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 23 | 24 | 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); } } 25 | 26 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 27 | 28 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } 29 | 30 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } 31 | 32 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } 33 | 34 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } 35 | 36 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } 37 | 38 | function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 39 | 40 | function _templateObject3() { 41 | var data = _taggedTemplateLiteral(["\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n"]); 42 | 43 | _templateObject3 = function _templateObject3() { 44 | return data; 45 | }; 46 | 47 | return data; 48 | } 49 | 50 | function _templateObject2() { 51 | var data = _taggedTemplateLiteral(["\n z-index: 1;\n"]); 52 | 53 | _templateObject2 = function _templateObject2() { 54 | return data; 55 | }; 56 | 57 | return data; 58 | } 59 | 60 | function _templateObject() { 61 | var data = _taggedTemplateLiteral(["\n position: relative;\n width: 100%;\n height: 100%;\n"]); 62 | 63 | _templateObject = function _templateObject() { 64 | return data; 65 | }; 66 | 67 | return data; 68 | } 69 | 70 | function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } 71 | 72 | var ParticleLineWraper = _styledComponents["default"].div(_templateObject()); 73 | 74 | var ChildWraper = _styledComponents["default"].div(_templateObject2()); 75 | 76 | var CanvasWraper = _styledComponents["default"].canvas.attrs({ 77 | id: 'react-particle-line-canvas' 78 | })(_templateObject3()); 79 | 80 | var ReactParticleLine = 81 | /*#__PURE__*/ 82 | function (_Component) { 83 | _inherits(ReactParticleLine, _Component); 84 | 85 | function ReactParticleLine() { 86 | _classCallCheck(this, ReactParticleLine); 87 | 88 | return _possibleConstructorReturn(this, _getPrototypeOf(ReactParticleLine).apply(this, arguments)); 89 | } 90 | 91 | _createClass(ReactParticleLine, [{ 92 | key: "componentDidMount", 93 | value: function componentDidMount() { 94 | var _this$props = this.props, 95 | lineWidth = _this$props.lineWidth, 96 | dotsNumber = _this$props.dotsNumber, 97 | dotsDistance = _this$props.dotsDistance, 98 | hoverEffect = _this$props.hoverEffect; 99 | new _particleLine["default"]('#react-particle-line-canvas', { 100 | lineWidth: lineWidth, 101 | dotsNumber: dotsNumber, 102 | dotsDistance: dotsDistance, 103 | hoverEffect: hoverEffect 104 | }); 105 | } 106 | }, { 107 | key: "render", 108 | value: function render() { 109 | return _react["default"].createElement(ParticleLineWraper, null, _react["default"].createElement(ChildWraper, null, this.props.children), _react["default"].createElement(CanvasWraper, null)); 110 | } 111 | }]); 112 | 113 | return ReactParticleLine; 114 | }(_react.Component); 115 | 116 | exports["default"] = ReactParticleLine; 117 | 118 | _defineProperty(ReactParticleLine, "propTypes", { 119 | lineWidth: _propTypes["default"].number, 120 | dotsNumber: _propTypes["default"].number, 121 | dotsDistance: _propTypes["default"].number, 122 | hoverEffect: _propTypes["default"].bool 123 | }); 124 | 125 | _defineProperty(ReactParticleLine, "defaultProps", { 126 | lineWidth: 0.3, 127 | dotsNumber: 100, 128 | dotsDistance: 100, 129 | hoverEffect: true 130 | }); --------------------------------------------------------------------------------