No more percentage based positioning.

Client zoom now supports both over- and undersampling.
This commit is contained in:
ahocevar
2012-06-10 16:53:56 +02:00
parent 405cebd482
commit f0ad48597f
12 changed files with 202 additions and 331 deletions

View File

@@ -22,12 +22,6 @@ OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, {
*/
type: OpenLayers.Control.TYPE_TOOL,
/**
* Property: containerCenter
* {Object} Cached object representing the layer container center (in pixels).
*/
containerCenter: null,
/**
* Property: pinchOrigin
* {Object} Cached object representing the pinch start (in pixels).
@@ -70,57 +64,6 @@ OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, {
}, this.handlerOptions);
},
/**
* APIMethod: activate
* Activate this control. Must be called after the control is added to a
* map.
*
* Returns:
* {Boolean} The control was successfully activated.
*/
activate: function() {
var activated = OpenLayers.Control.prototype.activate.apply(this,arguments);
if (activated) {
this.map.events.on({
moveend: this.updateContainerCenter,
scope: this
});
this.updateContainerCenter();
}
return activated;
},
/**
* APIMethod: deactivate
* Deactivate this control.
*
* Returns:
* {Boolean} The control was successfully deactivated.
*/
deactivate: function() {
var deactivated = OpenLayers.Control.prototype.deactivate.apply(this,arguments);
if (this.map && this.map.events) {
this.map.events.un({
moveend: this.updateContainerCenter,
scope: this
});
}
return deactivated;
},
/**
* Method: updateContainerCenter
* Must be called each time the layer container moves.
*/
updateContainerCenter: function() {
var container = this.map.layerContainerDiv;
// the layer container div is a square of 100px/100px
this.containerCenter = {
x: parseInt(container.style.left, 10) + 50,
y: parseInt(container.style.top, 10) + 50
};
},
/**
* Method: pinchStart
*
@@ -144,12 +87,12 @@ OpenLayers.Control.PinchZoom = OpenLayers.Class(OpenLayers.Control, {
*/
pinchMove: function(evt, pinchData) {
var scale = pinchData.scale;
var containerCenter = this.containerCenter;
var containerOrigin = this.map.layerContainerOriginPx;
var pinchOrigin = this.pinchOrigin;
var current = evt.xy;
var dx = Math.round((current.x - pinchOrigin.x) + (scale - 1) * (containerCenter.x - pinchOrigin.x));
var dy = Math.round((current.y - pinchOrigin.y) + (scale - 1) * (containerCenter.y - pinchOrigin.y));
var dx = Math.round((current.x - pinchOrigin.x) + (scale - 1) * (containerOrigin.x - pinchOrigin.x));
var dy = Math.round((current.y - pinchOrigin.y) + (scale - 1) * (containerOrigin.y - pinchOrigin.y));
this.applyTransform(
"translate(" + dx + "px, " + dy + "px) scale(" + scale + ")"

View File

@@ -168,8 +168,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
/**
* Property: gridResolution
* {Number} The resolution of the current grid. Used for backbuffering.
* This property is updated each the grid is initialized.
* {Number} The resolution of the current grid. Used for backbuffer and
* client zoom. This property is updated every time the grid is
* initialized.
*/
gridResolution: null,
@@ -458,7 +459,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
}
if(!zoomChanged || this.transitionEffect === 'resize') {
this.applyBackBuffer(serverResolution);
this.applyBackBuffer(resolution);
}
this.initSingleTile(bounds);
@@ -477,25 +478,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
this.map.getMaxExtent()
});
if(resolution !== serverResolution) {
bounds = this.map.calculateBounds(null, serverResolution);
if(forceReTile) {
// stretch the layer div
var scale = serverResolution / resolution;
this.transformDiv(scale);
}
} else {
// reset the layer width, height, left, top, to deal with
// the case where the layer was previously transformed
this.div.style.width = '100%';
this.div.style.height = '100%';
this.div.style.left = '0%';
this.div.style.top = '0%';
}
if(forceReTile) {
if(zoomChanged && this.transitionEffect === 'resize') {
this.applyBackBuffer(serverResolution);
this.applyBackBuffer(resolution);
}
this.initGriddedTiles(bounds);
} else {
@@ -620,7 +605,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
/**
* Method: getServerResolution
* Return the closest highest server-supported resolution. Throw an
* Return the closest server-supported resolution. Throw an
* exception if none is found in the serverResolutions array.
*
* Parameters:
@@ -628,23 +613,24 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* map resolution is used.
*
* Returns:
* {Number} The closest highest server resolution value.
* {Number} The closest server resolution value.
*/
getServerResolution: function(resolution) {
var distance = Number.POSITIVE_INFINITY;
resolution = resolution || this.map.getResolution();
if(this.serverResolutions &&
OpenLayers.Util.indexOf(this.serverResolutions, resolution) === -1) {
var i, serverResolution;
var i, newDistance, newResolution, serverResolution;
for(i=this.serverResolutions.length-1; i>= 0; i--) {
serverResolution = this.serverResolutions[i];
if(serverResolution > resolution) {
resolution = serverResolution;
newResolution = this.serverResolutions[i];
newDistance = Math.abs(newResolution - resolution);
if (newDistance > distance) {
break;
}
distance = newDistance;
serverResolution = newResolution;
}
if(i === -1) {
throw 'no appropriate resolution in serverResolutions';
}
resolution = serverResolution;
}
return resolution;
},
@@ -665,33 +651,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
this.map.getZoomForResolution(resolution) + (this.zoomOffset || 0);
},
/**
* Method: transformDiv
* Transform the layer div.
*
* Parameters:
* scale - {Number} The value by which the layer div is to
* be scaled.
*/
transformDiv: function(scale) {
// scale the layer div
this.div.style.width = 100 * scale + '%';
this.div.style.height = 100 * scale + '%';
// and translate the layer div as necessary
var size = this.map.getSize();
var lcX = parseInt(this.map.layerContainerDiv.style.left, 10);
var lcY = parseInt(this.map.layerContainerDiv.style.top, 10);
var x = (lcX - (size.w / 2.0)) * (scale - 1);
var y = (lcY - (size.h / 2.0)) * (scale - 1);
this.div.style.left = x + '%';
this.div.style.top = y + '%';
},
/**
* Method: getResolutionScale
* Return the value by which the layer is currently scaled.
@@ -733,21 +692,26 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
};
this.backBufferResolution = this.gridResolution;
}
var style = backBuffer.style;
// scale the back buffer
var ratio = this.backBufferResolution / resolution;
style.width = 100 * ratio + '%';
style.height = 100 * ratio + '%';
// scale the tiles inside the back buffer
var tiles = backBuffer.childNodes, tile;
for (var i=tiles.length-1; i>=0; --i) {
tile = tiles[i];
tile.style.top = ((ratio * tile._i * tile._h) | 0) + 'px';
tile.style.left = ((ratio * tile._j * tile._w) | 0) + 'px';
tile.style.width = Math.round(ratio * tile._w) + 'px';
tile.style.height = Math.round(ratio * tile._h) + 'px';
}
// and position it (based on the grid's top-left corner)
var position = this.getViewPortPxFromLonLat(
this.backBufferLonLat, resolution);
var leftOffset = parseInt(this.map.layerContainerDiv.style.left, 10);
var topOffset = parseInt(this.map.layerContainerDiv.style.top, 10);
backBuffer.style.left = Math.round(position.x - leftOffset) + '%';
backBuffer.style.top = Math.round(position.y - topOffset) + '%';
var leftOffset = this.map.layerContainerOriginPx.x;
var topOffset = this.map.layerContainerOriginPx.y;
backBuffer.style.left = Math.round(position.x - leftOffset) + 'px';
backBuffer.style.top = Math.round(position.y - topOffset) + 'px';
},
/**
@@ -765,19 +729,17 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
backBuffer.id = this.div.id + '_bb';
backBuffer.className = 'olBackBuffer';
backBuffer.style.position = 'absolute';
backBuffer.style.width = '100%';
backBuffer.style.height = '100%';
for(var i=0, lenI=this.grid.length; i<lenI; i++) {
for(var j=0, lenJ=this.grid[i].length; j<lenJ; j++) {
var tile = this.grid[i][j].createBackBuffer();
if(!tile) {
continue;
var tile = this.grid[i][j],
markup = this.grid[i][j].createBackBuffer();
if (markup) {
markup._i = i;
markup._j = j;
markup._w = tile.size.w;
markup._h = tile.size.h;
backBuffer.appendChild(markup);
}
// to be able to correctly position the back buffer we
// place the tiles grid at (0, 0) in the back buffer
tile.style.top = (i * this.tileSize.h) + '%';
tile.style.left = (j * this.tileSize.w) + '%';
backBuffer.appendChild(tile);
}
}
}
@@ -923,16 +885,22 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
var tilelon = resolution * this.tileSize.w;
var tilelat = resolution * this.tileSize.h;
var ratio = resolution / this.map.getResolution(),
tileSize = {
w: Math.round(this.tileSize.w * ratio),
h: Math.round(this.tileSize.h * ratio)
};
var offsetlon = bounds.left - origin.lon;
var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
var tilecolremain = offsetlon/tilelon - tilecol;
var tileoffsetx = -tilecolremain * this.tileSize.w;
var tileoffsetx = -tilecolremain * tileSize.w;
var tileoffsetlon = origin.lon + tilecol * tilelon;
var offsetlat = bounds.top - (origin.lat + tilelat);
var tilerow = Math.ceil(offsetlat/tilelat) + this.buffer;
var tilerowremain = tilerow - offsetlat/tilelat;
var tileoffsety = -tilerowremain * this.tileSize.h;
var tileoffsety = -tilerowremain * tileSize.h;
var tileoffsetlat = origin.lat + tilerow * tilelat;
return {
@@ -982,19 +950,25 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
// tiles required to cover the viewport plus at least one for panning
var viewSize = this.map.getSize();
var minRows = Math.ceil(viewSize.h/this.tileSize.h) +
2 * this.buffer + 1;
var minCols = Math.ceil(viewSize.w/this.tileSize.w) +
2 * this.buffer + 1;
var origin = this.getTileOrigin();
var resolution = this.getServerResolution();
var tileLayout = this.calculateGridLayout(bounds, origin, resolution);
var resolution = this.map.getResolution(),
serverResolution = this.getServerResolution(),
ratio = resolution / serverResolution,
tileSize = {
w: this.tileSize.w / ratio,
h: this.tileSize.h / ratio
};
var minRows = Math.ceil(viewSize.h/tileSize.h) +
2 * this.buffer + 1;
var minCols = Math.ceil(viewSize.w/tileSize.w) +
2 * this.buffer + 1;
var tileLayout = this.calculateGridLayout(bounds, origin, serverResolution);
var tileoffsetx = Math.round(tileLayout.tileoffsetx); // heaven help us
var tileoffsety = Math.round(tileLayout.tileoffsety);
var tileoffsetlon = tileLayout.tileoffsetlon;
var tileoffsetlat = tileLayout.tileoffsetlat;
@@ -1006,8 +980,8 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
var rowidx = 0;
var layerContainerDivLeft = parseInt(this.map.layerContainerDiv.style.left);
var layerContainerDivTop = parseInt(this.map.layerContainerDiv.style.top);
var layerContainerDivLeft = this.map.layerContainerOriginPx.x;
var layerContainerDivTop = this.map.layerContainerOriginPx.y;
var tileData = [], center = this.map.getCenter();
do {
@@ -1051,27 +1025,29 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
});
tileoffsetlon += tilelon;
tileoffsetx += this.tileSize.w;
tileoffsetx += tileSize.w;
} while ((tileoffsetlon <= bounds.right + tilelon * this.buffer)
|| colidx < minCols);
tileoffsetlat -= tilelat;
tileoffsety += this.tileSize.h;
tileoffsety += tileSize.h;
} while((tileoffsetlat >= bounds.bottom - tilelat * this.buffer)
|| rowidx < minRows);
//shave off exceess rows and colums
this.removeExcessTiles(rowidx, colidx);
var resolution = this.getServerResolution(),
immediately = resolution === this.gridResolution;
// store the resolution of the grid
this.gridResolution = this.getServerResolution();
this.gridResolution = resolution;
//now actually draw the tiles
tileData.sort(function(a, b) {
return a.distance - b.distance;
});
for (var i=0, ii=tileData.length; i<ii; ++i) {
tileData[i].tile.draw();
tileData[i].tile.draw(immediately);
}
},
@@ -1194,28 +1170,27 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
return;
}
var buffer = this.buffer + 1;
var scale = this.getResolutionScale();
while(true) {
var tlTile = this.grid[0][0];
var tlViewPort = {
x: (this.grid[0][0].position.x * scale) +
parseInt(this.div.style.left, 10) +
parseInt(this.map.layerContainerDiv.style.left),
y: (this.grid[0][0].position.y * scale) +
parseInt(this.div.style.top, 10) +
parseInt(this.map.layerContainerDiv.style.top)
x: tlTile.position.x +
this.map.layerContainerOriginPx.x,
y: tlTile.position.y +
this.map.layerContainerOriginPx.y
};
var ratio = this.getServerResolution() / this.map.getResolution();
var tileSize = {
w: this.tileSize.w * scale,
h: this.tileSize.h * scale
w: Math.round(this.tileSize.w * ratio),
h: Math.round(this.tileSize.h * ratio)
};
if (tlViewPort.x > -tileSize.w * (buffer - 1)) {
this.shiftColumn(true);
this.shiftColumn(true, tileSize);
} else if (tlViewPort.x < -tileSize.w * buffer) {
this.shiftColumn(false);
this.shiftColumn(false, tileSize);
} else if (tlViewPort.y > -tileSize.h * (buffer - 1)) {
this.shiftRow(true);
this.shiftRow(true, tileSize);
} else if (tlViewPort.y < -tileSize.h * buffer) {
this.shiftRow(false);
this.shiftRow(false, tileSize);
} else {
break;
}
@@ -1229,15 +1204,15 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* Parameters:
* prepend - {Boolean} if true, prepend to beginning.
* if false, then append to end
* tileSize - {<OpenLayers.Size>} rendered tile size
*/
shiftRow:function(prepend) {
shiftRow:function(prepend, tileSize) {
var modelRowIndex = (prepend) ? 0 : (this.grid.length - 1);
var grid = this.grid;
var modelRow = grid[modelRowIndex];
var resolution = this.getServerResolution();
var deltaY = (prepend) ? -this.tileSize.h : this.tileSize.h;
var deltaLat = resolution * -deltaY;
var sign = prepend ? -1 : 1;
var deltaLat = this.getServerResolution() * -sign * this.tileSize.h;
var row = (prepend) ? grid.pop() : grid.shift();
@@ -1247,7 +1222,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
var position = modelTile.position.clone();
bounds.bottom = bounds.bottom + deltaLat;
bounds.top = bounds.top + deltaLat;
position.y = position.y + deltaY;
position.y = position.y + sign * tileSize.h;
row[i].moveTo(bounds, position);
}
@@ -1265,11 +1240,11 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
* Parameters:
* prepend - {Boolean} if true, prepend to beginning.
* if false, then append to end
* tileSize - {<OpenLayers.Size>} rendered tile size
*/
shiftColumn: function(prepend) {
var deltaX = (prepend) ? -this.tileSize.w : this.tileSize.w;
var resolution = this.getServerResolution();
var deltaLon = resolution * deltaX;
shiftColumn: function(prepend, tileSize) {
var sign = prepend ? -1 : 1;
var deltaLon = this.getServerResolution() * sign * this.tileSize.w;
for (var i=0, len=this.grid.length; i<len; i++) {
var row = this.grid[i];
@@ -1280,7 +1255,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, {
var position = modelTile.position.clone();
bounds.left = bounds.left + deltaLon;
bounds.right = bounds.right + deltaLon;
position.x = position.x + deltaX;
position.x = position.x + sign * tileSize.w;
var tile = prepend ? this.grid[i].pop() : this.grid[i].shift();
tile.moveTo(bounds, position);

View File

@@ -482,9 +482,9 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
viewHeight = viewSize.h,
offsetLeft = (viewWidth / 2 * this.ratio) - viewWidth / 2,
offsetTop = (viewHeight / 2 * this.ratio) - viewHeight / 2;
offsetLeft += parseInt(this.map.layerContainerDiv.style.left, 10);
offsetLeft += this.map.layerContainerOriginPx.x;
offsetLeft = -Math.round(offsetLeft);
offsetTop += parseInt(this.map.layerContainerDiv.style.top, 10);
offsetTop += this.map.layerContainerOriginPx.y;
offsetTop = -Math.round(offsetTop);
this.div.style.left = offsetLeft + 'px';

View File

@@ -423,6 +423,12 @@ OpenLayers.Map = OpenLayers.Class({
*/
paddingForPopups : null,
/**
* Property: layerContainerOriginPx
* {Object} Cached object representing the layer container origin (in pixels).
*/
layerContainerOriginPx: null,
/**
* Property: minPx
* {Object} An object with a 'x' and 'y' values that is the lower
@@ -575,9 +581,8 @@ OpenLayers.Map = OpenLayers.Class({
// the layerContainerDiv is the one that holds all the layers
id = this.id + "_OpenLayers_Container";
this.layerContainerDiv = OpenLayers.Util.createDiv(id);
this.layerContainerDiv.style.width = '100px';
this.layerContainerDiv.style.height = '100px';
this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE['Popup']-1;
this.layerContainerOriginPx = {x: 0, y: 0};
this.viewPortDiv.appendChild(this.layerContainerDiv);
@@ -1752,13 +1757,13 @@ OpenLayers.Map = OpenLayers.Class({
this.center = null;
if (dx) {
this.layerContainerDiv.style.left =
parseInt(this.layerContainerDiv.style.left) - dx + "px";
(this.layerContainerOriginPx.x -= dx) + "px";
this.minPx.x -= dx;
this.maxPx.x -= dx;
}
if (dy) {
this.layerContainerDiv.style.top =
parseInt(this.layerContainerDiv.style.top) - dy + "px";
(this.layerContainerOriginPx.y -= dy) + "px";
this.minPx.y -= dy;
this.maxPx.y -= dy;
}
@@ -1919,8 +1924,11 @@ OpenLayers.Map = OpenLayers.Class({
// (re)set the layerContainerDiv's location
if (zoomChanged || this.layerContainerOrigin == null) {
this.layerContainerOrigin = this.getCachedCenter();
this.layerContainerDiv.style.left = "0px";
this.layerContainerDiv.style.top = "0px";
var style = this.layerContainerDiv.style;
style.left = "0px";
style.top = "0px";
this.layerContainerOriginPx.x = 0;
this.layerContainerOriginPx.y = 0;
var maxExtent = this.getMaxExtent({restricted: true});
var maxExtentCenter = maxExtent.getCenterLonLat();
var lonDelta = this.center.lon - maxExtentCenter.lon;
@@ -2006,12 +2014,14 @@ OpenLayers.Map = OpenLayers.Class({
var newPx = this.getViewPortPxFromLonLat(lonlat);
if ((originPx != null) && (newPx != null)) {
var oldLeft = parseInt(this.layerContainerDiv.style.left);
var oldTop = parseInt(this.layerContainerDiv.style.top);
var oldLeft = this.layerContainerOriginPx.x;
var oldTop = this.layerContainerOriginPx.y;
var newLeft = Math.round(originPx.x - newPx.x);
var newTop = Math.round(originPx.y - newPx.y);
this.layerContainerDiv.style.left = newLeft + "px";
this.layerContainerDiv.style.top = newTop + "px";
this.layerContainerDiv.style.left =
(this.layerContainerOriginPx.x = newLeft) + "px";
this.layerContainerDiv.style.top =
(this.layerContainerOriginPx.y = newTop) + "px";
var dx = oldLeft - newLeft;
var dy = oldTop - newTop;
this.minPx.x -= dx;
@@ -2572,8 +2582,8 @@ OpenLayers.Map = OpenLayers.Class({
getViewPortPxFromLayerPx:function(layerPx) {
var viewPortPx = null;
if (layerPx != null) {
var dX = parseInt(this.layerContainerDiv.style.left);
var dY = parseInt(this.layerContainerDiv.style.top);
var dX = this.layerContainerOriginPx.x;
var dY = this.layerContainerOriginPx.y;
viewPortPx = layerPx.add(dX, dY);
}
return viewPortPx;
@@ -2592,8 +2602,8 @@ OpenLayers.Map = OpenLayers.Class({
getLayerPxFromViewPortPx:function(viewPortPx) {
var layerPx = null;
if (viewPortPx != null) {
var dX = -parseInt(this.layerContainerDiv.style.left);
var dY = -parseInt(this.layerContainerDiv.style.top);
var dX = -this.layerContainerOriginPx.x;
var dY = -this.layerContainerOriginPx.y;
layerPx = viewPortPx.add(dX, dY);
if (isNaN(layerPx.x) || isNaN(layerPx.y)) {
layerPx = null;

View File

@@ -193,21 +193,21 @@ OpenLayers.Tile = OpenLayers.Class({
* is to call <clear> and return the result from <shouldDraw>.
*
* Parameters:
* deferred - {Boolean} When drawing was aborted by returning false from a
* *beforedraw* listener, the queue manager needs to pass true, so the
* tile will not be cleared and immediately be drawn. Otherwise, the
* tile will be cleared and a *beforedraw* event will be fired.
* immediately - {Boolean} When e.g. drawing was aborted by returning false
* from a *beforedraw* listener, the queue manager needs to pass true,
* so the tile will not be cleared and immediately be drawn. Otherwise,
* the tile will be cleared and a *beforedraw* event will be fired.
*
* Returns:
* {Boolean} Whether or not the tile should actually be drawn.
*/
draw: function(deferred) {
if (!deferred) {
draw: function(immediately) {
if (!immediately) {
//clear tile's contents and mark as not drawn
this.clear();
}
var draw = this.shouldDraw();
if (draw && !deferred) {
if (draw && !immediately) {
draw = this.events.triggerEvent("beforedraw") !== false;
}
return draw;

View File

@@ -212,11 +212,15 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, {
positionTile: function() {
var style = this.getTile().style,
size = this.frame ? this.size :
this.layer.getImageSize(this.bounds);
style.left = this.position.x + "%";
style.top = this.position.y + "%";
style.width = size.w + "%";
style.height = size.h + "%";
this.layer.getImageSize(this.bounds),
ratio = 1;
if (this.layer instanceof OpenLayers.Layer.Grid) {
ratio = this.layer.getServerResolution() / this.layer.map.getResolution();
}
style.left = (this.position.x | 0) + "px";
style.top = (this.position.y | 0) + "px";
style.width = Math.round(ratio * size.w) + "px";
style.height = Math.round(ratio * size.h) + "px";
},
/**