Skip to content

Instantly share code, notes, and snippets.

@milroc
Last active June 4, 2016 23:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save milroc/15f8046a7ce5e8a9730f6109d66745ce to your computer and use it in GitHub Desktop.
Save milroc/15f8046a7ce5e8a9730f6109d66745ce to your computer and use it in GitHub Desktop.
fresh block
// Taken from https://groups.google.com/forum/#!msg/d3-js/WC_7Xi6VV50/j1HK0vIWI-EJ
// Calls a function only after the total transition ends
export default function endall(transition, callback) {
let n = 0;
transition
.each(function() { ++n; })
.each('end', function() { if (!--n) callback.apply(this, arguments); });
}// endall
<!DOCTYPE html>
<script src="https://jspm.io/system@0.19.js"></script>
<script>
System.config({
transpiler: 'babel',
babelOptions: {}
});
System.import('./main');
</script>
import React from 'react';
import ReactDOM from 'react-dom';
import d3 from 'd3';
import endall from './endall';
// Number of clocks on the page
let spinnerCounter = 0;
class GooeySpinner extends React.Component {
static defaultProps = {
width: 60,
height: 60,
margin: {top: 0, right: 0, bottom: 0, left: 0},
steps: 12,
color: [
'#a50026', '#d73027', '#f46d43',
'#fdae61', '#fee08b',
'#d9ef8b', '#a6d96a', '#66bd63',
'#1a9850', '#006768', '#00425d',
],
};
constructor(props) {
super(props);
this.spinnerID = spinnerCounter++;
this._repeat = this._repeat.bind(this);
this._getFilterID = this._getFilterID.bind(this);
}
componentDidMount() {
const {width, steps, color} = this.props;
// Create scale
this.radialScale = d3.scale.linear()
.domain([-1.5, 1.5])
.range([-width/2, width/2]);
// color from http://colrd.com/palette/24070/
this.colorScale = d3.scale.ordinal().range(color);
this._flyCirclesContainer = d3.select(ReactDOM.findDOMNode(this.refs.flyCircles));
this._flyCircles = this._flyCirclesContainer.selectAll('.flyCircle')
.data(d3.range(steps).map((num) => (num / steps ) * (2 * Math.PI)));
this._flyCircles.enter()
.append('circle')
.attr({
class: 'flyCircle',
cx: 0,
cy: 0,
r: 4,
})
.style('fill', (d, i) => this.colorScale(i))
.call(this._repeat);
}
_repeat() {
const {steps} = this.props;
const dur = 1000;
const del = 100;
this._flyCircles
.transition('outward')
.duration(dur)
.delay((_,i) => i * del)
.attr({
cx: (d) => this.radialScale(Math.cos(d)),
cy: (d) => this.radialScale(Math.sin(d)),
})
.transition('inward')
.duration(dur)
.delay((d,i) => (steps * 1.2) * del + i * del)
.attr('cx', 0)
.attr('cy', 0)
.call(endall, this._repeat);
}
_getFilterID() {
return `gooey-${this.spinnerID}`;
}
render() {
const {width, height, margin} = this.props;
return (
<div>
<svg
width={width + margin.left + margin.right}
height={height + margin.top + margin.bottom}>
<defs>
<filter id={this._getFilterID()}>
<feGaussianBlur
in="SourceGraphic"
stdDeviation={4}
result="blur"
/>
<feColorMatrix
in="blur"
mode="matrix"
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7"
/>
</filter>
</defs>
<g
filter={`url(#${this._getFilterID()})`}
transform={`translate(${width/2 + margin.left}, ${height/2 + margin.top})`}>
<circle
className="centerCircle"
cx={0}
cy={0}
r={4}
fill="#ffffbf"
/>
<g ref="flyCircles" />
</g>
</svg>
</div>
);
}
}
class App extends React.Component {
render() {
return (
<div style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'flexstart',
}}>
{[0].map((i) => (
<GooeyClock key={i} steps={12} />
))}
</div>
);
}
}
ReactDOM.render(
<App />,
document.body.appendChild(document.createElement("div"))
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment