/*______________
| ______ | U I Z E J A V A S C R I P T F R A M E W O R K
| / / | ---------------------------------------------------
| / O / | MODULE : Uize.Math.LogicalPos Class
| / / / |
| / / / /| | ONLINE : http://uize.com
| /____/ /__/_| | COPYRIGHT : (c)2005-2016 UIZE
| /___ | LICENSE : Available under MIT License or GNU General Public License
|_______________| http://uize.com/license.html
*/
/* Module Meta Data
type: Class
importance: 2
codeCompleteness: 100
docCompleteness: 2
*/
/*?
Introduction
The =Uize.Math.LogicalPos= module provides methods for working with logical positioning of rectangles within a view port.
*DEVELOPERS:* `Chris van Rensburg`
The =Uize.Math.LogicalPos= class supports logical sizing behaviors such as fit and fill, and logical positioning behaviors such as left, center, and right aligned, or top, center, and bottom aligned, among others.
*/
Uize.module ({
name:'Uize.Math.LogicalPos',
builder:function (_superclass) {
'use strict';
var
/*** Variables for Scruncher Optimization ***/
_undefined,
_Math = Math,
/*** references to statics used internally ***/
_getScaledRect,
/*** General Variables ***/
_paramDefaults = {
coordConverter:Uize.returnX,
sizingLowerBound:'fit',
sizingUpperBound:'fill',
sizingValue:1,
maxScaling:Infinity,
alignX:.5,
alignY:.5
}
;
/*** Utility Functions ***/
function _getDefaultedParam (_propertyName,_params,_defaults) {
return (
_params [_propertyName] !== _undefined
? _params [_propertyName]
: (_defaults || _paramDefaults) [_propertyName]
);
}
function _fitOrFill (_rect,_port,_align,_isFill) {
if (typeof _rect == 'number')
_rect = {width:_rect,height:1}
;
return _getScaledRect (
Uize.copyInto (
{
rectWidth:_rect.width,
rectHeight:_rect.height,
portWidth:_port.width,
portHeight:_port.height,
sizingValue:+_isFill
},
_align
)
);
}
return Uize.package ({
getScaledRect:_getScaledRect = function (_params,_defaults) {
/* PARAMS:
- rectWidth
- rectHeight
- portWidth
- portHeight
- coordConverter
- sizingLowerBound
- sizingUpperBound
- sizingValue
- maxScaling
- alignX
- alignY
*/
var
_portWidth = _params.portWidth,
_portHeight = _params.portHeight,
_rectWidth = _params.rectWidth,
_rectHeight = _params.rectHeight,
_coordConverter = _getDefaultedParam ('coordConverter',_params,_defaults),
_fillScaleFactorWidth = _portWidth / _rectWidth,
_fillScaleFactorHeight = _portHeight / _rectHeight,
_fitFillScaleFactors = {
fit:_Math.min (_fillScaleFactorWidth,_fillScaleFactorHeight),
fill:_Math.max (_fillScaleFactorWidth,_fillScaleFactorHeight)
},
_scaleFactorLowerBound =
_fitFillScaleFactors [_getDefaultedParam ('sizingLowerBound',_params,_defaults)] || 0,
_scaleFactorUpperBound =
_fitFillScaleFactors [_getDefaultedParam ('sizingUpperBound',_params,_defaults)] || 0,
_scaleFactor = _Math.min (
_scaleFactorLowerBound + (_scaleFactorUpperBound - _scaleFactorLowerBound) * _getDefaultedParam ('sizingValue',_params,_defaults),
_getDefaultedParam ('maxScaling',_params,_defaults)
),
_scaledWidth = _rectWidth * _scaleFactor,
_scaledHeight = _rectHeight * _scaleFactor
;
return {
left:_coordConverter ((_portWidth - _scaledWidth) * _getDefaultedParam ('alignX',_params,_defaults)),
top:_coordConverter ((_portHeight - _scaledHeight) * _getDefaultedParam ('alignY',_params,_defaults)),
width:_coordConverter (_scaledWidth),
height:_coordConverter (_scaledHeight)
};
},
getSizingAndAlign:function (_params,_defaults) {
/* PARAMS:
- rectX
- rectY
- rectWidth
- rectHeight
- portWidth
- portHeight
- sizingLowerBound
- sizingUpperBound
*/
function _getAlignForAxis (_pos,_dim,_portDim,_alignPin0,_alignPin1) {
if (typeof _alignPin0 != 'number') _alignPin0 = parseFloat (_alignPin0) || 0;
if (typeof _alignPin1 != 'number') _alignPin1 = parseFloat (_alignPin1) || 1;
_pos = +_pos + _alignPin0 * _dim;
_dim *= (_alignPin1 - _alignPin0);
return _dim == _portDim ? .5 : _pos / (_portDim - _dim);
}
var
_portWidth = _params.portWidth,
_portHeight = _params.portHeight,
_rectWidth = _params.rectWidth,
_rectHeight = _params.rectHeight,
_rectArea = _rectWidth * _rectHeight,
_fillScaleFactorWidth = _portWidth / _rectWidth,
_fillScaleFactorHeight = _portHeight / _rectHeight,
_fitScaleFactor = _Math.min (_fillScaleFactorWidth,_fillScaleFactorHeight),
_fillScaleFactor = _Math.max (_fillScaleFactorWidth,_fillScaleFactorHeight),
_fitFillAreas = {
fit:_fitScaleFactor * _fitScaleFactor * _rectArea,
fill:_fillScaleFactor * _fillScaleFactor * _rectArea
},
_scaledAreaLowerBound = _fitFillAreas [_getDefaultedParam ('sizingLowerBound',_params,_defaults)] || 0,
_scaledAreaUpperBound = _fitFillAreas [_getDefaultedParam ('sizingUpperBound',_params,_defaults)] || 0
;
return {
sizingValue:
_Math.sqrt (_rectArea - _scaledAreaLowerBound) /
_Math.sqrt (_scaledAreaUpperBound - _scaledAreaLowerBound)
,
alignX:_getAlignForAxis (_params.rectX,_rectWidth,_portWidth),
alignY:_getAlignForAxis (_params.rectY,_rectHeight,_portHeight)
};
},
fit:function (_rect,_port,_align) {
return _fitOrFill (_rect,_port,_align,0);
},
fill:function (_rect,_port,_align) {
return _fitOrFill (_rect,_port,_align,1);
}
});
}
});