1
+ module Color.Fountain
2
+
3
+ // Color Fountain by Erik Novales: https://github.com/enovales
4
+
5
+ open Fable.Core .JsInterop
6
+ open Fable.Import
7
+ open Fable.Import .Browser
8
+
9
+ let canvas = document.getElementsByTagName_ canvas().[ 0 ]
10
+ canvas.width <- 1000.
11
+ canvas.height <- 800.
12
+ let ctx = canvas.getContext_ 2d()
13
+
14
+ let rng (): float = JS.Math.random()
15
+
16
+ let particleLimit = 200
17
+
18
+ type Particle = {
19
+ x: double
20
+ y: double
21
+ xvel: double
22
+ yvel: double
23
+ c: ( int * int * int )
24
+ rot: double
25
+ rotVel: double
26
+ }
27
+ with
28
+ override this.ToString () =
29
+ let ( r , g , b ) = this.c
30
+ sprintf " Particle(x = %O , y = %O , xvel = %O , yvel = %O , c = (%O , %O , %O ))"
31
+ this.x this.y this.xvel this.yvel r g b
32
+
33
+
34
+ let updateParticle ( dt : double )( p : Particle ) =
35
+ {
36
+ p with
37
+ x = p.x + p.xvel * dt
38
+ y = p.y + p.yvel * dt
39
+ yvel = p.yvel + 1. * dt
40
+ rot = ( p.rot + p.rotVel * dt) % ( 2. * 3.14159 )
41
+ }
42
+
43
+ let refillParticles ( p : Particle array , dt : double ) =
44
+ let stillValid =
45
+ p |> Array.filter( fun pt -> ( pt.y < 1000. ))
46
+ //System.Console.WriteLine("stillValid.Length = " + stillValid.Length.ToString())
47
+ let updatedPos =
48
+ stillValid
49
+ |> Array.map( updateParticle( dt))
50
+
51
+ //System.Console.WriteLine("updatedPos = " + updatedPos |> Array.map(fun p -> p.ToString()).ToString())
52
+ let toCreate = particleLimit - stillValid.Length
53
+ //System.Console.WriteLine("going to create " + toCreate.ToString() + " particles")
54
+ let newParticles =
55
+ seq {
56
+ for i in 0 .. toCreate do
57
+ yield {
58
+ Particle.x = 200.
59
+ y = 300.
60
+ xvel = ( rng() - 0.5 ) * ( rng() * 30. )
61
+ yvel = -( rng() * 25. )
62
+ c = ( int ( rng() * 255. ), int ( rng() * 255. ), int ( rng() * 255. ))
63
+ rot = ( rng() * 2. * 3.14159 )
64
+ rotVel = ( rng() * 1.5 )
65
+ }
66
+ }
67
+ |> Seq.toArray
68
+
69
+ updatedPos |> Array.append( newParticles)
70
+
71
+ let mutable particles = [||]
72
+ let timestep = 0.8
73
+
74
+ let rec loop last t =
75
+ // Comment out this line to make sure the animation runs
76
+ // with same speed on different frame rates
77
+ // let timestep = (t - last) / 20.
78
+ particles <- refillParticles( particles, timestep)
79
+
80
+ ctx.clearRect( 0. , 0. , 10000. , 10000. )
81
+ let drawParticle ( p : Particle ) =
82
+ let ( r , g , b ) = p.c
83
+ let fs = " rgb(" + r.ToString() + " , " + g.ToString() + " , " + b.ToString() + " )"
84
+ ctx.fillStyle <- !^ fs
85
+
86
+ let x1 = ( p.x - 5. )
87
+ let x2 = ( p.x + 5. )
88
+ let y1 = ( p.y - 5. )
89
+ let y2 = ( p.y + 5. )
90
+
91
+ // let x1 = (p.x - (10. * System.Math.Cos(p.rot)))
92
+ // let x2 = (p.x + (10. * System.Math.Cos(p.rot)))
93
+ // let y1 = (p.y - (10. * System.Math.Sin(p.rot)))
94
+ // let y2 = (p.y + (10. * System.Math.Sin(p.rot)))
95
+
96
+ // ctx.fillRect(x1, y1, 10., 10.)
97
+ ctx.beginPath()
98
+ ctx.moveTo( x1, y1)
99
+ ctx.lineTo( x2, y1)
100
+ ctx.lineTo( x2, y2)
101
+ ctx.lineTo( x1, y2)
102
+ ctx.lineTo( x1, y1)
103
+ ctx.closePath()
104
+ ctx.fill()
105
+
106
+ particles
107
+ |> Array.iter drawParticle
108
+
109
+ window.requestAnimationFrame( loop t) |> ignore
110
+
111
+ // start the loop
112
+ loop 0. 0.
0 commit comments