Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add d3-state-visualizer package #556

Merged
merged 4 commits into from
Aug 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
},
"workspaces": [
"packages/*",
"packages/d3-state-visualizer/examples/tree",
"packages/react-json-tree/examples",
"packages/redux-devtools/examples/counter",
"packages/redux-devtools/examples/todomvc",
Expand Down
4 changes: 4 additions & 0 deletions packages/d3-state-visualizer/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": ["@babel/plugin-proposal-class-properties", "@babel/plugin-proposal-export-default-from"]
}
83 changes: 83 additions & 0 deletions packages/d3-state-visualizer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
d3-state-visualizer
===================
Enables real-time visualization of your application state.

Created by [@romseguy](https://github.com/romseguy) and merged from [`reduxjs/d3-state-visualizer`](https://github.com/reduxjs/d3-state-visualizer).

[Demo](http://reduxjs.github.io/d3-state-visualizer)

## Installation

`yarn install d3-state-visualizer`

## Usage

```javascript
import { tree } from 'd3-state-visualizer';

const appState = {
todoStore: {
todos: [
{ title: 'd3'},
{ title: 'state' },
{ title: 'visualizer' },
{ title: 'tree' }
],
completedCount: 1
}
};

const render = tree(document.getElementById('root'), {
state: appState,
id: 'treeExample',
size: 1000,
aspectRatio: 0.5,
isSorted: false,
widthBetweenNodesCoeff: 1.5,
heightBetweenNodesCoeff: 2,
style: {border: '1px solid black'},
tooltipOptions: {offset: {left: 30, top: 10}, indentationSize: 2}
});

render();
```
## Charts API

The APIs are minimal and consists of a single function you provide with:
- a DOM element
- a plain old JS object for options.

#### Tree

This chart is a bit special as it accepts either one of the two following options, but **not both**:

- `tree`: a properly formed tree structure such as one generated by [map2tree](https://github.com/reduxjs/redux-devtools/tree/master/packages/map2tree) or [react2tree](https://github.com/romseguy/react2tree)
- `state`: a plain javascript object mapping arbitrarily nested keys to values – which will be transformed into a tree structure, again using [map2tree](https://github.com/reduxjs/redux-devtools/tree/master/packages/map2tree).

Other options are listed below and have reasonable default values if you want to omit them:

Option | Type | Default | Description
--------------------------|----------|-------------|-------------------------------------------------------------------------
`id` | String | `'d3svg'` | Sets the identifier of the SVG element —i.e your chart— that will be added to the DOM element you passed as first argument
`style` | Object | `{}` | Sets the CSS style of the chart
`size` | Number | `500` | Sets size of the chart in pixels
`aspectRatio` | Float | `1.0` | Sets the chart height to `size * aspectRatio` and [viewBox](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox) in order to preserve the aspect ratio of the chart. [Great video](https://www.youtube.com/watch?v=FCOeMy7HrBc) if you want to learn more about how SVG works
`widthBetweenNodesCoeff` | Float | `1.0` | Alters the horizontal space between each node
`heightBetweenNodesCoeff` | Float | `1.0` | Alters the vertical space between each node
`isSorted` | Boolean | `false` | Sorts the chart in alphabetical order
`transitionDuration` | Number | `750` | Sets the duration of all the transitions used by the chart
`tooltipOptions` | Object | [here](https://github.com/reduxjs/redux-devtools/tree/master/packages/d3tooltip) | Sets the options for the [tooltip](https://github.com/reduxjs/redux-devtools/tree/master/packages/d3tooltip) that is showing up when you're hovering the nodes
`rootKeyName` | String | `'state'` | Sets the first node's name of the resulting tree structure. **Warning**: only works if you provide a `state` option
`pushMethod` | String | `'push'` | Sets the method that shall be used to add array children to the tree. **Warning**: only works if you provide a `state` option

More to come...

## Bindings

### React

[example](https://github.com/reduxjs/redux-devtools/tree/master/packages/d3-state-visualizer/examples/react-tree) implementation.

## Roadmap

* Threshold for large arrays so only a single node is displayed instead of all the children. That single node would be exclude from searching until selected.
42 changes: 42 additions & 0 deletions packages/d3-state-visualizer/examples/tree/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<html>
<head>
<title>State tree with d3-state-visualizer</title>
<style type="text/css">

.node {
cursor: pointer;
}

.nodeCircle {
stroke: black;
stroke-width: 1.5px;
}

.nodeText {
font-family: sans-serif;
font-size: 10px;
}

.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}

.tooltip {
font-family: Consolas, Menlo, Monaco, monospace;
font-size: 0.8em;
background: rgba(0, 0, 0, 0.5);
color: white;
padding: 10px;
border-radius: 5px;
}

</style>
</head>
<body>
<div id="root">
</div>
<script src="/static/bundle.js"></script>
</body>
</html>
35 changes: 35 additions & 0 deletions packages/d3-state-visualizer/examples/tree/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { tree } from 'd3-state-visualizer';

const appState = {
todoStore: {
todos: [
{ title: 'd3'},
{ title: 'state' },
{ title: 'visualizer' },
{ title: 'tree' }
],
completedCount: 1,
alphabeticalOrder: true
},
someStore: {
someProperty: 0,
someObject: {
anotherProperty: 'value',
someArray: [0, 1, 2]
}
}
};

const render = tree(document.getElementById('root'), {
state: appState,
id: 'treeExample',
size: 1000,
aspectRatio: 0.5,
isSorted: false,
widthBetweenNodesCoeff: 1.5,
heightBetweenNodesCoeff: 2,
style: {border: '1px solid black'},
tooltipOptions: {offset: {left: 30, top: 10}, indentationSize: 2}
});

render();
35 changes: 35 additions & 0 deletions packages/d3-state-visualizer/examples/tree/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "d3-state-visualizer-tree-example",
"version": "0.0.0",
"description": "Visualize your app state as a tree",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"repository": {
"type": "git",
"url": "https://github.com/reduxjs/redux-devtools.git"
},
"keywords": [
"d3",
"state",
"store",
"visualization"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/reduxjs/redux-devtools/issues"
},
"homepage": "https://github.com/reduxjs/redux-devtools",
"dependencies": {
"d3-state-visualizer": "^1.0.1",
"map2tree": "^1.3.0"
},
"devDependencies": {
"@babel/core": "^7.11.0",
"babel-loader": "^8.1.0",
"node-libs-browser": "^0.5.2",
"webpack": "^4.44.1",
"webpack-dev-server": "^3.11.0"
}
}
20 changes: 20 additions & 0 deletions packages/d3-state-visualizer/examples/tree/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');

new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true,
stats: {
colors: true
}
}).listen(3000, 'localhost', function (err) {
if (err) {
// eslint-disable-next-line no-console
console.log(err);
}

// eslint-disable-next-line no-console
console.log('Listening at localhost:3000');
});
31 changes: 31 additions & 0 deletions packages/d3-state-visualizer/examples/tree/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
var path = require('path');
var webpack = require('webpack');

module.exports = {
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
devtool: 'eval-source-map',
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'./index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
],
resolve: {
extensions: ['.js']
},
module: {
rules: [{
test: /\.js$/,
loaders: ['babel-loader'],
exclude: /node_modules/,
include: __dirname
}]
}
};
55 changes: 55 additions & 0 deletions packages/d3-state-visualizer/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"name": "d3-state-visualizer",
"version": "1.3.2",
"description": "Visualize your app state with a range of reusable charts",
"main": "lib/index.js",
"files": [
"dist",
"lib",
"src"
],
"scripts": {
"clean": "rimraf lib dist",
"build": "babel src --out-dir lib",
"build:umd": "webpack src/index.js -o dist/d3-state-visualizer.js --config webpack.config.development.js",
"build:umd:min": "webpack src/index.js -o dist/d3-state-visualizer.min.js --config webpack.config.production.js",
"prepare": "npm run build",
"prepublishOnly": "npm run clean && npm run build && npm run build:umd && npm run build:umd:min"
},
"repository": {
"type": "git",
"url": "https://github.com/reduxjs/redux-devtools.git"
},
"keywords": [
"d3",
"state",
"store",
"tree",
"visualization"
],
"author": "romseguy",
"license": "MIT",
"bugs": {
"url": "https://github.com/reduxjs/redux-devtools/issues"
},
"homepage": "https://github.com/reduxjs/redux-devtools",
"devDependencies": {
"@babel/cli": "^7.10.5",
"@babel/core": "^7.11.0",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/plugin-proposal-export-default-from": "^7.10.4",
"@babel/preset-env": "^7.11.0",
"@babel/preset-react": "^7.10.4",
"babel-loader": "^8.1.0",
"rimraf": "^2.7.1",
"webpack": "^4.44.1"
},
"dependencies": {
"d3": "^3.5.17",
"d3tooltip": "^1.2.2",
"deepmerge": "^0.2.10",
"is-plain-object": "^2.0.4",
"map2tree": "^1.4.1",
"ramda": "^0.17.1"
}
}
1 change: 1 addition & 0 deletions packages/d3-state-visualizer/src/charts/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export tree from './tree/tree';
23 changes: 23 additions & 0 deletions packages/d3-state-visualizer/src/charts/tree/sortAndSerialize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
function sortObject(obj, strict) {
if (obj instanceof Array) {
let ary
if (strict) {
ary = obj.sort()
} else {
ary = obj
}
return ary
}

if (obj && typeof obj === 'object') {
const tObj = {}
Object.keys(obj).sort().forEach(key => tObj[key] = sortObject(obj[key]))
return tObj
}

return obj
}

export default function sortAndSerialize(obj) {
return JSON.stringify(sortObject(obj, true), undefined, 2)
}
Loading