if (document.getElementById('gernots-svg-container') === null)
disableLimits(); // disable the 500 function call limit
// ---------------------------------------------------------------------------------------
const scrWidth = 230; // screen width at learn.grasshopper.app
const scrHeight = 400; // screen height at learn.grasshopper.app
const rMax = 10; // max radius of the balls
const rMin = 6; // min radius of the balls
const number = 20; // number of balls
const time = 5000; // duration of transition
const colors = [ // const array with color pairs for the ball's gradients
['orangered', 'darkred'],
['pink', 'deeppink'],
['orange', 'red'],
['lime', 'green'],
['yellow', 'orangered'],
['purple', 'violett']
];
const scrGradient = { // gradient for the screen
type: 'linear',
id: 'scr',
geo: [0.2, 0, 0.8, 1],
offset: [0, 1],
color: ['blue', 'midnightblue'],
opacity: [1, 1]
}
const ballGradient = { // Template, which holds the const properties
type: 'radial',
id: '', // id is not constant and will get assign unique values to
geo: [0.35, 0.35, 0.65],
offset: [0, 1],
color: [], // color is not constant and will store a unique pair of colors
opacity: [1, 0.5]
}
// -------------------------------------------------------------------------------------------------------------------------------------
if (document.getElementById('gernots-svg-container') !== null) {
var svg = d3
.select('#gernots-svg-container').append('svg')
.attr('width', scrWidth).attr('height', scrHeight);
}
var defs = svg.append('defs');
var fillBall = [];
var balls = [];
var gradients = []; // nested array to store the gradientID
var gradientsAssigned = 0; // until now gradients never been assigned
// -------------------------------------------------------------------------------------------------------------------------------------
function addGradient(gradient) { // add a gradient to defs of svg
let newGradient = defs
.append(gradient.type + 'Gradient')
.attr('id', gradient.id);
if (gradient.type === 'radial') { // if gradient.type is 'radial'
newGradient // set x- and y-center and the radius of the gradient
.attr('cx', gradient.geo[0])
.attr('cy', gradient.geo[1])
.attr('r', gradient.geo[2])
} else if (gradient.type === 'linear') { // if gradient.type is 'linear'
newGradient // set start- and end-points of the gradient
.attr('x1', gradient.geo[0])
.attr('y1', gradient.geo[1])
.attr('x2', gradient.geo[2])
.attr('y2', gradient.geo[3])
}
for (let i = 0; i < gradient.offset.length; i++) { // for every given stop
newGradient.append('stop') // add the stop to the new gradient
.attr('offset', gradient.offset[i]) // store their attr values
.attr('stop-color', gradient.color[i])
.attr('opacity', gradient.opacity[i]);
}
return 'url(#' + gradient.id + ')'; // RETURN VALUE is used to call .attr('fill', RETURN VALUE)
}
// -------------------------------------------------------------------------------------------------------------------------------------
function addBallGradients() {
// every element in the const array 'colors' (see const declaration section above) is a unique pair of colors for the balls. for every
// element in 'colors' a unique gradient will be created, where the property 'color' will hold the unique pair of colors, and 'id' will
// hold a unique identifier (a letter followed by a counter). the other properties will stay constant for every gradient.
// the gradient will be added to 'svg.defs' and a string "'url(#' + id + ')'" will be stored in the var array 'fillBall'
var gradient = ballGradient; // assign the const values to the properties
for (let c = 0; c < colors.length; c++) { // assign the unique values to:
gradient.id = 'ball' + c; // - the 'id' property
gradient.color = colors[c]; // - the 'color' property
fillBall[c] = addGradient(gradient); // append the gradient to svg.defs and add the returned string
} // to the var array 'fillBall'. string pattern is "'url(#' + id + ')'"
}
// -------------------------------------------------------------------------------------------------------------------------------------
var scr = // variable 'scr' will be used to create a click event handler
svg.append('rect') // inside the svg-container draw the background rectangle
.attr('width', scrWidth).attr('height', scrHeight) // use const scrWidth and scrHeight declared above
.attr('fill', addGradient(scrGradient)); // use const scrGradient declared above
addBallGradients();
var gradientID;
var ball;
var r;
gradients[0] = []; // 1. element of array 'gradients' is an empty array
for (let i = 0; i < number; i++) {
r = rMin + Math.floor(Math.random() * (rMax - rMin) ); // pick random radius r in the range rMin - rMax
gradientID = Math.floor(Math.random() * colors.length); // pick a random member of the var array 'fillBall' and ...
ball = svg.append('circle') // inside the svg-container draw a ball with ...
.attr('cx',r + Math.floor(Math.random() * (scrWidth - 2 * r)))// ... random x coordinate of center and ...
.attr('cy',r + Math.floor(Math.random() * (scrHeight - 2 * r)))// ... random y coordinate of center and with ...
.attr('r', r) // the random radius r
.attr('fill',fillBall[gradientID]); // ... fill the ball with that color gradient
gradients[0][i] = gradientID; // store the used gradient index in gradients[0][i]
balls[i] = ball; // add the ball to the array variable 'balls'
}
gradientsAssigned = 1; // gradients were assigned once until now
scr.on('click', () => { // event handler
gradients.push([]); // add a new element (empty array) to array variable 'gradients'
for (let i = 0; i < number; i++) {
r = rMin + Math.floor(Math.random() * (rMax - rMin) ); // pick random radius r in the range rMin - rMax
do {
gradientID = Math.floor(Math.random() * colors.length); // pick a random member of the var array 'fillBall' and
} while (gradientID === gradients[gradientsAssigned - 1][i]); // make sure that it's not the same as before the click
balls[i].transition().duration(time).ease(d3.easeElastic)
.attr('cx',r + Math.floor(Math.random() * (scrWidth - 2 * r)))// ... random x coordinate of center and ...
.attr('cy',r + Math.floor(Math.random() * (scrHeight - 2 * r)))// ... random y coordinate of center and with ...
.attr('r', r) // the random radius r
.transition().duration(0)
.attr('fill',fillBall[gradientID]);
gradients[gradientsAssigned][i] = gradientID; // store the used gradient index in gradients[gradientsAssigned][i]
}
gradientsAssigned++; // gradients were assigned one more time
});