rpd
Version:
RPD is a minimal framework for building Node-Based User Interfaces, powered by Reactive Programming
358 lines (282 loc) • 14.4 kB
JavaScript
function applyRpdLogoPatch(logoNode, planetsSvgNode, patchTargetNode) {
var logoBox = logoNode.getBoundingClientRect();
var animationWidth = 500,
animationHeight = logoBox.height;
var widthRequiredForNodes = 300;
var topMargin = 20, bottomMargin = 20;
d3.select(planetsSvgNode)
.style('position', 'absolute')
.style('left', logoBox.left + 'px').style('top', logoBox.top + 'px')
d3.select(patchTargetNode)
.style('position', 'absolute')
.style('left', (logoBox.left - widthRequiredForNodes) + 'px').style('top', (logoBox.top - topMargin) + 'px')
/* ======= Register Patch Types ======= */
Rpd.nodetype('docs/logo-anim', {
inlets: {
'test': { type: 'core/any' }
}
});
Rpd.noderenderer('docs/logo-anim', 'svg', {
size: { width: animationWidth + 10, height: animationHeight },
first: function() {
},
always: function() {
}
});
/* ======= Building Patch Network ======= */
Rpd.renderNext('svg', patchTargetNode,
{ style: 'compact-v', nodeMovingAllowed: false });
var patch = Rpd.addPatch('Docs Patch');
//patch.moveCanvas(logoBox.left - widthRequiredForNodes, logoBox.top);
patch.resizeCanvas(widthRequiredForNodes + animationWidth + 10,
animationHeight + topMargin + bottomMargin);
patch.addNode('core/basic', 'Basic');
var animNode = patch.addNode('docs/logo-anim', 'Animation');
animNode.move(widthRequiredForNodes - 5, 10);
/* ======= Animation with D3 ======= */
attachPlanetsAnimation(planetsSvgNode, logoNode,
{}, animationWidth, animationHeight);
}
function attachPlanetsAnimation(planetsNode, logoNode, config, width, height) {
var LOGO_SUN_REF = '#Oval-1';
var LOGO_NEPTUNE_REF = '#Oval-2';
var LOGO_TEXT_REF = '#RPD-text';
var planets = [
{ name: 'Sun', size: 109.3, colors: [ '#fda42b', '#f96e22', '#f00e1a' ] }, /*0*/
{ name: 'Mercury', size: 0.3829, colors: [ '#b5adaa', '#535355', '#232323' ] }, /*1*/
{ name: 'Venus', size: 0.9499, colors: [ '#cdc8c2', '#615d41', '#525355' ] }, /*2*/
{ name: 'Earth', size: 1.0, colors: [ '#314051', '#b79a76', '#e8f1e2' ] }, /*3*/
{ name: 'Mars', size: 0.5320, colors: [ '#ed955f', '#b3734a', '#163c6a' ] }, /*4*/
{ name: 'Jupiter', size: 10.97, colors: [ '#f0eff4', '#935f51', '#cbbaa1' ] }, /*5*/
{ name: 'Saturn', size: 9.140, colors: [ '#dfceb0', '#b99a7d', '#d7c4d2' ] }, /*6*/
{ name: 'Uranus', size: 3.981, colors: [ '#cef4f5', '#acd3d8', '#49696d' ] }, /*7*/
{ name: 'Neptune', size: 3.865, colors: [ '#466aff', '#3948bf', '#1e2051' ] } /*8*/
//{ name: "Pluto", size: 0.186 } /*9*/
];
// Configuration
var spaceColor = '#003c66'; // #09046a
var delay = 0,
duration = 5000,
shapeShiftEasing = 'cubic-in',
colorShiftEasing = 'quad-out';
var textHideDuration = 100,
textHideEasing = 'quad-in';
var hideDuration = 2000;
var shadowXOffset = 1.5, //1.5,
shadowYOffset = 0.5, //0.5,
shadowSizeFactor = 1.15, //1.15,
shadowColor = 'rgb(50, 80, 80)',
shadowOpacity = 0.1;
var withSunBurn = true,
sunBurnSize = 1.22;
function addPlanets(root, logoRef, config, width, height) {
// Load required values from the shapes of original logo
var sunInitial, neptuneInitial, textInitial;
var logoWidth, logoHeight,
logoViewBoxWidth, logoViewBoxHeight;
d3.select(logoRef).call(function(logoRef) {
sunInitial = logoRef.select(LOGO_SUN_REF);
neptuneInitial = logoRef.select(LOGO_NEPTUNE_REF);
textInitial = logoRef.select(LOGO_TEXT_REF);
logoWidth = parseInt(logoRef.attr('width'));
logoHeight = parseInt(logoRef.attr('height'));
var viewBox = logoRef.attr('viewBox').split(' ');
logoViewBoxWidth = viewBox[2];
logoViewBoxHeight = viewBox[3];
});
// Bulding planets' gradients
var defs = d3.select(root).append('defs');
var gradients = [];
var stop_distribution = ['0%', '60%', '100%'];
defs.selectAll('radialGradient')
.data(planets)
.enter().append('radialGradient')
.attr('id', function(planet) { return 'gradient-' + planet.name; })
.classed('planet-gradient', true)
.attr('gradientUnits', 'objectBoundingBox')
.attr('cx', '0')
.attr('cy', '0')
.attr('r', '100%')
.each(function() {
d3.select(this).selectAll('stop')
.data(function(planet) { return planet.colors; })
.enter().append('stop')
.attr('offset', function(color, i) { return stop_distribution[i]; })
.attr('stop-color', 'black')
.attr('stop-opacity', 1)
});
if (withSunBurn) {
defs.append('radialGradient')
.attr('id', 'sun-burn-gradient')
.attr('gradientUnits', 'objectBoundingBox')
.attr('cx', '50%').attr('cy', '50%')
.attr('fx', '50%').attr('fy', '50%')
.attr('r', '50%')
.call(function(gradient) {
gradient.append('stop')
.attr('offset', '0%')
.attr('stop-color', spaceColor)
.attr('stop-opacity', 0);
gradient.append('stop')
.attr('offset', '72%')
.attr('stop-color', '#f00e1a')
.attr('stop-opacity', 0)
gradient.append('stop')
.attr('offset', '85%')
.attr('stop-color', '#f00e1a')
gradient.append('stop')
.attr('offset', '90%')
.attr('stop-color', '#f96e22')
gradient.append('stop')
.attr('offset', '93%')
.attr('stop-color', '#fda42b')
gradient.append('stop')
.attr('offset', '100%')
.attr('stop-color', spaceColor)
.attr('stop-opacity', 0)
gradient.append('stop')
.attr('offset', '100%')
.attr('stop-color', spaceColor)
.attr('stop-opacity', 0);
});
}
// Prepare data for planet's animation
var startValues = planets.map(function(planet) {
return {
x: (planet.name !== 'Neptune') ? (sunInitial.attr('cx') / logoViewBoxWidth * logoWidth)
: (neptuneInitial.attr('cx') / logoViewBoxWidth * logoWidth),
y: (planet.name !== 'Neptune') ? (sunInitial.attr('cy') / logoViewBoxHeight * logoHeight)
: (neptuneInitial.attr('cy') / logoViewBoxHeight * logoHeight),
r: (planet.name !== 'Neptune') ? (sunInitial.attr('r') / logoViewBoxWidth * logoWidth)
: (neptuneInitial.attr('r') / logoViewBoxWidth * logoWidth),
strokeWidth: (planet.name !== 'Neptune') ? 0 : (neptuneInitial.attr('stroke-width') / logoViewBoxWidth * logoWidth),
strokeColor: (planet.name !== 'Neptune') ? 'rgba(66, 66, 66, 1)' : 'white'
};
});
var step = width / (planets.length - 1);
var proportion = logoHeight / planets[5].size * 0.47; //0.6; //* 0.85;
var endValues = planets.map(function(planet, i) {
return {
x: (planets.length - i/* + 1*/ - 1) * step,
y: startValues[i].y,
r: (planet.size * proportion) / 2,
strokeWidth: 0.75,
strokeColor: (planet.name !== 'Neptune') ? startValues[i].strokeColor : 'white'
};
});
var planetOffset = step / 2/*(neptuneInitial.attr('cx') / logoViewBoxWidth * logoWidth) + 7*/;
function startValue(name) { return function(planet, i) { return startValues[i][name]; } };
function startValueAnd(name, f) { return function(planet, i) { return f(startValues[i][name]); } };
function endValue(name) { return function(planet, i) { return endValues[i][name]; } };
function endValueAnd(name, f) { return function(planet, i) { return f(endValues[i][name]); } };
var universe = d3.select(root).append('g').attr('id', 'universe');
// Add background
d3.select(universe.node()).append('rect')
.attr('width', width).attr('height', height)
.attr('fill', 'white')
.attr('fill-opacity', 0);
// Add planets in their initial state
d3.select(universe.node()).selectAll('g')
.data(planets)
.enter().append('g').classed('planet', true)
.attr('id', function(planet) { return planet.name; })
.call(function(group) {
group.append('circle').classed('back', true)
.attr('cx', startValue('x'))
.attr('cy', startValue('y'))
.attr('r', startValue('r'))
.attr('fill', 'white')
.attr('fill-opacity', 0);
group.append('circle').classed('front', true)
.attr('cx', startValue('x'))
.attr('cy', startValue('y'))
.attr('r', startValue('r'))
.attr('fill', function(planet) { return 'url(#gradient-' + planet.name + ')'; })
.attr('stroke', startValue('strokeColor'))
.attr('stroke-width', startValue('strokeWidth'));
});
if (withSunBurn) {
d3.select(root).select('g.planet#Sun')
.append('circle')
.attr('id', 'sun-burn')
.attr('cx', startValue('x'))
.attr('cy', startValue('y'))
.attr('r', startValueAnd('r', function(r) { return r * sunBurnSize; }))
.attr('fill', 'url(#sun-burn-gradient)')
.attr('fill-opacity', 0);
}
// Add "Horizon" line
d3.select(universe.node()).insert('line', 'g.planet#' + planets[1].name)
.attr('id', 'horizon')
.attr('x1', 0).attr('y1', height / 2)
.attr('x2', width).attr('y2', height / 2)
.attr('stroke', 'white')
.attr('stroke-opacity', 0)
.attr('stroke-width', 2.5);
// Return function which makes everything move
return function() {
// Hide initial shapes
sunInitial.transition().delay(delay).duration(hideDuration)
.attr('fill-opacity', 0);
neptuneInitial.transition().delay(delay).duration(hideDuration)
.attr('fill-opacity', 0)
.attr('stroke-opacity', 0);
// Make "horizon" appeared
d3.select(root).select('g#universe line#horizon')
.transition().delay(delay).duration(duration * 0.75).ease(shapeShiftEasing)
.attr('stroke-opacity', 0.3)
.attr('stroke-width', 3)
.transition().duration(duration * 0.25).ease(shapeShiftEasing)
.attr('stroke-opacity', 0.1)
.attr('stroke-width', 1.5);
// Make background change color to something spacey
d3.select(root).select('g#universe > rect')
.transition().delay(delay).duration(duration).ease(shapeShiftEasing)
.attr('fill-opacity', 1)
.attr('fill', spaceColor);
// Move shapes of the planets
d3.select(root).selectAll('g.planet > circle.front')
.transition().duration(duration).delay(delay).ease(shapeShiftEasing)
.attr('r', endValue('r'))
.attr('cx', endValueAnd('x', function(x) { return x + planetOffset; }))
.attr('cy', endValue('y'))
.attr('stroke', endValue('strokeColor'))
.attr('stroke-width', endValue('strokeWidth'));
// Move shadows of the planets
d3.select(root).selectAll('g.planet > circle.back')
//.transition('foo').duration(duration).ease(shadowColorEasing)
.transition().delay(delay).duration(duration).ease(shapeShiftEasing)
.attr('fill', shadowColor)
.attr('fill-opacity', shadowOpacity)
.attr('r', endValueAnd('r', function(r) { return r * shadowSizeFactor; }))
.attr('cx', endValueAnd('x', function(x) { return x + planetOffset + shadowXOffset; }))
.attr('cy', endValueAnd('y', function(y) { return y + shadowYOffset; }));
// Animate planet's gradients
d3.select(defs.node()).selectAll('radialGradient.planet-gradient')
.each(function(planet, i) {
d3.select(this).selectAll('stop').each(function() {
d3.select(this)
.transition().delay(delay).duration(duration).ease(colorShiftEasing)
.attr('stop-color', function(toColor) { return toColor; });
});
});
// ...And burning sun
if (withSunBurn) {
d3.select(root).select('g.planet#Sun #sun-burn')
.transition().delay(delay).duration(duration).ease(shapeShiftEasing)
.attr('r', endValueAnd('r', function(r) { return r * sunBurnSize; }))
.attr('cx', endValueAnd('x', function(x) { return x + planetOffset; }))
.attr('cy', endValue('y'))
.attr('fill-opacity', 0.8);
}
};
}
d3.select('#rpd-logo path').attr('fill-opacity', 1);
d3.select('#rpd-logo path')
.transition().duration(textHideDuration).ease(textHideEasing)
.attr('fill-opacity', 0)
.each('end', function() {
var animate = addPlanets(planetsNode, logoNode, config, width, height);
animate();
});
}