+++ /dev/null
-/*
-* © 2007-2008 Benoît Pin – Centre de recherche en informatique – École des mines de Paris
-* http://plinn.org
-* Licence Creative Commons http://creativecommons.org/licenses/by-nc/2.0/
-*
-*
-*/
-
-var Mosaique;
-
-(function(){
-
-var hiddenTilesNumber = 1;
-var batchSize = 5;
-var reNb = /\-?\d+/ ;
-
-Mosaique = function(screenArea, imgUrlBase, margins) {
- this.screenArea = screenArea;
- if (!margins)
- margins = {'top':0, 'right':0, 'bottom':0, 'left':0};
- this.margins = margins;
- this.prepareScreen();
- this.setContainerPosition(new Point(0,0));
-
- this.imgUrlBase = imgUrlBase;
- this.xmlPath = imgUrlBase + "/tiling_infos.xml";
-
- this.tiles = null;
- this.xTileRange = [0,0];
- this.yTileRange = [0,0];
-
- this._loadingQueue = new Array();
- this._currentSequence = null;
- this._loadingIterator = 0;
- this.loadingState = 0;
-
- this.dragInProgress = false;
- this.initialClickPoint = null;
- this.initialPosition = null;
- var thisMos = this;
- this._ddHandlers = {'down' : function(evt){thisMos._mouseDownHandler(evt);},
- 'move' : function(evt){thisMos._mouseMoveHandler(evt);},
- 'up' : function(evt){thisMos._mouseUpHandler(evt);}};
- this.ddHandlers = null;
-
- this.rcsItoC = new Point(0, 0); // vector to translate coordinate systems
-
- this.remainD = new Point(0, 0);
- this.getXmlInfo();
-}
-
-Mosaique.prototype.getXmlInfo = function() {
- var req = new XMLHttpRequest();
- var thisMosaique = this;
- req.onreadystatechange = function() {
- if(req.readyState == 4)
- thisMosaique._loadXmlInfo(req);
- };
- req.open("GET",thisMosaique.xmlPath,true);
- req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
- req.send(null);
-};
-
-Mosaique.prototype._loadXmlInfo = function(req) {
- var doc = req.responseXML.documentElement;
- this.thumbnailWidth = parseInt(doc.getElementsByTagName('thumbnailwidth')[0].firstChild.data);
- this.thumbnailHeight = parseInt(doc.getElementsByTagName('thumbnailheight')[0].firstChild.data);
- this.tileSize = parseInt(doc.getElementsByTagName('tilesize')[0].firstChild.data);
-
- var zoomList = doc.getElementsByTagName("zoom");
- this.zoomTable = new Array(zoomList.length);
- var zoom;
- for (var i=0 ; i<zoomList.length ; i++) {
- zoom = zoomList[i];
- var zoomInfo = new Object();
- zoomInfo['level'] = parseInt(zoom.getAttribute('zoomlevel'));
- zoomInfo['width'] = parseInt(zoom.getElementsByTagName('width')[0].firstChild.data);
- zoomInfo['height'] = parseInt(zoom.getElementsByTagName('height')[0].firstChild.data);
- zoomInfo['tilesX'] = parseInt(zoom.getElementsByTagName('tilesx')[0].firstChild.data);
- zoomInfo['tilesY'] = parseInt(zoom.getElementsByTagName('tilesy')[0].firstChild.data);
- this.zoomTable[i] = zoomInfo;
- }
-
- this.setCurrentDimensionValues(this.getBestFitZoom());
- this.navigateur = new Navigateur(this);
-
- this.prepareContainer();
- this.setLoadingOrder();
- var ulc = new Point(this.imageWidth/2 - this.screenWidth/2, 0);
- if (this.screenHeight >= this.imageHeight)
- ulc.y = this.imageHeight/2 - this.screenHeight/2;
- this.loadScreen(ulc);
- this.addEventListeners();
-};
-
-Mosaique.prototype.addEventListeners = function() {
- var thisMos = this;
- addListener(document, 'mousedown', function(evt){thisMos.mouseDownHandler(evt);}, 'mosaique.dd');
- addListener(document, 'mouseup', function(evt){thisMos.mouseUpHandler(evt);}, 'mosaique.dd');
-};
-
-Mosaique.prototype.getBestFitZoom = function() {
- var i;
- for (i = 1 ; i < this.zoomTable.length ; i++)
- if (this.screenWidth - this.zoomTable[i]['width'] < 0 ||
- this.screenHeight - this.zoomTable[i]['height'] < 0)
- break;
- return i-1;
-};
-
-Mosaique.prototype.setCurrentDimensionValues = function(zoomIndex) {
- var zoomInfo = this.zoomTable[zoomIndex];
- this.zoomIndex = zoomIndex;
- this.zoomLevel = zoomInfo['level'];
- this.imageWidth = zoomInfo['width'];
- this.imageHeight = zoomInfo['height'];
- this.xtiles = zoomInfo['tilesX'];
- this.ytiles = zoomInfo['tilesY'];
- this.halfTileSize = this.tileSize / 2;
- this.gridWidth = this.xtiles*this.tileSize;
- this.gridHeight = this.ytiles*this.tileSize;
-
- var WnbTiles = Math.ceil(this.screenWidth/this.tileSize) + 2 * hiddenTilesNumber;
- var HnbTiles = Math.ceil(this.screenHeight/this.tileSize) + 2 * hiddenTilesNumber;
- this.WnbTiles = (WnbTiles > this.xtiles) ? this.xtiles : WnbTiles;
- this.HnbTiles = (HnbTiles > this.ytiles) ? this.ytiles : HnbTiles;
-
-};
-
-Mosaique.prototype.prepareScreen = function() {
- this.screenWidth = getObjectWidth(this.screenArea);
- this.screenHeight = getObjectHeight(this.screenArea);
- var mask = this.rootElement = document.createElement('div');
- with (mask.style) {
- position = 'absolute';
- width = this.screenWidth - this.margins['right'] + 'px';
- height = this.screenHeight - this.margins['bottom'] + 'px';
- background = base_properties["contentBackgroundColor"];
- overflow = 'hidden';
- }
- this.screenArea.insertBefore(mask, this.screenArea.firstChild);
-
- var container = document.createElement('div');
- with (container.style) {
- position = 'absolute';
- top = '0px';
- left = '0px';
- cursor = 'move';
- }
-
- mask.appendChild(container);
- this.container = container;
-};
-
-Mosaique.prototype.prepareContainer = function() {
- var __getImg;
- if (browser.isGecko) {
- __getImg = function(evt, o) {
- return o;
- }
- }
- else {
- __getImg = function(evt) {
- return getTargetedObject(evt);
- }
- }
- var thisMos = this;
- var loadNext;
- if (browser.isIE) {
- loadNext = function(evt) {
- var tile = __getImg(evt, this);
- tile.style.visibility = 'visible';
- setTimeout(function(){thisMos._loadNextTile();}, 1);
- }
- }
- else {
- loadNext = function(evt) {
- var tile = __getImg(evt, this);
- tile.style.visibility = 'visible';
- thisMos._loadNextTile();
- }
- }
-
- this.setContainerPosition(new Point(0,0));
- this.xTileRange = [0,0];
- this.yTileRange = [0,0];
-
- var size = parseInt(this.tileSize);
- this.tiles = new Array(this.WnbTiles);
- for (var x = 0 ; x < this.WnbTiles ; x++) {
- this.tiles[x] = new Array(this.HnbTiles);
- for (var y = 0 ; y < this.HnbTiles ; y++) {
- var img = document.createElement("img");
- with(img) {
- width = size;
- height = size;
- }
- addListener(img, 'load', loadNext, 'mosaique.tiles');
- img.style.position='absolute';
- img.style.left = x * size + 'px';
- img.style.top = y * size + 'px';
- this.container.appendChild(img);
- this.tiles[x][y] = img;
- }
- }
- with(this.container.style) {
- width = size * this.WnbTiles + 'px';
- height = size * this.HnbTiles + 'px';
- }
-};
-
-
-Mosaique.prototype.setContainerPosition = function(point) {
- with(this.container.style) {
- left = point.x + 'px';
- top = point.y + 'px';
- }
-};
-
-Mosaique.prototype.getContainerPosition = function() {
- var x = parseInt(this.container.style.left);
- var y = parseInt(this.container.style.top);
- var p = new Point(x, y);
- return p;
-};
-
-Mosaique.prototype.setImagePosition = function(point) {
- this.setContainerPosition(this.rcsItoC.diff(point));
-};
-
-Mosaique.prototype.getImagePosition = function() {
- var cp = this.getContainerPosition();
- return this.rcsItoC.diff(cp);
-};
-
-Mosaique.prototype.getImageCenterPosition = function() {
- var ip = this.getImagePosition();
- return ip.add(new Point(this.screenWidth/2, this.screenHeight/2));
-}
-
-
-
-Mosaique.prototype.loadScreen = function(position) {
-
- var tSize = this.tileSize;
- var ulTileCoord = new Point(Math.floor(position.x/tSize), Math.floor(position.y/tSize));
- var modulo = new Point(position.x % tSize, position.y % tSize);
-
- var adjX, adjY;
- if (modulo.x > this.halfTileSize) {
- adjX = function(n){return n - hiddenTilesNumber + 1;};
- this.remainD.x = - (modulo.x - tSize);
- }
- else {
- adjX = function(n){return n - hiddenTilesNumber;};
- this.remainD.x = - modulo.x;
- }
- if (modulo.y > this.halfTileSize) {
- this.remainD.y = - (modulo.y - tSize);
- adjY = function(n){return n - hiddenTilesNumber + 1;};
- }
- else {
- adjY = function(n){return n - hiddenTilesNumber;};
- this.remainD.y = - modulo.y;
- }
-
- var xTileRange, yTileRange;
- xTileRange = [ulTileCoord.x, ulTileCoord.x + this.WnbTiles].map(adjX);
- yTileRange = [ulTileCoord.y, ulTileCoord.y + this.HnbTiles].map(adjY);
-
- //console.assert(xTileRange[1] - xTileRange[0] == this.WnbTiles, xTileRange, this.WnbTiles);
- //console.assert(yTileRange[1] - yTileRange[0] == this.HnbTiles, yTileRange, this.HnbTiles);
-
- if (xTileRange[0] < 0) {
- this.remainD.x = Math.abs(xTileRange[0] + ((position.x < 0) ? 1 : 0)) * tSize - modulo.x;
- xTileRange = [0, this.WnbTiles];
- }
- else if (xTileRange[1] > this.xtiles) {
- this.remainD.x = - (xTileRange[1] - this.xtiles - ((modulo.x > this.halfTileSize) ? 1 : 0)) * tSize - modulo.x;
- xTileRange = [this.xtiles - this.WnbTiles, this.xtiles];
- }
-
- if (yTileRange[0] < 0) {
- this.remainD.y = Math.abs(yTileRange[0] + ((position.y < 0) ? 1 : 0)) * tSize - modulo.y;
- yTileRange = [0, this.HnbTiles];
- }
- else if (yTileRange[1] > this.ytiles) {
- this.remainD.y = - (yTileRange[1] - this.ytiles - ((modulo.y > this.halfTileSize) ? 1 : 0)) * tSize - modulo.y;
- yTileRange = [this.ytiles - this.HnbTiles, this.ytiles];
- }
-
- //console.assert(xTileRange[0] >= 0 && xTileRange[1] <= this.xtiles);
- //console.assert(yTileRange[0] >= 0 && yTileRange[1] <= this.ytiles);
-
- var dTx = this.xTileRange[0] - xTileRange[0];
- var dTy = this.yTileRange[0] - yTileRange[0];
- this.rcsItoC = this.rcsItoC.diff(new Point(dTx * tSize, dTy * tSize));
-
- this.setImagePosition(position);
-
- this.xTileRange = xTileRange;
- this.yTileRange = yTileRange;
-
- var xOffset = this.xTileRange[0];
- var yOffset = this.yTileRange[0];
-
- var baseUrl = this.imgUrlBase + '/getTile?zoom=' + this.zoomLevel / 100.0;
-
- var tilesSrc = new Array(this.WnbTiles);
- for (var x = 0 ; x < this.WnbTiles ; x++) {
- tilesSrc[x] = new Array(this.HnbTiles);
- for (var y = 0 ; y < this.HnbTiles ; y++) {
- tilesSrc[x][y] = baseUrl + '&x=' + (x + xOffset) + '&y=' + (y + yOffset);
- }
- }
- this.queueLoadingSequence({'type':'full',
- 'src' : tilesSrc,
- 'order' : this.loadingOrder,
- 'length' : this.loadingOrder.length});
-};
-
-Mosaique.prototype.loadColumns = function(n){
- /*
- n > 0 <=> x displacement > 0 => shift columns from right to left
- Returns the number of columns that have been loaded.
- */
-
-
- var newRange;
-
- while (n != 0) {
- newRange = [this.xTileRange[0] - n, this.xTileRange[1] - n]
- if (newRange[0]<0 || newRange[1] > this.xtiles) {
- (n>0) ? n-- : n++;
- continue;
- }
- else {
- this.xTileRange = newRange;
- break;
- }
- return 0;
- }
-
-
- var shift, from, to, increment;
- if (n>0) {
- shift = - (this.WnbTiles) * this.tileSize;
- from = 0;
- to = n;
- increment = 1;
- }
- else {
- shift = (this.WnbTiles) * this.tileSize;
- from = this.WnbTiles - 1;
- to = this.WnbTiles + n -1;
- increment = -1;
- }
-
- var thisMos = this;
- var beforeSequence = function(){thisMos._shiftColumns(n, shift, from, to, increment)};
-
- var order = new Array();
- var tilesSrc = new Array();
- var baseUrl = this.imgUrlBase + '/getTile?zoom=' + this.zoomLevel / 100.0;
- var xOffset = this.xTileRange[0];
- var yOffset = this.yTileRange[0];
-
- for (var x = from ; x != to ; x += increment) {
- tilesSrc[x] = new Array();
- for (var y = 0 ; y < this.HnbTiles ; y++) {
- order.push([x, y]);
- tilesSrc[x][y] = baseUrl + '&x=' + (x + xOffset) + '&y=' + (y + yOffset);
- }
- }
- order = order.reverse();
- this.queueLoadingSequence({'type':'column',
- 'src' : tilesSrc,
- 'order' : order,
- 'length' : order.length,
- 'beforeSequence' : beforeSequence});
- return n;
-};
-
-Mosaique.prototype._shiftColumns = function(n, shift, from, to, increment){
- /* rows rotations */
- this.tiles = rotateArray(this.tiles, -n);
- var tile, left;
- /* positional shifting */
- for (var x = from ; x != to ; x += increment) {
- left = parseInt(this.tiles[x][0].style.left);
- for (var y = 0 ; y < this.HnbTiles ; y++) {
- var tile = this.tiles[x][y];
- tile.style.left = left + shift + 'px';
- tile.style.visibility = 'hidden';
- }
- }
-
-};
-
-
-
-Mosaique.prototype.loadRows = function(n) {
- /*
- n > 0 <=> y displacement > 0 => shift rows from bottom to top
- Returns the number of rows that's have been loaded.
- */
-
- var newRange;
-
- while (n != 0) {
- newRange = [this.yTileRange[0] - n, this.yTileRange[1] - n]
- if (newRange[0]<0 || newRange[1] > this.ytiles) {
- (n>0) ? n-- : n++;
- continue;
- }
- else {
- this.yTileRange = newRange;
- break;
- }
- return 0;
- }
-
- var shift, from, to, increment;
- if (n>0) {
- shift = - (this.HnbTiles) * this.tileSize;
- from = 0;
- to = n;
- increment = 1;
- }
- else {
- shift = (this.HnbTiles) * this.tileSize;
- from = this.HnbTiles - 1;
- to = this.HnbTiles + n -1;
- increment = -1;
- }
-
- var thisMos = this;
- var beforeSequence = function(){thisMos._shiftRows(n, shift, from, to, increment)};
-
- var order = new Array();
- var tilesSrc = new Array();
- var baseUrl = this.imgUrlBase + '/getTile?zoom=' + this.zoomLevel / 100.0;
- var xOffset = this.xTileRange[0];
- var yOffset = this.yTileRange[0];
-
- for (var y = from ; y != to ; y += increment) {
- for (var x = 0 ; x < this.WnbTiles ; x++) {
- order.push([x, y]);
- if (!tilesSrc[x])
- tilesSrc[x] = new Array();
- tilesSrc[x][y] = baseUrl + '&x=' + (x + xOffset) + '&y=' + (y + yOffset);
- }
- }
- order = order.reverse();
- this.queueLoadingSequence({'type':'row',
- 'src' : tilesSrc,
- 'order' : order,
- 'length' : order.length,
- 'beforeSequence' : beforeSequence});
- return n;
-};
-
-Mosaique.prototype._shiftRows = function(n, shift, from, to, increment) {
- /* columns rotations */
- for (var x = 0 ; x < this.WnbTiles ; x++)
- this.tiles[x] = rotateArray(this.tiles[x], -n);
-
- var tile, top;
-
- /* positional shifting */
- for (var y = from ; y != to ; y += increment) {
- top = parseInt(this.tiles[0][y].style.top);
- for (var x = 0 ; x < this.WnbTiles ; x++) {
- var tile = this.tiles[x][y];
- tile.style.top = top + shift + 'px';
- tile.style.visibility = 'hidden';
- }
- }
-};
-
-
-Mosaique.prototype.queueLoadingSequence = function(sequenceInfo) {
- if(!sequenceInfo.length) return;
- this._loadingQueue.push(sequenceInfo);
- if (!this.loadingState && this._loadingQueue.length)
- this._loadNextSequence();
-};
-
-Mosaique.prototype._loadNextSequence = function() {
- var seq = this._loadingQueue.shift();
- if (seq == null) {
- this._loadingQueue = new Array();
- this.loadingState = 0;
- return;
- }
- switch(seq['type']) {
- case 'full' :
- this.loadingState = 1;
- break;
- case 'row' :
- case 'column' :
- this.loadingState = 2;
- seq['beforeSequence']();
- break;
- }
- this._loadingIterator = 0;
- //this._loadNextTile();
- this._startSequence(seq);
-};
-
-Mosaique.prototype._startSequence = function(seq) {
- this._currentSequence = seq;
-
- var size = Math.min(batchSize, this._currentSequence.length);
- this._loadingIterator += size;
-
- var coord, src, tile;
- for (var i=0 ; i<size ; i++) {
- coord = this._currentSequence.order[i];
- src = this._currentSequence.src[coord[0]][coord[1]];
- tile = this.tiles[coord[0]][coord[1]];
- tile.src = src;
- }
-};
-
-Mosaique.prototype._loadNextTile = function() {
- if (this.loadingState == 0)
- return;
- else if (this._loadingIterator >= this._currentSequence['length']) {
- this._loadNextSequence();
- return;
- }
-
- var coord = this._currentSequence.order[this._loadingIterator];
- this._loadingIterator++;
-
- var src = this._currentSequence.src[coord[0]][coord[1]];
- var tile = this.tiles[coord[0]][coord[1]];
- tile.src = src;
-};
-
-
-/* drag and drop generic handlers */
-Mosaique.prototype.mouseDownHandler = function(evt) {
- var target = getTargetedObject(evt);
- if (target.tagName == 'INPUT' || target.tagName == 'TEXTAREA')
- return;
- disableDefault(evt);
- evt = getEventObject(evt);
- var navDisp = this.navigateur.display;
-
- if (target.parentNode.parentNode == navDisp) {
- if (target == this.navigateur.frame.firstChild)
- this.ddHandlers = this.navigateur._ddHandlers;
- else {
- this.ddHandlers = null;
- return;
- }
- }
- else
- this.ddHandlers = this._ddHandlers;
-
- addListener(document, 'mousemove', this.ddHandlers['move'], 'mosaique.dd');
-
- this.ddHandlers['down'](evt);
-};
-
-Mosaique.prototype.mouseUpHandler = function(evt) {
- if (this.ddHandlers != null) {
- removeListener(document, 'mousemove', this.ddHandlers['move']);
- this.ddHandlers['up'](evt);
- this.ddHandlers = null;
- }
-}
-
-
-/* Mosaique drag and drop handlers */
-Mosaique.prototype._mouseDownHandler = function(evt) {
- this.initialClickPoint = new Point(evt.clientX, evt.clientY);
- this.initialPosition = this.getContainerPosition();
- this.rShift = 0;
- this.cShift = 0;
- this.dragInProgress = true;
-}
-
-Mosaique.prototype._mouseMoveHandler = function(evt) {
- disableDefault(evt);
- if(!this.dragInProgress)
- return;
-
- evt = getEventObject(evt);
- var currentPoint = new Point(evt.clientX, evt.clientY);
- var displacement = currentPoint.diff(this.initialClickPoint);
- this.setContainerPosition(this.initialPosition.add(displacement));
-
- var r = (displacement.y + this.halfTileSize + this.remainD.y) / this.tileSize;
- r = Math.floor(r);
-
- if (this.rShift - r != 0)
- this.rShift += this.loadRows(r - this.rShift);
-
- var c = (displacement.x + this.halfTileSize + this.remainD.x) / this.tileSize;
- c = Math.floor(c);
-
- if (this.cShift - c != 0)
- this.cShift += this.loadColumns(c - this.cShift);
-};
-
-Mosaique.prototype._mouseUpHandler = function(evt) {
- this.dragInProgress = false;
- evt = getEventObject(evt);
- this._mouseMoveHandler(evt);
- var finalPoint = new Point(evt.clientX, evt.clientY);
- var displacement = finalPoint.diff(this.initialClickPoint);
- this.remainD = this.remainD.add(new Point(displacement.x - this.cShift * this.tileSize, displacement.y - this.rShift * this.tileSize));
- this.navigateur.alignFrame();
-};
-
-
-
-Mosaique.prototype.setLoadingOrder = function() {
- var startX = 0;
- var stopX = this.WnbTiles;
- var startY = 0;
- var stopY = this.HnbTiles;
- var x = 0, y = 0;
- var order = new Array();
-
- var direction=0;
-
-
- while((startX != stopX) && (startY != stopY)) {
- switch(direction) {
- case 0 : // left -> right
- startY++;
-
- for (x = startX ; x < stopX ; x++)
- order.push([x, y]);
- x--;
- break;
-
- case 1 : // up -> bottom
- stopX--;
- for (y = startY ; y < stopY ; y++)
- order.push([x, y]);
- y--;
- break;
-
- case 2 : // right -> left
- stopY--;
-
- for (x = stopX-1 ; x >= startX ; x--)
- order.push([x, y])
- x++;
- break;
-
- case 3 : // bottom -> up
- startX++;
-
- for (y = stopY-1 ; y >= startY ; y--)
- order.push([x,y]);
- y++;
- break;
- }
-
- direction++;
- if (direction % 4 == 0)
- direction = 0;
- }
-
-
- this.loadingOrder = order.reverse();
-}
-
-Mosaique.prototype.cleanContainer = function() {
- removeGroupListeners('mosaique.tiles');
- while (this.container.childNodes[0])
- this.container.removeChild(this.container.childNodes[0]);
-}
-
-Mosaique.prototype.loadZoomLevel = function(zoomIndex) {
- this.loadingState = 0;
- var oldWnbTiles = this.WnbTiles;
- var oldHnbTiles = this.HnbTiles;
- var oldCenter = this.getImageCenterPosition();
- var zoomInfo = this.zoomTable[zoomIndex];
- var newLevel = zoomInfo['level'];
-
- // center coordinates translated into target zoom level
- var center = oldCenter.mul(newLevel / this.zoomLevel);
- var ulc = center.diff(new Point(this.screenWidth/2, this.screenHeight/2)); // upper left corner
-
- this.setCurrentDimensionValues(zoomIndex);
-
- if (oldWnbTiles != this.WnbTiles || oldHnbTiles != this.HnbTiles) {
- this.cleanContainer();
- this.prepareContainer();
- this.rcsItoC = new Point(0,0);
- this.setLoadingOrder();
- }
- this.loadScreen(ulc);
-};
-
-Mosaique.prototype.unload = function() {
- this.navigateur.unload();
- removeGroupListeners('mosaique.dd');
- removeGroupListeners('mosaique.tiles');
- this.screenArea.removeChild(this.rootElement);
-};
-
-})();
-
-/* UTILS */
-function Point(x, y) {
- this.x = Math.round(x);
- this.y = Math.round(y);
-}
-Point.prototype.diff = function(point) { return new Point(this.x - point.x, this.y - point.y); };
-Point.prototype.add = function(point) { return new Point(this.x + point.x, this.y + point.y); };
-Point.prototype.mul = function(k) { return new Point(this.x * k, this.y *k)};
-Point.prototype.toString = function() { return "(" + String(this.x) + ", " + String(this.y) + ")"; };
-
-function rotateArray(t, n) {
- return t.slice(n,t.length).concat(t.slice(0,n));
-}
-
-if (!Array.prototype.map) {
- Array.prototype.map = function(f) {
- var r = new Array(this.length);
- for (var i = 0 ; i < this.length ; i++ ){
- r[i] = f(this[i]);
- }
- return r;
- };
-}