learning_d3_mapping_8_4 =
{
const houseSelection = d3.select(model);
const rainSelection = houseSelection.select('defs').append('g').attr('id', 'rain');
const dur = 3000;
const rainDrops = rain.createDrops();
let running = false;
let started = false;
let clicked = false;
context.canvas.addEventListener('click', d => clicked = true);
function databind (data) {
console.log('Running? ', running);
if (running) return false;
const join = rainSelection.selectAll('circle.drop')
.data(data, d => d.id);
const enter = join.enter()
.append('circle')
.attr('class', 'drop')
.attr('cx', d => d.xCloud)
.attr('cy', d => d.yCloud)
.attr('r', (d, i) => {
return d.radiusCloud;
})
.text(d => '(x:' + Math.floor(d.xCloud) + ', y:' + Math.floor(d.yCloud) + ')')
.attr('fill', 'rgba(0, 0, 255)')
.attr('fill-opacity', '0')
.transition().delay((d, i) => i * 2)
.attr('fill', 'rgba(0, 0, 255)')
.attr('fill-opacity', '0.5');
const update = join.transition() // implicit update()
.duration(d => Math.random()*1000 + 900)
.delay((d, i) => (i/data.length)*dur)
.ease(d3.easeLinear)
.attr('cx', d => d.xPuddle)
.attr('cy', d => d.yPuddle)
.attr('r', (d, i) => {
return d.radiusPuddle;
})
.text(d => '(x:' + Math.floor(d.xPuddle) + ', y:' + Math.floor(d.yPuddle) + ')');
const exit = join.exit()
.transition()
.duration(dur)
.delay((d, i) => i)
.attr('r', d => d.radiusGrass)
.attr('fill', '#01A611');
} // databind()
function drawRainScene() {
// Cloud
// point cloud roughly from 60,10 to 540, 70
context.beginPath();
context.moveTo(65, 65);
context.lineTo(535, 65);
context.bezierCurveTo(560, 5, 441, 5, 441, 40);
context.bezierCurveTo(441, 0, 347, 0, 347, 40);
context.bezierCurveTo(347, 5, 253, 5, 253, 40);
context.bezierCurveTo(253, 10, 159, 10, 159, 40);
context.bezierCurveTo(159, 15, 40, 15, 65, 65);
context.closePath();
context.fillStyle = '#f7f7f7';
context.fill();
// Rain path
// cloud shape from 65, 65 to 535, 65
context.beginPath();
context.moveTo(65, 70);
context.lineTo(535, 70);
context.lineTo(530, canvas.height + 20);
context.lineTo(45, canvas.height + 20);
context.closePath();
context.fillStyle = '#ffffff';
context.fill();
// Puddle
// puddle shape from 30, 250 to 560, 270
context.save();
context.translate(0, -20);
context.beginPath();
context.moveTo(529.52,256.19);
context.bezierCurveTo(532.01,260.53,513.31,265.85,516.94,272.4);
context.bezierCurveTo(521.06,279.82,547.94,278.27,553.81,286.4);
context.bezierCurveTo(557.57,291.58,552.04,299.53,542.08,303.045);
context.bezierCurveTo(520.38,310.726,493.13,291.9,444.8,292.045);
context.bezierCurveTo(410.16,292.184,409.0,301.976,364.45,307.383);
context.bezierCurveTo(302.314,314.91,237.732,304.003,237.0,296.383);
context.bezierCurveTo(236.582,290.383,276.83,287.115,275.633,282.75);
context.bezierCurveTo(273.71,275.856,167.702,276.425,166.71,281.485);
context.bezierCurveTo(166.073,284.753,209.81,287.045,209.44,291.124);
context.bezierCurveTo(208.85,297.744,92.88,304.52,83.76,291.124);
context.bezierCurveTo(78.85,283.90,106.86,273.726,100.52,268.77);
context.bezierCurveTo(94.66,264.20,68.52,271.16,39.35,264.83);
context.bezierCurveTo(32.35,263.314,26.7303,261.36,25.118,258.26);
context.bezierCurveTo(23.78,255.71,34.735,251.362,43.54,250.814);
context.bezierCurveTo(56.446,250.982,453.02,250.753,458.2,250.883);
context.bezierCurveTo(506.06,249.68,525,248.36,529.52,256.19);
context.closePath();
context.fillStyle = "rgba(255, 255, 255, 0.75)";
context.fill();
context.restore();
} // drawRainScene()
function rainAnimation (data) {
const t = d3.timer(elapsed => {
running = elapsed > 1 && elapsed < (dur) ? true : false;
draw(context);
d3.selectAll('button').style('color', '#aaa');
if (elapsed > dur * 2) {
d3.selectAll('button').style('color', '#555');
t.stop();
}
});
} // rainAnimation()
function enterRain (data) {
databind(data);
rainAnimation(data);
}
function updateRain (data) {
databind(data);
rainAnimation(data);
}
function exitRain (data) {
databind(data);
rainAnimation(data);
}
function draw (ctx) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawRainScene();
drawBackground(canvas.width/4, -10);
const elements = rainSelection
.selectAll('circle.drop')
.each(function (d, i) {
const node = d3.select(this);
const op = ctx.globalCompositeOperation;
ctx.save();
ctx.beginPath();
ctx.globalCompositeOperation = 'source-atop';
ctx.fillStyle = node.attr('fill');
if (node.attr('fill-opacity'))
ctx.fillStyle = ctx.fillStyle.replace(')', ', '+ node.attr('fill-opacity') +')');
ctx.arc(node.attr('cx'), node.attr('cy'), node.attr('r'), 0, 2*Math.PI);
ctx.fill();
ctx.globalCompositeOperation = op;
ctx.restore();
});
context.fillStyle = "black";
if (clicked) {
context.fillText("Animation with D3 data control", canvas.width - 150, 10);
} else {
context.fillText("*Click to begin animation with D3 data control", canvas.width - 180, 10);
}
}
/* Generator code (iterator) */
/* ======================== */
//
while (true) {
if (started === false && clicked === true) {
started = true;
enterRain(rainDrops);
setTimeout(updateRain, dur * 3, rainDrops);
setTimeout(exitRain, dur * 5, []);
} else {
draw(context);
}
await Promises.delay(33);
yield (rainSelection.node().children);
} // Time-delayed
}