@hackcapital/hd3
v1.0.4
Published
A module D3 library for React.
Downloads
2
Readme
HD3 (HackCapital D3)
Installation
npm install @hackcapital/hd3
Examples
Basic usage:
Here's an example of a very basic graph:
import React, { Component } from 'react';
import { scaleLinear } from 'd3-scale';
import { line } from 'd3-shape';
import { GraphElement, Graph } from '@hackcapital/hd3';
// Some random test data
const testData = [
{ x: 1, y: 2 },
{ x: 2, y: 4 },
{ x: 3, y: 9 },
{ x: 4, y: 15 },
{ x: 5, y: 5 },
];
/**
* This is a very basic Line that extends the GraphElement. The only method that needs to
* exist within a class that extends GraphElement is the `draw()` method. This is the one
* that will be called by the parent Graph to actually draw the element.
*
* Inside the `draw()` function you will have access to:
* - `this.graph` is a reference to the base graph.
* - `this.graph.plotNode` is a reference to the base SVG element that's already wrapped by
* the D3 select function.
* - `this.props` includes any properties that were passed in to this element.
*/
class Line extends GraphElement {
draw() {
// Take the data that was passed in to the props.
const { data } = this.props;
// Define a basic line using the x and y scale of the parent graph.
const meanLine = line()
.x(d => this.graph.xScale(d.x))
.y(d => this.graph.yScale(d.y));
const lineObj = this.graph.plotNode
.append('g')
.append('path')
.attr('d', meanLine(data));
this.applyStyles(lineObj);
}
}
/**
* This component will be the wrapper for the graph. If we need to position the graph in an specific
* way, it should be done using the wrapper div.
*/
class BasicGraph extends Component {
render() {
// Find the xRange and yRange of our data set
const xRange = [Number.MAX_SAFE_INTEGER, -Number.MAX_SAFE_INTEGER];
const yRange = [Number.MAX_SAFE_INTEGER, -Number.MAX_SAFE_INTEGER];
for (let point of testData) {
if (point.x < xRange[0]) {
xRange[0] = point.x;
} else if (point.x > xRange[1]) {
xRange[1] = point.x;
}
if (point.y < yRange[0]) {
yRange[0] = point.y;
} else if (point.y > yRange[1]) {
yRange[1] = point.y;
}
}
return (
<div>
<Graph
name={'basic-graph'}
style={{ backgroundColor: 'blue' }}
xRange={xRange}
yRange={yRange}
scaleType={scaleLinear}
height={500}
width={500}
>
<Line
data={testData}
name={'scope'}
style={{ fill: 'none', 'stroke-width': 2, stroke: '#50E7F1' }}
/>
</Graph>
</div>
);
}
}
export default BasicGraph;
Responsive Graph:
This next example demonstrates how to make that same graph responsive. When the
responsive
property is set to true on the Graph
component, the graph will size
itself based on whatever it is placed inside of. In this example, the Graph
is
placed inside a div
that is placed in the middle of the page and sized to be
50% of the page.
import React, { Component } from 'react';
import { scaleLinear } from 'd3-scale';
import { line } from 'd3-shape';
import { GraphElement, Graph } from '@hackcapital/hd3';
// Some random test data
const testData = [
{ x: 1, y: 2 },
{ x: 2, y: 4 },
{ x: 3, y: 9 },
{ x: 4, y: 15 },
{ x: 5, y: 5 },
];
class Line extends GraphElement {
draw() {
// Take the data that was passed in to the props.
const { data } = this.props;
// Define a basic line using the x and y scale of the parent graph.
const meanLine = line()
.x(d => this.graph.xScale(d.x))
.y(d => this.graph.yScale(d.y));
const lineObj = this.graph.plotNode
.append('g')
.append('path')
.attr('d', meanLine(data));
this.applyStyles(lineObj);
}
}
class BasicResponsiveGraph extends Component {
render() {
// Find the xRange and yRange of our data set
const xRange = [Number.MAX_SAFE_INTEGER, -Number.MAX_SAFE_INTEGER];
const yRange = [Number.MAX_SAFE_INTEGER, -Number.MAX_SAFE_INTEGER];
for (let point of testData) {
if (point.x < xRange[0]) {
xRange[0] = point.x;
} else if (point.x > xRange[1]) {
xRange[1] = point.x;
}
if (point.y < yRange[0]) {
yRange[0] = point.y;
} else if (point.y > yRange[1]) {
yRange[1] = point.y;
}
}
return (
<div
style={{
width: '100vw',
height: '100vh',
backgroundColor: 'pink',
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
}}
>
<div
style={{ width: '50vw', height: '50vh' }}
>
<Graph
name={'basic-graph'}
style={{ backgroundColor: 'blue' }}
xRange={xRange}
yRange={yRange}
scaleType={scaleLinear}
height={500}
width={500}
responsive={true} // Responsive defaults to false. Set it to true here to enable responsiveness.
>
<Line
data={testData}
name={'scope'}
style={{ fill: 'none', 'stroke-width': 2, stroke: '#50E7F1' }}
/>
</Graph>
</div>
</div>
);
}
}
export default BasicResponsiveGraph;
An Element Outside
This example shows how to handle a GraphElement
that needs to be drawn outside the plot. For example,
lets say you have an X-axis that should be drawn below the graph.
import React, { Component } from 'react';
import { scaleLinear } from 'd3-scale';
import { line } from 'd3-shape';
import { axisBottom } from 'd3-axis';
import { GraphElement, Graph } from '@hackcapital/hd3';
// Some random test data
const testData = [
{ x: 1, y: 2 },
{ x: 2, y: 4 },
{ x: 3, y: 9 },
{ x: 4, y: 15 },
{ x: 5, y: 5 },
];
class Line extends GraphElement {
draw() {
// Take the data that was passed in to the props.
const { data } = this.props;
// Define a basic line using the x and y scale of the parent graph.
const meanLine = line()
.x(d => this.graph.xScale(d.x))
.y(d => this.graph.yScale(d.y));
const lineObj = this.graph.plotNode
.append('g')
.append('path')
.attr('d', meanLine(data));
this.applyStyles(lineObj);
}
}
/**
* A basic X-Axis that would normally be outside the bounds of the SVG. We can
* add padding to account for this element by explicitly stating how much
* padding will be need and in what direction.
*/
class XAxis extends GraphElement {
/**
* Overriding the paddingBottom to `30`, will let the parent graph know that
* this element needs at least an extra `30px` to be able to render properly.
*/
get paddingBottom() {
return 30;
}
/**
* The rest of the directions do not need to be set to `0` since they default
* to `0`. They are set here to show how they can be set.
*/
get paddingTop() {
return 0;
}
get paddingRight() {
return 0;
}
get paddingLeft() {
return 0;
}
draw() {
let axis = axisBottom()
.scale(this.graph.xScale);
const axisNode = this.graph.plotNode
.append('g')
.attr('transform', `translate(0, ${this.graph.height + 25})`)
.call(axis);
this.applyStyles(axisNode);
}
}
class BasicPaddingGraph extends Component {
render() {
// Find the xRange and yRange of our data set
const xRange = [Number.MAX_SAFE_INTEGER, -Number.MAX_SAFE_INTEGER];
const yRange = [Number.MAX_SAFE_INTEGER, -Number.MAX_SAFE_INTEGER];
for (let point of testData) {
if (point.x < xRange[0]) {
xRange[0] = point.x;
} else if (point.x > xRange[1]) {
xRange[1] = point.x;
}
if (point.y < yRange[0]) {
yRange[0] = point.y;
} else if (point.y > yRange[1]) {
yRange[1] = point.y;
}
}
/**
* Any padding that is set on the `Graph` component will be added to the
* largest minimum of all the children.
*/
return (
<div>
<Graph
name={'basic-graph'}
style={{ backgroundColor: 'blue', padding: 20 }}
xRange={xRange}
yRange={yRange}
scaleType={scaleLinear}
height={500}
width={500}
>
<Line
data={testData}
name={'scope'}
style={{ fill: 'none', 'stroke-width': 2, stroke: 'red' }}
/>
<XAxis style={{ color: 'white' }}/>
</Graph>
</div>
);
}
}
export default BasicPaddingGraph;
API
Graph
- Component Properties:
name
: The name for the graph being drawn.style
: Regular styling object that React Javascript uses. (ie.{ "color": "blue" }
)xRange
: An array with 2 elements. First element is the minimum of the X-range and the second is the maximum of the X-range. (ie.[0, 15]
)yRange
: An array with 2 elements. First element is the minimum of the Y-range and the second is the maximum of the Y-range. (ie.[0, 15]
)scaleType
: The D3 scale function to be used for this graph. (ie.scaleLinear
,scaleLog
)height
: Height for the graph in pixels. This will be ignored ifresponsive
is set. (ie.400
is400px
)width
: Width for the graph in pixels. This will be ignore ifresponsive
is set. (ie.400
is400px
)responsive
: Use this to force you graph to take up the entire height and width of the parent element (whatever that size may be).
- API (accessible from within
GraphElements
):plotNode
: An instance of a D3 selection for the plot that was drawn for the graph. AllGraphElements
should draw themselves within this.height
: Height of the plot in pixels.width
: Width of the plot in pixels.name
: Name of the graph.xRange
: Minimum and maximum of the X-Axis. (ie.[0, 15]
)yRange
: Minimum and maximum of the Y-Axis. (ie.[0, 15]
)xScale
: The X-scale generated by thexRange
and thescaleType
.yScale
: The Y-scale generated by theYRange
and thescaleType
.
GraphElement
- Component Properties
style
: Any styling that should be applied using theapplyStyles()
method. *Any styles that are passed in should be the regular CSS3 property names rather than the React style property names (which arecamelCase
). (ie. usestroke-width
instead ofstrokeWidth
).- Any property can be passed in here and be accessible within the
draw()
method. The only reserved property isstyle
.
- API:
draw()
: The function that will be called by the parentGraph
component during rendering.applyStyles(node)
: Apply any styles that were passed to the component to a given node.node
: should be an instance of an element selected using D3'sselect()
function.
graph
: The parentGraph
component.props
: An object that contains any properties that were passed in to the component.paddingTop
: The amount of padding in pixels that this element needs on the top of theGraph
.paddingRight
: The amount of padding in pixels that this element needs on the right of theGraph
.paddingBottom
: The amount of padding in pixels that this element needs on the bottom of theGraph
.paddingLeft
: The amount of padding in pixels that this element needs on the left of theGraph
.