Skip to content
This repository has been archived by the owner on Feb 19, 2022. It is now read-only.

Legend #189

Merged
merged 23 commits into from
Jan 19, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
dc3142d
Add initial victory-legend
janesh-travolta Aug 24, 2016
e203fe0
updated victory-legend
janesh-travolta Aug 31, 2016
08ecee3
merged master
janesh-travolta Sep 12, 2016
358af4a
minor improvements
janesh-travolta Sep 13, 2016
7d15430
Merge pull request #116 from janesh-travolta/victory-legend
boygirl Sep 21, 2016
e3a9c31
Merge branch 'master' into legend
angelanicholas Jan 11, 2017
8846970
lint and spelling
angelanicholas Jan 18, 2017
6da5333
address PR comments and other refactoring
angelanicholas Jan 18, 2017
619fc26
update demo
angelanicholas Jan 18, 2017
62d081f
update tests
angelanicholas Jan 18, 2017
1294b67
reorder component methods
angelanicholas Jan 18, 2017
4a42957
move leftOffset calc to getLegendState
angelanicholas Jan 18, 2017
080c387
don't pass props around unnecessarily
angelanicholas Jan 18, 2017
1dadd57
fix standalone demo
angelanicholas Jan 18, 2017
d3a59df
move demo for consistency
angelanicholas Jan 18, 2017
1373951
remove state in favor of calculated props in render
angelanicholas Jan 19, 2017
88b1abf
consolidate orientation checks by storing in calculated props
angelanicholas Jan 19, 2017
e9905c8
add theme prop and move default styles
angelanicholas Jan 19, 2017
783031a
fix tests
angelanicholas Jan 19, 2017
d74b1ff
add colorScale prop
angelanicholas Jan 19, 2017
bb1252d
alphabetize props
angelanicholas Jan 19, 2017
ea7a65e
alphabetize default props, remove default padding prop
angelanicholas Jan 19, 2017
bb3a74a
allow height width padding to be specified in theme
angelanicholas Jan 19, 2017
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
Prev Previous commit
Next Next commit
minor improvements
  • Loading branch information
janesh-travolta committed Sep 13, 2016
commit 358af4adc222af85c09c697dac3c95cf43f596af
131 changes: 56 additions & 75 deletions src/victory-legend/victory-legend.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
/*global document:false */

import React, { PropTypes } from "react";
import { merge, assign, isEmpty } from "lodash";
import { merge, assign, isEmpty, defaults } from "lodash";
import VictoryLabel from "../victory-label/victory-label";
import VictoryContainer from "../victory-container/victory-container";
import Point from "../point/point"; // it should be replaced

