diff --git a/src/components/app.js b/src/components/app.js index b67e782f..998b2f67 100644 --- a/src/components/app.js +++ b/src/components/app.js @@ -6,7 +6,7 @@ import { connect } from "react-redux"; import PulseLoader from "halogen/PulseLoader"; import LeftSideBar from "./leftsidebar"; -import Continuous from "./continuous/continuous"; +import Parallel from "./continuous/parallel"; import DynamicScatterplot from "./scatterplot/scatterplot"; import Joy from "./joy/joy"; import Graph from "./graph/graph"; @@ -70,7 +70,7 @@ class App extends React.Component { }}> - {/**/} + {/**/} diff --git a/src/components/continuous/parallel.js b/src/components/continuous/parallel.js new file mode 100644 index 00000000..9660e084 --- /dev/null +++ b/src/components/continuous/parallel.js @@ -0,0 +1,157 @@ +/* rc slider https://www.npmjs.com/package/rc-slider */ + +import React from 'react'; +import _ from "lodash"; +import { connect } from "react-redux"; + +import styles from './parallelCoordinates.css'; +import SectionHeader from "../framework/sectionHeader"; + +import setupParallelCoordinates from "./setupParallelCoordinates"; +import drawAxes from "./drawAxes"; +import drawLinesCanvas from "./drawLinesCanvas"; + +import { + margin, + width, + height, + createDimensions, +} from "./util"; + +@connect((state) => { + + const ranges = state.cells.cells && state.cells.cells.data.ranges ? state.cells.cells.data.ranges : null; + const metadata = state.cells.cells && state.cells.cells.data.metadata ? state.cells.cells.data.metadata : null; + + const initializeRanges = state.initialize.data && state.initialize.data.data.ranges ? state.initialize.data.data.ranges : null; + + return { + ranges, + metadata, + initializeRanges, + colorAccessor: state.controls.colorAccessor, + colorScale: state.controls.colorScale, + graphBrushSelection: state.controls.graphBrushSelection, + currentCellSelection: state.controls.currentCellSelection, + axesHaveBeenDrawn: state.controls.axesHaveBeenDrawn, + } +}) +class Parallel extends React.Component { + constructor(props) { + super(props); + this.state = { + svg: null, + ctx: null, + axes: null, + dimensions: null, + }; + } + componentDidMount() { + const {svg, ctx} = setupParallelCoordinates( + width, + height, + margin + ); + this.setState({svg, ctx}) + } + componentWillReceiveProps(nextProps) { + this.maybeDrawAxes(nextProps); + this.maybeDrawLines(nextProps); + } + maybeDrawAxes(nextProps) { + if ( + !this.state.axes && + nextProps.initializeRanges /* axes are created on full range of data */ + ) { + + const dimensions = createDimensions(nextProps.initializeRanges); + + const xscale = d3.scalePoint() + .domain(d3.range(dimensions.length)) + .range([0, width]); + + const axes = drawAxes( + this.state.svg, + this.state.ctx, + dimensions, + xscale, + height, + width, + this.handleBrushAction.bind(this), + this.handleColorAction.bind(this), + ); + + this.setState({ + axes, + xscale, + dimensions, + }) + + this.props.dispatch({ + type: "parallel coordinates axes have been drawn" + }) + + } + } + maybeDrawLines = _.debounce((nextProps) => { /* https://stackoverflow.com/questions/23123138/perform-debounce-in-react-js */ + if ( + nextProps.ranges && + nextProps.currentCellSelection && + nextProps.axesHaveBeenDrawn + ) { + + if (this.state._drawLinesCanvas) { + this.state._drawLinesCanvas.invalidate(); /* this is only necessary if the internals of drawLinesCanvas are using the render queue */ + } + + this.state.ctx.clearRect(0, 0, width, height); + + const _drawLinesCanvas = drawLinesCanvas( + nextProps.currentCellSelection, + this.state.dimensions, + this.state.xscale, + this.state.ctx, + nextProps.colorAccessor, + nextProps.colorScale, + ); + + this.setState({ + _drawLinesCanvas, /* this will only exist if the internals of drawLinesCanvas are using the render queue */ + }) + } + }, 200) + + handleBrushAction (selection) { + this.props.dispatch({ + type: "continuous selection using parallel coords brushing", + data: selection + }) + } + handleColorAction (key) { + this.props.dispatch({ + type: "color by continuous metadata", + colorAccessor: key, + rangeMaxForColorAccessor: this.props.initializeRanges[key].range.max + }); + } + + render() { + + return ( +
+
+
+ ) + } +}; + +export default Parallel; + + +//