1 /** 2 * Hilo 3 * Copyright 2015 alibaba.com 4 * Licensed under the MIT License 5 */ 6 7 var win = window, 8 doc = document, 9 docElem = doc.documentElement, 10 uid = 0; 11 12 var hasWarnedDict = {}; 13 14 /** 15 * @namespace Hilo的基础核心方法集合。 16 * @static 17 * @module hilo/core/Hilo 18 * @requires hilo/util/browser 19 * @requires hilo/util/util 20 */ 21 var Hilo = { 22 /** 23 * Hilo version 24 * @type String 25 */ 26 version: '{{$version}}', 27 /** 28 * 获取一个全局唯一的id。如Stage1,Bitmap2等。 29 * @param {String} prefix 生成id的前缀。 30 * @returns {String} 全局唯一id。 31 */ 32 getUid: function(prefix) { 33 var id = ++uid; 34 if (prefix) { 35 var charCode = prefix.charCodeAt(prefix.length - 1); 36 if (charCode >= 48 && charCode <= 57) prefix += "_"; //0至9之间添加下划线 37 return prefix + id; 38 } 39 return id; 40 }, 41 42 /** 43 * 为指定的可视对象生成一个包含路径的字符串表示形式。如Stage1.Container2.Bitmap3。 44 * @param {View} view 指定的可视对象。 45 * @returns {String} 可视对象的字符串表示形式。 46 */ 47 viewToString: function(view) { 48 var result, obj = view; 49 while (obj) { 50 result = result ? (obj.id + '.' + result) : obj.id; 51 obj = obj.parent; 52 } 53 return result; 54 }, 55 56 /** 57 * 简单的浅复制对象。 58 * @deprecated 使用 Hilo.util.copy 59 * @param {Object} target 要复制的目标对象。 60 * @param {Object} source 要复制的源对象。 61 * @param {Boolean} strict 指示是否复制未定义的属性,默认为false,即不复制未定义的属性。 62 * @returns {Object} 复制后的对象。 63 */ 64 copy: function(target, source, strict) { 65 util.copy(target, source, strict); 66 if (!hasWarnedDict.copy) { 67 hasWarnedDict.copy = true; 68 console.warn('Hilo.copy has been Deprecated! Use Hilo.util.copy instead.'); 69 } 70 return target; 71 }, 72 73 /** 74 * 浏览器特性集合。 75 * @see browser 76 */ 77 browser: browser, 78 79 /** 80 * 事件类型枚举对象。包括: 81 * <ul> 82 * <li><b>POINTER_START</b> - 鼠标或触碰开始事件。对应touchstart或mousedown。</li> 83 * <li><b>POINTER_MOVE</b> - 鼠标或触碰移动事件。对应touchmove或mousemove。</li> 84 * <li><b>POINTER_END</b> - 鼠标或触碰结束事件。对应touchend或mouseup。</li> 85 * </ul> 86 */ 87 event: { 88 POINTER_START: browser.POINTER_START, 89 POINTER_MOVE: browser.POINTER_MOVE, 90 POINTER_END: browser.POINTER_END 91 }, 92 93 /** 94 * 可视对象对齐方式枚举对象。包括: 95 * <ul> 96 * <li><b>TOP_LEFT</b> - 左上角对齐。</li> 97 * <li><b>TOP</b> - 顶部居中对齐。</li> 98 * <li><b>TOP_RIGHT</b> - 右上角对齐。</li> 99 * <li><b>LEFT</b> - 左边居中对齐。</li> 100 * <li><b>CENTER</b> - 居中对齐。</li> 101 * <li><b>RIGHT</b> - 右边居中对齐。</li> 102 * <li><b>BOTTOM_LEFT</b> - 左下角对齐。</li> 103 * <li><b>BOTTOM</b> - 底部居中对齐。</li> 104 * <li><b>BOTTOM_RIGHT</b> - 右下角对齐。</li> 105 * </ul> 106 */ 107 align: { 108 TOP_LEFT: 'TL', //top & left 109 TOP: 'T', //top & center 110 TOP_RIGHT: 'TR', //top & right 111 LEFT: 'L', //left & center 112 CENTER: 'C', //center 113 RIGHT: 'R', //right & center 114 BOTTOM_LEFT: 'BL', //bottom & left 115 BOTTOM: 'B', //bottom & center 116 BOTTOM_RIGHT: 'BR' //bottom & right 117 }, 118 119 /** 120 * 获取DOM元素在页面中的内容显示区域。 121 * @param {HTMLElement} elem DOM元素。 122 * @returns {Object} DOM元素的可视区域。格式为:{left:0, top:0, width:100, height:100}。 123 */ 124 getElementRect: function(elem) { 125 var bounds; 126 try { 127 //this fails if it's a disconnected DOM node 128 bounds = elem.getBoundingClientRect(); 129 } catch (e) { 130 bounds = { 131 top: elem.offsetTop, 132 left: elem.offsetLeft, 133 right: elem.offsetLeft + elem.offsetWidth, 134 bottom: elem.offsetTop + elem.offsetHeight 135 }; 136 } 137 138 var offsetX = ((win.pageXOffset || docElem.scrollLeft) - (docElem.clientLeft || 0)) || 0; 139 var offsetY = ((win.pageYOffset || docElem.scrollTop) - (docElem.clientTop || 0)) || 0; 140 var styles = win.getComputedStyle ? getComputedStyle(elem) : elem.currentStyle; 141 var parseIntFn = parseInt; 142 143 var padLeft = (parseIntFn(styles.paddingLeft) + parseIntFn(styles.borderLeftWidth)) || 0; 144 var padTop = (parseIntFn(styles.paddingTop) + parseIntFn(styles.borderTopWidth)) || 0; 145 var padRight = (parseIntFn(styles.paddingRight) + parseIntFn(styles.borderRightWidth)) || 0; 146 var padBottom = (parseIntFn(styles.paddingBottom) + parseIntFn(styles.borderBottomWidth)) || 0; 147 148 var top = bounds.top || 0; 149 var left = bounds.left || 0; 150 var right = bounds.right || 0; 151 var bottom = bounds.bottom || 0; 152 153 return { 154 left: left + offsetX + padLeft, 155 top: top + offsetY + padTop, 156 width: right - padRight - left - padLeft, 157 height: bottom - padBottom - top - padTop 158 }; 159 }, 160 161 /** 162 * 创建一个DOM元素。可指定属性和样式。 163 * @param {String} type 要创建的DOM元素的类型。比如:'div'。 164 * @param {Object} properties 指定DOM元素的属性和样式。 165 * @returns {HTMLElement} 一个DOM元素。 166 */ 167 createElement: function(type, properties) { 168 var elem = doc.createElement(type), 169 p, val, s; 170 for (p in properties) { 171 val = properties[p]; 172 if (p === 'style') { 173 for (s in val) elem.style[s] = val[s]; 174 } else { 175 elem[p] = val; 176 } 177 } 178 return elem; 179 }, 180 181 /** 182 * 根据参数id获取一个DOM元素。此方法等价于document.getElementById(id)。 183 * @param {String} id 要获取的DOM元素的id。 184 * @returns {HTMLElement} 一个DOM元素。 185 */ 186 getElement: function(id) { 187 return doc.getElementById(id); 188 }, 189 190 /** 191 * 设置可视对象DOM元素的CSS样式。 192 * @param {View} obj 指定要设置CSS样式的可视对象。 193 * @private 194 */ 195 setElementStyleByView: function(obj) { 196 var drawable = obj.drawable, 197 style = drawable.domElement.style, 198 stateCache = obj._stateCache || (obj._stateCache = {}), 199 prefix = Hilo.browser.jsVendor, 200 px = 'px', 201 flag = false; 202 203 if (this.cacheStateIfChanged(obj, ['visible'], stateCache)) { 204 style.display = !obj.visible ? 'none' : ''; 205 } 206 if (this.cacheStateIfChanged(obj, ['alpha'], stateCache)) { 207 style.opacity = obj.alpha; 208 } 209 if (!obj.visible || obj.alpha <= 0) return; 210 211 if (this.cacheStateIfChanged(obj, ['width'], stateCache)) { 212 style.width = obj.width + px; 213 } 214 if (this.cacheStateIfChanged(obj, ['height'], stateCache)) { 215 style.height = obj.height + px; 216 } 217 if (this.cacheStateIfChanged(obj, ['depth'], stateCache)) { 218 style.zIndex = obj.depth + 1; 219 } 220 if (obj.transform){ 221 var transform = obj.transform; 222 if (flag = this.cacheStateIfChanged(obj, ['pivotX', 'pivotY'], stateCache)) { 223 style[prefix + 'TransformOrigin'] = '0 0'; 224 } 225 style[prefix + 'Transform'] = 'matrix3d(' + transform.a + ', '+ transform.b + ', 0, 0, '+ transform.c + ', '+ transform.d + ', 0, 0, 0, 0, 1, 0, '+ transform.tx + ', '+ transform.ty + ', 0, 1)'; 226 } 227 else{ 228 if (flag = this.cacheStateIfChanged(obj, ['pivotX', 'pivotY'], stateCache)) { 229 style[prefix + 'TransformOrigin'] = obj.pivotX + px + ' ' + obj.pivotY + px; 230 } 231 232 if (this.cacheStateIfChanged(obj, ['x', 'y', 'rotation', 'scaleX', 'scaleY'], stateCache) || flag) { 233 style[prefix + 'Transform'] = this.getTransformCSS(obj); 234 } 235 } 236 237 if (this.cacheStateIfChanged(obj, ['background'], stateCache)) { 238 style.backgroundColor = obj.background; 239 } 240 if (!style.pointerEvents) { 241 style.pointerEvents = 'none'; 242 } 243 244 //render image as background 245 var image = drawable.image; 246 if (image) { 247 var src = image.src; 248 if (src !== stateCache.image) { 249 stateCache.image = src; 250 style.backgroundImage = 'url(' + src + ')'; 251 } 252 253 var rect = drawable.rect; 254 if (rect) { 255 var sx = rect[0], 256 sy = rect[1]; 257 if (sx !== stateCache.sx) { 258 stateCache.sx = sx; 259 style.backgroundPositionX = -sx + px; 260 } 261 if (sy !== stateCache.sy) { 262 stateCache.sy = sy; 263 style.backgroundPositionY = -sy + px; 264 } 265 } 266 } 267 268 //render mask 269 var mask = obj.mask; 270 if (mask) { 271 var maskImage = mask.drawable.domElement.style.backgroundImage; 272 if (maskImage !== stateCache.maskImage) { 273 stateCache.maskImage = maskImage; 274 style[prefix + 'MaskImage'] = maskImage; 275 style[prefix + 'MaskRepeat'] = 'no-repeat'; 276 } 277 278 var maskX = mask.x, 279 maskY = mask.y; 280 if (maskX !== stateCache.maskX || maskY !== stateCache.maskY) { 281 stateCache.maskX = maskX; 282 stateCache.maskY = maskY; 283 style[prefix + 'MaskPosition'] = maskX + px + ' ' + maskY + px; 284 } 285 } 286 }, 287 288 /** 289 * @private 290 */ 291 cacheStateIfChanged: function(obj, propNames, stateCache) { 292 var i, len, name, value, changed = false; 293 for (i = 0, len = propNames.length; i < len; i++) { 294 name = propNames[i]; 295 value = obj[name]; 296 if (value != stateCache[name]) { 297 stateCache[name] = value; 298 changed = true; 299 } 300 } 301 return changed; 302 }, 303 304 /** 305 * 生成可视对象的CSS变换样式。 306 * @param {View} obj 指定生成CSS变换样式的可视对象。 307 * @returns {String} 生成的CSS样式字符串。 308 */ 309 getTransformCSS: function(obj) { 310 var use3d = this.browser.supportTransform3D, 311 str3d = use3d ? '3d' : ''; 312 313 return 'translate' + str3d + '(' + (obj.x - obj.pivotX) + 'px, ' + (obj.y - obj.pivotY) + (use3d ? 'px, 0px)' : 'px)') + 314 'rotate' + str3d + (use3d ? '(0, 0, 1, ' : '(') + obj.rotation + 'deg)' + 315 'scale' + str3d + '(' + obj.scaleX + ', ' + obj.scaleY + (use3d ? ', 1)' : ')'); 316 } 317 };