UNPKG

tinyjs-plugin-ui

Version:
308 lines (275 loc) 7.73 kB
import UIBase from './UIBase'; /** * 九宫格 * * @description * * <pre> * -----------— * | 1 | 2 | 3 | * ------------- * | 4 | 5 | 6 | * ------------- * | 7 | 8 | 9 | * ------------- * scale9Grid=[a, b, c, d] 表示: * - a:区域1 的宽度值 * - b:区域1 的高度值 * - c:区域2 的宽度值,取值范围是 [宽度 < 源图片宽 ? 源图片宽 - 宽度 : 1, 源图片宽 - a] * - d:区域4 的高度值,取值范围是 [高度 < 源图片高 ? 源图片高 - 高度 : 1, 源图片高 - b] * </pre> * * @example * var np = new Tiny.ui.NinePatch( * Tiny.Texture.fromImage('https://gw.alipayobjects.com/zos/rmsportal/ipdnmCVbXeVBPprGCYlW.png'), * 200, * 300, * [30, 30, 100, 100] * ); * np.setPosition(10, 10); * * @class * @extends Tiny.ui.UIBase * @memberof Tiny.ui * @version 0.1.0 */ class NinePatch extends UIBase { /** * @constructor * @param {Tiny.BaseTexture} texture - 九宫格纹理 * @param {number} width - 宽度 * @param {number} height - 高度 * @param {Array<Number>} scale9Grid - 九宫格定义 * @param {Array<Number>} [overlapPadding=1] - Canvas 渲染模式下可能会有缝隙,用这个来修复,默认是1 */ constructor(texture, width, height, scale9Grid, overlapPadding = 1) { super(); this._gridTexture = texture; this._debugDraw = false; /** * 存储九宫格纹理 * * @private */ this._textures = []; /** * 存储九宫格 Sprite 对象 * * @private */ this._gridSprites = []; /** * 真实宽度 * * @private */ this._targetWidth = width || 0; /** * 真实高度 * * @private */ this._targetHeight = height || 0; /** * 素材的原始尺寸 * * @private */ this._textureOrigFrame = new Tiny.Rectangle(0, 0, this._gridTexture.width, this._gridTexture.height); /** * 九宫格设置 * * @private */ this._scale9Grid = null; this._gridData = {}; this._overlapPadding = overlapPadding; this._inited = false; this.scale9Grid = scale9Grid; if (this._gridTexture.baseTexture.hasLoaded) { this._onGridTextureUpdate(); } else { this._gridTexture.once('update', this._onGridTextureUpdate, this); } } _onGridTextureUpdate() { this._init(); this._update(); } /** * 根据 scale9Grid 初始化9宫格基础 texture 和 sprite */ _init() { if (this._inited) return; this._inited = true; for (let i = 0; i < 9; i++) { const t = new Tiny.Texture( this._gridTexture, this._gridTexture.frame, this._gridTexture.orig, null, 0 ); this._textures.push(t); const child = new Tiny.Sprite(t); child.visible = false; this._gridSprites.push(child); this.addChild(child); } // 初始化九宫格每个 sprite const scale9Grid = this._scale9Grid; const w1 = scale9Grid[0]; const w2 = Math.max(0, scale9Grid[2]); const w3 = Math.max(0, this._gridTexture.width - w1 - w2); const h1 = scale9Grid[1]; const h2 = Math.max(0, scale9Grid[3]); const h3 = Math.max(0, this._gridTexture.height - h1 - h2); const wArr = [w1, w2, w3]; const xArr = [0, w1, w1 + w2]; const hArr = [h1, h2, h3]; const yArr = [0, h1, h1 + h2]; this._gridData = { wArr, xArr, hArr, yArr }; for (let row = 0; row < 3; row++) { for (let col = 0; col < 3; col++) { const i = row * 3 + col; const frame = new Tiny.Rectangle(...this._offsetFrame(i, xArr[col], yArr[row]), wArr[col], hArr[row]); this._textures[i].frame = frame; } } } /** * @name Tiny.ui.NinePatch#debug * @property {boolean} debug - 是否开启调试模式 默认false */ get debug() { return this._debugDraw; } set debug(value) { this._debugDraw = value; this._update(); } /** * @name Tiny.ui.NinePatch#scale9Grid * @property {string | Array} scale9Grid - 九宫格数据 "30,10,10,5" 或者 [30,10,10,5] */ get scale9Grid() { return this._scale9Grid; } set scale9Grid(value) { if (value) { let newGrid = typeof value === 'string' ? value.split(',') : value; if (newGrid.length !== 4) { console.error('error scale9Grid format', value); return; } newGrid = newGrid.map((e) => parseFloat(e)); this._scale9Grid = newGrid; } else { this._scale9Grid = [0, 0, 0, 0]; } this._update(); } /** * @name Tiny.ui.NinePatch#width * @property {number} width - 宽度 */ get width() { return this._targetWidth || this._gridTexture.width; } set width(value) { this._targetWidth = value; this._update(); } /** * @name Tiny.ui.NinePatch#height * @property {number} height - 高度 */ get height() { return this._targetHeight || this._gridTexture.height; } set height(value) { this._targetHeight = value; this._update(); } /** * @name Tiny.ui.NinePatch#overlapPadding * @property {number} overlapPadding - 九宫格之间的重合度,Canvas 渲染模式下可能会有缝隙,用这个来修复,默认是1 */ get overlapPadding() { return this._overlapPadding; } set overlapPadding(value) { this._overlapPadding = +value || 0; this._update(); } /** * 改变尺寸 * * @param {number} width - 宽度 * @param {number} height - 高度 */ resize(width, height) { this._targetWidth = width; this._targetHeight = height; this._update(); } /** * 定位到正确的位置,tileset纹理 * * @private * @param {number} index * @param {number} x * @param {number} y * @return {number[]} */ _offsetFrame(index, x, y) { const frameX = this._textures[index].frame.x || 0; const frameY = this._textures[index].frame.y || 0; const offsetX = frameX + x; const offsetY = frameY + y; return [offsetX, offsetY]; } /** * 更新 * * @private * @param {number} [width=null] * @param {number} [height=null] */ _update() { if (!this._gridTexture) return; if (!this._gridTexture.baseTexture.hasLoaded) return; if (!this._inited) return; // 容错 if (this.width < this._gridTexture.width || this.height < this._gridTexture.height) { console.warn('九宫格尺寸设置异常,尺寸不能小于素材尺寸'); } const realWidth = Math.max(this.width, this._gridTexture.width); const realHeight = Math.max(this.height, this._gridTexture.height); const { wArr, hArr } = this._gridData; const overlapPadding = this.overlapPadding; for (let row = 0; row < 3; row++) { for (let col = 0; col < 3; col++) { const i = row * 3 + col; const child = this._gridSprites[i]; const w = (col === 0 || col === 2) ? wArr[col] : Math.max(0, realWidth - wArr[0] - wArr[2]); const h = (row === 0 || row === 2) ? hArr[row] : Math.max(0, realHeight - hArr[0] - hArr[2]); const x = col === 0 ? 0 : col === 1 ? wArr[0] : Math.max(0, realWidth - wArr[2]); const y = row === 0 ? 0 : row === 1 ? hArr[0] : Math.max(0, realHeight - hArr[2]); if (w > 0 && h > 0) { child.anchor.set(0, 0); child.x = x - col * overlapPadding; child.y = y - row * overlapPadding; child.alpha = this._debugDraw ? (0.1 + i * 0.05) : 1; child.width = w; child.height = h; child.visible = true; } else { child.visible = false; } } } this.emit('resize'); } } export default NinePatch;