const defaultFontStyle = {
fontSize: 14,
fontFamily: "'Gill Sans', 'Gill Sans MT', 'Ser­avek', 'Trebuchet MS', sans-serif",
color: "#252525",
backgroundColor: "#d9d9d9",
stroke: "transparent"
import Point from "../victory-primitives/point";
import Textsize from "../victory-util/textsize";

const fallbackProps = {
style: {
symbol: {
fill: "black",
type: "circle"
},
labels: {
fontSize: 14,
fontFamily: "'Gill Sans', 'Gill Sans MT', 'Ser­avek', 'Trebuchet MS', sans-serif",
color: "#252525",
backgroundColor: "#d9d9d9",
stroke: "transparent"
}
}
};

const defaultLegendStyle = {
Expand All @@ -21,24 +28,15 @@ const defaultLegendStyle = {
};

const defaultLegendData = [{
name: "Series 1",
symbol: {
type: "circle",
style: {
fill: "red"
}
}
name: "Series 1"
}, {
name: "Series 2",
symbol: {
type: "diamond",
style: {
fill: "blue"
}
}
name: "Series 2"
}];

export default class VictoryLegend extends React.Component {
static displayName = "VictoryLegend";
static role = "legend";

static propTypes = {
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
Expand All @@ -56,7 +54,10 @@ export default class VictoryLegend extends React.Component {
rowItemSpacing: PropTypes.number,
groupComponent: PropTypes.element,
standalone: PropTypes.bool,
style: PropTypes.object
style: PropTypes.shape({
symbol: PropTypes.object,
labels: PropTypes.object
})
};

static defaultProps = {
Expand All @@ -67,48 +68,24 @@ export default class VictoryLegend extends React.Component {
orientation: "vertical",
columnItemSpacing: 10,
rowItemSpacing: 8,
symbolComponent: <Point/>,
dataComponent: <Point/>,
labelComponent: <VictoryLabel/>,
containerComponent: <VictoryContainer/>,
groupComponent: <g/>,
standalone: true
standalone: true,
style: {}
};

getFontStyles(props) {
return merge({}, defaultFontStyle, props.label);
getLabelStyles(props) {
return merge({}, fallbackProps.style.labels, props.label);
}

getLegendStyle(props) {
return {
style: merge({}, defaultLegendStyle, props.style)
style: defaults({}, defaultLegendStyle, props.style)
};
}

// it should be changed to approximateTextSize
getLabelBbox(text, font) {
const body = document.body;
const container = document.createElement("svg");
const label = document.createElement("text");

label.innerText = text;
label.setAttribute("style",
`fill: ${font.color};
font-size: ${font.fontSize}px;
font-family: ${font.fontFamily};
background-color: ${font.backgroundColor};
stroke: ${font.stroke};
top: -10000px;
position: absolute;`
);
body.appendChild(container);
container.appendChild(label);

const bBox = label.getBoundingClientRect();
body.removeChild(container);

return bBox;
}

renderContainer(props, group) {
return React.cloneElement(
props.containerComponent,
Expand All @@ -125,62 +102,66 @@ export default class VictoryLegend extends React.Component {
);
}

getSymbolProps(series) {
return assign({}, fallbackProps.style.symbol, this.props.style.symbol, series.symbol);
}

render() {
let yPadding = 0;
let xPadding = 0;
const props = this.props;
const itemXPosition = [];
const symbolComponents = [];
const dataComponents = [];
const labelComponents = [];
const { symbolComponent, labelComponent } = props;
const { dataComponent, labelComponent } = props;
const data = isEmpty(props.data) ? defaultLegendData : props.data;

data.forEach((series, index) => {
const font = this.getFontStyles(series);
data.forEach((series, i) => {
const font = this.getLabelStyles(series);
const symbolSize = font.fontSize;
const hPadding = symbolSize * 0.87;
const yPos = props.y + index * yPadding;
const yPos = props.y + i * yPadding;
const labelSymbolPadding = symbolSize * 1.5 + props.columnItemSpacing;

if (props.orientation === "horizontal") {
itemXPosition.push(xPadding);
xPadding += labelSymbolPadding + this.getLabelBbox(series.name, font).width;
itemXPosition[i] = xPadding;
xPadding += labelSymbolPadding + Textsize.approximateTextSize(series.name, font).width;
} else {
yPadding = symbolSize + props.rowItemSpacing;
}

const xLabelPos = (props.orientation !== "horizontal" ?
props.x : itemXPosition[index]) + hPadding;
props.x : itemXPosition[i]) + hPadding;
const xSymbolPos = props.orientation !== "horizontal" ?
props.x : itemXPosition[index];
props.x : itemXPosition[i];

const symbolProps = assign({
key: `symbol-${index}`
key: `symbol-${i}`
}, {
x: xSymbolPos,
y: yPos,
size: series.symbol.size || symbolSize / 2.5,
symbol: series.symbol.type
}, series.symbol);
size: series.symbol ? series.symbol.size || symbolSize / 2.5 : symbolSize / 2.5,
symbol: this.getSymbolProps(series).type
}, this.getSymbolProps(series));

const labelProps = assign({
key: `label-${index}`
key: `label-${i}`
}, {
x: xLabelPos,
y: yPos,
style: font,
text: series.name
}, series.label);
}, assign({}, fallbackProps.style.labels, props.style.labels, series.label));

symbolComponents[index] = React.cloneElement(
symbolComponent, assign({}, symbolProps)
dataComponents[i] = React.cloneElement(
dataComponent, assign({}, symbolProps)
);
labelComponents[index] = React.cloneElement(
labelComponents[i] = React.cloneElement(
labelComponent, assign({}, labelProps)
);
});

const group = this.renderGroup([...symbolComponents, ...labelComponents]);
const group = this.renderGroup([...dataComponents, ...labelComponents]);
return props.standalone ? this.renderContainer(props, group) : group;
}
}
43 changes: 41 additions & 2 deletions test/client/spec/victory-legend/victory-legend.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe("components/victory-legend", () => {
const output = wrappedLegend.find("Point");

expect(output.at(0).prop("x")).to.be.equal(0);
expect(output.at(1).prop("x")).to.be.equal(76);
expect(output.at(1).prop("x")).to.be.equal(87.68016194331983);
expect(output.at(0).prop("y")).to.be.equal(0);
expect(output.at(1).prop("y")).to.be.equal(0);
});
Expand All @@ -58,7 +58,7 @@ describe("components/victory-legend", () => {
const output = wrappedLegend.find("text");

expect(output.eq(0).prop("x")).to.be.equal("12.18");
expect(output.eq(1).prop("x")).to.be.equal("88.18");
expect(output.eq(1).prop("x")).to.be.equal("99.86016194331984");

expect(output.eq(0).prop("y")).to.be.equal("0");
expect(output.eq(1).prop("y")).to.be.equal("0");
Expand Down Expand Up @@ -119,4 +119,43 @@ describe("components/victory-legend", () => {
expect(output.get(1).props.symbol).to.be.equal("triangleUp");
});
});

describe("legend style prop", () => {
const legendData = [{
name: "Thing 1"
}, {
name: "Thing 2"
}];

const styleObject = {
symbol: {
type: "triangleUp",
fill: "green"
},
labels: {
fontSize: 16
}
};

wrapper = shallow(
<VictoryLegend data={legendData} style={styleObject} />
);
const outputPoints = wrapper.find("Point");
const outputLabels = wrapper.find("VictoryLabel");

it("has expected symbol type", () => {
expect(outputPoints.at(0).prop("type")).to.be.equal("triangleUp");
expect(outputPoints.at(1).prop("type")).to.be.equal("triangleUp");
});

it("has expected symbol colors", () => {
expect(outputPoints.at(0).prop("fill")).to.be.equal("green");
expect(outputPoints.at(1).prop("fill")).to.be.equal("green");
});

it("has expected symbol colors", () => {
expect(outputLabels.at(0).prop("color")).to.be.equal("#252525");
expect(outputLabels.at(1).prop("color")).to.be.equal("#252525");
});
});
});