Skip to content
[WIP] A set of react components that encapsulate the d3-selection api
TypeScript JavaScript HTML
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.storybook
.vscode
public
src
src_old
.gitignore
.npmignore
.prettierrc
LICENSE
README.md
package.json
tsconfig.json
yarn.lock

README.md

thirdAct

A set of react components that encapsulate d3-selection api

Disclaimer

thirdact is still on a very early stage. It is born of our frustration of using the different workflows that mix React and d3 together.

d3's general update pattern is quite incompatible with React's data binding as React only keeps track of the current data.

This is an experimental attempt to express the d3-selection API in a jsx style. This way, we can mix d3 and React into the render method, without using React hooks such as componentDidUpdate to manage d3 instructions.

  • It uses the d3-selection API under the hood, we are just transforming jsx components to d3 instructions
  • React's Virtual DOM is not involved or aware of the generated DOM, but we isolate it into an empty React element

A first overview

you can find a full example here

import { scaleLinear } from 'd3-scale';
import React from 'react';
import {
    SelectAll,
    Transition,
    Selection,
    Append,
    Remove
} from '@seracio/thirdact';

const App = ({ data }) => {
    const size = 500;

    const scaleX = scaleLinear()
        .domain([0, data.length - 1])
        .range([100, 400]);

    return (
        <svg
            preserveAspectRatio="xMinYMin meet"
            viewBox={`0 0 ${size} ${size}`}
        >
            <text
                x={size / 2}
                y={50}
                style={{
                    alignmentBaseline: 'middle',
                    textAnchor: 'middle',
                    fontFamily: 'sans-serif'
                }}
            >
                Hello thirdact
            </text>
            <SelectAll data={data} selector={'.circle'} root={<g />}>                
                <Selection type="enter">
                    <Append>
                        {/* use react conventions to specify your data */}
                        <circle
                            className="circle"
                            cx={(d, i) => scaleX(i)}
                            cy={100}
                            r={10}
                            style={{ fill: 'transparent' }}
                        />
                    </Append>
                    {/* on a transition, only specify the attr, styles or events you want to update */}
                    <Transition duration={1000}>
                        <circle cy={200} style={{ fill: d => d }} />
                    </Transition>
                </Selection>
                <Selection type="update">
                    <Transition duration={1000}>
                        <circle cx={(d, i) => scaleX(i)} />
                    </Transition>
                </Selection>
                <Selection type="exit">
                    {/* you can chain transitions */}
                    <Transition duration={500}>
                        <circle cy={250} r={5} />
                    </Transition>
                    <Transition duration={500}>
                        <circle cy={400} style={{ fill: 'transparent' }} />
                    </Transition>
                    <Remove />
                </Selection>
            </SelectAll>        
        </svg>
    );
};

Install

yarn add react react-dom d3-selection d3-selection-multi d3-transition lodash.kebabcase
yarn add @seracio/thirdact

Usage

First of all - and if you use d3 modules - you'll need to patch d3-selection-multi and d3-transition to d3 in your root file:

import * as d3 from 'd3-selection';
import 'd3-selection-multi';
import 'd3-transition';

Then you can import the different components of thirdact:

import {
    SelectAll,
    Transition,
    Selection,
    Append,
    Remove
} from '@seracio/thirdact';

API

SelectAll

SelectAll is the root component, it takes several props:

name type description
data Array
selector string the equivalent of the d3's selector in d3.selectAll(selector)
getKey (d,i) => string an optional function to get the key of the current datum
root React$Element the react element where the DOM managed by d3 will be

Selection

Selection is the only component allowed as direct child of SelectAll.
It allows you to use d3's data join by specifying a type props:

name type description
type string enter or update or exit (and soon enter+exit)

Once you have split your data into selections thanks to the general update pattern, you can finally do the mapping between your data and the DOM thans to modifiers:

  • Append to create items
  • Remove to remove them
  • Transition for updating them
  • Call to apply them a function

You can chain modifiers.

Append

Append is used to add new tags to the DOM, define their attributes and styles or attach events. thirdact's API is here quite different to its d3 counterpart:

<Append>
    <rect className="toto" 
        x={0} 
        y={(d,i) => i*10} 
        width={(d,i) => d} 
        height={10} 
        styles={{strokeWidth: 2}}
        onClick={(d,i) => console.log(d)}
        />
</Append>

will be transcripted on:

selection.append('rect')
    .attr('class', 'toto')
    .attr('x', 0)
    .attr('y', i*10)
    .attr('width', (d,i) => d)
    .attr('height', 10)
    .style('stroke-width', 2)
    .on('click', (d,i) => console.log(d));

Transitions

Transition currently support these props:

name type description
duration number

You just have to specify the attributes or styles you want to update:

<Transition duration={500}>
    <path
        style={{fill: 'blue'}}
        tween-d={tween}
        />
</Transition>

Note the equivalent of d3's attrTween: tween-[attr name]

Remove

Remove has no props

Call

Call uses a function as a children

<Selection type="enter">
    <Append>
        {/**/}
    </Append>
    <Call>
    {function(selection){
        // ...
    }}
    </Call>
</Selection>

Chaining transformations

<Selection type="enter">
    <Append>
        <circle
            className="circle"
            cx={(d, i) => scaleX(i)}
            cy={100}
            r={10}
            style={{ fill: 'transparent' }}
        />
    </Append>
    <Transition duration={1000}>
        <circle cy={200} style={{ fill: d => d }} />
    </Transition>
</Selection>

License

MIT License

Copyright (c) 2017 serac.io

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.

You can’t perform that action at this time.