Skip to content

Commit ac1558d

Browse files
committed
backport fixes from complexdatacollective/Fresco#77
1 parent be7d44f commit ac1558d

File tree

11 files changed

+130
-260
lines changed

11 files changed

+130
-260
lines changed

.prettierrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"tabWidth": 2,
3+
"useTabs": false
4+
}

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"build:ci": "cross-env NC_TARGET_PLATFORM=electron REACT_APP_NO_FULLSCREEN=true REACT_APP_NO_PERSIST=true node scripts/build.js",
2121
"build:ios": "cross-env NC_TARGET_PLATFORM=ios node scripts/build.js && cordova prepare ios",
2222
"lint": "eslint src && eslint public",
23+
"lint:fix": "eslint src --fix && eslint public --fix",
2324
"sass-lint": "stylelint '**/*.scss'",
2425
"test": "node scripts/test.js",
2526
"test:integration": "cross-env TEST_ENV=development jest --config=integration-tests/jest.config.js --runInBand",
Lines changed: 91 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,107 @@
1-
import React, { Component } from 'react';
2-
import PropTypes from 'prop-types';
1+
import { entityAttributesProperty } from '@codaco/shared-consts';
32
import { findIndex } from 'lodash';
4-
import getAbsoluteBoundingRect from '../../utils/getAbsoluteBoundingRect';
5-
import { ConvexHull } from './ConvexHull';
3+
import PropTypes from 'prop-types';
4+
import React, {
5+
useEffect, useMemo, useRef, useState,
6+
} from 'react';
7+
import { useSelector } from 'react-redux';
8+
import { getCategoricalOptions } from '../../selectors/network';
9+
import ConvexHull from './ConvexHull';
10+
import { getStageForCurrentSession } from '../../selectors/session';
11+
12+
const useResizeObserver = (callback, elementRef, options) => {
13+
useEffect(() => {
14+
if (!elementRef.current) return;
15+
16+
const resizeObserver = new ResizeObserver(callback);
17+
resizeObserver.observe(elementRef.current, options);
18+
19+
// eslint-disable-next-line consistent-return
20+
return () => {
21+
resizeObserver.disconnect();
22+
};
23+
}, [callback, elementRef, options]);
24+
};
625

726
const getColor = (group, options) => {
827
const colorIndex = findIndex(options, ['value', group]) + 1 || 1;
928
const color = `cat-color-seq-${colorIndex}`;
1029
return color;
1130
};
1231

