Skip to content

Commit 8b270f1

Browse files
committed
WIP: Add Color Scale Data Viewer
Basic color range works Better types Support mid color WIP Fix imports
1 parent 22ca5af commit 8b270f1

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed

__fixtures__/ColorScale.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// @flow
2+
3+
import { createFixture } from "react-cosmos";
4+
import Spreadsheet, {
5+
createEmptyMatrix
6+
} from "../src/SpreadsheetStateProvider";
7+
import createColorScaleDataViewer from "../src/ColorScaleDataViewer";
8+
import "./index.css";
9+
10+
const ROWS = 10;
11+
12+
const initialData = createEmptyMatrix(ROWS, 4);
13+
14+
const GreenAndWhiteColorScaleDataViewer = createColorScaleDataViewer({
15+
minPoint: { type: "minimum", color: "#57BB8A" },
16+
maxPoint: { type: "maximum", color: "#FFFFFF" }
17+
});
18+
19+
const RedYellowGreenColorScaleDataViewer = createColorScaleDataViewer({
20+
minPoint: { type: "minimum", color: "#57BB8A" },
21+
midPoint: { type: "percent", color: "#FFD665", value: 0.5 },
22+
maxPoint: { type: "maximum", color: "#E67B73" }
23+
});
24+
25+
const UnbalanacedRedYellowGreenColorScaleDataViewer = createColorScaleDataViewer(
26+
{
27+
minPoint: { type: "minimum", color: "#57BB8A" },
28+
midPoint: { type: "percent", color: "#FFD665", value: 0.7 },
29+
maxPoint: { type: "maximum", color: "#E67B73" }
30+
}
31+
);
32+
33+
for (let i = 0; i < ROWS; i++) {
34+
initialData[i][0] = {
35+
DataViewer: GreenAndWhiteColorScaleDataViewer,
36+
value: i + 1
37+
};
38+
initialData[i][1] = {
39+
DataViewer: RedYellowGreenColorScaleDataViewer,
40+
value: i + 1
41+
};
42+
initialData[i][2] = {
43+
DataViewer: UnbalanacedRedYellowGreenColorScaleDataViewer,
44+
value: i + 1
45+
};
46+
}
47+
48+
export default createFixture({
49+
component: Spreadsheet,
50+
props: {
51+
data: initialData
52+
}
53+
});

src/ColorScaleDataViewer.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// @flow
2+
3+
import React from "react";
4+
import { connect } from "unistore/react";
5+
import tinygradient from "tinygradient";
6+
import DataViewer from "./DataViewer";
7+
import type { Props as DataViewerProps } from "./DataViewer";
8+
9+
type ColorScalePoint =
10+
| { color: string, type: "number", value: number }
11+
| { color: string, type: "percent", value: number }
12+
| { color: string, type: "percentile", value: number };
13+
14+
type MinPoint = ColorScalePoint | { type: "minimum", color: string };
15+
type MidPoint = ColorScalePoint | null;
16+
type MaxPoint = ColorScalePoint | { type: "maximum", color: string };
17+
18+
type Props = DataViewerProps & {
19+
columnMaxValue: number,
20+
columnMinValue: number,
21+
columnSize: number,
22+
minPoint: MinPoint,
23+
midPoint: MidPoint,
24+
maxPoint: MaxPoint
25+
};
26+
27+
const resolveColor = (props: Props): ?string => {
28+
const {
29+
columnMaxValue,
30+
columnMinValue,
31+
minPoint,
32+
midPoint,
33+
maxPoint,
34+
columnSize,
35+
cell
36+
} = props;
37+
if (!cell || !cell.value) {
38+
return null;
39+
}
40+
const { value } = cell;
41+
42+
const colors = midPoint
43+
? [
44+
{ color: minPoint.color, pos: 0 },
45+
{ color: midPoint.color, pos: midPoint.value },
46+
{ color: maxPoint.color, pos: 1 }
47+
]
48+
: [{ color: minPoint.color, pos: 0 }, { color: maxPoint.color, pos: 1 }];
49+
50+
const gradient = tinygradient(colors);
51+
const relativeValue =
52+
(value - columnMinValue) / (columnMaxValue - columnMinValue);
53+
return gradient.rgbAt(relativeValue);
54+
};
55+
56+
const ColorScaleDataViewer = (props: Props) => {
57+
const color = resolveColor(props);
58+
return (
59+
<div style={{ backgroundColor: color }}>
60+
<DataViewer {...props} />
61+
</div>
62+
);
63+
};
64+
65+
const mapStateToProps = (state, props) => {
66+
let columnMaxValue: number;
67+
let columnMinValue: number;
68+
for (const row of state.data) {
69+
const cell = row[props.column];
70+
const value = cell && cell.value;
71+
if (!value) {
72+
continue;
73+
}
74+
columnMaxValue = columnMaxValue ? Math.max(value, columnMaxValue) : value;
75+
columnMinValue = columnMinValue ? Math.min(value, columnMinValue) : value;
76+
}
77+
return { columnMaxValue, columnMinValue, columnSize: state.data.length };
78+
};
79+
80+
const createColorScaleDataViewer = ({
81+
minPoint,
82+
maxPoint,
83+
midPoint
84+
}: {
85+
minPoint: MinPoint,
86+
maxPoint: MaxPoint,
87+
midPoint?: MidPoint
88+
}) => {
89+
const BoundScaleDataViewer = props => {
90+
return (
91+
<ColorScaleDataViewer
92+
{...props}
93+
minPoint={minPoint}
94+
midPoint={midPoint}
95+
maxPoint={maxPoint}
96+
/>
97+
);
98+
};
99+
return connect(mapStateToProps)(BoundScaleDataViewer);
100+
};
101+
102+
export default createColorScaleDataViewer;

0 commit comments

Comments
 (0)