@polytrope/

julia-fractals-click-pan

HTML, CSS, JS

No description

fork
loading
Files
  • index.html
index.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
<!DOCTYPE html>
<html>
<head>
  <title>Julia Fractals</title>
</head>

<style>
  body {
    background: black;
    color: white;
  }
  canvas {
    border: 1px solid white;
  }
</style>

<body>
  <h2></h2>
  <canvas></canvas>
</body>

<!-- Import math.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/5.6.0/math.min.js"></script>

<script>

// The HTML elements we are using
var header = document.querySelector('h2')
var canvas = document.querySelector('canvas')
var ctx = canvas.getContext('2d')

// The size of our canvas
var width = 200
var height = 200

// Set the size of our canvas
canvas.width = width
canvas.height = height

// The XY coordinates of the mouse over the canvas
var mouseX = 0
var mouseY = 0

// The point we use for C in our Julia Set equation
var constant = math.complex(0.28, 0.01)

// The maximum number of times we iterate a point to see if it escapes
var maxIterations = 64

// Whether we have clicked yet
var clicked = false

// How much we move the image
var pan = math.complex(0, 0)

// Apply the Julia Set formula to see if point z "escapes"
function julia(z, i = 0) {
  // Apply the Julia Set formula: z*z+constant
  z = z.mul(z)
  z = z.add(constant)

  // Has our point escaped, or hit the iteration limit?
  if (math.abs(z) > 2 || i == maxIterations)
    // If so, return number of iterations
    return i
  else
    // If not, iterate again!
    return julia(z, i+1)
}

// Turn a point on the complex plane into a color
function pointToColor(point) {
  // How many iterations on this point before it escapes?
  var iterations = julia(point)

  // What percentage of our limit is that?
  var percentage = iterations/maxIterations

  var red = percentage*255
  var green = percentage*255
  var blue = percentage*255

  // Create a color from that percentage
  return `rgb(${red}, ${green}, ${blue})`
}

// Turn XY pixel coordinates into a point on the complex plane
function pixelToPoint(x, y) {
  // Map percentage of total width/height to a value from -1 to +1
  var zx = (x/width)*2-1
  var zy = 1-(y/height)*2

  // Create a complex number based on our new XY values
  var z = math.complex(zx, zy)

  // Pan the camera
  z = z.add(pan)

  return z
}

// Draw a single pixel on our canvas
function drawPixel(x, y, color) {
  ctx.fillStyle = color
  ctx.fillRect(x, y, 1, 1)
}

// Redraw our canvas
function draw() {
  // Loop over every column of pixels
  for (var y = 0; y < height; y++) {
    // Loop over every row of pixels
    for (var x = 0; x < width; x++) {
      // Turn this pixel into a point in the complex plane
      var point = pixelToPoint(x, y)

      // Turn that point into a color
      var color = pointToColor(point)

      // Draw over this pixel with that color
      drawPixel(x, y, color)
    }
  }
}

// Update the elements that need to change
function update() {
  header.innerHTML = constant.toString()
  draw()
}

function click(event) {
  // Ignore the first click
  if (!clicked) {
    clicked = true
    return
  }

  // Get the mouse's XY coordinates on canvas
  mouseX = event.clientX-canvas.offsetLeft
  mouseY = event.clientY-canvas.offsetTop

  // Turn mouse coordinates into a point on the complex plane
  pan = pixelToPoint(mouseX, mouseY)

  // Update everything!
  update()
}

// What to do when the mouse moves over the canvas
function move(event) {
  // Don't move after first click
  if (clicked) {
    return
  }

  // Get the mouse's XY coordinates on canvas
  mouseX = event.clientX-canvas.offsetLeft
  mouseY = event.clientY-canvas.offsetTop

  // Turn mouse coordinates into a point on the complex plane
  constant = pixelToPoint(mouseX, mouseY)

  // Round that point off to the nearest 0.01
  constant.re = math.round(constant.re*100)/100
  constant.im = math.round(constant.im*100)/100

  // Update everything!
  update()
}

// Trigger click every time the canvas is clicked
canvas.addEventListener('click', click)

// Trigger move every time the mouse moves over canvas
canvas.addEventListener('pointermove', move)

// Update everything!
update()

</script>
</html>
result
console