React

React Art and Paths.js

Intro

Paths.js is a cool library. It comes with 3 levels of generating paths.

  • Low level which helps you generate paths/lines.
  • Mid level which generates paths for shapes
  • High level which takes a set of data and generates graphs

All of these are great when working with react-art because it's just returning data. I'll say it once, and a million more but libraries that just generate data make it easy to traverse and render with react-art.

<!-- more -->

Paths

UPDATE:

Sebastian Markbage (the creator of ReactART and ART), informed me that ReactART itself has a Path implementation. I realized this but didn't think much of it. However per the discussion here https://discuss.reactjs.org/t/react-art-with-paths-js/492 the ART path is faster as it takes advantage of the current mode to create the most efficient path instead of taking a string and converting it back into native for instructions for canvas rendering.

The ReactART.Path has similar methods. Check out the discuss thread for a link to the implementation to find out the supported methods. I'm currently working on ReactART documentation so expect that soon.

Example:

var path = Path()
  .moveto(10, 20)
  .lineto(30, 50)
  .lineto(25, 28)
  .qcurveto(27, 30, 32, 27)
  .closepath();

This is can just be plugged right into react-art Shape element.

Like so

var React = require('react'),
	ReactArt = require('react-art'),
	Surface = ReactArt.Surface,
	Shape = ReactArt.Shape,
	Path = require('paths-js/path');

var Demo = React.createClass({
	getInitialState: function() {
		return {
			to: {
				x: 30,
				y: 50
			}
		}
	},
	getPath: function() {
		var path = Path()
					  .moveto(10, 20)
					  .lineto(this.state.to.x, this.state.to.y)
					  .lineto(25, 28)
					  .qcurveto(27, 30, 32, 27)
					  .closepath();

	 	return path.print();
	},
	startAnimating: function() {

		if (this.state.to.x === 100) {
			this.addToPosition = -1;
		} else if (this.state.to.x === 29) {
			this.addToPosition = 1;
		}

		this.state.to.x += this.addToPosition;
		this.state.to.y += this.addToPosition;

		this.setState(this.state);
	},
	componentDidMount: function() {
		this.addToPosition = 1;
		setInterval(this.startAnimating, 17)
	},
	render: function() {
		return (
			<div>
				<Surface
					width={500}
					height={500}
				>
					<Shape d={this.getPath()} stroke="#000" strokeWidth={1} />
				</Surface>
			</div>
		)
	}
});

module.exports = Demo;
<p data-height="624" data-theme-id="0" data-slug-hash="VLmOOE" data-default-tab="result" data-user="browniefed" class='codepen'>See the Pen <a href='http://codepen.io/browniefed/pen/VLmOOE/'>VLmOOE</a> by Jason Brown (<a href='http://codepen.io/browniefed'>@browniefed</a>) on <a href='http://codepen.io'>CodePen</a>.</p> <script async src="//assets.codepen.io/assets/embed/ei.js"></script>

Simple Shapes

Now react-art already comes with a few different shapes but paths.js have a few built in as well, like Rectangle and Bezier curve.

var rectangle = Rectangle({
  top: 10,
  bottom: 3,
  left: -2,
  right: 5
});

And how that looks is very similar to the previous example

var React = require('react'),
	ReactArt = require('react-art'),
	Surface = ReactArt.Surface,
	Group = ReactArt.Group,
	Shape = ReactArt.Shape,
	Rectangle = require('paths-js/rectangle'),
	Bezier = require('paths-js/bezier');

var Demo = React.createClass({
	getPath: function() {
		var rectangle = Rectangle({
					  top: 10,
					  bottom: 3,
					  left: -2,
					  right: 5
					});

	 	return rectangle.path.print();
	},
	getBez: function() {
		var points = [[1, 50], [50, 100], [100, 3], [4, 0]];
		var curve = Bezier({
		  points: points,
		  tension: 0.2
		});

		return curve.path.print();
	},
	render: function() {
		return (
			<div>
				<Surface
					width={500}
					height={500}
				>
					<Group x={100} y={100}>
						<Shape d={this.getPath()} stroke="#000" strokeWidth={1} />
					</Group>
					<Group x={200} y={200}>
						<Shape d={this.getBez()} stroke="#000" strokeWidth={1} />
					</Group>
				</Surface>
			</div>
		)
	}
});

