/
myFile.html
127 lines (106 loc) · 2.68 KB
/
myFile.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
<!DOCTYPE html>
<html>
<head>
<script>
</script>
</head>
<style>
body {
margin: 0;
text-align: center;
}
.ball {
cursor: grab;
cursor: -webkit-grab;
}
.ball:active {
cursor: grabbing;
cursor: -webkit-grabbing;
}
</style>
<body>
<svg id="canvas">
<defs>
<radialGradient id="sphere-gradient">
<stop offset="0%" stop-color="MediumPurple"></stop>
<stop offset="100%" stop-color="Indigo"></stop>
</radialGradient>
</defs>
</svg>
</body>
<script>
var width = 400, height = 400
const BALL_SIZE = 20,
BALL_OFFSET = window.innerHeight/8,
BALL_SPEED = 3;
const canvasWidth = window.innerWidth,
canvasHeight = window.innerHeight;
// DOM nodes
const svgCanvas = d3.select('svg#canvas')
.attr('width', canvasWidth)
.attr('height', canvasHeight),
wiresG = svgCanvas.append('g'),
ballsG = svgCanvas.append('g');
const balls = [
{ id: '0', init: { x: canvasWidth/2 - 6*BALL_SIZE, y: canvasHeight*1/3, vx: 0, vy: 0 } },
{ id: '1', init: { x: canvasWidth/2 - 3*BALL_SIZE, y: canvasHeight*(1/3 + .01), vx: 0, vy: 0 } },
{ id: '2', init: { x: canvasWidth/2 - 0*BALL_SIZE, y: canvasHeight*1/3, vx: 0, vy: 0 } },
{ id: '3', init: { x: canvasWidth/2 + 3*BALL_SIZE, y: canvasHeight*1/3, vx: 0, vy: 0 } },
{ id: '4', init: { x: canvasWidth/2 + 6*BALL_SIZE, y: canvasHeight*1/3, vx: 0, vy: 0 } }
];
// start the left ball moving
balls[0].init.x -= BALL_OFFSET;
balls[0].init.y -= 0;
balls[0].init.vx = BALL_SPEED;
let init = false;
const forceSim = d3.forceSimulation()
.alphaDecay(0)
.velocityDecay(0)
.nodes([...balls])
.force('elastic', d3.forceBounce()
.radius(node => BALL_SIZE)
.elasticity(1)
)
.force('init', () => {
if (!init) {
balls.forEach((ball) => {
ball.x = ball.init.x;
ball.y = ball.init.y;
ball.vx = ball.init.vx;
ball.vy = ball.init.vy;
});
init = true;
}
})
.on('tick', () => { ballDigest(); });
//
// Periodical kickstart
kickStart();
setInterval(kickStart, 5000);
function ballDigest() {
let ball = ballsG.selectAll('circle.ball').data(balls);
ball.exit().remove();
ball.merge(
ball.enter().append('circle')
.classed('ball', true)
.attr('r', BALL_SIZE)
.attr('fill', 'url(#sphere-gradient)')
.call(d3.drag()
.on("start", d => { d.fx = d.x; d.fy = d.y; })
.on("drag", d => { d.fx = d3.event.x; d.fy = d3.event.y; })
.on("end", d => { d.fx = null; d.fy = null; })
)
)
.attr('cx', d => d.x)
.attr('cy', d => d.y);
}
function kickStart() {
balls.forEach((ball) => {
ball.x = ball.init.x;
ball.y = ball.init.y;
ball.vx = ball.init.vx;
ball.vy = ball.init.vy;
});
}
</script>
</html>