You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
24 KiB
JavaScript
188 lines
24 KiB
JavaScript
2 weeks ago
|
/* Copyright (c) 2016 Jean-Marc VIGLINO,
|
||
|
released under the CeCILL-B license (French BSD license)
|
||
|
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
|
||
|
*/
|
||
|
/** ol.control.Cloud adds an old map effect on a canvas renderer.
|
||
|
* It colors the map, adds a parchment texture and compass onto the map.
|
||
|
* @constructor
|
||
|
* @param {Object} options
|
||
|
* @param {_ol_color_} options.hue color to set hue of the map, default #963
|
||
|
* @param {Number} options.saturation saturation of the hue color, default 0.6
|
||
|
* @param {Number} options.opacity opacity of the overimpose image, default 0.7
|
||
|
* @todo add effects on pan / zoom change
|
||
|
*/
|
||
|
ol.control.Cloud = function(options) {
|
||
|
options = options || {};
|
||
|
var div = document.createElement('div');
|
||
|
div.className = "ol-cloud ol-unselectable ol-control";
|
||
|
ol.control.Control.call(this, {
|
||
|
element: div
|
||
|
});
|
||
|
// Defaut cloud image
|
||
|
this.cloud = options.img;
|
||
|
if (!this.cloud) {
|
||
|
this.cloud = new Image();
|
||
|
this.cloud.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAMAAABrrFhUAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AYRBhgFS4lkHAAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAA6lBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+Le70HAAAATnRSTlMAAwkMDxUXGiAiJSowMzU3Ojw/QkRGSUtOT1JUV1lbXmBiZGZoam1ucXN0d3l6fX6AgoSGh4qLjY6QkpSVl5mbnJ6foaKkpaeoqqutrrA/NNYeAAAAAWJLR0QB/wIt3gAALhJJREFUeNrtfel6azeuLAryd9//fbuFuj+IkYtLkr2902dyEseDLIkkiKFQAET+h3/gH/iL//v4Xy0w//Ul53/xJcAHq3q1WHD+/9feEbH+u3zw7+4H//Jpg++2Ctc3cvwT/gPSwX9U3PHhfvct5H8RDXE8r+/dirZ8+Mrg14AQggL252R8TfAf3oAfv+DdH2K+yvv9Zt+H3xWEv64Drq+HswDcvih36fft4N9Y+usN+HPZw+nu490rtC1Al4A/vQy3f47fXvd19Ygrn7bijfYbB94lgL+wAfsK8X1b9tHqh/Dv/7vRpGy/2y+E68XfFwP8vnJBlwB8bgSPBnCqAP6+cfxdJejiPZZ/kALmZ97dgnH4/Yvf3gJ8V/u9/D32he/2b78FtxIAXkWAf8E0+tvkDxd8v/yuBHDZiRQBvvSBt8Vf9uFv+QGvD/nenuCk/ptLEN/z+DRTBXQJIPjnUnBePX9LB1xkPxZ82JOXB44bK5Ar50E3/qetgLTj3RaNzS/wt4DL0nGjDgn25XKeP//o/DcvnT97Ipci7NYfcl3+JRwmuG1G+1VX+9Ma4BfVIf5s//KcQfRzxnQBLzEBL89bC+ZZD447QPCzHXh7rvuZfNsNRPvX/0+kdpn3/wYI4ulbXveAu2P8G4ESfkP3+S6eRf9kC187g7xoA25bcNyQ/8AGoEtAN3Qp+oRsNuH7e9AVAS9q4M0WfHgFfmZIEGeLoyEsNwvnV8IN9uWaH+4oUU5bcNWNP9Nk+JPjx77u7gPy3v7DVQHugmBej3/swCFG+KlTgD9eP2S7ATjY2NOG487tPQEiww3Yv/4TTYA/uf3t6ImuCgjh4eyH5wnB1fzxhUrgi/9+HijjJ84Tc/G7GsQ9Ajos4/pCxdRURGwsBwfP6PbQe6zAH+gB/Fj81ycKDlYAvF776w3Q+sZ2L+d4Pe5Fnz8OEvFtzVmaf9cBuwo4vET/tVaqzLcgfJsXwBBvrsCPtwAfq8ymNUsCLn4AXjz3epyaqNXqkXbdrnpgftmN/3EHtg389VigbjHm/S9P+LT+TfHrBhao1QGb78bJFG4mgHfKkX/VCnRtt/uAtzhY+0bLC/DVNx0otGkKpyHctcDZDJDf0OjfBkSwiz+OHlH7H+elbw/S/sRhBqwFh7w6CF0L4OoX/cQg4puPxTj+viNyFwutU5YRIOvlyc1Pz9T2SOiAiF1Env17yucXGz8+/yYFPeRvMZCeZO1y+G0Lhgq0HRo/40K8LP97qhBDx71+qLt7S9UhIBC0gLjQEDVdpgMDAuiHX0c9fAGCZXNMXkYBmyR8LANtqR+jwtjV/6YP60sXeVzyJSUVmwvUv7zgpHbYgT0C6Iv/pjHA99X/UQ2WMOgFAmvnPdaPWq+1z8MKLmVobXHXLBG7WWRYAv7xBlxjf5x2oPmG6O7di9uu9ZhYkm3SsJlBEwrByR9IuIgnLfAqyfvmCoR+5CXrARnrH6in+3kd+9Hz6neAiLEDdoMRsaKlg3vEtglTD/LXrgDaIa+lX9Jg8OimvGE9rr1FBGEfjZsIaHyl8Ws7+LpxStyX/60dwGcKsMt/vwilIFL80deq7W7rVCd5WyhipCFvr5qKxH8itvyDGwXPofs2Vcj3Ch4f6r+pAUfck9+E+Ovu+vGQRFuWAn6CT77Q3CZkMwZX0IQXA8B2K17bQ9wriWKV7KePif8h7DuG/6OWGnGQEsMXQPwBSeN6vxCK6XEHxHT5SjzklEPrcSrFe5eoLe4TEcAu/RgpULhmn+sfT09cLENoDZLyDEewHVpzlCxWYud1cVt2bMcnMvA+YrpKwCUK0nGzu6Ef8h/BAWRKgAlJsbEBOh2EsQOn5Nmm/yhdOf6RFYh1X86/7n77oq0+cXFu8XDlkFwJkmsHSnNr6cd+8PlVBDK8wiFs8sD3cQHeQaCXm182sDl+mKu/wOBsYcAEUvLdkib0ZLEKEAFvyUDbgXPylBcF8F4Gvjajeu8IYMd20E5fp4sH8ZVgcwDZZWf32tXKuWwP8d/536aPQH+VIBesCKqhjOD65wdXoCWL8/SRi3YB6JZfC+Vs0R/jHtB1f3iNGHBoOvCpBrBe0WSIQI9+rDvLF4CAuwDwpzpgu/fTDUZfv+4p0BXFFLscTfmhpQXhFyBd3rUD2gAC63hBrcZELfmTIzfA8c+Gkh1Yje9coFKBaFEB+u3X9Ah0IhkzMHLktECI/GSId2qirkuaUrSePNiCSMqASSm1n3yvCN9uwLYJzSdWgQjU+vpVBB3ZCzuIipIB1AWoVHcthuVBr7zZ3IK5C3bNmxBj7XwNEb2yApf1dwsA0dR+mqKAfk1baZBahsBAWEHCRCgIGLCUm7Q9kXkRuoCNjePGJPDV87VH+LpoyhfddUCqaG3XH37G6KbZDjFwdyhEBgLaw+EUEJuwoB1zabajZnnz8/xf6EF8SwOiyX+Ygbb+rtrBFtwOFg2UIijQD3WhfUMgh028bOwAUW3qe7b1v1YD+HT9KQBwJe1qUFE3PLyXOhwV08Wa6k/akFgxZYBgtjk3GdzoOPNtB/aLkPkRDkXAW0//vQtc1z89AF23IGMgnQDBcHHC9nsiWcNFHuAOMuTdT3yHT/vjrE58vwi+A6ECbkUA79bfRADhwELT/EU0hJkYnJyNIFE0f7jOfdNpWR5Bgan7/e307GoWNg1B7jvwSgvg8/U3k6DuqqQAzNRgx6p35vAeJ8OO+V8hCzDy2rp4ZmPLqDfZXyiSdN3Xd+DbG5AW4MX6h/5HMiPqAu8gkElHDsNR3thAHc4DhQRIQOiPt3DubHOGEBnm2IGuBM478PVCA/YvwslHrLcZN91Z0sQh++qaDJAtlVKxmFwLg3JHlUJ4aKGGARxYulsQqjl8vooxEZmmm7gI70zA0IPuAqM5AO4Q5TmrFQeaDQbT5uWslWoJefrwWjrOPB0XSmGDyZdB0O4h5gUKgK2fPm8y5/hg/Zse0LSAaycaPNhimHasEr8RS9QQBammdC5ryQn8YQTMiX/a9AQrqeTbk9HA3IsPr0BP9UzmDwb4h5EKuENYM3YTanAjEWxKFYMz5VAsE04nHRn/O9Aw/i58bUtmqq47sV6rdvB4Bb5eUQGwITgYYKavH5gs4QIznUJGzyUz31/Ax/RAGhk7Q8iVdh46lE5EdEswyovVDmmYoNnmw9ESa283AOPEJzMCBfpjPEKtgrhWm++xQ7vDlk70MvaeHYCIedpdBCTit25LSzocaU9lF8+79AHapqQIBPn4WxJwiQFaKKwjxlk/6Xn/YpSpw/zETI3qhXJE0RXLpuJfr8pO6vW7wUPpjVY0SVGjXwIpdO64BXrvHEBmQrBUvha84c+t23P6wauKKJrHB9b6NWxCBEoQQKHuVq6wmRFAo0OxAMY1POv1JoCYUvhSAnAgRJQBiE3T3QHYuACFks9
|
||
|
}
|
||
|
this.bird = options.bird;
|
||
|
if (!this.bird) {
|
||
|
this.bird = new Image();
|
||
|
this.bird.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAABDCAQAAAD+S8VaAAAAAnNCSVQICFXsRgQAAAAJcEhZcwAAAvMAAALzAdLpCioAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAG90lEQVR42uWaaVRTRxTHJ4AUUIoIiqISOArIDiIhBBfccCMoR0vVUpXjTqun4Fr1tO5i3YuodaFqRMECKm4VUHEhUvWgBYuilgpiRVZpCARI3r8fWA4hYY9AXu77+ObNzO/O8u787xDSyeYSTzSICpu+DjV0ogrze84PBneByuJv3JpbBlx6MEBbJfG/8S2RAACFXXtU0gERN1BjCc9UEN/e7I2w1gFPinv3UDkHbFiGOqOwJVjlHMALRT3LLJ7trGIOuHwFUsY7q2IOuJ0u7YB//pswWFn6/vnUcbOCAn7ctfnUrsijl85dv5pw786fd9OTsvg5/JykN3fTb6ZcTDgVvefIkqXmVvKr0NN/IUQDO7C1qwJrOwyftIZ7cmIiN21eZlB+SOUtFKNl9kF0hb9ujmyVM73FMmWv3m+2J4zxw74NDN5/5vT1qzeT7j3n5/Bz7mcmPk24cy32Ai8i9Pj2nwIX+jo4kc8UMMqeXr5bfC6N/2tUHrdsCQ4gAR/QNhNRJ8+6GklXH7xStlxW+ViLxrpjqBswJ/z4rYyCFrQnwJPCxGe/x53i+fO+XOth2xpsvQm+PkfGP3YuYIo1oInTyIJiLDFtoZfUP+AXeaW2rZHXKZ8xJ35NeU+1odVSbIIBbEQeb70Tffd6ckmj0QbDy9/zOufdILE6SN0TBkVafnn0ka/NatrrditDXpmYKw36pREwPyr+Y0V72n0CsxoedTDFrMJJyRMDZJYIx8+yYICQKbDJtcjtL9IGAcEMKN7efIy+snnTYv/tR8Ry3+eWRUYFzavRB9SWL7icXKWAVrPRr96wEqjBTjg5bop03GGi77XF85FdqVZNIQ1konOsEvx35yOCN1xMFimszjNSDqh+ektGfVG3xjyTzaqkX3uDTiaCdh0ZA/qSgWXWWfb7CYMQQsiUUANK1j8hoJf1lSFUg0u+z1xCiFuMUYWsAy7QCj9ZzhIgIDCkpi4nhBCGsafNGx2peXCQRvhlcGrEAQSOhYQQQtyTG74YCglN8CswrVF8goEVhBBCrMzdozi33OOHJmvUvQqghQtKMEUu+GDB0Cj2Q/vsUdJn0JH8+oXG4rWS46djSD0ePcr2lUuafbZlIbN0UAnngpyA0I3FumeZxxQYVlZ/ooWleKm0+FHQbTDuWnAp5F6cbNfskcDtcg9J9aMGNUxDIiglgy+CPxhypj4Ddu/cfFpxOrIqrv7QAsH4V2nwYxoEvwQEOpRlAeeG07hWnopH7FMHgTr6VmhAA1xEQNjF4bMxQwpcj2I9duVZLiVtTb7YT7T2I30JccyqrrA7ZuESRF0SvhQ/QKfByDu/VZAs5O6rXS9U6onZ+A2CLgQvwWn0l5n4TAFnjOKksR5En6i73q6/q3IRhvwugB8LBylwi6IhixxX9Wd/CoWQwTrJTuaEOSwzENcKDR7Yj4xOg4+Hq3SEXzX8fIfcObAZPizV+bGxqLZhMyxBWgdP+xi4ScGbCNnhhrodqxnrso65pLidNxMQENihqoPgS3AY5rU7krh35eCPbon2c4hap2nnxob2GQQE+zpAM4qFb53EoUWxE3t93jXyBwyXcG1KD+8/IXwBAmFYg26Vx37oHjnIlnQlGzbJvMCX+lQrPgT6dat9yAcT/S6aSOIs2rjjxLaQ9SsX83gv8uShiNuAn4mR9fZ5dizpphRpREvj1YvOhiU84OdmoghFyKH47y/GHohtLf45ITvVuLyfyKLI5RlntyJSXx2+P+gaejt5O7FNCSEkcFHTuAmPom6/qqxJqFRee33wHGc6rVLjXtym8C8nTTcnDNMh/n5BfnN8mFY18jWdbPlceeBViEsPi16xxFSL7ncjukVelTvxUzsxjOlAUzsULv8/GfdEJa7G7D7YWLCcUzbNkfb42zaXNaG2h4XTHH/n9x+bjIHKqeAdNMZf55fbrKBYLNq+lqb433lkFrUk5hNKdu6mIf5XA1KetzibR+09TLcfonrMtVYlNKk9h2gV//FCW3tCFmMXT0nOe83bxpklbdDJqrD+BC1mwUzTtOw2Sl/UFjpsh8ci2pHirFgxV8nxV/oJxO2RwR6+HNFbmfkZ15PaqwQe/VmJ+R18Aql37XTAsQ9EefUBW6NeEk34IaWN8HkIQk+Jva0SzwGXP6p1XDeEoqB1qx/L0B3dKY+VSr0JDurDFNaK2ZoYg5142sx1m3LEYxUsq+Vv8ejVSv8bdJ/UXySds9eDB4JwEnFIRS6KUIi/8RJxCEEARte74GBR6DycFpGgtZNFPkHrHgOx61miSaPDEOtEn8qWwvepZMc5Mel3ItZmHbbM12wSXV/snMHZQ6eRlzEzI9d9rnftskwERhXVNxF7ik1Krd87pbLCbWYR9Y7v0f/htaJHbsoDhwAAAABJRU5ErkJggg==";
|
||
|
}
|
||
|
// Parameters
|
||
|
this.set('opacity', options.opacity||0.3);
|
||
|
this.set('density', options.density||0.5);
|
||
|
this.setWind(options);
|
||
|
};
|
||
|
ol.ext.inherits(ol.control.Cloud, ol.control.Control);
|
||
|
/**
|
||
|
* Remove the control from its current map and attach it to the new map.
|
||
|
* Subclasses may set up event handlers to get notified about changes to
|
||
|
* the map here.
|
||
|
* @param {_ol_Map_} map Map.
|
||
|
* @api stable
|
||
|
*/
|
||
|
ol.control.Cloud.prototype.setMap = function (map) {
|
||
|
if (this._listener) ol.Observable.unByKey(this._listener);
|
||
|
this._listener = null;
|
||
|
ol.control.Control.prototype.setMap.call(this, map);
|
||
|
if (map) {
|
||
|
this._listener = map.on('postcompose', this.drawCloud_.bind(this));
|
||
|
}
|
||
|
};
|
||
|
/** Set wind direction / force
|
||
|
*/
|
||
|
ol.control.Cloud.prototype.setWind= function (options) {
|
||
|
options = options || {};
|
||
|
var rnd = Math.random;
|
||
|
var a = options.windAngle || rnd()*Math.PI;
|
||
|
var speed = options.windSpeed || rnd();
|
||
|
this.wind = { angle: a, cos: Math.cos(a), sin: Math.sin(a), speed: speed };
|
||
|
}
|
||
|
/**
|
||
|
* @private
|
||
|
*/
|
||
|
ol.control.Cloud.prototype.drawCloud_ = function (event) {
|
||
|
if (!this.getMap()) return;
|
||
|
var ctx = event.context || ol.ext.getMapCanvas(this.getMap()).getContext('2d');
|
||
|
var canvas = ctx.canvas;
|
||
|
// var ratio = event.frameState.pixelRatio;
|
||
|
// var m = Math.max(canvas.width, canvas.height);
|
||
|
// var res = view.getResolution()/ratio;
|
||
|
// var rot = view.getRotation();
|
||
|
// Not ready !
|
||
|
if (!this.cloud.width) return;
|
||
|
// Go!
|
||
|
var p = this.particules;
|
||
|
var rnd = Math.random;
|
||
|
var w = this.cloud.width;
|
||
|
var h = this.cloud.height;
|
||
|
var w2 = this.cloud.width/2;
|
||
|
var h2 = this.cloud.height/2;
|
||
|
var d = (this.get('density')*10*canvas.width*canvas.height/w/h) << 0;
|
||
|
var i;
|
||
|
function addClouds (nb) {
|
||
|
for (i=0; i<nb; i++) {
|
||
|
p.push({ x: rnd()*canvas.width-w2, y: rnd()*canvas.height-h2 });
|
||
|
}
|
||
|
}
|
||
|
// First time: init clouds
|
||
|
if (!p) {
|
||
|
p = this.particules = [];
|
||
|
addClouds(d);
|
||
|
// Wind
|
||
|
this.width = canvas.width;
|
||
|
this.height = canvas.height;
|
||
|
// Birds
|
||
|
this.birds = [];
|
||
|
for (i=0; i<5; i++) {
|
||
|
var b = { angle: rnd()*2*Math.PI, x: rnd()*canvas.width, y: rnd()*canvas.height, rot:0, fly:0 };
|
||
|
b.cos = Math.cos(b.angle);
|
||
|
b.sin = Math.cos(b.angle);
|
||
|
this.birds.push (b);
|
||
|
}
|
||
|
} else if (d != p.length) {
|
||
|
// Parameters changed
|
||
|
if (this.width !== canvas.width || this.height !== canvas.height) {
|
||
|
p = this.particules = [];
|
||
|
addClouds(d);
|
||
|
this.width = canvas.width;
|
||
|
this.height = canvas.height;
|
||
|
} else if (d > p.length) {
|
||
|
addClouds(1);
|
||
|
} else if (d < p.length) {
|
||
|
p.splice ( (p.length*rnd()) << 0, 1);
|
||
|
}
|
||
|
}
|
||
|
// Draw clouds
|
||
|
var dx = this.wind.cos * this.wind.speed;
|
||
|
var dy = this.wind.sin * this.wind.speed;
|
||
|
for (i=0; i<p.length; i++) {
|
||
|
p[i].x += dx + rnd()*2-1;
|
||
|
p[i].y += dy + rnd()*2-1;
|
||
|
// out!
|
||
|
if (p[i].x < -w) {
|
||
|
p[i].x = canvas.width;
|
||
|
p[i].y = rnd()*canvas.height-h2;
|
||
|
} else if (p[i].x > canvas.width) {
|
||
|
p[i].x = -w;
|
||
|
p[i].y = rnd()*canvas.height-h2;
|
||
|
}
|
||
|
if (p[i].y < -h) {
|
||
|
p[i].y = canvas.height;
|
||
|
p[i].x = rnd()*canvas.width-w2;
|
||
|
} else if (p[i].y > canvas.height) {
|
||
|
p[i].y = -h;
|
||
|
p[i].x = rnd()*canvas.width-w2;
|
||
|
}
|
||
|
}
|
||
|
// Draw clouds
|
||
|
ctx.globalAlpha = this.get('opacity');
|
||
|
for (i=0; i<p.length; i++) {
|
||
|
ctx.drawImage(this.cloud, p[i].x,p[i].y);
|
||
|
}
|
||
|
ctx.globalAlpha = 1;
|
||
|
// Draw birds
|
||
|
w = this.bird.width/2;
|
||
|
h = this.bird.height/2;
|
||
|
var sc = 0.5;
|
||
|
var dw = canvas.width+w;
|
||
|
var dh = canvas.height+h;
|
||
|
for (i=0; i<this.birds.length; i++) {
|
||
|
var bi = this.birds[i];
|
||
|
// Animate birds
|
||
|
var sx = 0;
|
||
|
if (bi.fly) {
|
||
|
bi.fly = (++bi.fly%5)
|
||
|
sx = -0.1
|
||
|
} else if (rnd()<0.01) bi.fly=1;
|
||
|
// Rotate birds
|
||
|
if (bi.rot) {
|
||
|
bi.angle += bi.rot;
|
||
|
bi.cos = Math.cos(bi.angle);
|
||
|
bi.sin = Math.sin(bi.angle);
|
||
|
}
|
||
|
if (rnd()<0.01) {
|
||
|
bi.rot = bi.rot ? 0 : rnd()*Math.PI/200-Math.PI/400;
|
||
|
bi.cos = Math.cos(bi.angle);
|
||
|
bi.sin = Math.sin(bi.angle);
|
||
|
}
|
||
|
// Move birds
|
||
|
bi.x += bi.sin;
|
||
|
if (bi.x>dw) bi.x = -w;
|
||
|
if (bi.x<-w) bi.x = dw;
|
||
|
bi.y -= bi.cos;
|
||
|
if (bi.y>dh) bi.y = -h;
|
||
|
if (bi.y<-h) bi.y = dh;
|
||
|
// Draw birds
|
||
|
ctx.save();
|
||
|
ctx.translate (bi.x, bi.y);
|
||
|
ctx.rotate(bi.angle)
|
||
|
ctx.scale(sc+sx,sc);
|
||
|
ctx.drawImage( this.bird, -w,-h );
|
||
|
ctx.restore();
|
||
|
}
|
||
|
// Continue animation
|
||
|
this.getMap().render();
|
||
|
}
|