module.exports = Demo;
<p data-height="624" data-theme-id="0" data-slug-hash="xGRNvW" data-default-tab="result" data-user="browniefed" class='codepen'>See the Pen <a href='http://codepen.io/browniefed/pen/xGRNvW/'>xGRNvW</a> by Jason Brown (<a href='http://codepen.io/browniefed'>@browniefed</a>) on <a href='http://codepen.io'>CodePen</a>.</p> <script async src="//assets.codepen.io/assets/embed/ei.js"></script>

Graphs

var pie = Pie({
  data: [
    { name: 'Italy', population: 59859996 },
    { name: 'Mexico', population: 118395054 },
    { name: 'France', population: 65806000 },
    { name: 'Argentina', population: 40117096 },
    { name: 'Japan', population: 127290000 }
  ],
  accessor: function(x) { return x.population; },
  compute: {
    color: function(i) { return somePalette[i]; }
  },
  center: [20, 15],
  r: 30,
  R: 50
});

Some code of it in action

var React = require('react'),
	ReactArt = require('react-art'),
	Surface = ReactArt.Surface,
	Group = ReactArt.Group,
	Shape = ReactArt.Shape,
	Pie = require('paths-js/Pie');


var pie = Pie({
  data: [
    { name: 'Italy', population: 59859996 },
    { name: 'Mexico', population: 118395054 },
    { name: 'France', population: 65806000 },
    { name: 'Argentina', population: 40117096 },
    { name: 'Japan', population: 127290000 }
  ],
  accessor: function(x) { return x.population; },
  compute: {
    color: function(i) { return '#000'; }
  },
  center: [20, 15],
  r: 30,
  R: 50
});

var Demo = React.createClass({

	getPie: function() {
		return pie.curves.map(function(shape) {
			return (
				<Group>
					<Text fill="#A6BD8A" font='bold 12px "Arial"' x={shape.sector.centroid[0] - 12} y={shape.sector.centroid[1]}>{shape.item.name}</Text>
					<Shape d={shape.sector.path.print()} stroke={shape.color} strokeWidth={1} />
				</Group>
			)
		})
	},
	render: function() {
		return (
			<div>
				<Surface
					width={500}
					height={500}
				>
					<Group x={50} y={45}>
						{this.getPie()}
					</Group>
				</Surface>
			</div>
		)
	}
});


module.exports = Demo;
<p data-height="624" data-theme-id="0" data-slug-hash="waoLvB" data-default-tab="result" data-user="browniefed" class='codepen'>See the Pen <a href='http://codepen.io/browniefed/pen/waoLvB/'>waoLvB</a> by Jason Brown (<a href='http://codepen.io/browniefed'>@browniefed</a>) on <a href='http://codepen.io'>CodePen</a>.</p> <script async src="//assets.codepen.io/assets/embed/ei.js"></script>

Conclusion

These examples may look boring but they just show off a bit of the control you can have with react-art and a simple path generator. Not only that but because we aren't depending on the DOM in any case these examples should also work on react-native. Combined with some tweening you could make some very effective graphs that animate. That is a topic for another time.

Liked this content?

Get notified more about React!

No Spam! We Promise!

Related Content

Create a useMousePosition Hook with useEffect and useState in React

In this lesson we'll explore how to combine useEffect with useState to create a reusable hook. It will listen add a window listener for mousemove and update state with each movement.

Create a componentDidMount useEffect hook in React

In this lesson we'll explore how to create useEffect call, and listen to the window for mouse movement. We'll learn about cleaning up our effects, and how to pass an empty array into the second argument of our effect to create a componentDidMount like effect. Finally we'll trigger a mount/unmount to show effects getting cleaned up correctly.

Create a useMousePosition Hook with useEffect and useState in React

In this lesson we'll explore how to combine useEffect with useState to create a reusable hook. It will listen add a window listener for mousemove and update state with each movement.

Create a componentDidMount useEffect hook in React

In this lesson we'll explore how to create useEffect call, and listen to the window for mouse movement. We'll learn about cleaning up our effects, and how to pass an empty array into the second argument of our effect to create a componentDidMount like effect. Finally we'll trigger a mount/unmount to show effects getting cleaned up correctly.