UNPKG

@amoy/components

Version:
345 lines (314 loc) 11 kB
import * as PIXI from 'pixi.js' import { getValue, error } from '../../utils' const isContainer = (target: any) => { return target instanceof PIXI.Container && !(target instanceof PIXI.Sprite ) && !(target instanceof PIXI.Graphics) } export function transform(uiDesignRatio: number = 1) { function rotation(angle: string | number) { if (typeof angle === 'string') { const _angle = angle.trim() const degreeUnit = Math.PI / 180 const hasUnit = _angle.endsWith('deg') if (hasUnit) { const [ degree ] = _angle.split('deg') return parseFloat(degree) * degreeUnit } else { return parseFloat(_angle) } } return angle } function _parseUnit(parentSize: number, value: string) { value = value.trim() if (value.endsWith('px')) { return parseInt(value) } else if (value.endsWith('%')) { return parentSize * parseInt(value) / 100 } else { return parseInt(value) / uiDesignRatio } } function length(parentSize: number, value: string | number) { let result: number = 0 if (typeof value === 'string') result = _parseUnit(parentSize, value) if (typeof value === 'number') result = value / uiDesignRatio return Math.round(result) } function pos(parentSize: number, spriteSize: number, value: number | string) { if (['number', 'string'].includes(typeof value)) { let result: number = 0 if (typeof value === 'number') { result = value / uiDesignRatio } else { if (value.includes(':')) { const [key, number] = value.split(':') switch (key.trim()) { case 'left': case 'top': result = _parseUnit(parentSize, number) break case 'right': case 'bottom': result = parentSize - spriteSize result -= _parseUnit(parentSize, number) break case 'center': result = (parentSize - spriteSize) / 2 result += _parseUnit(parentSize, number) break } } else if (value === 'center') { result = (parentSize - spriteSize) / 2 } else { result = _parseUnit(parentSize, value) } } return Math.round(result) } else { throw error('value must be number or string') } } function actualScale(parent: Layout.element) { const scale = { x: parent.scale.x, y: parent.scale.y, } let _parent = parent.parent while (_parent) { scale.x *= _parent.scale.x scale.y *= _parent.scale.y _parent = _parent.parent } return scale } function getPixiContainerSize(container: PIXI.Container) { if (container.parent) { if (container['isStage']) { return { width: window.innerWidth, height: window.innerHeight, } } else if (container.width > 0 && container.height > 0) { return { width: container.width, height: container.height, } } else if (isContainer(container.parent)) { return getPixiContainerSize(container.parent) } else { return { width: container.parent['width'], height: container.parent['height'], } } } else { return { width: window.innerWidth, height: window.innerHeight, } } } function actualSize(target: any) { if (isContainer(target)) { return getPixiContainerSize(target) } else { const width = getValue(target, 'layout.pixilayout.width') || target.width const height = getValue(target, 'layout.pixilayout.height') || target.height if (target.parent) { const { x: scaleX, y: scaleY } = actualScale(target.parent) return { width: ~~(width * scaleX), height: ~~(height * scaleY), } } else { return { width, height, } } } } function getRatio(target: Layout.element) { if (['sprite', 'animatedsprite'].includes(target['type']) && target['_texture']) { return target['_texture'].width / target['_texture'].height } else { return 1 } } function _getDefaultSize(target: any) { switch (target.type) { case 'animatedsprite': case 'sprite': { return target._texture } case 'text': { if (getValue(target, 'layout.container')) { const { width, height } = target.layout.container return { width, height, } } else { return { width: 1, height: 1, } } } default: { return { width: 1, height: 1, } } } } function elementSize(target: Layout.element, style: Layout.style, parentSize: Layout.size) { const { width, height } = style const { width: targetWidth, height: targetHeight } = _getDefaultSize(target) const { width: parentWidth, height: parentHeight } = parentSize const targetRatio = getRatio(target) let finalWidth = targetWidth / uiDesignRatio let finalHeight = targetHeight / uiDesignRatio if (width) { finalWidth = length(parentWidth, width) if (height) { finalHeight = length(parentHeight, height) } else if (targetRatio) { finalHeight = finalWidth / targetRatio } } else if (height) { finalHeight = length(parentHeight, height) finalWidth = finalHeight * targetRatio } return { width: Math.round(finalWidth), height: Math.round(finalHeight), } } function _getPos(style: any, keyArr: string[]) { let result: number | string = 0 for (let i = 0; i < keyArr.length; i++) { const key = keyArr[i] const value = getValue(style, key) if (value !== undefined) { if (['x', 'y'].includes(key)) { result = value break } else if (key.includes('center')) { result = `center: ${value}` break } else { result = `${key}: ${value}` break } } } return result } function elementPos(targetSize: Layout.size, style: Layout.style, parentSize: Layout.size) { const { rotation: _rotation = 0 } = style const x = _getPos(style, ['x', 'left', 'centerX', 'right', 'center.x']) const y = _getPos(style, ['y', 'top', 'centerY', 'bottom', 'center.y']) const { width: parentWidth, height: parentHeight } = parentSize const { width: targetWidth, height: targetHeight } = targetSize return { x: pos(parentWidth, targetWidth, x), y: pos(parentHeight, targetHeight, y), rotation: rotation(_rotation), } } // 获取父级容器 function container(element: Layout.element) { const { width, height } = actualSize(element) const scale = actualScale(element) return { element, width, height, ratio: width / height, scale, } } function rlayout2pixilayout( container: Layout.containerStatus, anchor: Layout.point, rlayout: Layout.layout, ): Layout.layout { const { width: containerWidth, height: containerHeight, scale: containerScale, element: parent, } = container const { x: scaleX, y: scaleY } = containerScale let { width: sw, height: sh, x: sx, y: sy } = rlayout sx += sw * anchor.x sy += sh * anchor.y if (parent['anchor']) { sx -= containerWidth * parent['anchor'].x sy -= containerHeight * parent['anchor'].y } else if (parent['pivot']) { sx -= containerWidth * parent['pivot'].x sy -= containerHeight * parent['pivot'].y } sw /= scaleX sh /= scaleY sx /= scaleX sy /= scaleY return { width: Math.round(sw), height: Math.round(sh), x: Math.round(sx), y: Math.round(sy), rotation: rlayout.rotation, } } // 反向同步布局信息 function pixilayout2rlayout( container: Layout.containerStatus, anchor: Layout.point, pixilayout: Layout.layout, ): Layout.layout { const { width: containerWidth, height: containerHeight, scale: { x: scaleX, y: scaleY }, element: parent, } = container let { width: sw, height: sh, x: sx, y: sy } = pixilayout sw *= scaleX sh *= scaleY sx *= scaleX sy *= scaleY if (parent['anchor']) { sx += containerWidth * parent['anchor'].x sy += containerHeight * parent['anchor'].y } else if (parent['pivot']) { sx += containerWidth * parent['pivot'].x sy += containerHeight * parent['pivot'].y } sx -= sw * anchor.x sy -= sh * anchor.y return { width: Math.round(sw), height: Math.round(sh), x: Math.round(sx), y: Math.round(sy), rotation: pixilayout.rotation, } } return { rotation, length, pos, actualScale, actualSize, getRatio, elementSize, elementPos, container, rlayout2pixilayout, pixilayout2rlayout, } }