13-
class ConvexHulls extends Component {
14-
constructor() {
15-
super();
32+
const getNodesByGroup = (nodes, categoricalVariable) => {
33+
const groupedList = {};
1634

17-
this.hullComponent = React.createRef();
18-
this.state = {
19-
size: { width: 0, height: 0 },
20-
};
21-
}
22-
23-
componentDidMount() {
24-
this.updateSize();
25-
}
26-
27-
shouldComponentUpdate() {
28-
this.updateSize();
29-
return true;
30-
}
31-
32-
updateSize = () => {
33-
const { size } = this.state;
34-
if (this.hullComponent.current && (
35-
size.width !== getAbsoluteBoundingRect(this.hullComponent.current).width
36-
|| size.height !== getAbsoluteBoundingRect(this.hullComponent.current).height)) {
37-
this.setState({
38-
size: {
39-
width: getAbsoluteBoundingRect(this.hullComponent.current).width,
40-
height: getAbsoluteBoundingRect(this.hullComponent.current).height,
41-
},
42-
});
35+
nodes.forEach((node) => {
36+
const categoricalValues = node[entityAttributesProperty][categoricalVariable];
37+
38+
// Filter out nodes with no value for this variable.
39+
if (!categoricalValues) {
40+
return;
4341
}
44-
}
45-
46-
render() {
47-
const {
48-
nodesByGroup,
49-
layoutVariable,
50-
categoricalOptions,
51-
} = this.props;
52-
const {
53-
size,
54-
} = this.state;
55-
56-
return (
57-
<div style={{ width: '100%', height: '100%' }} ref={this.hullComponent}>
58-
{Object.values(nodesByGroup).map(({ group, nodes }, index) => {
59-
const color = getColor(group, categoricalOptions);
60-
return (
61-
<ConvexHull
62-
windowDimensions={size}
63-
color={color}
64-
nodePoints={nodes}
65-
key={index}
66-
layoutVariable={layoutVariable}
67-
/>
68-
);
69-
})}
70-
</div>
71-
);
72-
}
73-
}
7442

75-
ConvexHulls.propTypes = {
76-
layoutVariable: PropTypes.string.isRequired,
77-
nodesByGroup: PropTypes.object.isRequired,
78-
categoricalOptions: PropTypes.array,
43+
categoricalValues.forEach((categoricalValue) => {
44+
if (groupedList[categoricalValue]) {
45+
groupedList[categoricalValue].nodes.push(node);
46+
} else {
47+
groupedList[categoricalValue] = { group: categoricalValue, nodes: [] };
48+
groupedList[categoricalValue].nodes.push(node);
49+
}
50+
});
51+
});
52+
53+
return groupedList;
54+
};
55+
56+
const ConvexHulls = ({ nodes, groupVariable, layoutVariable }) => {
57+
const hullRef = useRef(null);
58+
const [size, setSize] = useState({ width: 0, height: 0 });
59+
60+
const nodesByGroup = useMemo(
61+
() => getNodesByGroup(nodes, groupVariable),
62+
[nodes, groupVariable],
63+
);
64+
const categoricalOptions = useSelector((state) => getCategoricalOptions(state, {
65+
stage: getStageForCurrentSession(state),
66+
variableId: groupVariable,
67+
}));
68+
69+
useResizeObserver(hullRef, () => {
70+
setSize({
71+
width: hullRef.contentRect.width,
72+
height: hullRef.contentRect.height,
73+
});
74+
});
75+
76+
useEffect(() => {
77+
setSize({
78+
width: hullRef.current.clientWidth,
79+
height: hullRef.current.clientHeight,
80+
});
81+
}, [hullRef]);
82+
83+
return (
84+
<div style={{ width: '100%', height: '100%' }} ref={hullRef}>
85+
{Object.values(nodesByGroup).map(({ group, nodes: groupNodes }, index) => {
86+
const color = getColor(group, categoricalOptions);
87+
return (
88+
<ConvexHull
89+
windowDimensions={size}
90+
color={color}
91+
nodePoints={groupNodes}
92+
key={index}
93+
layoutVariable={layoutVariable}
94+
/>
95+
);
96+
})}
97+
</div>
98+
);
7999
};
80100

81-
ConvexHulls.defaultProps = {
82-
categoricalOptions: [],
101+
ConvexHulls.propTypes = {
102+
layoutVariable: PropTypes.string.isRequired,
103+
nodes: PropTypes.array.isRequired,
104+
groupVariable: PropTypes.string.isRequired,
83105
};
84106

85107
export default ConvexHulls;

src/components/Canvas/__tests__/ConvexHulls.test.js

Lines changed: 0 additions & 56 deletions
This file was deleted.

src/containers/Canvas/ConvexHulls.js

Lines changed: 0 additions & 48 deletions
This file was deleted.

src/containers/Canvas/__tests__/ConvexHulls.test.js

Lines changed: 0 additions & 69 deletions
This file was deleted.

src/containers/Canvas/index.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@
22

33
export { default as PresetSwitcherKey } from './PresetSwitcherKey';
44
export { default as Annotations } from './Annotations';
5-
export { default as ConvexHulls } from './ConvexHulls';
65
export { default as Accordion } from './Accordion';
76
export { default as PresetSwitcher } from './PresetSwitcher';

0 commit comments

Comments
 (0)