pano.js 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079
  1. if (ref_points == undefined) var ref_points = new Array();
  2. if (image_loop == undefined) var image_loop = false;
  3. var debug_mode = false;
  4. var canvas;
  5. var cntext;
  6. var point_list = new Array();
  7. var zoom = 0;
  8. var zooms = new Array();
  9. var prev_zm;
  10. var zm;
  11. var tile = {width:256, height:256};
  12. var ntiles = {x:228, y:9};
  13. var border_width = 2;
  14. var imageObj = new Array();
  15. var fingr = 0; // mémorisation de lécart entre doigts;
  16. var last = {x:0,y:0};
  17. var shift = {x:0,y:0};
  18. var mouse = {x:0,y:0};
  19. var speed = {x:0,y:0};
  20. var canvas_pos = {x:0,y:0};
  21. var tmt;
  22. var is_located = false;
  23. var point_colors = {
  24. 'pano_point' : '255,128,128', // red
  25. 'ref_point' : '128,128,255', // blue
  26. 'loc_point' : '128,255,128', // green
  27. 'temporary' : '255,255,128', // yellow
  28. 'unlocated' : '255,255,255' // white
  29. };
  30. var test = {x:0, y:0, i:100};
  31. function getXMLHttpRequest() {
  32. var xhr = null;
  33. if (window.XMLHttpRequest || window.ActiveXObject) {
  34. if (window.ActiveXObject) {
  35. try {
  36. xhr = new ActiveXObject("Msxml2.XMLHTTP");
  37. } catch(e) {
  38. xhr = new ActiveXObject("Microsoft.XMLHTTP");
  39. }
  40. } else {
  41. xhr = new XMLHttpRequest();
  42. }
  43. } else {
  44. alert("Votre navigateur ne supporte pas l'objet XMLHTTPRequest...");
  45. return null;
  46. }
  47. return xhr;
  48. }
  49. function nmodulo(val, div) { // pour obtenir un modulo dans l'espace des nombres naturels N.
  50. return Math.floor((val%div+div)%div); // il y a peut être plus simple, mais en attendant ....
  51. }
  52. function fmodulo(val, div) { // pour obtenir un modulo dans l'espace des nombres réels positifs.
  53. return (val%div+div)%div; // il y a peut être plus simple, mais en attendant ....
  54. }
  55. function distort_canvas(p, x, y) {
  56. if (p == 0) distort = 0;
  57. else {
  58. cntext.save();
  59. distort++;
  60. cntext.clearRect(0, 0, canvas.width, 2*canvas.height);
  61. var ratio = (canvas.width-2*distort)/canvas.width;
  62. var shift = canvas.height/2*(1-ratio);
  63. cntext.scale(1, ratio);
  64. if (p == 1) cntext.translate(0, 0);
  65. else if (p == -1) cntext.translate(0, 0);
  66. draw_image(x, y);
  67. cntext.restore();
  68. document.getElementById('res').innerHTML = 'distort : ' + distort + ' shift ' + shift + ' ratio : ' + ratio + '<br/>';
  69. }
  70. }
  71. function draw_image(ox, oy) {
  72. var ref_vals = {x:last.x, y:last.y, zoom:zoom};
  73. ox = nmodulo(ox-canvas.width/2, zm.im.width); // pour placer l'origine au centre du canvas
  74. oy = Math.floor(oy-canvas.height/2); // pas de rebouclage vertical
  75. cntext.clearRect(0, 0, canvas.width, canvas.height);
  76. cntext.fillStyle = "rgba(128,128,128,0.8)";
  77. if (canvas.height > zm.im.height) {
  78. var fy = Math.floor((oy+canvas.height/2-zm.im.height/2)/(tile.height*zm.ntiles.y))*zm.ntiles.y;
  79. if (fy < 0) fy = 0;
  80. var ly = fy + zm.ntiles.y;
  81. } else {
  82. var fy = Math.floor(oy/tile.height);
  83. var ly = Math.floor((oy+canvas.height+tile.height-1)/tile.height+1);
  84. if (fy < 0) fy = 0;
  85. if (ly > zm.ntiles.y) ly = zm.ntiles.y;
  86. }
  87. for (var j=fy; j<ly; j++) {
  88. var delta_y = (Math.floor(j/zm.ntiles.y) - Math.floor(fy/zm.ntiles.y)) * (tile.height - zm.last_tile.height);
  89. var dy = j*tile.height - oy - delta_y;
  90. var ny = j%ntiles.y;
  91. var wy = zm.tile.width;
  92. if (ny == zm.ntiles.y - 1) wy = zm.last_tile.height;
  93. var cpx = 0;
  94. var i = 0;
  95. var Nx = zm.ntiles.x;
  96. while (cpx < ox+canvas.width) {
  97. var cur_width = zm.tile.width;
  98. if (i%Nx == zm.ntiles.x-1) cur_width = zm.last_tile.width;
  99. if (cpx >= ox-cur_width) {
  100. var nx = i%Nx;
  101. var idx = nx+'-'+ny+'-'+ref_vals.zoom;
  102. if (imageObj[idx] && imageObj[idx].complete) {
  103. draw_tile(idx, cpx-ox, dy); // l'image est déja en mémoire, on force le dessin sans attendre.
  104. } else {
  105. var fname = get_file_name(nx, ny, ref_vals.zoom);
  106. imageObj[idx] = new Image();
  107. imageObj[idx].src = fname;
  108. var ts = zm.get_tile_size(nx, ny);
  109. cntext.fillRect(cpx-ox, dy, ts.width, ts.height);
  110. imageObj[idx].addEventListener('load', (function(ref, idx, dx, dy, ox, oy, ts) {
  111. return function() { // closure nécéssaire pour gestion assynchronisme !!!
  112. draw_tile_del(ref, idx, dx, dy, ox, oy, ts.width, ts.height);
  113. };
  114. })(ref_vals, idx, cpx-ox, dy, ox, oy, ts), false);
  115. }
  116. // load_image(zoom, nx, ny, shx, shy, cpx-ox, dy, ox, oy);
  117. }
  118. cpx += cur_width;
  119. i++;
  120. }
  121. }
  122. drawDecorations(ox, oy);
  123. var cap_ele = zm.get_cap_ele(last.x, zm.im.height/2-last.y);
  124. angle_control.value = cap_ele.cap.toFixed(2);
  125. elvtn_control.value = cap_ele.ele.toFixed(2);
  126. }
  127. function draw_tile_del(ref, idx, tx, ty, ox, oy, twidth, theight) {
  128. if (ref.zoom == zoom && ref.x == last.x && ref.y == last.y) {
  129. draw_tile(idx, tx, ty);
  130. drawDecorations(ox, oy, tx, ty, twidth, theight);
  131. }
  132. }
  133. function draw_tile(idx, ox, oy) {
  134. var img = imageObj[idx];
  135. cntext.drawImage(img, ox, oy);
  136. }
  137. /** Draws the colored circles
  138. */
  139. function drawDecorations(ox, oy, tx, ty, twidth, theight) {
  140. if (twidth) {
  141. cntext.save();
  142. cntext.beginPath();
  143. cntext.rect(tx, ty, twidth, theight);
  144. cntext.clip();
  145. }
  146. var wgrd = zm.im.width/360;
  147. var od = ((ox+canvas.width/2)/wgrd)%360;
  148. var el = (zm.im.height/2 - (oy+canvas.height/2))/wgrd;
  149. cntext.fillStyle = "rgba(0,128,128,0.9)";
  150. cntext.strokeStyle = "rgb(255,255,255)";
  151. cntext.lineWidth = 1;
  152. cntext.fillRect(canvas.width/2-5, canvas.height/2-5, 10, 10);
  153. cntext.strokeRect(canvas.width/2-5, canvas.height/2-5, 10, 10);
  154. for(var i = 0; i < zm.pt_list.length; i++) {
  155. if (zm.pt_list[i]['type'] != 'unlocated') {
  156. cntext.fillStyle = 'rgba('+point_colors[zm.pt_list[i]['type']]+',0.5)';
  157. var cx = nmodulo(zm.pt_list[i]['xc'] - ox, zm.im.width);
  158. var cy = zm.pt_list[i]['yc'] - oy;
  159. cntext.beginPath();
  160. cntext.arc(cx, cy, 20, 0, 2*Math.PI, true);
  161. cntext.fill();
  162. }
  163. }
  164. if (twidth) {
  165. cntext.restore();
  166. }
  167. }
  168. function insert_drawn_point(lat, lon, alt) {
  169. var rt = 6371; // Rayon de la terre
  170. var pt_alt = document.getElementById('pos_alt').childNodes[0].nodeValue;
  171. var pt_lat = document.getElementById('pos_lat').childNodes[0].nodeValue;
  172. var pt_lon = document.getElementById('pos_lon').childNodes[0].nodeValue;
  173. var alt1 = pt_alt;
  174. var lat1 = pt_lat*Math.PI/180;
  175. var lon1 = pt_lon*Math.PI/180;
  176. var alt2 = alt;
  177. var lat2 = lat*Math.PI/180;
  178. var lon2 = lon*Math.PI/180;
  179. var dLat = lat2-lat1;
  180. var dLon = lon2-lon1;
  181. var a = Math.sin(dLat/2)*Math.sin(dLat/2) + Math.sin(dLon/2)*Math.sin(dLon/2)*Math.cos(lat1)*Math.cos(lat2); //
  182. var angle = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  183. var d = angle*rt; // distance du point en Kms
  184. var y = Math.sin(dLon) * Math.cos(lat2);
  185. var x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
  186. var cap = Math.atan2(y,x); // cap pour atteindre le point en radians
  187. var e = Math.atan2((alt2 - alt1)/1000 - d*d/(2*rt),d); // angle de l'élévation en radians
  188. return {d:d, cap:cap*180/Math.PI, ele:e*180/Math.PI}; // les résultats sont en degrés
  189. }
  190. function localate_point() {
  191. var lat = document.getElementById("loca_latitude").value;
  192. var lon = document.getElementById("loca_longitude").value;
  193. var alt = document.getElementById("loca_altitude").value;
  194. if (lat == '' || isNaN(lat) || lat <= -90 || lat > 90) {
  195. alert("La latitude "+lat+"n'est pas correcte");
  196. return;
  197. }
  198. if (lat == '' || isNaN(lon) || lon <= -180 || lon > 180) {
  199. alert("La longitude "+lon+"n'est pas correcte");
  200. return;
  201. }
  202. if (lat == '' || isNaN(alt) || alt < -400 || alt > 10000000) {
  203. alert("l'altitude "+alt+"n'est pas correcte");
  204. return;
  205. }
  206. var opt_ced = new Array();
  207. opt_dce = insert_drawn_point(lat, lon, alt);
  208. display_temp(opt_dce.d, opt_dce.cap, opt_dce.ele);
  209. }
  210. function display_temp(d,cap,ele) {
  211. point_list[point_list.length] = new Array("point temporaire", d,cap,ele, "temporary");
  212. reset_zooms();
  213. putImage(last.x, last.y);
  214. }
  215. function arrayUnset(array, value){
  216. array.splice(array.indexOf(value), 1);
  217. }
  218. function erase_point() {
  219. for (var i=0; i<point_list.length; i++) {
  220. if(point_list[i][0] == "point temporaire"){
  221. arrayUnset(point_list,point_list[i]);
  222. loop = erase_point();
  223. }
  224. }
  225. reset_zooms();
  226. putImage(last.x, last.y);
  227. }
  228. /** Returns a 3-width zero-padded version of an int
  229. * ex: 3 -> "003"
  230. */
  231. function zero_pad(number) {
  232. var temp = number.toString(10);
  233. while (temp.length < 3) {
  234. temp = '0' + temp;
  235. }
  236. return temp;
  237. }
  238. function get_file_name(x, y, z) { // recherche du fichier correspondant au zoom et à la position
  239. return img_prefix+'/'+zero_pad(z)+'-'+zero_pad(x)+'-'+zero_pad(y)+'.jpg';
  240. }
  241. function get_base_name() {
  242. /**
  243. * @returns the base name, which is the name (not path) of the folder where
  244. * the tiles are.
  245. */
  246. return img_prefix.split('/').reverse()[0];
  247. }
  248. function keys(key) {
  249. hide_links();
  250. evt = key || event;
  251. //evt.preventDefault();
  252. //evt.stopPropagation();
  253. if (!key) {
  254. key = window.event;
  255. key.which = key.keyCode;
  256. }
  257. // alert(key);
  258. // if (!evt.shiftKey) return;
  259. switch (key.which) {
  260. /*case 66: // b
  261. alert(key.pageX);
  262. test.x=tile.width*(ntiles.x-3);
  263. test.y=0;
  264. putImage(test.x, test.y);
  265. return;
  266. case 67: // c
  267. test.x=0;
  268. test.y=tile.height*(ntiles.y-3);
  269. putImage(test.x, test.y);
  270. return;*/
  271. case 36: // home
  272. putImage(0, zm.im.height/2);
  273. return;
  274. case 35: // end
  275. putImage(last.x+zm.im.width/2, last.y);
  276. return;
  277. case 39: // left
  278. putImage(last.x+40, last.y);
  279. return;
  280. case 40: // up
  281. putImage(last.x, last.y+20);
  282. return;
  283. case 37: // right
  284. putImage(last.x-40, last.y);
  285. return;
  286. case 38: // down
  287. putImage(last.x, last.y-20);
  288. return;
  289. case 33: // pageup
  290. zoom_control.value--;
  291. change_zoom()
  292. return;
  293. case 34: // pagedown
  294. zoom_control.value++;
  295. change_zoom()
  296. return;
  297. default:
  298. // alert(key.which)
  299. return;
  300. }
  301. }
  302. function onImageClick(e) {
  303. hide_contextmenu();
  304. var index = {};
  305. if (e.touches && e.touches.length == 2) {
  306. e.preventDefault();
  307. fingr = Math.sqrt((e.touches[0].clientX - e.touches[1].clientX)^2 +
  308. (e.touches[0].clientY - e.touches[1].clientY)^2);
  309. } else {
  310. if (e.touches) {
  311. e.preventDefault();
  312. index.x = e.changedTouches[0].clientX;
  313. index.y = e.changedTouches[0].clientY;
  314. } else {
  315. index.x = e.pageX;
  316. index.y = e.pageY;
  317. }
  318. shift.x = last.x;
  319. shift.y = last.y;
  320. speed.x = 0;
  321. speed.y = 0;
  322. mouse.x = index.x;
  323. mouse.y = index.y;
  324. }
  325. clearTimeout(tmt); //arrêt de l'éffet eventuel d'amorti en cours.
  326. canvas.addEventListener('mousemove', stickImage, false);
  327. canvas.addEventListener('touchmove', stickImage, false);
  328. canvas.addEventListener('mouseup', launchImage, false);
  329. canvas.addEventListener('touchend', launchImage, false);
  330. //canvas.addEventListener('mouseout', launchImage, false);
  331. canvas.style.cursor='move';
  332. //document.onmousemove = stickImage;
  333. //document.onmouseup = launchImage;
  334. hide_links();
  335. }
  336. function stickImage(e) {
  337. var index = {};
  338. if (e.changedTouches && e.changedTouches.length == 2) {
  339. e.preventDefault();
  340. // cas du zoom à 2 doigts
  341. var nfingr = Math.sqrt((e.changedTouches[0].clientX - e.changedTouches[1].clientX)^2 +
  342. (e.changedTouches[0].clientY - e.changedTouches[1].clientY)^2);
  343. var evt = {}
  344. evt.pageX = (e.changedTouches[0].clientX + e.changedTouches[1].clientX)/2;
  345. evt.pageY = (e.changedTouches[0].clientY + e.changedTouches[1].clientY)/2;
  346. if (fingr > nfingr*2 || fingr < nfingr/2) {
  347. evt.wheelDelta = fingr - nfingr;
  348. fingr = nfingr;
  349. return wheel_zoom(evt);
  350. } else {
  351. return;
  352. }
  353. }
  354. if (e.touches) {
  355. e.preventDefault();
  356. index.x = e.changedTouches[0].clientX;
  357. index.y = e.changedTouches[0].clientY;
  358. } else {
  359. index.x = e.pageX;
  360. index.y = e.pageY;
  361. }
  362. var xs = mouse.x - index.x + shift.x;
  363. var ys = mouse.y - index.y + shift.y;
  364. speed.x = xs - last.x; //mémorisation des vitesses horizontales
  365. speed.y = ys - last.y; //et verticales lors de ce déplacement
  366. putImage(xs, ys);
  367. }
  368. function launchImage(e) {
  369. var index = {};
  370. if (e.touches) {
  371. e.preventDefault();
  372. index.x = e.changedTouches[0].clientX;
  373. index.y = e.changedTouches[0].clientY;
  374. } else {
  375. index.x = e.pageX;
  376. index.y = e.pageY;
  377. }
  378. distort_canvas(0);
  379. canvas.removeEventListener('mousemove', stickImage, false);
  380. canvas.removeEventListener('touchmove', stickImage, false);
  381. //document.onmousemove = null;
  382. shift.x = index.x - mouse.x + shift.x;
  383. shift.y = index.y - mouse.y + shift.y;
  384. tmt = setTimeout(inertialImage, 100);
  385. }
  386. function putImage(x, y) { // est destiné à permettre l'effet d'amortissement par la mémorisation de la position courante.
  387. if (!zm.is_updated) return;
  388. if (x >= zm.im.width) { // rebouclage horizontal
  389. shift.x -= zm.im.width;
  390. x -= zm.im.width;
  391. } else if (x < 0) {
  392. shift.x += zm.im.width;
  393. x += zm.im.width;
  394. }
  395. if (y >= zm.im.height) { // pas de rebouclage vertical mais blocage
  396. //distort_canvas(1, x, y);
  397. shift.y = zm.im.height-1;
  398. y = zm.im.height-1;
  399. } else if (y < 0) {
  400. //distort_canvas(-1, x, y);
  401. shift.y = 0;
  402. y = 0;
  403. }
  404. last.x = x;
  405. last.y = y;
  406. draw_image(x, y);
  407. }
  408. function inertialImage() {
  409. speed.x *= 0.9;
  410. speed.y *= 0.9;
  411. if (Math.abs(speed.x) > 2 || Math.abs(speed.y) > 2) {
  412. putImage(last.x+speed.x, last.y+speed.y);
  413. tmt = setTimeout(inertialImage, 100);
  414. } else {
  415. show_links();
  416. }
  417. }
  418. function tri_ref_points(v1, v2) {
  419. return v1['x'] - v2['x'];
  420. }
  421. function tzoom(zv) {
  422. this.value = zv;
  423. this.ntiles = {x:0,y:0};
  424. this.tile = {width:0,height:0};
  425. this.last_tile = {width:0,height:0};
  426. this.max_tile = {width:0,height:0};
  427. this.im = {width:0,height:0};
  428. this.is_updated = false;
  429. this.refresh = function() {
  430. this.im.visible_width = this.tile.width*(this.ntiles.x-1)+this.last_tile.width;
  431. this.is_updated = true;
  432. this.im.width = this.im.visible_width;
  433. this.im.height = this.tile.height*(this.ntiles.y-1)+this.last_tile.height;
  434. if (this.last_tile.width > this.tile.width) {
  435. this.max_tile.width = this.im.last_tile.width;
  436. } else {
  437. this.max_tile.width = this.tile.width;
  438. }
  439. if (this.last_tile.height > this.tile.height) {
  440. this.max_tile.height = this.im.last_tile.height;
  441. } else {
  442. this.max_tile.height = this.tile.height;
  443. }
  444. var ord_pts = new Array();
  445. for(var label in ref_points) {
  446. ord_pts.push(ref_points[label]);
  447. }
  448. ord_pts = ord_pts.sort(tri_ref_points);
  449. is_located = (ord_pts.length > 1)
  450. || image_loop && (ord_pts.length > 0);
  451. var alpha_domain = {start:0, end:360};
  452. this.pixel_y_ratio = this.im.width/360;
  453. if (is_located) {
  454. this.ref_pixels = new Array;
  455. this.ref_pixels[0] = new Array(); // Attention il faut compter un intervalle de plus !
  456. for (var i=0; i < ord_pts.length; i++) { // premier parcours pour les paramètres cap/x
  457. this.ref_pixels[i+1] = new Array();
  458. this.ref_pixels[i+1].x = Math.floor(ord_pts[i].x*this.im.width);
  459. this.ref_pixels[i+1].cap = fmodulo(ord_pts[i].cap, 360);
  460. if (i != ord_pts.length-1) {
  461. this.ref_pixels[i+1].ratio_x = (ord_pts[i+1].x - ord_pts[i].x) /
  462. fmodulo(ord_pts[i+1].cap - ord_pts[i].cap, 360)*this.im.width;
  463. }
  464. }
  465. if (image_loop == true) {
  466. var dpix = this.im.width;
  467. var dangle = 360;
  468. if (ord_pts.length > 1) {
  469. dpix = this.im.width - this.ref_pixels[this.ref_pixels.length-1].x + this.ref_pixels[1].x;
  470. dangle = fmodulo(this.ref_pixels[1].cap - this.ref_pixels[this.ref_pixels.length-1].cap, 360);
  471. }
  472. this.ref_pixels[0].ratio_x = dpix/dangle;
  473. this.ref_pixels[ord_pts.length].ratio_x = this.ref_pixels[0].ratio_x;
  474. dpix = this.im.width - this.ref_pixels[ord_pts.length].x;
  475. this.ref_pixels[0].cap = fmodulo(this.ref_pixels[ord_pts.length].cap + dpix / this.ref_pixels[0].ratio_x, 360);
  476. } else {
  477. this.ref_pixels[0].ratio_x = this.ref_pixels[1].ratio_x;
  478. this.ref_pixels[ord_pts.length].ratio_x = this.ref_pixels[ord_pts.length-1].ratio_x;
  479. this.ref_pixels[0].cap = fmodulo(this.ref_pixels[1].cap - this.ref_pixels[1].x / this.ref_pixels[1].ratio_x, 360);
  480. alpha_domain.start = this.ref_pixels[0].cap;
  481. alpha_domain.end = fmodulo(this.ref_pixels[ord_pts.length].cap+(this.im.width-this.ref_pixels[ord_pts.length].x)/this.ref_pixels[ord_pts.length].ratio_x, 360);
  482. this.pixel_y_ratio = this.im.width/fmodulo(alpha_domain.end-alpha_domain.start, 360);
  483. }
  484. this.ref_pixels[0].x = 0;
  485. for (var i=0; i < ord_pts.length; i++) { // second parcours pour les paramètres elevation/y
  486. this.ref_pixels[i+1].shift_y = Math.floor(this.pixel_y_ratio*ord_pts[i].ele - ord_pts[i].y*this.im.height);
  487. if (i != ord_pts.length-1) {
  488. var next_shift = Math.floor(this.pixel_y_ratio*ord_pts[i+1].ele - ord_pts[i+1].y*this.im.height);
  489. this.ref_pixels[i+1].dshft_y = (next_shift - this.ref_pixels[i+1].shift_y)/(this.ref_pixels[i+2].x - this.ref_pixels[i+1].x);
  490. }
  491. }
  492. if (image_loop == true) {
  493. var dpix = this.im.width;
  494. var delt = 0;
  495. if (ord_pts.length > 1) {
  496. dpix = this.im.width - this.ref_pixels[this.ref_pixels.length-1].x + this.ref_pixels[1].x;
  497. delt = this.ref_pixels[this.ref_pixels.length-1].shift_y - this.ref_pixels[1].shift_y;
  498. }
  499. this.ref_pixels[0].dshft_y = -delt/dpix;
  500. this.ref_pixels[ord_pts.length].dshft_y = this.ref_pixels[0].dshft_y;
  501. dpix = this.im.width - this.ref_pixels[ord_pts.length].x;
  502. this.ref_pixels[0].shift_y = this.ref_pixels[ord_pts.length].shift_y + dpix*this.ref_pixels[0].dshft_y;
  503. } else {
  504. this.ref_pixels[0].shift_y = this.ref_pixels[1].shift_y;
  505. this.ref_pixels[0].dshft_y = 0;
  506. this.ref_pixels[ord_pts.length].dshft_y = 0;
  507. }
  508. if (debug_mode) {
  509. var res = document.getElementById('res');
  510. res.innerHTML = 'liste des '+this.ref_pixels.length+' valeurs de correction (image = '+this.im.width+'x'+this.im.height+') zoom = '+this.value+':<br/>';
  511. for (var i=0; i < this.ref_pixels.length; i++) { // pour le debug
  512. res.innerHTML += '<p>point '+i+' :</p><ul>';
  513. for (var key in this.ref_pixels[i]) { // pour le debug
  514. res.innerHTML += '<li>'+key + '['+i+'] = '+this.ref_pixels[i][key]+'</li>';
  515. }
  516. if (i != this.ref_pixels.length-1) {
  517. var tx0 = this.ref_pixels[i+1].x-1;
  518. //var ty0 = this.ref_pixels[i+1].shift_y;
  519. var ty0 = 0;
  520. } else {
  521. var tx0 = this.im.width-1;
  522. var ty0 = 0;
  523. }
  524. res.innerHTML += '</ul><p>test sur : '+tx0+','+ty0+'</p>';
  525. var tst = this.get_cap_ele(tx0, ty0);
  526. res.innerHTML += '<p>cap:'+tst.cap+', ele:'+tst.ele+'</p>';
  527. var tst2 = this.get_pos_xy(tst.cap, tst.ele);
  528. res.innerHTML += '</ul><p>x:'+tst2.x+', y:'+tst2.y+'</p>';
  529. }
  530. }
  531. }
  532. this.pt_list = new Array();
  533. for (var i=0; i<point_list.length; i++) {
  534. var lbl = point_list[i][0];
  535. var dst = point_list[i][1];
  536. var cap = point_list[i][2];
  537. var ele = point_list[i][3];
  538. var lnk = point_list[i][4];
  539. var url = point_list[i][5];
  540. var typ = 'unlocated';
  541. var rxy = this.get_pos_xy(cap, ele);
  542. var is_visible = (
  543. fmodulo(cap - alpha_domain.start, 360)
  544. <=
  545. fmodulo(alpha_domain.end -
  546. alpha_domain.start -0.0001, 360)+0.0001
  547. && is_located);
  548. this.pt_list[i] = new Array();
  549. if (ref_points[lbl] != undefined && lnk == '') {
  550. typ = 'ref_point';
  551. if (!is_located) {
  552. rxy = {
  553. x:ref_points[lbl].x*this.im.width,
  554. y:ref_points[lbl].y*this.im.height
  555. };
  556. }
  557. } else if(lnk == '' && is_visible && lbl != 'point temporaire') {
  558. typ = 'loc_point';
  559. }else if(is_visible && lbl =='point temporaire') {
  560. typ = 'temporary';
  561. } else if(is_visible) {
  562. typ = 'pano_point';
  563. }
  564. this.pt_list[i]['type'] = typ;
  565. this.pt_list[i]['cap'] = cap;
  566. this.pt_list[i]['ele'] = ele;
  567. this.pt_list[i]['dist'] = dst;
  568. this.pt_list[i]['label'] = lbl;
  569. this.pt_list[i]['lnk'] = lnk;
  570. this.pt_list[i]['url'] = url;
  571. this.pt_list[i]['xc'] = rxy.x;
  572. this.pt_list[i]['yc'] = Math.floor(this.im.height/2 - rxy.y);
  573. }
  574. },
  575. this.get_tile_size = function(nx, ny) {
  576. var res = {width:0, height:0};
  577. if (nx == this.ntiles.x-1) res.width = this.last_tile.width;
  578. else res.width = this.tile.width;
  579. if (ny == this.ntiles.y-1) res.height = this.last_tile.height;
  580. else res.height = this.tile.height;
  581. return res;
  582. }
  583. this.get_cap_ele = function(px, py) { // recherche d'un cap et d'une élévation à partir d'un pixel X,Y.
  584. if (is_located) {
  585. for (var i=0; i < this.ref_pixels.length; i++) {
  586. if (i == this.ref_pixels.length - 1 || px < this.ref_pixels[i+1].x) {
  587. var dpix = px-this.ref_pixels[i].x;
  588. var cp = fmodulo(this.ref_pixels[i].cap + dpix/this.ref_pixels[i].ratio_x, 360);
  589. var el = (py+this.ref_pixels[i].shift_y+this.ref_pixels[i].dshft_y*dpix)/this.pixel_y_ratio;
  590. return {cap:cp, ele:el};
  591. }
  592. }
  593. } else {
  594. var cp = 360*px/this.im.width;
  595. var el = 360*py/this.im.height;
  596. return {cap:cp, ele:el};
  597. }
  598. }
  599. this.get_pos_xy = function(cap, ele) { // recherche des coordonnées pixel à partir d'un cap et d'une élévation.
  600. if (is_located) {
  601. var dcap = fmodulo(cap-this.ref_pixels[0].cap, 360);
  602. for (var i=0; i < this.ref_pixels.length; i++) {
  603. if (i == this.ref_pixels.length - 1 || dcap < fmodulo(this.ref_pixels[i+1].cap-this.ref_pixels[0].cap, 360)) {
  604. var px = this.ref_pixels[i].x + this.ref_pixels[i].ratio_x*fmodulo(cap - this.ref_pixels[i].cap, 360);
  605. var dpix = px-this.ref_pixels[i].x;
  606. var py = this.pixel_y_ratio*ele - this.ref_pixels[i].shift_y - this.ref_pixels[i].dshft_y*dpix;
  607. return {x:px, y:py};
  608. }
  609. }
  610. } else {
  611. var px = fmodulo(cap, 360)/360*this.im.width;
  612. var py = ele/360*this.im.height;
  613. return {x:px, y:py};
  614. }
  615. }
  616. }
  617. function reset_zooms () {
  618. for(i=0; i<zooms.length; i++) zooms[i].is_updated = false;
  619. zm.refresh();
  620. }
  621. function wheel_zoom (event) {
  622. var zshift = {x:0, y:0};
  623. if (event.pageX != undefined && event.pageX != undefined) {
  624. zshift.x = event.pageX-canvas.width/2-canvas_pos.x;
  625. zshift.y = event.pageY-canvas.height/2-canvas_pos.y;
  626. }
  627. //event.preventDefault();
  628. if (event.wheelDelta < 0 && zoom_control.value < zoom_control.max) {
  629. zoom_control.value++;
  630. change_zoom(zshift.x, zshift.y);
  631. } else if (event.wheelDelta > 0 && zoom_control.value > zoom_control.min) {
  632. zoom_control.value--;
  633. change_zoom(zshift.x, zshift.y);
  634. }
  635. }
  636. function change_zoom(shx, shy) {
  637. var zoom_control = document.getElementById("zoom_ctrl");
  638. var v = zoom_control.value;
  639. prev_zm = zm;
  640. if (zooms[v]) {
  641. if (!zooms[v].is_updated) zooms[v].refresh();
  642. } else {
  643. zooms[v] = new tzoom(v);
  644. }
  645. if (zooms[v].is_updated) {
  646. if (shx == undefined || shy == undefined) {
  647. shx=0;
  648. shy=0;
  649. }
  650. zm = zooms[v];
  651. var px = (last.x+shx)*zm.im.width/prev_zm.im.width - shx;
  652. var py = (last.y+shy)*zm.im.height/prev_zm.im.height - shy;
  653. if (py < zm.im.height && py >= 0) {
  654. zoom = zm.value;
  655. tile = zm.tile;
  656. ntiles = zm.ntiles;
  657. putImage(px, py);
  658. } else {
  659. zm = prev_zm;
  660. zoom_control.value = zm.value;
  661. }
  662. }
  663. }
  664. function change_angle() {
  665. var elvtn_control = document.getElementById('elvtn_ctrl');
  666. var angle_control = document.getElementById('angle_ctrl');
  667. var resxy = zm.get_pos_xy(angle_control.value, elvtn_control.value);
  668. var pos_x = resxy.x;
  669. var pos_y = Math.floor(zm.im.height/2 - resxy.y);
  670. putImage(pos_x, pos_y);
  671. }
  672. function check_prox(x, y, r) { //verification si un point de coordonnées x, y est bien dans un cercle de rayon r centré en X,Y.
  673. return Math.sqrt(x*x + y*y) < r;
  674. }
  675. function check_links(e) {
  676. var mouse_x = e.pageX-canvas_pos.x;
  677. var mouse_y = e.pageY-canvas_pos.y;
  678. var pos_x = nmodulo(last.x + mouse_x - canvas.width/2, zm.im.width);
  679. var pos_y = last.y + mouse_y - canvas.height/2;
  680. for(var i = 0; i < zm.pt_list.length; i++) {
  681. if (is_located && zm.pt_list[i]['type'] == 'pano_point') {
  682. if (check_prox(zm.pt_list[i]['xc']-pos_x, zm.pt_list[i]['yc']-pos_y, 20)) {
  683. if (zm.pt_list[i]['lnk'] != '') window.location = zm.pt_list[i]['lnk'];
  684. break;
  685. }
  686. }
  687. }
  688. }
  689. function display_links(e) {
  690. var index = {};
  691. if (e.touches) {
  692. e.preventDefault();
  693. index.x = e.changedTouches[0].clientX;
  694. index.y = e.changedTouches[0].clientY;
  695. } else {
  696. index.x = e.pageX;
  697. index.y = e.pageY;
  698. }
  699. var info = document.getElementById('info');
  700. var mouse_x = index.x-canvas_pos.x;
  701. var mouse_y = index.y-canvas_pos.y;
  702. var pos_x = nmodulo(last.x + mouse_x - canvas.width/2, zm.im.width);
  703. var pos_y = last.y + mouse_y - canvas.height/2;
  704. //var cap = ((pos_x/zm.im.width)*360).toFixed(2);
  705. var res = zm.get_cap_ele(pos_x, zm.im.height/2 - pos_y);
  706. //var ele = ((zm.im.height/2 - pos_y)/zm.im.width)*360;
  707. info.innerHTML = 'élévation : '+res.ele.toFixed(2)+'<br/>cap : '+res.cap.toFixed(2);
  708. info.style.top = index.y+'px';
  709. info.style.left = index.x+'px';
  710. info.style.backgroundColor = '#FFC';
  711. info.style.display = 'block';
  712. canvas.style.cursor='crosshair';
  713. for(var i = 0; i < zm.pt_list.length; i++) {
  714. if (is_located || zm.pt_list[i]['type'] == 'ref_point') {
  715. if (check_prox(zm.pt_list[i]['xc']-pos_x, zm.pt_list[i]['yc']-pos_y, 20)) {
  716. info.innerHTML = zm.pt_list[i]['label'];
  717. if (zm.pt_list[i]['dist'] < 10) var dst = Math.round(zm.pt_list[i]['dist']*1000)+' m';
  718. else var dst = zm.pt_list[i]['dist'].toFixed(1)+' kms';
  719. info.innerHTML += '<br/> à ' + dst;
  720. info.style.backgroundColor = 'rgb('+point_colors[zm.pt_list[i]['type']]+')';
  721. canvas.style.cursor='auto';
  722. break;
  723. }
  724. }
  725. }
  726. }
  727. function hide_links() {
  728. canvas.removeEventListener( "mousemove", display_links, false);
  729. canvas.removeEventListener( "touchmove", display_links, false);
  730. var info = document.getElementById('info');
  731. info.style.display = 'none';
  732. }
  733. function show_links() {
  734. canvas.addEventListener( "mousemove", display_links, false);
  735. canvas.addEventListener( "touchmove", display_links, false);
  736. // var info = document.getElementById('info');
  737. // info.style.display = 'block';
  738. }
  739. function hide_contextmenu() {
  740. document.getElementById('insert').style.display = 'none';
  741. }
  742. function manage_ref_points(e) {
  743. //event.preventDefault();
  744. //event.stopPropagation();
  745. var sel_pt = document.getElementById('sel_point');
  746. var do_insert = document.getElementById('do-insert');
  747. var do_delete = document.getElementById('do-delete');
  748. var do_cancel = document.getElementById('do-cancel');
  749. var show_cap = document.getElementById('show-cap');
  750. var insrt = document.getElementById('insert');
  751. var pos_x = nmodulo(last.x + e.pageX - canvas_pos.x - canvas.width/2, zm.im.width);
  752. var pos_y = last.y + e.pageY - canvas_pos.y - canvas.height/2;
  753. insrt.style.left = e.pageX+'px';
  754. insrt.style.top = e.pageY+'px';
  755. insrt.style.display = 'block';
  756. if (do_insert) {// true if there are ref points
  757. for(var i = 0; i < zm.pt_list.length; i++) {
  758. if (zm.pt_list[i]['type'] == 'ref_point') {
  759. if (check_prox(zm.pt_list[i]['xc']-pos_x,
  760. zm.pt_list[i]['yc']-pos_y, 20)) {
  761. sel_pt.value = zm.pt_list[i]['label'];
  762. }
  763. }
  764. }
  765. do_delete.onclick = function() {delete_ref_point(insrt)};
  766. do_insert.onclick = function() {insert_ref_point(insrt, e.pageX-canvas_pos.x, e.pageY-canvas_pos.y)};
  767. show_cap.onclick = function() {
  768. window.open('show_capline.php?title='+encodeURIComponent(btoa(title))+'&cap='+res.cap+'&org_lat='+pt_lat+'&org_lon='+pt_lon+'&dist=120000');
  769. };
  770. }
  771. do_cancel.onclick = hide_contextmenu;
  772. var res = zm.get_cap_ele(pos_x, zm.im.height/2 - pos_y);
  773. var pt_lat = document.getElementById('pos_lat').childNodes[0].nodeValue;
  774. var pt_lon = document.getElementById('pos_lon').childNodes[0].nodeValue;
  775. return false;
  776. }
  777. function insert_ref_point(el, x, y) {
  778. var label, posx, posy;
  779. el.style.display = 'none';
  780. var selected_label = document.getElementById('sel_point').value;
  781. var found = false;
  782. var refpoint_url;
  783. for(var i = 0; i < zm.pt_list.length; i++) {
  784. label = zm.pt_list[i]['label'];
  785. if(label == selected_label) {
  786. refpoint_url = zm.pt_list[i]['url'];
  787. posx = nmodulo(last.x + x - canvas.width/2, zm.im.width)/zm.im.width;
  788. posy = 0.5 - (last.y + y - canvas.height/2)/zm.im.height;
  789. var pval = {x:posx, y:posy, cap:zm.pt_list[i]['cap'], ele:zm.pt_list[i]['ele'], label:label};
  790. ref_points[label] = pval;
  791. document.getElementById('res').innerHTML = '<h4>Dernier point entré</h4>';
  792. document.getElementById('res').innerHTML += '<p>reference["'+label+'"] = '+posx.toFixed(5)+','+posy.toFixed(5)+'</p>';
  793. reset_zooms();
  794. putImage(last.x, last.y);
  795. found = true;
  796. break;
  797. }
  798. }
  799. if (!found) {
  800. alert('unknown ref_point: '+label);
  801. }
  802. show_result();
  803. // Then push the modif
  804. var xhr = getXMLHttpRequest();
  805. xhr.open("POST", "/api/v1/references/", true);
  806. xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  807. alert("x=" + x + " y=" + y + " last.x=" + last.x + " last.y=" + last.y);
  808. xhr.send("reference_point=" + refpoint_url
  809. + "&panorama=" + panorama_url
  810. + "&csrfmiddlewaretoken=" + csrf_token
  811. + "&x=" + Math.floor(posx * image_width)
  812. + "&y=" + Math.floor((posy + 0.5) * image_height));
  813. }
  814. function show_result(clear_before) {
  815. var res = document.getElementById('res');
  816. var strg = '';
  817. for (var lbl in ref_points) {
  818. strg += '<li>reference["'+lbl+'"] = '+ref_points[lbl].x.toFixed(5)+','+ref_points[lbl].y.toFixed(5)+'</li>';
  819. }
  820. if (strg) strg = '<h3>Liste de tous les points de référence</h3>\n<ul>' + strg + '</ul>';
  821. if (clear_before) res.innerHTML = strg;
  822. else res.innerHTML += strg;
  823. }
  824. function delete_ref_point(el) {
  825. var ref_name = document.getElementById('sel_point').value;
  826. el.style.display = 'none';
  827. delete ref_points[ref_name];
  828. reset_zooms();
  829. putImage(last.x, last.y);
  830. show_result(true);
  831. // Then push the modif
  832. var xhr = getXMLHttpRequest();
  833. xhr.open("POST", "ajax/rm_reference.php", true);
  834. xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  835. xhr.send("ref_point="+encodeURIComponent(ref_name)
  836. +"&panorama="+encodeURIComponent(get_base_name()));
  837. }
  838. function clean_canvas_events(e) {
  839. canvas.removeEventListener('mousemove', stickImage, false);
  840. canvas.removeEventListener('touchmove', stickImage, false);
  841. document.getElementById('info').style.display = 'none';
  842. speed.x = 0;
  843. speed.y = 0;
  844. }
  845. canvas_set_size = function() {
  846. canvas.style.border = border_width+"px solid red";
  847. canvas.width = window.innerWidth-2*border_width;
  848. canvas.height = window.innerHeight-2*border_width;
  849. canvas_pos.x = canvas.offsetLeft+border_width;
  850. canvas_pos.y = canvas.offsetTop+border_width;
  851. }
  852. canvas_resize = function() {
  853. canvas_set_size();
  854. putImage(last.x, last.y);
  855. }
  856. function paramIn(e) {
  857. e = e || window.event;
  858. var relatedTarget = e.relatedTarget || e.fromElement;
  859. while (relatedTarget != adding && relatedTarget.nodeName != 'BODY' && relatedTarget != document && relatedTarget != localisation) {
  860. relatedTarget = relatedTarget.parentNode;
  861. }
  862. if (relatedTarget != adding && relatedTarget != localisation) {
  863. document.removeEventListener('keydown', keys, false);
  864. }
  865. }
  866. function paramOut(e) {
  867. e = e || window.event;
  868. var relatedTarget = e.relatedTarget || e.toElement;
  869. while (relatedTarget != adding && relatedTarget.nodeName != 'BODY' && relatedTarget != document && relatedTarget != localisation) {
  870. relatedTarget = relatedTarget.parentNode;
  871. }
  872. if (relatedTarget != adding && relatedTarget != localisation) {
  873. document.addEventListener('keydown', keys, false);
  874. }
  875. }
  876. /* Parse initial orientation from URL, either:
  877. #zoom=A/x=B/y=C
  878. #zoom=A/cap=B/elev=C
  879. In the first case, (x, y) is an image coordinate in pixels, where (0, 0)
  880. is the lower left corner.
  881. In the second case, point to the given cap and elevation, assuming the
  882. current panorama is already calibrated.
  883. */
  884. function get_orientation_from_url() {
  885. // Parse window.location.hash to get either x/y or cap/ele
  886. var regexp1 = /^#zoom=(\d)\/cap=(-?\d+|-?\d+\.\d+)\/ele=(-?\d+|-?\d+\.\d+)$/;
  887. var regexp2 = /^#zoom=(\d)\/x=(\d+)\/y=(\d+)$/;
  888. var res = window.location.hash.match(regexp1);
  889. if (res) {
  890. return { zoom: parseInt(res[1], 10),
  891. cap: parseFloat(res[2]),
  892. elevation: parseFloat(res[3]) };
  893. }
  894. else {
  895. res = window.location.hash.match(regexp2);
  896. if (res) {
  897. return { zoom: parseInt(res[1], 10),
  898. x: parseInt(res[2], 10),
  899. y: parseInt(res[3], 10) };
  900. }
  901. else {
  902. /* By default, center the view */
  903. return { zoom: 2, x: image_width / 2, y: image_height / 2 };
  904. }
  905. }
  906. }
  907. var initial_orientation;
  908. function load_pano() {
  909. localisation = document.getElementById("locadraw");
  910. adding = document.getElementById("adding");
  911. canvas = document.getElementById("mon-canvas");
  912. cntext = canvas.getContext("2d");
  913. canvas_set_size();
  914. canvas.addEventListener("click", check_links, false);
  915. //canvas.addEventListener("oncontextmenu", manage_ref_points, false);
  916. canvas.oncontextmenu = manage_ref_points;
  917. canvas.addEventListener("mouseout" , clean_canvas_events, false);
  918. show_links();
  919. initial_orientation = get_orientation_from_url();
  920. var to_zoom = initial_orientation.zoom;
  921. var max_zoom = zooms.length - 1;
  922. zoom_control = document.getElementById("zoom_ctrl");
  923. zoom_control.onchange = change_zoom;
  924. zoom_control.max = max_zoom;
  925. if (to_zoom > max_zoom) to_zoom = Math.floor(max_zoom/2);
  926. zm = zooms[to_zoom];
  927. zoom_control.value = to_zoom;
  928. zm.refresh();
  929. zoom = zm.value;
  930. tile = zm.tile;
  931. ntiles = zm.ntiles;
  932. if (!("cap" in initial_orientation)) {
  933. /* Compute cap and elevation from (x, y) coordinates */
  934. var res = zm.get_cap_ele(initial_orientation.x >> zoom,
  935. (initial_orientation.y - image_height / 2) >> zoom);
  936. initial_orientation.cap = res.cap;
  937. initial_orientation.elevation = res.ele;
  938. }
  939. angle_control = document.getElementById("angle_ctrl");
  940. angle_control.value = initial_orientation.cap;
  941. angle_control.onchange = change_angle;
  942. angle_control.onclick = change_angle;
  943. elvtn_control = document.getElementById("elvtn_ctrl");
  944. elvtn_control.value = initial_orientation.elevation;
  945. elvtn_control.onchange = change_angle;
  946. elvtn_control.onclick = change_angle;
  947. change_angle();
  948. loca_temp = document.getElementById("loca_show");
  949. if (loca_temp) {
  950. loca_temp.onclick = showLoca;
  951. loca_temp = document.getElementById("loca_hide");
  952. loca_temp.onclick = hideLoca;
  953. loca_temp = document.getElementById("loca_button");
  954. loca_temp.onclick = localate_point;
  955. loca_erase = document.getElementById("loca_erase");
  956. loca_erase.onclick = erase_point;
  957. localisation.addEventListener('mouseover',paramIn,false);
  958. localisation.addEventListener('mouseout',paramOut,false);
  959. }
  960. canvas.addEventListener('mousedown', onImageClick, false);
  961. canvas.addEventListener('touchstart', onImageClick, false);
  962. document.addEventListener('keydown', keys, false);
  963. canvas.addEventListener('mousewheel', wheel_zoom, false);
  964. window.onresize = canvas_resize;
  965. if (adding) {
  966. document.getElementById("paramFormHide").onclick = hideForm;
  967. document.getElementById("paramFormShow").onclick = showForm;
  968. adding.addEventListener('mouseover', paramIn, false);
  969. adding.addEventListener('mouseout', paramOut, false);
  970. }
  971. };