Skip to content

Commit

Permalink
feat(colors): add smart declarative color management
Browse files Browse the repository at this point in the history
  • Loading branch information
Raphael Benitte committed Apr 17, 2016
1 parent 7122dca commit c4fb533
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 44 deletions.
34 changes: 34 additions & 0 deletions src/ColorUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import d3 from 'd3';


export const getColorGenerator = instruction => {
if (instruction === 'none') {
return 'none';
}

if (instruction === 'inherit') {
return d => d.data.color;
}

const inheritMatches = instruction.match(/inherit:(darker|brighter)\(([0-9.]+)\)/);
if (inheritMatches) {
const method = inheritMatches[1];
const amount = inheritMatches[2];

return d => d3.rgb(d.data.color)[method](parseFloat(amount));
}

throw new Error('Unable to determine color generator');
};


export const getColorStyleObject = (instruction, property) => {
const style = {};

const color = getColorGenerator(instruction);
if (color !== 'none') {
style[property] = color;
}

return style;
};
9 changes: 7 additions & 2 deletions src/components/layouts/Pie.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ class Pie extends Component {
}));

const color = d3.scale.category20();
/*
const color = d3.scale.linear()
.domain([0, data.length / 2, data.length])
.range(['#ba1300', '#c6482e', '#ff9068'])
;
*/

let slices = container.selectAll('.chart__layout__pie__slice');
const previousData = slices.data();
Expand Down Expand Up @@ -112,7 +118,6 @@ class Pie extends Component {
}

componentWillMount() {
console.log('Pie.render()');
const { children } = this.props;

const legends = [];
Expand Down Expand Up @@ -162,7 +167,7 @@ Pie.defaultProps = {
startAngle: 0,
endAngle: 360,
padAngle: 0,
transitionDuration: 1000,
transitionDuration: 600,
transitionEasing: 'cubic-out',
innerRadius: 0
};
Expand Down
17 changes: 13 additions & 4 deletions src/components/layouts/PieColumnLegends.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ import React, { Component, PropTypes } from 'react';
import invariant from 'invariant';
import d3 from 'd3';
import { midAngle, findNeighbor } from '../../ArcUtils';
import { getColorStyleObject } from '../../ColorUtils';


class PieColumnLegends extends Component {
static createLegendsFromReactElement(element) {
const { props } = element;

const lineColorStyle = getColorStyleObject(props.lineColor, 'stroke');
const textColorStyle = getColorStyleObject(props.textColor, 'fill');

// Receive context from Parent Pie component
return ({ element, arc, identity, pie, previousData, newData, radius }) => {

Expand All @@ -21,11 +25,11 @@ class PieColumnLegends extends Component {
let lines = element.selectAll('.line').data(newData, identity);
lines.enter()
.append('polyline')
.attr('stroke', '#fff')
.attr('fill', 'none')
.attr('class', 'line')
;
lines
.style(lineColorStyle)
.attr('points', d => {
const p0 = arc.centroid(d);
const p1 = outerArc.centroid(d);
Expand All @@ -48,6 +52,7 @@ class PieColumnLegends extends Component {
;
labels
.text(labelFn)
.style(textColorStyle)
.attr('text-anchor', d => {
return midAngle(d) < Math.PI ? 'start' : 'end';
})
Expand All @@ -74,19 +79,23 @@ class PieColumnLegends extends Component {
}
}

const { number, func } = PropTypes;
const { number, func, any } = PropTypes;

PieColumnLegends.propTypes = {
labelFn: func,
radiusOffset: number.isRequired,
horizontalOffset: number.isRequired,
textOffset: number.isRequired
textOffset: number.isRequired,
lineColor: any.isRequired,
textColor: any.isRequired
};

PieColumnLegends.defaultProps = {
radiusOffset: 16,
horizontalOffset: 30,
textOffset: 10
textOffset: 10,
lineColor: 'none',
textColor: 'none'
};


Expand Down
88 changes: 80 additions & 8 deletions src/components/layouts/PieRadialLegends.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,93 @@ import React, { Component, PropTypes } from 'react';
import invariant from 'invariant';
import d3 from 'd3';
import { midAngle, radiansToDegrees } from '../../ArcUtils';
import { getColorGenerator } from '../../ColorUtils';


class PieRadialLegends extends Component {
static createLegendsFromReactElement(element) {
const { props } = element;

return ({ element, arc, keyProp, pie, data, radius }) => {
const color = getColorGenerator(props.textColor);

const labelFn = props.labelFn || (d => d.data[keyProp]);
return ({ element, arc, identity, pie, newData, radius }) => {
const labelFn = props.labelFn || identity;

const outerArc = d3.svg.arc()
.innerRadius(radius + props.radiusOffset)
.outerRadius(radius + props.radiusOffset)
;

let labels = element.selectAll('.radial-label').data(data, d => d.data[keyProp]);
let labels = element.selectAll('.radial-label').data(newData, identity);
labels.enter().append('g')
.attr('class', 'radial-label')
.append('text')
.style('opacity', 0)
;

labels
.each(function (d) {
const el = d3.select(this);

const angle = midAngle(d);
const angleOffset = angle < Math.PI ? -90 : 90;

const styles = { opacity: 1 };
if (color !== 'none') {
styles.fill = color(d);
}

el.select('text')
.text(labelFn)
.attr('text-anchor', d => (midAngle(d) < Math.PI ? 'start' : 'end'))
.transition()
.duration(props.transitionDuration)
.ease(props.transitionEasing)
.style(styles)
.attr('transform', `translate(${radius + props.radiusOffset}, 0)`)
;
})
.transition()
.duration(props.transitionDuration)
.ease(props.transitionEasing)
.attr('transform', d => {
const angle = midAngle(d);

return `rotate(${radiansToDegrees(angle)}, 0, 0)`;
})
;
labels.exit()
.each(function (d) {
const el = d3.select(this);

el.select('text')
.transition()
.duration(props.transitionDuration)
.ease(props.transitionEasing)
.style('opacity', 0)
.attr('transform', `translate(${radius + props.radiusOffset + 50}, 0)`)
;
})
.transition()
.duration(0)
.delay(props.transitionDuration)
.remove()
;


/*
labels.enter()
.append('text')
.attr('fill', '#fff')
.attr('class', 'radial-label')
;
labels
.text(labelFn)
.attr('text-anchor', d => {
return midAngle(d) < Math.PI ? 'start' : 'end';
})
.transition()
.duration(props.transitionDuration)
.ease(props.transitionEasing)
.attr('transform', d => {
const centroid = outerArc.centroid(d);
const angle = midAngle(d);
Expand All @@ -38,8 +99,13 @@ class PieRadialLegends extends Component {
})
;
labels.exit()
.transition()
.duration(props.transitionDuration)
.ease(props.transitionEasing)
.style('opacity', 0)
.remove()
;
*/
};
}

Expand All @@ -51,15 +117,21 @@ class PieRadialLegends extends Component {
}
}

const { number, func } = PropTypes;
const { number, string, func, any } = PropTypes;

PieRadialLegends.propTypes = {
labelFn: func,
radiusOffset: number.isRequired
labelFn: func,
radiusOffset: number.isRequired,
transitionDuration: number.isRequired,
transitionEasing: string.isRequired,
textColor: any.isRequired
};

PieRadialLegends.defaultProps = {
radiusOffset: 16
radiusOffset: 16,
transitionDuration: 600,
transitionEasing: 'cubic-out',
textColor: 'none'
};


Expand Down

0 comments on commit c4fb533

Please sign in to comment.