1 // ========================================================================== 2 // Project: SproutCore - JavaScript Application Framework 3 // Copyright: ©2006-2011 Strobe Inc. and contributors. 4 // Portions ©2008-2011 Apple Inc. All rights reserved. 5 // License: Licensed under MIT license (see license.js) 6 // ========================================================================== 7 8 /** 9 @type String 10 @constant 11 */ 12 SC.SCALE_NONE = "none"; 13 14 /** 15 Stretch/shrink the shape to fill the frame 16 17 @type String 18 @constant 19 */ 20 SC.FILL = "fill"; 21 22 /** 23 Stretch/shrink the shape to fill the frame while maintaining aspect ratio, such 24 that the shortest dimension will just fit within the frame and the longest dimension will 25 overflow and be cropped. 26 27 @type String 28 @constant 29 */ 30 SC.FILL_PROPORTIONALLY = SC.BEST_FILL = "best-fill"; 31 32 /** 33 Stretch/shrink the shape to fit the frame while maintaining aspect ratio, such that the 34 longest dimension will just fit within the frame 35 36 @type String 37 @constant 38 */ 39 SC.BEST_FIT = "best-fit"; 40 41 /** 42 Shrink the shape to fit the frame while maintaining aspect ratio, such that 43 the longest dimension will just fit within the frame. Do not stretch the shape if the shape's 44 width is less than the frame's width. 45 46 @type String 47 @constant 48 */ 49 SC.BEST_FIT_DOWN_ONLY = "best-fit-down"; 50 51 /** 52 @namespace 53 54 InnerFrame provides the innerFrameForSize function, which will return a frame for the given size adjusted 55 to fit within the given outer size, according to the align and scale properties. 56 57 View's that render images will find this mixin particularly useful for fitting their images. 58 */ 59 SC.InnerFrame = { 60 61 /** 62 Align the shape within its frame. Possible values: 63 64 - SC.ALIGN_TOP_LEFT 65 - SC.ALIGN_TOP 66 - SC.ALIGN_TOP_RIGHT 67 - SC.ALIGN_LEFT 68 - SC.ALIGN_CENTER 69 - SC.ALIGN_RIGHT 70 - SC.ALIGN_BOTTOM_LEFT 71 - SC.ALIGN_BOTTOM 72 - SC.ALIGN_BOTTOM_RIGHT 73 74 @type String 75 @default SC.ALIGN_CENTER 76 */ 77 align: SC.ALIGN_CENTER, 78 79 /** 80 Returns a frame (x, y, width, height) fitting the source size (sourceWidth & sourceHeight) within the 81 destination size (destWidth & destHeight) according to the align and scale properties. This is essential to 82 positioning child views or elements within parent views or elements in elegant ways. 83 84 @param {Number} sourceWidth 85 @param {Number} sourceHeight 86 @param {Number} destWidth 87 @param {Number} destHeight 88 @returns {Object} the inner frame with properties: {x: value, y: value, width: value, height: value } 89 */ 90 innerFrameForSize: function(sourceWidth, sourceHeight, destWidth, destHeight) { 91 var align = this.get('align'), 92 scale = this.get('scale'), 93 scaleX, 94 scaleY, 95 result; 96 97 // Fast path 98 result = { x: 0, y: 0, width: destWidth, height: destHeight }; 99 if (scale === SC.FILL) return result; 100 101 // Determine the appropriate scale 102 scaleX = destWidth / sourceWidth; 103 scaleY = destHeight / sourceHeight; 104 105 switch (scale) { 106 case SC.BEST_FILL: 107 scale = scaleX > scaleY ? scaleX : scaleY; 108 break; 109 case SC.BEST_FIT: 110 scale = scaleX < scaleY ? scaleX : scaleY; 111 break; 112 case SC.BEST_FIT_DOWN_ONLY: 113 if ((sourceWidth > destWidth) || (sourceHeight > destHeight)) { 114 scale = scaleX < scaleY ? scaleX : scaleY; 115 } else { 116 scale = 1.0; 117 } 118 break; 119 case SC.SCALE_NONE: 120 scale = 1.0; 121 break; 122 default: // Number 123 if (isNaN(window.parseFloat(scale)) || (window.parseFloat(scale) <= 0)) { 124 SC.Logger.warn("SC.InnerFrame: The scale '%@' was not understood. Scale must be one of SC.FILL, SC.BEST_FILL, SC.BEST_FIT, SC.BEST_FIT_DOWN_ONLY or a positive number greater than 0.00.".fmt(scale)); 125 126 // Don't attempt to scale or offset the image 127 return result; 128 } 129 } 130 131 sourceWidth *= scale; 132 sourceHeight *= scale; 133 result.width = Math.round(sourceWidth); 134 result.height = Math.round(sourceHeight); 135 136 // Align the image within its frame 137 switch (align) { 138 case SC.ALIGN_LEFT: 139 result.x = 0; 140 result.y = (destHeight / 2) - (sourceHeight / 2); 141 break; 142 case SC.ALIGN_RIGHT: 143 result.x = destWidth - sourceWidth; 144 result.y = (destHeight / 2) - (sourceHeight / 2); 145 break; 146 case SC.ALIGN_TOP: 147 result.x = (destWidth / 2) - (sourceWidth / 2); 148 result.y = 0; 149 break; 150 case SC.ALIGN_BOTTOM: 151 result.x = (destWidth / 2) - (sourceWidth / 2); 152 result.y = destHeight - sourceHeight; 153 break; 154 case SC.ALIGN_TOP_LEFT: 155 result.x = 0; 156 result.y = 0; 157 break; 158 case SC.ALIGN_TOP_RIGHT: 159 result.x = destWidth - sourceWidth; 160 result.y = 0; 161 break; 162 case SC.ALIGN_BOTTOM_LEFT: 163 result.x = 0; 164 result.y = destHeight - sourceHeight; 165 break; 166 case SC.ALIGN_BOTTOM_RIGHT: 167 result.x = destWidth - sourceWidth; 168 result.y = destHeight - sourceHeight; 169 break; 170 default: // SC.ALIGN_CENTER || SC.ALIGN_MIDDLE 171 //@if(debug) 172 if (align !== SC.ALIGN_CENTER && align !== SC.ALIGN_MIDDLE) { 173 SC.Logger.warn("SC.InnerFrame: The align '%@' was not understood. Align must be one of SC.ALIGN_CENTER/SC.ALIGN_MIDDLE, SC.ALIGN_LEFT, SC.ALIGN_RIGHT, SC.ALIGN_TOP, SC.ALIGN_BOTTOM, SC.ALIGN_TOP_LEFT, SC.ALIGN_TOP_RIGHT, SC.ALIGN_BOTTOM_LEFT or SC.ALIGN_BOTTOM_RIGHT.".fmt(align)); 174 } 175 //@endif 176 result.x = (destWidth / 2) - (sourceWidth / 2); 177 result.y = (destHeight / 2) - (sourceHeight / 2); 178 } 179 180 return result; 181 }, 182 183 /** 184 Determines how the shape will scale to fit within its containing space. Possible values: 185 186 - SC.SCALE_NONE 187 - SC.FILL 188 - SC.BEST_FILL 189 - SC.BEST_FIT 190 - SC.BEST_FIT_DOWN_ONLY 191 192 @type String 193 @default SC.FILL 194 */ 195 scale: SC.FILL 196 }; 197