Ménage, lint.
[Portfolio.git] / Products / Portfolio / skins / mosaique.js
1 /*
2 * © 2007-2008 Benoît Pin – Centre de recherche en informatique – École des mines de Paris
3 * http://plinn.org
4 * Licence Creative Commons http://creativecommons.org/licenses/by-nc/2.0/
5 *
6 *
7 */
8
9 var Mosaique;
10
11 (function(){
12
13 var hiddenTilesNumber = 1;
14 var batchSize = 5;
15 var reNb = /\-?\d+/ ;
16
17 Mosaique = function(screenArea, imgUrlBase, margins) {
18 this.screenArea = screenArea;
19 if (!margins)
20 margins = {'top':0, 'right':0, 'bottom':0, 'left':0};
21 this.margins = margins;
22 this.prepareScreen();
23 this.setContainerPosition(new Point(0,0));
24
25 this.imgUrlBase = imgUrlBase;
26 this.xmlPath = imgUrlBase + "/tiling_infos.xml";
27
28 this.tiles = null;
29 this.xTileRange = [0,0];
30 this.yTileRange = [0,0];
31
32 this._loadingQueue = new Array();
33 this._currentSequence = null;
34 this._loadingIterator = 0;
35 this.loadingState = 0;
36
37 this.dragInProgress = false;
38 this.initialClickPoint = null;
39 this.initialPosition = null;
40 var thisMos = this;
41 this._ddHandlers = {'down' : function(evt){thisMos._mouseDownHandler(evt);},
42 'move' : function(evt){thisMos._mouseMoveHandler(evt);},
43 'up' : function(evt){thisMos._mouseUpHandler(evt);}};
44 this.ddHandlers = null;
45
46 this.rcsItoC = new Point(0, 0); // vector to translate coordinate systems
47
48 this.remainD = new Point(0, 0);
49 this.getXmlInfo();
50 }
51
52 Mosaique.prototype.getXmlInfo = function() {
53 var req = new XMLHttpRequest();
54 var thisMosaique = this;
55 req.onreadystatechange = function() {
56 if(req.readyState == 4)
57 thisMosaique._loadXmlInfo(req);
58 };
59 req.open("GET",thisMosaique.xmlPath,true);
60 req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
61 req.send(null);
62 };
63
64 Mosaique.prototype._loadXmlInfo = function(req) {
65 var doc = req.responseXML.documentElement;
66 this.thumbnailWidth = parseInt(doc.getElementsByTagName('thumbnailwidth')[0].firstChild.data);
67 this.thumbnailHeight = parseInt(doc.getElementsByTagName('thumbnailheight')[0].firstChild.data);
68 this.tileSize = parseInt(doc.getElementsByTagName('tilesize')[0].firstChild.data);
69
70 var zoomList = doc.getElementsByTagName("zoom");
71 this.zoomTable = new Array(zoomList.length);
72 var zoom;
73 for (var i=0 ; i<zoomList.length ; i++) {
74 zoom = zoomList[i];
75 var zoomInfo = new Object();
76 zoomInfo['level'] = parseInt(zoom.getAttribute('zoomlevel'));
77 zoomInfo['width'] = parseInt(zoom.getElementsByTagName('width')[0].firstChild.data);
78 zoomInfo['height'] = parseInt(zoom.getElementsByTagName('height')[0].firstChild.data);
79 zoomInfo['tilesX'] = parseInt(zoom.getElementsByTagName('tilesx')[0].firstChild.data);
80 zoomInfo['tilesY'] = parseInt(zoom.getElementsByTagName('tilesy')[0].firstChild.data);
81 this.zoomTable[i] = zoomInfo;
82 }
83
84 this.setCurrentDimensionValues(this.getBestFitZoom());
85 this.navigateur = new Navigateur(this);
86
87 this.prepareContainer();
88 this.setLoadingOrder();
89 var ulc = new Point(this.imageWidth/2 - this.screenWidth/2, 0);
90 if (this.screenHeight >= this.imageHeight)
91 ulc.y = this.imageHeight/2 - this.screenHeight/2;
92 this.loadScreen(ulc);
93 this.addEventListeners();
94 };
95
96 Mosaique.prototype.addEventListeners = function() {
97 var thisMos = this;
98 addListener(document, 'mousedown', function(evt){thisMos.mouseDownHandler(evt);}, 'mosaique.dd');
99 addListener(document, 'mouseup', function(evt){thisMos.mouseUpHandler(evt);}, 'mosaique.dd');
100 };
101
102 Mosaique.prototype.getBestFitZoom = function() {
103 var i;
104 for (i = 1 ; i < this.zoomTable.length ; i++)
105 if (this.screenWidth - this.zoomTable[i]['width'] < 0 ||
106 this.screenHeight - this.zoomTable[i]['height'] < 0)
107 break;
108 return i-1;
109 };
110
111 Mosaique.prototype.setCurrentDimensionValues = function(zoomIndex) {
112 var zoomInfo = this.zoomTable[zoomIndex];
113 this.zoomIndex = zoomIndex;
114 this.zoomLevel = zoomInfo['level'];
115 this.imageWidth = zoomInfo['width'];
116 this.imageHeight = zoomInfo['height'];
117 this.xtiles = zoomInfo['tilesX'];
118 this.ytiles = zoomInfo['tilesY'];
119 this.halfTileSize = this.tileSize / 2;
120 this.gridWidth = this.xtiles*this.tileSize;
121 this.gridHeight = this.ytiles*this.tileSize;
122
123 var WnbTiles = Math.ceil(this.screenWidth/this.tileSize) + 2 * hiddenTilesNumber;
124 var HnbTiles = Math.ceil(this.screenHeight/this.tileSize) + 2 * hiddenTilesNumber;
125 this.WnbTiles = (WnbTiles > this.xtiles) ? this.xtiles : WnbTiles;
126 this.HnbTiles = (HnbTiles > this.ytiles) ? this.ytiles : HnbTiles;
127
128 };
129
130 Mosaique.prototype.prepareScreen = function() {
131 this.screenWidth = getObjectWidth(this.screenArea);
132 this.screenHeight = getObjectHeight(this.screenArea);
133 var mask = this.rootElement = document.createElement('div');
134 with (mask.style) {
135 position = 'absolute';
136 width = this.screenWidth - this.margins['right'] + 'px';
137 height = this.screenHeight - this.margins['bottom'] + 'px';
138 background = base_properties["contentBackgroundColor"];
139 overflow = 'hidden';
140 }
141 this.screenArea.insertBefore(mask, this.screenArea.firstChild);
142
143 var container = document.createElement('div');
144 with (container.style) {
145 position = 'absolute';
146 top = '0px';
147 left = '0px';
148 cursor = 'move';
149 }
150
151 mask.appendChild(container);
152 this.container = container;
153 };
154
155 Mosaique.prototype.prepareContainer = function() {
156 var __getImg;
157 if (browser.isGecko) {
158 __getImg = function(evt, o) {
159 return o;
160 }
161 }
162 else {
163 __getImg = function(evt) {
164 return getTargetedObject(evt);
165 }
166 }
167 var thisMos = this;
168 var loadNext;
169 if (browser.isIE) {
170 loadNext = function(evt) {
171 var tile = __getImg(evt, this);
172 tile.style.visibility = 'visible';
173 setTimeout(function(){thisMos._loadNextTile();}, 1);
174 }
175 }
176 else {
177 loadNext = function(evt) {
178 var tile = __getImg(evt, this);
179 tile.style.visibility = 'visible';
180 thisMos._loadNextTile();
181 }
182 }
183
184 this.setContainerPosition(new Point(0,0));
185 this.xTileRange = [0,0];
186 this.yTileRange = [0,0];
187
188 var size = parseInt(this.tileSize);
189 this.tiles = new Array(this.WnbTiles);
190 for (var x = 0 ; x < this.WnbTiles ; x++) {
191 this.tiles[x] = new Array(this.HnbTiles);
192 for (var y = 0 ; y < this.HnbTiles ; y++) {
193 var img = document.createElement("img");
194 with(img) {
195 width = size;
196 height = size;
197 }
198 addListener(img, 'load', loadNext, 'mosaique.tiles');
199 img.style.position='absolute';
200 img.style.left = x * size + 'px';
201 img.style.top = y * size + 'px';
202 this.container.appendChild(img);
203 this.tiles[x][y] = img;
204 }
205 }
206 with(this.container.style) {
207 width = size * this.WnbTiles + 'px';
208 height = size * this.HnbTiles + 'px';
209 }
210 };
211
212
213 Mosaique.prototype.setContainerPosition = function(point) {
214 with(this.container.style) {
215 left = point.x + 'px';
216 top = point.y + 'px';
217 }
218 };
219
220 Mosaique.prototype.getContainerPosition = function() {
221 var x = parseInt(this.container.style.left);
222 var y = parseInt(this.container.style.top);
223 var p = new Point(x, y);
224 return p;
225 };
226
227 Mosaique.prototype.setImagePosition = function(point) {
228 this.setContainerPosition(this.rcsItoC.diff(point));
229 };
230
231 Mosaique.prototype.getImagePosition = function() {
232 var cp = this.getContainerPosition();
233 return this.rcsItoC.diff(cp);
234 };
235
236 Mosaique.prototype.getImageCenterPosition = function() {
237 var ip = this.getImagePosition();
238 return ip.add(new Point(this.screenWidth/2, this.screenHeight/2));
239 }
240
241
242
243 Mosaique.prototype.loadScreen = function(position) {
244
245 var tSize = this.tileSize;
246 var ulTileCoord = new Point(Math.floor(position.x/tSize), Math.floor(position.y/tSize));
247 var modulo = new Point(position.x % tSize, position.y % tSize);
248
249 var adjX, adjY;
250 if (modulo.x > this.halfTileSize) {
251 adjX = function(n){return n - hiddenTilesNumber + 1;};
252 this.remainD.x = - (modulo.x - tSize);
253 }
254 else {
255 adjX = function(n){return n - hiddenTilesNumber;};
256 this.remainD.x = - modulo.x;
257 }
258 if (modulo.y > this.halfTileSize) {
259 this.remainD.y = - (modulo.y - tSize);
260 adjY = function(n){return n - hiddenTilesNumber + 1;};
261 }
262 else {
263 adjY = function(n){return n - hiddenTilesNumber;};
264 this.remainD.y = - modulo.y;
265 }
266
267 var xTileRange, yTileRange;
268 xTileRange = [ulTileCoord.x, ulTileCoord.x + this.WnbTiles].map(adjX);
269 yTileRange = [ulTileCoord.y, ulTileCoord.y + this.HnbTiles].map(adjY);
270
271 //console.assert(xTileRange[1] - xTileRange[0] == this.WnbTiles, xTileRange, this.WnbTiles);
272 //console.assert(yTileRange[1] - yTileRange[0] == this.HnbTiles, yTileRange, this.HnbTiles);
273
274 if (xTileRange[0] < 0) {
275 this.remainD.x = Math.abs(xTileRange[0] + ((position.x < 0) ? 1 : 0)) * tSize - modulo.x;
276 xTileRange = [0, this.WnbTiles];
277 }
278 else if (xTileRange[1] > this.xtiles) {
279 this.remainD.x = - (xTileRange[1] - this.xtiles - ((modulo.x > this.halfTileSize) ? 1 : 0)) * tSize - modulo.x;
280 xTileRange = [this.xtiles - this.WnbTiles, this.xtiles];
281 }
282
283 if (yTileRange[0] < 0) {
284 this.remainD.y = Math.abs(yTileRange[0] + ((position.y < 0) ? 1 : 0)) * tSize - modulo.y;
285 yTileRange = [0, this.HnbTiles];
286 }
287 else if (yTileRange[1] > this.ytiles) {
288 this.remainD.y = - (yTileRange[1] - this.ytiles - ((modulo.y > this.halfTileSize) ? 1 : 0)) * tSize - modulo.y;
289 yTileRange = [this.ytiles - this.HnbTiles, this.ytiles];
290 }
291
292 //console.assert(xTileRange[0] >= 0 && xTileRange[1] <= this.xtiles);
293 //console.assert(yTileRange[0] >= 0 && yTileRange[1] <= this.ytiles);
294
295 var dTx = this.xTileRange[0] - xTileRange[0];
296 var dTy = this.yTileRange[0] - yTileRange[0];
297 this.rcsItoC = this.rcsItoC.diff(new Point(dTx * tSize, dTy * tSize));
298
299 this.setImagePosition(position);
300
301 this.xTileRange = xTileRange;
302 this.yTileRange = yTileRange;
303
304 var xOffset = this.xTileRange[0];
305 var yOffset = this.yTileRange[0];
306
307 var baseUrl = this.imgUrlBase + '/getTile?zoom=' + this.zoomLevel / 100.0;
308
309 var tilesSrc = new Array(this.WnbTiles);
310 for (var x = 0 ; x < this.WnbTiles ; x++) {
311 tilesSrc[x] = new Array(this.HnbTiles);
312 for (var y = 0 ; y < this.HnbTiles ; y++) {
313 tilesSrc[x][y] = baseUrl + '&x=' + (x + xOffset) + '&y=' + (y + yOffset);
314 }
315 }
316 this.queueLoadingSequence({'type':'full',
317 'src' : tilesSrc,
318 'order' : this.loadingOrder,
319 'length' : this.loadingOrder.length});
320 };
321
322 Mosaique.prototype.loadColumns = function(n){
323 /*
324 n > 0 <=> x displacement > 0 => shift columns from right to left
325 Returns the number of columns that have been loaded.
326 */
327
328
329 var newRange;
330
331 while (n != 0) {
332 newRange = [this.xTileRange[0] - n, this.xTileRange[1] - n]
333 if (newRange[0]<0 || newRange[1] > this.xtiles) {
334 (n>0) ? n-- : n++;
335 continue;
336 }
337 else {
338 this.xTileRange = newRange;
339 break;
340 }
341 return 0;
342 }
343
344
345 var shift, from, to, increment;
346 if (n>0) {
347 shift = - (this.WnbTiles) * this.tileSize;
348 from = 0;
349 to = n;
350 increment = 1;
351 }
352 else {
353 shift = (this.WnbTiles) * this.tileSize;
354 from = this.WnbTiles - 1;
355 to = this.WnbTiles + n -1;
356 increment = -1;
357 }
358
359 var thisMos = this;
360 var beforeSequence = function(){thisMos._shiftColumns(n, shift, from, to, increment)};
361
362 var order = new Array();
363 var tilesSrc = new Array();
364 var baseUrl = this.imgUrlBase + '/getTile?zoom=' + this.zoomLevel / 100.0;
365 var xOffset = this.xTileRange[0];
366 var yOffset = this.yTileRange[0];
367
368 for (var x = from ; x != to ; x += increment) {
369 tilesSrc[x] = new Array();
370 for (var y = 0 ; y < this.HnbTiles ; y++) {
371 order.push([x, y]);
372 tilesSrc[x][y] = baseUrl + '&x=' + (x + xOffset) + '&y=' + (y + yOffset);
373 }
374 }
375 order = order.reverse();
376 this.queueLoadingSequence({'type':'column',
377 'src' : tilesSrc,
378 'order' : order,
379 'length' : order.length,
380 'beforeSequence' : beforeSequence});
381 return n;
382 };
383
384 Mosaique.prototype._shiftColumns = function(n, shift, from, to, increment){
385 /* rows rotations */
386 this.tiles = rotateArray(this.tiles, -n);
387 var tile, left;
388 /* positional shifting */
389 for (var x = from ; x != to ; x += increment) {
390 left = parseInt(this.tiles[x][0].style.left);
391 for (var y = 0 ; y < this.HnbTiles ; y++) {
392 var tile = this.tiles[x][y];
393 tile.style.left = left + shift + 'px';
394 tile.style.visibility = 'hidden';
395 }
396 }
397
398 };
399
400
401
402 Mosaique.prototype.loadRows = function(n) {
403 /*
404 n > 0 <=> y displacement > 0 => shift rows from bottom to top
405 Returns the number of rows that's have been loaded.
406 */
407
408 var newRange;
409
410 while (n != 0) {
411 newRange = [this.yTileRange[0] - n, this.yTileRange[1] - n]
412 if (newRange[0]<0 || newRange[1] > this.ytiles) {
413 (n>0) ? n-- : n++;
414 continue;
415 }
416 else {
417 this.yTileRange = newRange;
418 break;
419 }
420 return 0;
421 }
422
423 var shift, from, to, increment;
424 if (n>0) {
425 shift = - (this.HnbTiles) * this.tileSize;
426 from = 0;
427 to = n;
428 increment = 1;
429 }
430 else {
431 shift = (this.HnbTiles) * this.tileSize;
432 from = this.HnbTiles - 1;
433 to = this.HnbTiles + n -1;
434 increment = -1;
435 }
436
437 var thisMos = this;
438 var beforeSequence = function(){thisMos._shiftRows(n, shift, from, to, increment)};
439
440 var order = new Array();
441 var tilesSrc = new Array();
442 var baseUrl = this.imgUrlBase + '/getTile?zoom=' + this.zoomLevel / 100.0;
443 var xOffset = this.xTileRange[0];
444 var yOffset = this.yTileRange[0];
445
446 for (var y = from ; y != to ; y += increment) {
447 for (var x = 0 ; x < this.WnbTiles ; x++) {
448 order.push([x, y]);
449 if (!tilesSrc[x])
450 tilesSrc[x] = new Array();
451 tilesSrc[x][y] = baseUrl + '&x=' + (x + xOffset) + '&y=' + (y + yOffset);
452 }
453 }
454 order = order.reverse();
455 this.queueLoadingSequence({'type':'row',
456 'src' : tilesSrc,
457 'order' : order,
458 'length' : order.length,
459 'beforeSequence' : beforeSequence});
460 return n;
461 };
462
463 Mosaique.prototype._shiftRows = function(n, shift, from, to, increment) {
464 /* columns rotations */
465 for (var x = 0 ; x < this.WnbTiles ; x++)
466 this.tiles[x] = rotateArray(this.tiles[x], -n);
467
468 var tile, top;
469
470 /* positional shifting */
471 for (var y = from ; y != to ; y += increment) {
472 top = parseInt(this.tiles[0][y].style.top);
473 for (var x = 0 ; x < this.WnbTiles ; x++) {
474 var tile = this.tiles[x][y];
475 tile.style.top = top + shift + 'px';
476 tile.style.visibility = 'hidden';
477 }
478 }
479 };
480
481
482 Mosaique.prototype.queueLoadingSequence = function(sequenceInfo) {
483 if(!sequenceInfo.length) return;
484 this._loadingQueue.push(sequenceInfo);
485 if (!this.loadingState && this._loadingQueue.length)
486 this._loadNextSequence();
487 };
488
489 Mosaique.prototype._loadNextSequence = function() {
490 var seq = this._loadingQueue.shift();
491 if (seq == null) {
492 this._loadingQueue = new Array();
493 this.loadingState = 0;
494 return;
495 }
496 switch(seq['type']) {
497 case 'full' :
498 this.loadingState = 1;
499 break;
500 case 'row' :
501 case 'column' :
502 this.loadingState = 2;
503 seq['beforeSequence']();
504 break;
505 }
506 this._loadingIterator = 0;
507 //this._loadNextTile();
508 this._startSequence(seq);
509 };
510
511 Mosaique.prototype._startSequence = function(seq) {
512 this._currentSequence = seq;
513
514 var size = Math.min(batchSize, this._currentSequence.length);
515 this._loadingIterator += size;
516
517 var coord, src, tile;
518 for (var i=0 ; i<size ; i++) {
519 coord = this._currentSequence.order[i];
520 src = this._currentSequence.src[coord[0]][coord[1]];
521 tile = this.tiles[coord[0]][coord[1]];
522 tile.src = src;
523 }
524 };
525
526 Mosaique.prototype._loadNextTile = function() {
527 if (this.loadingState == 0)
528 return;
529 else if (this._loadingIterator >= this._currentSequence['length']) {
530 this._loadNextSequence();
531 return;
532 }
533
534 var coord = this._currentSequence.order[this._loadingIterator];
535 this._loadingIterator++;
536
537 var src = this._currentSequence.src[coord[0]][coord[1]];
538 var tile = this.tiles[coord[0]][coord[1]];
539 tile.src = src;
540 };
541
542
543 /* drag and drop generic handlers */
544 Mosaique.prototype.mouseDownHandler = function(evt) {
545 var target = getTargetedObject(evt);
546 if (target.tagName == 'INPUT' || target.tagName == 'TEXTAREA')
547 return;
548 disableDefault(evt);
549 evt = getEventObject(evt);
550 var navDisp = this.navigateur.display;
551
552 if (target.parentNode.parentNode == navDisp) {
553 if (target == this.navigateur.frame.firstChild)
554 this.ddHandlers = this.navigateur._ddHandlers;
555 else {
556 this.ddHandlers = null;
557 return;
558 }
559 }
560 else
561 this.ddHandlers = this._ddHandlers;
562
563 addListener(document, 'mousemove', this.ddHandlers['move'], 'mosaique.dd');
564
565 this.ddHandlers['down'](evt);
566 };
567
568 Mosaique.prototype.mouseUpHandler = function(evt) {
569 if (this.ddHandlers != null) {
570 removeListener(document, 'mousemove', this.ddHandlers['move']);
571 this.ddHandlers['up'](evt);
572 this.ddHandlers = null;
573 }
574 }
575
576
577 /* Mosaique drag and drop handlers */
578 Mosaique.prototype._mouseDownHandler = function(evt) {
579 this.initialClickPoint = new Point(evt.clientX, evt.clientY);
580 this.initialPosition = this.getContainerPosition();
581 this.rShift = 0;
582 this.cShift = 0;
583 this.dragInProgress = true;
584 }
585
586 Mosaique.prototype._mouseMoveHandler = function(evt) {
587 disableDefault(evt);
588 if(!this.dragInProgress)
589 return;
590
591 evt = getEventObject(evt);
592 var currentPoint = new Point(evt.clientX, evt.clientY);
593 var displacement = currentPoint.diff(this.initialClickPoint);
594 this.setContainerPosition(this.initialPosition.add(displacement));
595
596 var r = (displacement.y + this.halfTileSize + this.remainD.y) / this.tileSize;
597 r = Math.floor(r);
598
599 if (this.rShift - r != 0)
600 this.rShift += this.loadRows(r - this.rShift);
601
602 var c = (displacement.x + this.halfTileSize + this.remainD.x) / this.tileSize;
603 c = Math.floor(c);
604
605 if (this.cShift - c != 0)
606 this.cShift += this.loadColumns(c - this.cShift);
607 };
608
609 Mosaique.prototype._mouseUpHandler = function(evt) {
610 this.dragInProgress = false;
611 evt = getEventObject(evt);
612 this._mouseMoveHandler(evt);
613 var finalPoint = new Point(evt.clientX, evt.clientY);
614 var displacement = finalPoint.diff(this.initialClickPoint);
615 this.remainD = this.remainD.add(new Point(displacement.x - this.cShift * this.tileSize, displacement.y - this.rShift * this.tileSize));
616 this.navigateur.alignFrame();
617 };
618
619
620
621 Mosaique.prototype.setLoadingOrder = function() {
622 var startX = 0;
623 var stopX = this.WnbTiles;
624 var startY = 0;
625 var stopY = this.HnbTiles;
626 var x = 0, y = 0;
627 var order = new Array();
628
629 var direction=0;
630
631
632 while((startX != stopX) && (startY != stopY)) {
633 switch(direction) {
634 case 0 : // left -> right
635 startY++;
636
637 for (x = startX ; x < stopX ; x++)
638 order.push([x, y]);
639 x--;
640 break;
641
642 case 1 : // up -> bottom
643 stopX--;
644 for (y = startY ; y < stopY ; y++)
645 order.push([x, y]);
646 y--;
647 break;
648
649 case 2 : // right -> left
650 stopY--;
651
652 for (x = stopX-1 ; x >= startX ; x--)
653 order.push([x, y])
654 x++;
655 break;
656
657 case 3 : // bottom -> up
658 startX++;
659
660 for (y = stopY-1 ; y >= startY ; y--)
661 order.push([x,y]);
662 y++;
663 break;
664 }
665
666 direction++;
667 if (direction % 4 == 0)
668 direction = 0;
669 }
670
671
672 this.loadingOrder = order.reverse();
673 }
674
675 Mosaique.prototype.cleanContainer = function() {
676 removeGroupListeners('mosaique.tiles');
677 while (this.container.childNodes[0])
678 this.container.removeChild(this.container.childNodes[0]);
679 }
680
681 Mosaique.prototype.loadZoomLevel = function(zoomIndex) {
682 this.loadingState = 0;
683 var oldWnbTiles = this.WnbTiles;
684 var oldHnbTiles = this.HnbTiles;
685 var oldCenter = this.getImageCenterPosition();
686 var zoomInfo = this.zoomTable[zoomIndex];
687 var newLevel = zoomInfo['level'];
688
689 // center coordinates translated into target zoom level
690 var center = oldCenter.mul(newLevel / this.zoomLevel);
691 var ulc = center.diff(new Point(this.screenWidth/2, this.screenHeight/2)); // upper left corner
692
693 this.setCurrentDimensionValues(zoomIndex);
694
695 if (oldWnbTiles != this.WnbTiles || oldHnbTiles != this.HnbTiles) {
696 this.cleanContainer();
697 this.prepareContainer();
698 this.rcsItoC = new Point(0,0);
699 this.setLoadingOrder();
700 }
701 this.loadScreen(ulc);
702 };
703
704 Mosaique.prototype.unload = function() {
705 this.navigateur.unload();
706 removeGroupListeners('mosaique.dd');
707 removeGroupListeners('mosaique.tiles');
708 this.screenArea.removeChild(this.rootElement);
709 };
710
711 })();
712
713 /* UTILS */
714 function Point(x, y) {
715 this.x = Math.round(x);
716 this.y = Math.round(y);
717 }
718 Point.prototype.diff = function(point) { return new Point(this.x - point.x, this.y - point.y); };
719 Point.prototype.add = function(point) { return new Point(this.x + point.x, this.y + point.y); };
720 Point.prototype.mul = function(k) { return new Point(this.x * k, this.y *k)};
721 Point.prototype.toString = function() { return "(" + String(this.x) + ", " + String(this.y) + ")"; };
722
723 function rotateArray(t, n) {
724 return t.slice(n,t.length).concat(t.slice(0,n));
725 }
726
727 if (!Array.prototype.map) {
728 Array.prototype.map = function(f) {
729 var r = new Array(this.length);
730 for (var i = 0 ; i < this.length ; i++ ){
731 r[i] = f(this[i]);
732 }
733 return r;
734 };
735 }