-
Notifications
You must be signed in to change notification settings - Fork 0
/
mandelbrot-layer.js
117 lines (99 loc) · 3.45 KB
/
mandelbrot-layer.js
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
import L from './leaflet-shim.js';
import MandelbrotRenderer from './mandelbrot-renderer.js';
import { devicePixelRatio } from './util.js';
export default L.GridLayer.extend({
options: {
iterations: 64,
workers: 4,
updateWhenIdle: true,
updateWhenZooming: false,
},
initialize(options) {
L.Util.setOptions(this, options);
this._renderer = new MandelbrotRenderer(this.options.workers);
},
setIterations(iterations) {
iterations = Math.round(iterations);
if (!Number.isFinite(iterations)) return;
this._renderer.clearJobs();
this.options.iterations = iterations;
this.redraw();
this._map.fire('iterationschange', { value: this.options.iterations });
},
increaseIterations() {
this.setIterations(this.options.iterations * 2);
},
decreaseIterations() {
this.setIterations(this.options.iterations * .5);
},
onAdd(map) {
L.GridLayer.prototype.onAdd.apply(this, arguments);
map._mandelbrotLayer = this;
map.on('zoomend', () => {
const roundZoom = Math.round(map.getZoom());
this._renderer.clearJobs(job => job.message.zoom !== roundZoom);
});
map.on('moveend', () => {
this._renderer.clearJobs(job => {
const {
realMin,
imagMin,
realMax,
imagMax,
} = job.message.coords;
const jobBounds = L.latLngBounds(
L.latLng(imagMax, realMax),
L.latLng(imagMin, realMin),
);
return !this._map.getBounds().overlaps(jobBounds);
});
});
map.fire('iterationschange', { value: this.options.iterations });
},
createTile(coords, done) {
const tileSize = this.getTileSize();
const renderedTileSize = tileSize.multiplyBy(devicePixelRatio);
const tile = document.createElement('canvas');
tile.width = renderedTileSize.x;
tile.height = renderedTileSize.y;
const tileBounds = this._tileCoordsToBounds(coords, tileSize);
const complexBounds = {
realMin: tileBounds.getWest(),
imagMax: tileBounds.getNorth(),
realMax: tileBounds.getEast(),
imagMin: tileBounds.getSouth(),
};
this._renderer.getImageData(complexBounds, renderedTileSize, this.options.iterations, coords.z)
.then(imageData => {
tile.getContext('2d').putImageData(imageData, 0, 0);
done(null, tile);
})
.catch(error => {
console.error(error);
done(error);
});
return tile;
},
_tileCoordsToBounds(coords, tileSize) {
const point = L.point(coords.x, coords.y);
let nw = point.scaleBy(tileSize);
let se = nw.add(tileSize);
nw = this._map.unproject(nw, coords.z);
se = this._map.unproject(se, coords.z);
return L.latLngBounds(nw, se);
},
});
L.Map.include({
getIterations() {
return this._mandelbrotLayer.options.iterations;
},
setIterations(iterations) {
this._mandelbrotLayer.setIterations(iterations);
},
increaseIterations() {
this._mandelbrotLayer.increaseIterations();
},
decreaseIterations() {
this._mandelbrotLayer.decreaseIterations();
},
});