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

Commit

Permalink
Merge pull request #372 from FormidableLabs/improvement/cornerRadius
Browse files Browse the repository at this point in the history
Improvement/corner radius
  • Loading branch information
boygirl authored May 4, 2018
2 parents 4e07ea8 + 5db8060 commit d5ad695
Showing 1 changed file with 76 additions and 54 deletions.
130 changes: 76 additions & 54 deletions src/victory-primitives/bar.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";
import PropTypes from "prop-types";
import Helpers from "../victory-util/helpers";
import { assign } from "lodash";
import { assign, isObject } from "lodash";
import CommonProps from "./common-props";
import Path from "./path";
import * as d3Shape from "d3-shape";
Expand All @@ -12,7 +12,14 @@ export default class Bar extends React.Component {
...CommonProps,
alignment: PropTypes.oneOf(["start", "middle", "end"]),
barRatio: PropTypes.number,
cornerRadius: PropTypes.number,
cornerRadius: PropTypes.oneOfType([
PropTypes.number,
PropTypes.func,
PropTypes.shape({
top: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),
bottom: PropTypes.oneOfType([PropTypes.number, PropTypes.func])
})
]),
datum: PropTypes.object,
horizontal: PropTypes.bool,
padding: PropTypes.oneOfType([
Expand Down Expand Up @@ -43,35 +50,37 @@ export default class Bar extends React.Component {
};
}

getVerticalBarPath(props, width) {
getVerticalBarPath(props, width, cornerRadius) {
const { x0, x1, y0, y1 } = this.getPosition(props, width);
const cornerRadius = props.cornerRadius || 0;
const sign = y0 > y1 ? 1 : -1;
const direction = sign > 0 ? "0 0 1" : "0 0 0";
const arc = `${cornerRadius} ${cornerRadius} ${direction}`;
return `M ${x0}, ${y0}
L ${x0}, ${y1 + sign * cornerRadius}
A ${arc}, ${x0 + cornerRadius}, ${y1}
L ${x1 - cornerRadius}, ${y1}
A ${arc}, ${x1}, ${y1 + sign * cornerRadius}
L ${x1}, ${y0}
L ${x0}, ${y0}
const topArc = `${cornerRadius.top} ${cornerRadius.top} ${direction}`;
const bottomArc = `${cornerRadius.bottom} ${cornerRadius.bottom} ${direction}`;
return `M ${x0 + cornerRadius.bottom}, ${y0}
A ${bottomArc}, ${x0}, ${y0 - sign * cornerRadius.bottom}
L ${x0}, ${y1 + sign * cornerRadius.top}
A ${topArc}, ${x0 + cornerRadius.top}, ${y1}
L ${x1 - cornerRadius.top}, ${y1}
A ${topArc}, ${x1}, ${y1 + sign * cornerRadius.top}
L ${x1}, ${y0 - sign * cornerRadius.bottom}
A ${bottomArc}, ${x1 - cornerRadius.bottom}, ${y0}
z`;
}

getHorizontalBarPath(props, width) {
getHorizontalBarPath(props, width, cornerRadius) {
const { x0, x1, y0, y1 } = this.getPosition(props, width);
const cornerRadius = props.cornerRadius || 0;
const sign = y1 > y0 ? 1 : -1;
const direction = sign > 0 ? "0 0 1" : "0 0 0";
const arc = `${cornerRadius} ${cornerRadius} ${direction}`;
return `M ${y0}, ${x0}
L ${y0}, ${x1}
L ${y1 - sign * cornerRadius}, ${x1}
A ${arc}, ${y1}, ${x1 + cornerRadius}
L ${y1}, ${x0 - cornerRadius}
A ${arc}, ${y1 - sign * cornerRadius}, ${x0}
L ${y0}, ${x0}
const topArc = `${cornerRadius.top} ${cornerRadius.top} ${direction}`;
const bottomArc = `${cornerRadius.bottom} ${cornerRadius.bottom} ${direction}`;
return `M ${y0}, ${x1 + sign * cornerRadius.bottom}
A ${bottomArc}, ${y0 + cornerRadius.bottom}, ${x1}
L ${y1 - sign * cornerRadius.top}, ${x1}
A ${topArc}, ${y1}, ${x1 + cornerRadius.top}
L ${y1}, ${x0 - cornerRadius.top}
A ${topArc}, ${y1 - sign * cornerRadius.top}, ${x0}
L ${y0 + cornerRadius.bottom}, ${x0 }
A ${bottomArc}, ${y0}, ${x1 + sign * cornerRadius.bottom}
z`;
}

Expand Down Expand Up @@ -126,13 +135,7 @@ export default class Bar extends React.Component {
}
}

getPathMoves(path) {
const moves = path.match(/[A-Z]/g);
const coords = path.split(/[A-Z]/);
return moves.map((m, i) => ({ command: m, coords: coords[i + 1].split(",") }));
}

getVerticalPolarBarPath(props) { // eslint-disable-line max-statements
getVerticalPolarBarPath(props, cornerRadius) { // eslint-disable-line max-statements
const { datum, scale, style, index, alignment } = props;
const r1 = scale.y(datum._y0 || 0);
const r2 = scale.y(datum._y1 !== undefined ? datum._y1 : datum._y);
Expand All @@ -148,39 +151,39 @@ export default class Bar extends React.Component {
start = this.getStartAngle(props, index);
end = this.getEndAngle(props, index);
}
const cornerRadius = props.cornerRadius || 0;
const path = d3Shape.arc()

const getPath = (edge) => {
const pathFunction = d3Shape.arc()
.innerRadius(r1)
.outerRadius(r2)
.startAngle(this.transformAngle(start))
.endAngle(this.transformAngle(end));
if (cornerRadius) {
const withCorners = d3Shape.arc()
.innerRadius(r1)
.outerRadius(r2)
.startAngle(this.transformAngle(start))
.endAngle(this.transformAngle(end))
.cornerRadius(cornerRadius);
const moves = this.getPathMoves(path());
const cornerMoves = this.getPathMoves(withCorners());
// eslint-disable-next-line no-magic-numbers
const totalMoves = cornerMoves.slice(0, 4).concat(moves.slice(2));
return totalMoves.reduce((memo, move) => {
memo += `${move.command} ${move.coords.join()}`;
return memo;
}, "");
}
return path();
.endAngle(this.transformAngle(end))
.cornerRadius(cornerRadius[edge]);
const path = pathFunction();
const moves = path.match(/[A-Z]/g);
const middle = moves.indexOf("L");
const coords = path.split(/[A-Z]/).slice(1);
const subMoves = edge === "top" ? moves.slice(0, middle) : moves.slice(middle);
const subCoords = edge === "top" ? coords.slice(0, middle) : coords.slice(middle);
return subMoves.map((m, i) => ({ command: m, coords: subCoords[i].split(",") }));
};

const moves = getPath("top").concat(getPath("bottom"));
return moves.reduce((memo, move) => {
memo += `${move.command} ${move.coords.join()}`;
return memo;
}, "");
}

getBarPath(props, width) {
getBarPath(props, width, cornerRadius) {
return this.props.horizontal ?
this.getHorizontalBarPath(props, width) : this.getVerticalBarPath(props, width);
this.getHorizontalBarPath(props, width, cornerRadius) :
this.getVerticalBarPath(props, width, cornerRadius);
}

getPolarBarPath(props) {
getPolarBarPath(props, cornerRadius) {
// TODO Radial bars
return this.getVerticalPolarBarPath(props);
return this.getVerticalPolarBarPath(props, cornerRadius);
}

getBarWidth(props, style) {
Expand All @@ -197,6 +200,23 @@ export default class Bar extends React.Component {
return Math.max(1, defaultWidth);
}

getCornerRadius(props) {
const { cornerRadius, datum, active } = props;
if (!cornerRadius) {
return { top: 0, bottom: 0 };
} else if (isObject(cornerRadius)) {
return {
top: Helpers.evaluateProp(cornerRadius.top, datum, active),
bottom: Helpers.evaluateProp(cornerRadius.bottom, datum, active)
};
} else {
return {
top: Helpers.evaluateProp(cornerRadius, datum, active),
bottom: 0
};
}
}

render() {
const {
role, datum, active, shapeRendering, className, origin, polar, pathComponent, events
Expand All @@ -205,8 +225,10 @@ export default class Bar extends React.Component {
const baseStyle = { fill: "black", stroke };
const style = Helpers.evaluateStyle(assign(baseStyle, this.props.style), datum, active);
const width = this.getBarWidth(this.props, style);
const cornerRadius = this.getCornerRadius(this.props);
const path = polar ?
this.getPolarBarPath(this.props, width) : this.getBarPath(this.props, width);
this.getPolarBarPath(this.props, cornerRadius) :
this.getBarPath(this.props, width, cornerRadius);
const transform = polar && origin ? `translate(${origin.x}, ${origin.y})` : undefined;
return React.cloneElement(pathComponent, {
d: path, transform, className, style, role, shapeRendering, events
Expand Down

0 comments on commit d5ad695

Please sign in to comment.