diff --git a/client/src/components/continuous/continuous.js b/client/src/components/continuous/continuous.js
index 8c12609f..2056b92d 100644
--- a/client/src/components/continuous/continuous.js
+++ b/client/src/components/continuous/continuous.js
@@ -5,17 +5,8 @@ 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 HistogramBrush from "./histogramBrush";
-import { margin, width, height, createDimensions } from "./util";
-
@connect(state => {
const metadata = _.get(state.controls.world, "obsAnnotations", null);
const ranges = _.get(state.controls.world, "summary.obs", null);
@@ -29,35 +20,29 @@ import { margin, width, height, createDimensions } from "./util";
};
})
class Continuous extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- svg: null,
- ctx: null,
- axes: null,
- dimensions: null
- };
- }
-
handleBrushAction(selection) {
- this.props.dispatch({
+ const { dispatch } = this.props;
+ dispatch({
type: "continuous selection using parallel coords brushing",
data: selection
});
}
handleColorAction(key) {
- this.props.dispatch({
+ const { dispatch, ranges } = this.props;
+ dispatch({
type: "color by continuous metadata",
colorAccessor: key,
- rangeMaxForColorAccessor: this.props.ranges[key].range.max
+ rangeMaxForColorAccessor: ranges[key].range.max
});
}
render() {
+ const { ranges } = this.props;
+
return (
- {_.map(this.props.ranges, (value, key) => {
+ {_.map(ranges, (value, key) => {
const isColorField = key.includes("color") || key.includes("Color");
if (value.range && key !== "name" && !isColorField) {
return (
@@ -68,6 +53,7 @@ class Continuous extends React.Component {
/>
);
}
+ return null;
})}
);
@@ -75,5 +61,3 @@ class Continuous extends React.Component {
}
export default Continuous;
-
-//
diff --git a/client/src/components/continuous/drawAxes.js b/client/src/components/continuous/drawAxes.js
index 2ef6df4b..35aa43cf 100644
--- a/client/src/components/continuous/drawAxes.js
+++ b/client/src/components/continuous/drawAxes.js
@@ -1,4 +1,5 @@
// jshint esversion: 6
+import * as d3 from "d3";
import styles from "./parallelCoordinates.css";
import { yAxis, brushstart } from "./util";
@@ -19,13 +20,11 @@ const drawAxes = (
******************************************/
function brush() {
- var actives = [];
+ const actives = [];
svg
.selectAll(".parcoords_axis .parcoords_brush")
- .filter(function(d) {
- return d3.brushSelection(this);
- })
- .each(function(d) {
+ .filter(() => d3.brushSelection(this))
+ .each(d => {
actives.push({
dimension: d,
extent: d3.brushSelection(this)
@@ -35,20 +34,18 @@ const drawAxes = (
handleBrushAction(actives);
}
- var axes = svg
+ const axes = svg
.selectAll(".parcoords_axis")
.data(dimensions)
.enter()
.append("g")
.attr("class", `${styles.axis} parcoords_axis`)
- .attr("transform", (d, i) => {
- return "translate(" + xscale(i) + ")";
- });
+ .attr("transform", (d, i) => `translate(${xscale(i)})`);
axes
.append("g")
- .each(function(d) {
- var renderAxis =
+ .each(d => {
+ const renderAxis =
"axis" in d
? d.axis.scale(d.scale) // custom axis
: yAxis.scale(d.scale); // default axis
@@ -60,15 +57,13 @@ const drawAxes = (
})
.attr("class", styles.title)
.attr("text-anchor", "start")
- .text(function(d) {
- return "description" in d ? d.description + " 🖌️" : d.key + " 🖌️";
- });
+ .text(d => ("description" in d ? `${d.description} 🖌️` : `${d.key} 🖌️`));
// Add and store a brush for each axis.
axes
.append("g")
.attr("class", `${styles.brush} parcoords_brush`)
- .each(function(d) {
+ .each(d => {
d3.select(this).call(
(d.brush = d3
.brushY()
diff --git a/client/src/components/continuous/drawLinesCanvas.js b/client/src/components/continuous/drawLinesCanvas.js
index 05a23ae2..04d69b62 100644
--- a/client/src/components/continuous/drawLinesCanvas.js
+++ b/client/src/components/continuous/drawLinesCanvas.js
@@ -10,54 +10,46 @@ import renderQueue from "../../util/renderQueue";
******************************************
******************************************/
-const drawLinesCanvas = (
- ctx,
- dimensions,
- xscale,
- colorAccessor,
- colorScale
-) => {
- return d => {
- ctx.globalAlpha = 0.1;
+const drawLinesCanvas = (ctx, dimensions, xscale) => d => {
+ ctx.globalAlpha = 0.1;
- if (d["__selected__"]) {
- ctx.strokeStyle = d["__color__"];
- } else {
+ if (d.__selected__) {
+ ctx.strokeStyle = d.__color__;
+ } else {
+ return;
+ }
+
+ ctx.beginPath();
+ const coords = project(d, dimensions, xscale);
+ coords.forEach((p, i) => {
+ // this tricky bit avoids rendering null values as 0
+ if (p === null) {
+ // this bit renders horizontal lines on the previous/next
+ // dimensions, so that sandwiched null values are visible
+ if (i > 0) {
+ const prev = coords[i - 1];
+ if (prev !== null) {
+ ctx.moveTo(prev[0], prev[1]);
+ ctx.lineTo(prev[0] + 6, prev[1]);
+ }
+ }
+ if (i < coords.length - 1) {
+ const next = coords[i + 1];
+ if (next !== null) {
+ ctx.moveTo(next[0] - 6, next[1]);
+ }
+ }
return;
}
- ctx.beginPath();
- var coords = project(d, dimensions, xscale);
- coords.forEach((p, i) => {
- // this tricky bit avoids rendering null values as 0
- if (p === null) {
- // this bit renders horizontal lines on the previous/next
- // dimensions, so that sandwiched null values are visible
- if (i > 0) {
- var prev = coords[i - 1];
- if (prev !== null) {
- ctx.moveTo(prev[0], prev[1]);
- ctx.lineTo(prev[0] + 6, prev[1]);
- }
- }
- if (i < coords.length - 1) {
- var next = coords[i + 1];
- if (next !== null) {
- ctx.moveTo(next[0] - 6, next[1]);
- }
- }
- return;
- }
+ if (i === 0) {
+ ctx.moveTo(p[0], p[1]);
+ return;
+ }
- if (i == 0) {
- ctx.moveTo(p[0], p[1]);
- return;
- }
-
- ctx.lineTo(p[0], p[1]);
- });
- ctx.stroke();
- };
+ ctx.lineTo(p[0], p[1]);
+ });
+ ctx.stroke();
};
const drawCellLinesUsingRenderQueue = (
diff --git a/client/src/components/continuous/histogramBrush.js b/client/src/components/continuous/histogramBrush.js
index dda1219d..059f73f4 100644
--- a/client/src/components/continuous/histogramBrush.js
+++ b/client/src/components/continuous/histogramBrush.js
@@ -12,14 +12,12 @@ import * as d3 from "d3";
import memoize from "memoize-one";
import * as globals from "../../globals";
-@connect(state => {
- return {
- initializeRanges: _.get(state.controls.world, "summary.obs"),
- colorAccessor: state.controls.colorAccessor,
- colorScale: state.controls.colorScale,
- obsAnnotations: _.get(state.controls.world, "obsAnnotations", null)
- };
-})
+@connect(state => ({
+ initializeRanges: _.get(state.controls.world, "summary.obs"),
+ colorAccessor: state.controls.colorAccessor,
+ colorScale: state.controls.colorScale,
+ obsAnnotations: _.get(state.controls.world, "obsAnnotations", null)
+}))
class HistogramBrush extends React.Component {
calcHistogramCache = memoize((obsAnnotations, metadataField, ranges) => {
// recalculate expensive stuff
@@ -101,18 +99,10 @@ class HistogramBrush extends React.Component {
.enter()
.append("rect")
.attr("class", "bar")
- .attr("x", function(d) {
- return x(d.x0) + 1;
- })
- .attr("y", function(d) {
- return y(d.length / numValues);
- })
- .attr("width", function(d) {
- return Math.abs(x(d.x1) - x(d.x0) - 1);
- })
- .attr("height", function(d) {
- return y(0) - y(d.length / numValues);
- });
+ .attr("x", d => x(d.x0) + 1)
+ .attr("y", d => y(d.length / numValues))
+ .attr("width", d => Math.abs(x(d.x1) - x(d.x0) - 1))
+ .attr("height", d => y(0) - y(d.length / numValues));
if (!this.state.brush && !this.state.axis) {
const brush = d3
@@ -122,20 +112,14 @@ class HistogramBrush extends React.Component {
.call(
d3
.brushX()
- .on(
- "end",
- this.onBrush(this.props.metadataField, x.invert).bind(this)
- )
+ .on("end", this.onBrush(metadataField, x.invert).bind(this))
);
const xAxis = d3
.select(svgRef)
.append("g")
.attr("class", "axis axis--x")
- .attr(
- "transform",
- "translate(0," + (this.height - this.marginBottom) + ")"
- )
+ .attr("transform", `translate(0,${this.height - this.marginBottom})`)
.call(d3.axisBottom(x).ticks(5))
.append("text")
.attr("x", this.width - 2)
@@ -143,30 +127,30 @@ class HistogramBrush extends React.Component {
.attr("fill", "#000")
.attr("text-anchor", "end")
.attr("font-weight", "bold")
- .text(this.props.metadataField);
+ .text(metadataField);
this.setState({ brush, xAxis });
}
}
handleColorAction() {
- this.props.dispatch({
+ const { dispatch, metadataField, initializeRanges } = this.props;
+ dispatch({
type: "color by continuous metadata",
- colorAccessor: this.props.metadataField,
- rangeMaxForColorAccessor: this.props.initializeRanges[
- this.props.metadataField
- ].range.max
+ colorAccessor: metadataField,
+ rangeMaxForColorAccessor: initializeRanges[metadataField].range.max
});
}
render() {
+ const { metadataField, ranges, colorAccessor } = this.props;
return (
{
- var container = d3.select("#parcoords");
+import * as d3 from "d3";
- var svg = container
+const setupParallelCoordinates = (width, height, margin) => {
+ const container = d3.select("#parcoords");
+
+ const svg = container
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
- .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+ .attr("transform", `translate(${margin.left},${margin.top})`);
- var canvas = container
+ const canvas = container
.append("canvas")
.attr("width", width * devicePixelRatio)
.attr("height", height * devicePixelRatio)
- .style("width", width + "px")
- .style("height", height + "px")
- .style("margin-top", margin.top + "px")
- .style("margin-left", margin.left + "px");
+ .style("width", `${width}px`)
+ .style("height", `${height}px`)
+ .style("margin-top", `${margin.top}px`)
+ .style("margin-left", `${margin.left}px`);
- var ctx = canvas.node().getContext("2d");
+ const ctx = canvas.node().getContext("2d");
ctx.globalCompositeOperation = "darken";
ctx.globalAlpha = 0.15;
ctx.lineWidth = 1.5;
diff --git a/client/src/components/continuous/util.js b/client/src/components/continuous/util.js
index 80b18baa..212fe177 100644
--- a/client/src/components/continuous/util.js
+++ b/client/src/components/continuous/util.js
@@ -18,11 +18,10 @@ export const createDimensions = data => {
_.each(data, (value, key) => {
if (value.range) {
newArr.push({
- key: key /* room for confusion: lodash calls this key, it's also the name of the property parallel coords code is looking for */,
+ key /* room for confusion: lodash calls this key, it's also the name of the property parallel coords code is looking for */,
type: {
- within: (d, extent, dim) => {
- return extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1];
- }
+ within: (d, extent, dim) =>
+ extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1]
},
scale: d3
.scaleSqrt()
@@ -41,18 +40,13 @@ export const brushstart = () => {
};
export const d3_functor = v => {
- return typeof v === "function"
- ? v
- : () => {
- return v;
- };
+ return typeof v === "function" ? v : () => v;
};
-export const project = (d, dimensions, xscale) => {
- return dimensions.map((p, i) => {
+export const project = (d, dimensions, xscale) =>
+ dimensions.map((p, i) => {
// check if data element has property and contains a value
if (!(p.key in d) || d[p.key] === null) return null;
return [xscale(i), p.scale(d[p.key])];
});
-};