├── .DS_Store
├── .babelrc
├── .gitignore
├── .npmrc
├── README.md
├── example
├── app.jsx
└── index.html
├── index.jsx
├── package-lock.json
├── package.json
└── webpack.config.js
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlexSugak/react-svg-pathline/7b143d02bc9cf29a577169aea5af0e938f7e9031/.DS_Store
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["es2015", {"modules": false}],
4 | "stage-2",
5 | "react"
6 | ],
7 | "plugins": [
8 | "react-hot-loader/babel"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # nyc test coverage
18 | .nyc_output
19 |
20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21 | .grunt
22 |
23 | # node-waf configuration
24 | .lock-wscript
25 |
26 | # Compiled binary addons (http://nodejs.org/api/addons.html)
27 | build/Release
28 |
29 | # Dependency directories
30 | node_modules
31 | jspm_packages
32 |
33 | # Optional npm cache directory
34 | .npm
35 |
36 | # Optional REPL history
37 | .node_repl_history
38 |
39 | bundle.js
40 | index.js
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | registry = https://registry.npmjs.org/
2 | email=aleksandr.sugak@gmail.com
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-svg-pathline
2 |
3 | React component for drawing SVG path through set of points, smoothing the corners
4 |
5 | ## Why?
6 |
7 | SVG `polyline` is the simplest option for rendering "path" line through set of known points but it gives you a "broken" line with sharp corners.
8 | Using SVG `path` you can get smooth corners but it requires adding more points to original set.
9 | This component helps with rendering SVG path by generating correct SVG data from original set of points, producing "smooth path line" as result.
10 |
11 | So instead of this:
12 |
13 | ```html
14 |
21 | ```
22 |
23 | 
24 |
25 | You get this:
26 |
27 | ```javascript
28 | import React from 'react'
29 | import {PathLine} from 'react-svg-pathline'
30 |
31 | export class MyComponent extends React.Component {
32 | render() (
33 |
42 | )
43 | }
44 | ```
45 |
46 | 
47 |
48 | ## Installation
49 |
50 | Requires [nodejs](http://nodejs.org/).
51 |
52 | ```sh
53 | $ npm install react-svg-pathline
54 | ```
55 |
56 | ## Live Example
57 |
58 | ```sh
59 | $ npm i && npm i react react-dom && npm start
60 | ```
61 |
62 | Open a browser at localhost:8080
--------------------------------------------------------------------------------
/example/app.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import {PathLine} from '../index'
4 |
5 | export const Example = () => (
6 |
7 |
14 |
15 |
24 |
25 | );
26 |
27 | ReactDOM.render(
28 | ,
29 | document.getElementById('root'),
30 | )
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | React SVG path line example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types';
3 |
4 | const isCollinear = (p1, p2, p3) => {
5 | return (p1.y - p2.y) * (p1.x - p3.x) == (p1.y - p3.y) * (p1.x - p2.x);
6 | }
7 |
8 | const moveTo = (b, a, r) => {
9 | const vector = {x: b.x - a.x, y: b.y - a.y};
10 | const length = Math.sqrt((vector.x * vector.x) + (vector.y * vector.y));
11 | const unitVector = {x: vector.x / length, y: vector.y / length};
12 | return {x: a.x + unitVector.x * r, y: a.y + unitVector.y * r};
13 | }
14 |
15 | export const PathLine = ({ points, r, ...other }) => {
16 | const path = points
17 | .slice(1)
18 | .reduce((acc, p, i, points) => {
19 | let next = points[i + 1];
20 | let prev = acc[acc.length - 1];
21 |
22 | if (next && !isCollinear(prev.point, p, next)) {
23 | let before = moveTo(prev.point, p, r);
24 | let after = moveTo(next, p, r);
25 | return acc.concat({
26 | point:p,
27 | s:`L ${before.x} ${before.y} S ${p.x} ${p.y} ${after.x} ${after.y} `
28 | })
29 | } else {
30 | return acc.concat({
31 | point:p,
32 | s:`L ${p.x} ${p.y} `
33 | })
34 | };
35 | }
36 | , [{
37 | point: points[0],
38 | s: `M ${points[0].x} ${points[0].y} `
39 | }])
40 | .map(p => p.s)
41 | .join('');
42 | return (
43 |
44 | )
45 | };
46 |
47 | PathLine.propTypes = {
48 | points: PropTypes.array.isRequired,
49 | r: PropTypes.number.isRequired
50 | }
51 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-svg-pathline",
3 | "version": "0.6.0",
4 | "description": "React component for drawing SVG path through set of points, rendering straight lines where possible and smooth corners in other cases",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "webpack-dev-server",
8 | "build": "babel index.jsx -o index.js",
9 | "prepublish": "npm run build"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/AlexSugak/react-svg-pathline.git"
14 | },
15 | "files": [
16 | "index.js"
17 | ],
18 | "keywords": [
19 | "react",
20 | "svg",
21 | "path",
22 | "line",
23 | "smooth"
24 | ],
25 | "author": "Alexandr Sugak",
26 | "license": "MIT",
27 | "bugs": {
28 | "url": "https://github.com/AlexSugak/react-svg-pathline/issues"
29 | },
30 | "homepage": "https://github.com/AlexSugak/react-svg-pathline#readme",
31 | "devDependencies": {
32 | "babel-cli": "^6.10.1",
33 | "babel-core": "^6.10.4",
34 | "babel-loader": "^6.2.4",
35 | "babel-preset-es2015": "^6.9.0",
36 | "babel-preset-react": "^6.11.1",
37 | "babel-preset-stage-2": "^6.11.0",
38 | "json-loader": "^0.5.4",
39 | "react-hot-loader": "^3.1.3",
40 | "webpack": "^2.2.0",
41 | "webpack-dev-server": "^2.2.0"
42 | },
43 | "peerDependencies": {
44 | "react": "^16.2.0 || ^17.0.0 || ^18.0.0",
45 | "react-dom": "^16.2.0 || ^17.0.0 || ^18.0.0"
46 | },
47 | "dependencies": {
48 | "prop-types": "^15.5.8"
49 | }
50 | }
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require('path');
3 |
4 | module.exports = {
5 | entry: [
6 | 'react-hot-loader/patch',
7 | 'webpack-dev-server/client?http://localhost:8080',
8 | 'webpack/hot/only-dev-server',
9 | './example/app.jsx'
10 | ],
11 | module: {
12 | rules: [
13 | {
14 | test: /\.jsx?$/,
15 | use: [
16 | 'babel-loader',
17 | ],
18 | exclude: /node_modules/,
19 | },
20 | ],
21 | },
22 | output: {
23 | path: __dirname + "/example",
24 | publicPath: '/',
25 | filename: 'bundle.js'
26 | },
27 | devServer: {
28 | contentBase: './example',
29 | hot: true
30 | },
31 | plugins: [
32 | new webpack.HotModuleReplacementPlugin()
33 | ]
34 | };
--------------------------------------------------------------------------------