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 data layers #129

Merged
merged 68 commits into from
Apr 7, 2020
Merged
Show file tree
Hide file tree
Changes from 63 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
64a770d
Add custom ranking to layout algorithm
richardwestenra Oct 11, 2019
f93cca9
Add demo 'layers' dataset
richardwestenra Oct 11, 2019
3565b23
Add ranker toggle
richardwestenra Oct 11, 2019
4b2f042
Install WIP dagre PR branch
richardwestenra Oct 11, 2019
f32e31b
🌈
richardwestenra Oct 11, 2019
c48fc7b
Add ranking bands
richardwestenra Oct 14, 2019
e139461
Merge branch 'develop' into prototype/custom-ranking
richardwestenra Feb 21, 2020
fda2a2b
Fix dagre git URL in package.json + lockfile
richardwestenra Mar 3, 2020
ea1986c
Fix layers mock data path
richardwestenra Mar 3, 2020
5102938
Fix App proptype error
richardwestenra Mar 3, 2020
c746b51
Fix ranker toggler
richardwestenra Mar 3, 2020
0e483a3
Change bands to only show on hover
richardwestenra Mar 3, 2020
f5703de
Remove circles that were reintroduced in merge
richardwestenra Mar 3, 2020
63f7141
Add zoom extent
richardwestenra Mar 3, 2020
1542348
Move bands calculation into a selector
richardwestenra Mar 3, 2020
69acdac
Improve band height calculation
richardwestenra Mar 3, 2020
3cc9453
Add layer names
richardwestenra Mar 3, 2020
bc80fa1
Remove rainbow colours from bands
richardwestenra Mar 4, 2020
84bc4f4
Rename bands to layers
richardwestenra Mar 4, 2020
2671cf3
Distinguish between rank and layer
richardwestenra Mar 4, 2020
719d020
Move layer styles & selector into separate files
richardwestenra Mar 4, 2020
b9a993e
Allow multiple ranks per layer
richardwestenra Mar 4, 2020
4c966bd
Remove node fill rainbow colours
richardwestenra Mar 4, 2020
3a0085f
Add release note
richardwestenra Mar 5, 2020
c45ed3b
Revert "Add release note"
richardwestenra Mar 6, 2020
982144a
Add backwards-compatibility for layers/ranker
richardwestenra Mar 6, 2020
149babb
Add TODO comments for temporary code
richardwestenra Mar 13, 2020
a66828c
Merge branch 'develop' into prototype/custom-ranking
richardwestenra Mar 13, 2020
0e98eb0
Fix animation delay bug
richardwestenra Mar 13, 2020
3fae2ca
Break D3 draw function into multiple functions
richardwestenra Mar 13, 2020
0750800
Move layer name labels to left side
richardwestenra Mar 16, 2020
7650e85
Add button to toggle layers
richardwestenra Mar 16, 2020
a3be92f
Remove ranker toggle
richardwestenra Mar 16, 2020
450aba1
Fix filtered-layer bug
richardwestenra Mar 16, 2020
9aa74db
Add JSDoc comment
richardwestenra Mar 16, 2020
c82df25
Animate layer label dx when toggling sidebar
richardwestenra Mar 16, 2020
608ff1a
Remove leftover layer label bg rect
richardwestenra Mar 16, 2020
c14f774
Make layer labels HTML elements, add BG gradient
richardwestenra Mar 16, 2020
0bea7ba
Calculate custom node ranks with batching-toposort
richardwestenra Mar 17, 2020
b982c29
Remove ranks from mock dataset
richardwestenra Mar 17, 2020
39fc0ef
Move node/edge disabled selectors to new file
richardwestenra Mar 17, 2020
b3b2ef0
Move rank calculation into new file
richardwestenra Mar 17, 2020
7e89f00
Insert ranks directly into formatted node objects
richardwestenra Mar 17, 2020
8ff2630
Fix bug with non-sequential layers
richardwestenra Mar 18, 2020
1ce21f2
Prevent errors when no nodes are present
richardwestenra Mar 18, 2020
08e7f14
Fix layers on light theme
richardwestenra Mar 18, 2020
8b12358
Add new layers icon
richardwestenra Mar 19, 2020
92e857a
Limit zoom translate
richardwestenra Mar 20, 2020
a307d38
Add layer tags to mock dataset
richardwestenra Mar 20, 2020
8b3f48d
Don't calculate ranks if layers are hidden
richardwestenra Mar 23, 2020
a38d3b0
Set !state.visible.layers if dataset has no layers
richardwestenra Mar 23, 2020
3ac91d2
Save visible state to localStorage
richardwestenra Mar 23, 2020
3a37f06
Reducer layer band opacity
richardwestenra Mar 23, 2020
6c949e1
Update visible btn props, e.g. visible.layerBtn
richardwestenra Mar 23, 2020
05e97ad
Fix broken tests
richardwestenra Mar 23, 2020
f2c708c
Add tests for layers selector
richardwestenra Mar 23, 2020
b465230
Add rank tests
richardwestenra Mar 23, 2020
0633987
Revert temporary rank/layer name in tooltip text
richardwestenra Mar 23, 2020
87f1a17
Improve action/reducer test coverage
richardwestenra Mar 23, 2020
561adc2
Change origin branch for Dagre
richardwestenra Mar 24, 2020
d6d4c9b
Merge branch 'develop' into prototype/custom-ranking
richardwestenra Mar 27, 2020
392e702
Remove unnecessary 'draw' argument
richardwestenra Mar 27, 2020
a0b9e18
Merge branch 'develop' into prototype/custom-ranking
richardwestenra Apr 2, 2020
c59365d
Improve test naming
richardwestenra Apr 6, 2020
137979c
Improve variable naming
richardwestenra Apr 6, 2020
80f0f12
Improve getNodeDisabledTag tests
richardwestenra Apr 6, 2020
78dbf90
Don't run layout if !nodes.length
richardwestenra Apr 7, 2020
b32e849
Update test name
richardwestenra Apr 7, 2020
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
14 changes: 9 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
},
"dependencies": {
"@quantumblack/kedro-ui": "^1.1.2",
"batching-toposort": "^1.2.0",
"classnames": "^2.2.6",
"d3-fetch": "^1.1.2",
"d3-interpolate-path": "^2.1.0",
Expand All @@ -38,7 +39,7 @@
"d3-shape": "^1.3.5",
"d3-transition": "^1.2.0",
"d3-zoom": "^1.7.3",
"dagre": "^0.8.5",
"dagre": "git+https://github.com/richardwestenra/dagre.git#manual-ranking",
"konami-code": "^0.2.1",
"react-custom-scrollbars": "^4.2.1",
"react-flip-toolkit": "^7.0.7",
Expand Down
22 changes: 22 additions & 0 deletions src/actions/actions.test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import animals from '../utils/data/animals.mock';
import {
RESET_DATA,
TOGGLE_LAYERS,
TOGGLE_SIDEBAR,
TOGGLE_TEXT_LABELS,
TOGGLE_THEME,
UPDATE_CHART_SIZE,
UPDATE_FONT_LOADED,
resetData,
toggleLayers,
toggleSidebar,
toggleTextLabels,
toggleTheme,
updateChartSize,
Expand Down Expand Up @@ -36,6 +40,24 @@ describe('actions', () => {
expect(resetData(animals)).toEqual(expectedAction);
});

it('should create an action to toggle whether to show layers', () => {
const visible = false;
const expectedAction = {
type: TOGGLE_LAYERS,
visible
};
expect(toggleLayers(visible)).toEqual(expectedAction);
});

it('should create an action to toggle whether the sidebar is open', () => {
const visible = false;
const expectedAction = {
type: TOGGLE_SIDEBAR,
visible
};
expect(toggleSidebar(visible)).toEqual(expectedAction);
});

it('should create an action to toggle whether a node has been clicked', () => {
const nodeClicked = '12367890';
const expectedAction = {
Expand Down
13 changes: 13 additions & 0 deletions src/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,19 @@ export function resetData(data) {
};
}

export const TOGGLE_LAYERS = 'TOGGLE_LAYERS';

/**
* Toggle whether to show layers on/off
* @param {Boolean} layers True if text labels are to be shown
*/
export function toggleLayers(visible) {
return {
type: TOGGLE_LAYERS,
visible
};
}

export const TOGGLE_TEXT_LABELS = 'TOGGLE_TEXT_LABELS';

/**
Expand Down
6 changes: 5 additions & 1 deletion src/components/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class App extends React.Component {

App.propTypes = {
data: PropTypes.oneOfType([
PropTypes.oneOf(['random', 'lorem', 'animals', 'demo', 'json']),
PropTypes.oneOf(['random', 'lorem', 'animals', 'demo', 'json', 'layers']),
PropTypes.shape({
schema_id: PropTypes.string,
edges: PropTypes.array.isRequired,
Expand All @@ -84,6 +84,10 @@ App.propTypes = {
theme: PropTypes.oneOf(['dark', 'light']),
visible: PropTypes.shape({
labelBtn: PropTypes.bool,
layerBtn: PropTypes.bool,
layers: PropTypes.bool,
exportBtn: PropTypes.bool,
sidebar: PropTypes.bool,
themeBtn: PropTypes.bool
})
};
Expand Down
69 changes: 69 additions & 0 deletions src/components/flowchart/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,73 @@ import { select } from 'd3-selection';
import { curveBasis, line } from 'd3-shape';
import icon from './icon';

/**
* Render layer bands
*/
const drawLayers = function() {
const { layers, visibleLayers } = this.props;

this.el.layers = this.el.layerGroup
.selectAll('.layer')
.data(visibleLayers ? layers : [], layer => layer.id);

const enterLayers = this.el.layers
.enter()
.append('rect')
.attr('class', 'layer');

this.el.layers.exit().remove();

this.el.layers = this.el.layers.merge(enterLayers);

this.el.layers
.attr('x', d => d.x)
.attr('y', d => d.y)
.attr('height', d => d.height)
.attr('width', d => d.width);
};

/**
* Render layer name labels
*/
const drawLayerNames = function() {
const {
chartSize: { sidebarWidth = 0 },
layers,
visibleLayers
} = this.props;

this.el.layerNameGroup
.transition('layer-names-sidebar-width')
.duration(this.DURATION)
.style('transform', `translateX(${sidebarWidth}px)`);

this.el.layerNames = this.el.layerNameGroup
.selectAll('.layer-name')
.data(visibleLayers ? layers : [], layer => layer.id);

const enterLayerNames = this.el.layerNames
.enter()
.append('li')
.attr('class', 'layer-name')
.style('opacity', 0)
.transition('enter-layer-names')
.duration(this.DURATION)
.style('opacity', 1);

this.el.layerNames
.exit()
.style('opacity', 1)
.transition('exit-layer-names')
.duration(this.DURATION)
.style('opacity', 0)
.remove();

this.el.layerNames = this.el.layerNames.merge(enterLayerNames);

this.el.layerNames.text(d => d.name).attr('dy', 5);
};

/**
* Render node icons and name labels
*/
Expand Down Expand Up @@ -150,6 +217,8 @@ const drawEdges = function() {
* Render chart to the DOM with D3
*/
const draw = function() {
drawLayers.call(this);
drawLayerNames.call(this);
drawEdges.call(this);
drawNodes.call(this);
};
Expand Down
2 changes: 2 additions & 0 deletions src/components/flowchart/flowchart.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ describe('FlowChart', () => {
chartSize: expect.any(Object),
edges: expect.any(Array),
graphSize: expect.any(Object),
layers: expect.any(Array),
linkedNodes: expect.any(Object),
nodes: expect.any(Array),
textLabels: expect.any(Boolean),
visibleLayers: expect.any(Boolean),
visibleSidebar: expect.any(Boolean),
zoom: expect.any(Object)
};
Expand Down
26 changes: 23 additions & 3 deletions src/components/flowchart/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
getLayoutEdges,
getZoomPosition
} from '../../selectors/layout';
import { getLayers } from '../../selectors/layers';
import { getCentralNode, getLinkedNodes } from '../../selectors/linked-nodes';
import draw from './draw';
import './styles/flowchart.css';
Expand All @@ -39,6 +40,8 @@ export class FlowChart extends Component {
this.wrapperRef = React.createRef();
this.edgesRef = React.createRef();
this.nodesRef = React.createRef();
this.layersRef = React.createRef();
this.layerNamesRef = React.createRef();
}

componentDidMount() {
Expand Down Expand Up @@ -72,7 +75,9 @@ export class FlowChart extends Component {
svg: select(this.svgRef.current),
wrapper: select(this.wrapperRef.current),
edgeGroup: select(this.edgesRef.current),
nodeGroup: select(this.nodesRef.current)
nodeGroup: select(this.nodesRef.current),
layerGroup: select(this.layersRef.current),
layerNameGroup: select(this.layerNamesRef.current)
};
}

Expand Down Expand Up @@ -124,7 +129,7 @@ export class FlowChart extends Component {
*/
initZoomBehaviour() {
this.zoomBehaviour = zoom().on('zoom', () => {
const { k: scale } = event.transform;
const { k: scale, y } = event.transform;
const { sidebarWidth } = this.props.chartSize;
const { width, height } = this.props.graphSize;

Expand All @@ -140,6 +145,14 @@ export class FlowChart extends Component {
// Transform the <g> that wraps the chart
this.el.wrapper.attr('transform', event.transform);

// Update layer label y positions
this.el.layerNames
.style('height', d => `${d.height * scale}px`)
.style('transform', d => {
const ty = y + d.y * scale;
return `translateY(${ty}px)`;
});

// Hide the tooltip so it doesn't get misaligned to its node
this.hideTooltip();
});
Expand Down Expand Up @@ -255,7 +268,7 @@ export class FlowChart extends Component {
* Render React elements
*/
render() {
const { outerWidth, outerHeight } = this.props.chartSize;
const { outerWidth = 0, outerHeight = 0 } = this.props.chartSize;
const {
tooltipVisible,
tooltipIsRight,
Expand Down Expand Up @@ -290,6 +303,7 @@ export class FlowChart extends Component {
</marker>
</defs>
<g id="zoom-wrapper" ref={this.wrapperRef}>
<g className="pipeline-flowchart__layers" ref={this.layersRef} />
<g className="pipeline-flowchart__edges" ref={this.edgesRef} />
<g
id="nodes"
Expand All @@ -298,6 +312,10 @@ export class FlowChart extends Component {
/>
</g>
</svg>
<ul
className="pipeline-flowchart__layer-names"
ref={this.layerNamesRef}
/>
<div
className={classnames('pipeline-flowchart__tooltip kedro', {
'tooltip--visible': tooltipVisible,
Expand All @@ -316,9 +334,11 @@ export const mapStateToProps = state => ({
chartSize: getChartSize(state),
edges: getLayoutEdges(state),
graphSize: getGraphSize(state),
layers: getLayers(state),
linkedNodes: getLinkedNodes(state),
nodes: getLayoutNodes(state),
textLabels: state.textLabels,
visibleLayers: state.visible.layers,
visibleSidebar: state.visible.sidebar,
zoom: getZoomPosition(state)
});
Expand Down
1 change: 1 addition & 0 deletions src/components/flowchart/styles/_edges.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
@import './variables';

.edge path {
pointer-events: none;
fill: none;
stroke-width: 1.5px;

Expand Down
48 changes: 48 additions & 0 deletions src/components/flowchart/styles/_layers.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
@import './variables';

.layer {
opacity: 0;
transition: opacity ease 0.5s;

.kui-theme--dark & {
fill: rgba(white, 0.05);
}

.kui-theme--light & {
fill: rgba(black, 0.05);
}

&:hover {
opacity: 1;
}
}

.pipeline-flowchart__layer-names {
position: absolute;
top: 0;
left: 0;
margin: 0;
padding: 0;
list-style: none;
pointer-events: none;
}

.layer-name {
position: absolute;
top: 0;
display: flex;
align-items: center;
width: 130px;
padding-left: 15px;
font-weight: bold;
font-size: 1.6em;
white-space: nowrap;

.kui-theme--dark & {
background: linear-gradient(to right, $color-bg-dark, transparent);
}

.kui-theme--light & {
background: linear-gradient(to right, $color-bg-light, transparent);
}
}
1 change: 1 addition & 0 deletions src/components/flowchart/styles/flowchart.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@import './node';
@import './edges';
@import './layers';
@import './tooltip';

.pipeline-flowchart {
Expand Down
Loading